Fri Nov 7 21:28:32 2014 UTC ()
PR port-arm/49299: add support for BE8 byte swapped instructions.


(martin)
diff -r1.9 -r1.10 src/sys/arch/arm/arm32/kobj_machdep.c

cvs diff -r1.9 -r1.10 src/sys/arch/arm/arm32/kobj_machdep.c (expand / switch to unified diff)

--- src/sys/arch/arm/arm32/kobj_machdep.c 2013/08/27 06:41:05 1.9
+++ src/sys/arch/arm/arm32/kobj_machdep.c 2014/11/07 21:28:32 1.10
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: kobj_machdep.c,v 1.9 2013/08/27 06:41:05 skrll Exp $ */ 1/* $NetBSD: kobj_machdep.c,v 1.10 2014/11/07 21:28:32 martin Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2008 The NetBSD Foundation, Inc. 4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -42,37 +42,41 @@ @@ -42,37 +42,41 @@
42 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 42 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
43 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 43 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
44 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 44 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
45 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 45 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
46 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
47 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 47 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
48 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 48 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
49 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 49 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
50 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 50 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
51 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 51 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 */ 52 */
53 53
54#include <sys/cdefs.h> 54#include <sys/cdefs.h>
55__KERNEL_RCSID(0, "$NetBSD: kobj_machdep.c,v 1.9 2013/08/27 06:41:05 skrll Exp $"); 55__KERNEL_RCSID(0, "$NetBSD: kobj_machdep.c,v 1.10 2014/11/07 21:28:32 martin Exp $");
56 56
57#define ELFSIZE ARCH_ELFSIZE 57#define ELFSIZE ARCH_ELFSIZE
58 58
59#include <sys/param.h> 59#include <sys/param.h>
60#include <sys/systm.h> 60#include <sys/systm.h>
61#include <sys/kobj.h> 61#include <sys/kobj.h>
62#include <sys/exec.h> 62#include <sys/exec.h>
63#include <sys/exec_elf.h> 63#include <sys/exec_elf.h>
 64#include <sys/kmem.h>
 65#include <sys/ksyms.h>
 66#include <sys/kobj_impl.h>
64 67
65#include <arm/cpufunc.h> 68#include <arm/cpufunc.h>
 69#include <arm/locore.h>
