Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/arm/arm32 PR port-arm/49299: add support for BE8 by...
details: https://anonhg.NetBSD.org/src/rev/565187f095f9
branches: trunk
changeset: 333542:565187f095f9
user: martin <martin%NetBSD.org@localhost>
date: Fri Nov 07 21:28:32 2014 +0000
description:
PR port-arm/49299: add support for BE8 byte swapped instructions.
diffstat:
sys/arch/arm/arm32/kobj_machdep.c | 198 +++++++++++++++++++++++++++++++++++++-
1 files changed, 196 insertions(+), 2 deletions(-)
diffs (233 lines):
diff -r c365293d8a6b -r 565187f095f9 sys/arch/arm/arm32/kobj_machdep.c
--- a/sys/arch/arm/arm32/kobj_machdep.c Fri Nov 07 20:59:38 2014 +0000
+++ b/sys/arch/arm/arm32/kobj_machdep.c Fri Nov 07 21:28:32 2014 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: kobj_machdep.c,v 1.9 2013/08/27 06:41:05 skrll Exp $ */
+/* $NetBSD: kobj_machdep.c,v 1.10 2014/11/07 21:28:32 martin Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -52,7 +52,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kobj_machdep.c,v 1.9 2013/08/27 06:41:05 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kobj_machdep.c,v 1.10 2014/11/07 21:28:32 martin Exp $");
#define ELFSIZE ARCH_ELFSIZE
@@ -61,8 +61,12 @@
#include <sys/kobj.h>
#include <sys/exec.h>
#include <sys/exec_elf.h>
+#include <sys/kmem.h>
+#include <sys/ksyms.h>
+#include <sys/kobj_impl.h>
#include <arm/cpufunc.h>
+#include <arm/locore.h>
int
kobj_reloc(kobj_t ko, uintptr_t relocbase, const void *data,
@@ -203,11 +207,201 @@
return -1;
}
+#if __ARMEB__
+
+enum be8_magic_sym_type {
+ Other, ArmStart, ThumbStart, DataStart
+};
+
+struct be8_marker {
+ enum be8_magic_sym_type type;
+ void *addr;
+};
+
+struct be8_marker_list {
+ size_t cnt;
+ struct be8_marker *markers;
+};
+
+/*
+ * See ELF for the ARM Architecture, Section 4.5.5: Mapping Symbols
+ * ARM reserves $a/$d/$t (and variants like $a.2) to mark start of
+ * arm/thumb code sections to allow conversion from ARM32-EB to -BE8
+ * format.
+ */
+static enum be8_magic_sym_type
+be8_sym_type(const char *name, int info)
+{
+ if (ELF_ST_BIND(info) != STB_LOCAL)
+ return Other;
+ if (ELF_ST_TYPE(info) != STT_NOTYPE)
+ return Other;
+ if (name[0] != '$' || name[1] == '\0' ||
+ (name[2] != '\0' && name[2] != '.'))
+ return Other;
+
+ switch (name[1]) {
+ case 'a':
+ return ArmStart;
+ case 'd':
+ return DataStart;
+ case 't':
+ return ThumbStart;
+ default:
+ return Other;
+ }
+}
+
+static int
+be8_ksym_count(const char *name, int symindex, void *value, uint32_t size,
+ int info, void *cookie)
+{
+ size_t *res = cookie;
+ enum be8_magic_sym_type t = be8_sym_type(name, info);
+
+ if (t != Other)
+ (*res)++;
+ return 0;
+}
+
+static int
+be8_ksym_add(const char *name, int symindex, void *value, uint32_t size,
+ int info, void *cookie)
+{
+ size_t ndx;
+ struct be8_marker_list *list = cookie;
+ enum be8_magic_sym_type t = be8_sym_type(name, info);
+
+ if (t == Other)
+ return 0;
+
+ ndx = list->cnt++;
+ list->markers[ndx].type = t;
+ list->markers[ndx].addr = value;
+
+ return 0;
+}
+
+static int
+be8_ksym_comp(const void *a, const void *b)
+{
+ const struct be8_marker *ma = a, *mb = b;
+ uintptr_t va = (uintptr_t)ma->addr, vb = (uintptr_t)mb->addr;
+
+ if (va == vb)
+ return 0;
+ if (va < vb)
+ return -1;
+ return 1;
+}
+
+static void
+be8_ksym_swap(void *start, size_t size, const struct be8_marker_list *list)
+{
+ uintptr_t va_end = (uintptr_t)start + size;
+ size_t i;
+ uint32_t *p32, *p32_end, v32;
+ uint16_t *p16, *p16_end, v16;
+
+ /* find first relevant list entry */
+ for (i = 0; i < list->cnt; i++)
+ if (start <= list->markers[i].addr)
+ break;
+
+ /* swap all arm and thumb code parts of this section */
+ for ( ; i < list->cnt; i++) {
+ switch (list->markers[i].type) {
+ case ArmStart:
+ p32 = (uint32_t*)list->markers[i].addr;
+ p32_end = (uint32_t*)va_end;
+ if (i+1 < list->cnt) {
+ if ((uintptr_t)list->markers[i+1].addr
+ < va_end)
+ p32_end = (uint32_t*)
+ list->markers[i+1].addr;
+ }
+ while (p32 < p32_end) {
+ v32 = bswap32(*p32);
+ *p32++ = v32;
+ }
+ break;
+ case ThumbStart:
+ p16 = (uint16_t*)list->markers[i].addr;
+ p16_end = (uint16_t*)va_end;
+ if (i+1 < list->cnt) {
+ if ((uintptr_t)list->markers[i+1].addr
+ < va_end)
+ p16_end = (uint16_t*)
+ list->markers[i+1].addr;
+ }
+ while (p16 < p16_end) {
+ v16 = bswap16(*p16);
+ *p16++ = v16;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void
+kobj_be8_fixup(kobj_t ko)
+{
+ size_t relsym_cnt = 0, i, msize;
+ struct be8_marker_list list;
+ struct be8_marker tmp;
+
+ /*
+ * Count all special relocations symbols
+ */
+ ksyms_mod_foreach(ko->ko_name, be8_ksym_count, &relsym_cnt);
+
+ /*
+ * Provide storage for the address list and add the symbols
+ */
+ list.cnt = 0;
+ msize = relsym_cnt*sizeof(*list.markers);
+ list.markers = kmem_alloc(msize, KM_SLEEP);
+ ksyms_mod_foreach(ko->ko_name, be8_ksym_add, &list);
+ KASSERT(list.cnt == relsym_cnt);
+
+ /*
+ * Sort symbols by ascending address
+ */
+ if (kheapsort(list.markers, relsym_cnt, sizeof(*list.markers),
+ be8_ksym_comp, &tmp) != 0)
+ panic("could not sort be8 marker symbols");
+
+ /*
+ * Apply swaps to the .text section (XXX we do not have the
+ * section header available any more, it has been jetisoned
+ * already, so we can not check for all PROGBIT sections).
+ */
+ for (i = 0; i < ko->ko_nprogtab; i++) {
+ if (strcmp(ko->ko_progtab[i].name, ".text") != 0)
+ continue;
+ be8_ksym_swap(ko->ko_progtab[i].addr,
+ (size_t)ko->ko_progtab[i].size,
+ &list);
+ }
+
+ /*
+ * Done, free list
+ */
+ kmem_free(list.markers, msize);
+}
+#endif
+
int
kobj_machdep(kobj_t ko, void *base, size_t size, bool load)
{
if (load) {
+#if __ARMEB__
+ if (CPU_IS_ARMV7_P())
+ kobj_be8_fixup(ko);
+#endif
#ifndef _RUMPKERNEL
cpu_idcache_wbinv_range((vaddr_t)base, size);
cpu_tlb_flushID();
Home |
Main Index |
Thread Index |
Old Index