| @@ -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 | |
67 | int | | 71 | int |
68 | kobj_reloc(kobj_t ko, uintptr_t relocbase, const void *data, | | 72 | kobj_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 | |
| | | 212 | enum be8_magic_sym_type { |
| | | 213 | Other, ArmStart, ThumbStart, DataStart |
| | | 214 | }; |
| | | 215 | |
| | | 216 | struct be8_marker { |
| | | 217 | enum be8_magic_sym_type type; |
| | | 218 | void *addr; |
| | | 219 | }; |
| | | 220 | |
| | | 221 | struct 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 | */ |
| | | 232 | static enum be8_magic_sym_type |
| | | 233 | be8_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 | |
| | | 255 | static int |
| | | 256 | be8_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 | |
| | | 267 | static int |
| | | 268 | be8_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 | |
| | | 285 | static int |
| | | 286 | be8_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 | |
| | | 298 | static void |
| | | 299 | be8_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 | |
| | | 348 | static void |
| | | 349 | kobj_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 | |
206 | int | | 396 | int |
207 | kobj_machdep(kobj_t ko, void *base, size_t size, bool load) | | 397 | kobj_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 | } |