66 70
67int 71int
68kobj_reloc(kobj_t ko, uintptr_t relocbase, const void *data, 72kobj_reloc(kobj_t ko, uintptr_t relocbase, const void *data,
69 bool isrela, bool local) 73 bool isrela, bool local)
70{ 74{
71 Elf_Addr *where; 75 Elf_Addr *where;
72 Elf_Addr addr; 76 Elf_Addr addr;
73 Elf_Addr addend; 77 Elf_Addr addend;
74 Elf_Word rtype, symidx; 78 Elf_Word rtype, symidx;
75 const Elf_Rel *rel; 79 const Elf_Rel *rel;
76 const Elf_Rela *rela; 80 const Elf_Rela *rela;
77 81
78 if (isrela) { 82 if (isrela) {
@@ -193,26 +197,216 @@ kobj_reloc(kobj_t ko, uintptr_t relocbas @@ -193,26 +197,216 @@ kobj_reloc(kobj_t ko, uintptr_t relocbas
193 } 197 }
194 198
195 *where = (*where & 0x80000000) | (addend & 0x7fffffff); 199 *where = (*where & 0x80000000) | (addend & 0x7fffffff);
196 200
197 default: 201 default:
198 break; 202 break;
199 } 203 }
200 204
201 printf("kobj_reloc: unexpected/invalid relocation type %d @ %p symidx %u\n", 205 printf("kobj_reloc: unexpected/invalid relocation type %d @ %p symidx %u\n",
202 rtype, where, symidx); 206 rtype, where, symidx);
203 return -1; 207 return -1;
204} 208}
205 209
 210#if __ARMEB__
 211
 212enum be8_magic_sym_type {
 213 Other, ArmStart, ThumbStart, DataStart
 214};
 215
 216struct be8_marker {
 217 enum be8_magic_sym_type type;
 218 void *addr;
 219};
 220
 221struct be8_marker_list {
 222 size_t cnt;
 223 struct be8_marker *markers;
 224};
 225
 226/*
 227 * See ELF for the ARM Architecture, Section 4.5.5: Mapping Symbols
 228 * ARM reserves $a/$d/$t (and variants like $a.2) to mark start of
 229 * arm/thumb code sections to allow conversion from ARM32-EB to -BE8
 230 * format.
 231 */
 232static enum be8_magic_sym_type
 233be8_sym_type(const char *name, int info)
 234{
 235 if (ELF_ST_BIND(info) != STB_LOCAL)
 236 return Other;
 237 if (ELF_ST_TYPE(info) != STT_NOTYPE)
 238 return Other;
 239 if (name[0] != '$' || name[1] == '\0' ||
 240 (name[2] != '\0' && name[2] != '.'))
 241 return Other;
 242
 243 switch (name[1]) {
 244 case 'a':
 245 return ArmStart;
 246 case 'd':
 247 return DataStart;
 248 case 't':
 249 return ThumbStart;
 250 default:
 251 return Other;
 252 }
 253}
 254
 255static int
 256be8_ksym_count(const char *name, int symindex, void *value, uint32_t size,
 257 int info, void *cookie)
 258{
 259 size_t *res = cookie;
 260 enum be8_magic_sym_type t = be8_sym_type(name, info);
 261
 262 if (t != Other)
 263 (*res)++;
 264 return 0;
 265}
 266
 267static int
 268be8_ksym_add(const char *name, int symindex, void *value, uint32_t size,
 269 int info, void *cookie)
 270{
 271 size_t ndx;
 272 struct be8_marker_list *list = cookie;
 273 enum be8_magic_sym_type t = be8_sym_type(name, info);
 274
 275 if (t == Other)
 276 return 0;
 277
 278 ndx = list->cnt++;
 279 list->markers[ndx].type = t;
 280 list->markers[ndx].addr = value;
 281
 282 return 0;
 283}
 284
 285static int
 286be8_ksym_comp(const void *a, const void *b)
 287{
 288 const struct be8_marker *ma = a, *mb = b;
 289 uintptr_t va = (uintptr_t)ma->addr, vb = (uintptr_t)mb->addr;
 290
 291 if (va == vb)
 292 return 0;
 293 if (va < vb)
 294 return -1;
 295 return 1;
 296}
 297
 298static void
 299be8_ksym_swap(void *start, size_t size, const struct be8_marker_list *list)
 300{
 301 uintptr_t va_end = (uintptr_t)start + size;
 302 size_t i;
 303 uint32_t *p32, *p32_end, v32;
 304 uint16_t *p16, *p16_end, v16;
 305
 306 /* find first relevant list entry */
 307 for (i = 0; i < list->cnt; i++)
 308 if (start <= list->markers[i].addr)
 309 break;
 310
 311 /* swap all arm and thumb code parts of this section */
 312 for ( ; i < list->cnt; i++) {
 313 switch (list->markers[i].type) {
 314 case ArmStart:
 315 p32 = (uint32_t*)list->markers[i].addr;
 316 p32_end = (uint32_t*)va_end;
 317 if (i+1 < list->cnt) {
 318 if ((uintptr_t)list->markers[i+1].addr
 319 < va_end)
 320 p32_end = (uint32_t*)
 321 list->markers[i+1].addr;
 322 }
 323 while (p32 < p32_end) {
 324 v32 = bswap32(*p32);
 325 *p32++ = v32;
 326 }
 327 break;
 328 case ThumbStart:
 329 p16 = (uint16_t*)list->markers[i].addr;
 330 p16_end = (uint16_t*)va_end;
 331 if (i+1 < list->cnt) {
 332 if ((uintptr_t)list->markers[i+1].addr
 333 < va_end)
 334 p16_end = (uint16_t*)
 335 list->markers[i+1].addr;
 336 }
 337 while (p16 < p16_end) {
 338 v16 = bswap16(*p16);
 339 *p16++ = v16;
 340 }
 341 break;
 342 default:
 343 break;
 344 }
 345 }
 346}
 347
 348static void
 349kobj_be8_fixup(kobj_t ko)
 350{
 351 size_t relsym_cnt = 0, i, msize;
 352 struct be8_marker_list list;
 353 struct be8_marker tmp;
 354
 355 /*
 356 * Count all special relocations symbols
 357 */
 358 ksyms_mod_foreach(ko->ko_name, be8_ksym_count, &relsym_cnt);
 359
 360 /*
 361 * Provide storage for the address list and add the symbols
 362 */
 363 list.cnt = 0;
 364 msize = relsym_cnt*sizeof(*list.markers);
 365 list.markers = kmem_alloc(msize, KM_SLEEP);
 366 ksyms_mod_foreach(ko->ko_name, be8_ksym_add, &list);
 367 KASSERT(list.cnt == relsym_cnt);
 368
 369 /*
 370 * Sort symbols by ascending address
 371 */
 372 if (kheapsort(list.markers, relsym_cnt, sizeof(*list.markers),
 373 be8_ksym_comp, &tmp) != 0)
 374 panic("could not sort be8 marker symbols");
 375
 376 /*
 377 * Apply swaps to the .text section (XXX we do not have the
 378 * section header available any more, it has been jetisoned
 379 * already, so we can not check for all PROGBIT sections).
 380 */
 381 for (i = 0; i < ko->ko_nprogtab; i++) {
 382 if (strcmp(ko->ko_progtab[i].name, ".text") != 0)
 383 continue;
 384 be8_ksym_swap(ko->ko_progtab[i].addr,
 385 (size_t)ko->ko_progtab[i].size,
 386 &list);
 387 }
 388
 389 /*
 390 * Done, free list
 391 */
 392 kmem_free(list.markers, msize);
 393}
 394#endif
 395
206int 396int
207kobj_machdep(kobj_t ko, void *base, size_t size, bool load) 397kobj_machdep(kobj_t ko, void *base, size_t size, bool load)
208{ 398{
209 399
210 if (load) { 400 if (load) {
 401#if __ARMEB__
 402 if (CPU_IS_ARMV7_P())
 403 kobj_be8_fixup(ko);
 404#endif
211#ifndef _RUMPKERNEL 405#ifndef _RUMPKERNEL
212 cpu_idcache_wbinv_range((vaddr_t)base, size); 406 cpu_idcache_wbinv_range((vaddr_t)base, size);
213 cpu_tlb_flushID(); 407 cpu_tlb_flushID();
214#endif 408#endif
215 } 409 }
216 410
217 return 0; 411 return 0;
218} 412}