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