1 1.16 skrll /* $NetBSD: kobj_machdep.c,v 1.16 2023/04/28 07:33:56 skrll Exp $ */ 2 1.1 ad 3 1.1 ad /*- 4 1.1 ad * Copyright (c) 2008 The NetBSD Foundation, Inc. 5 1.1 ad * All rights reserved. 6 1.1 ad * 7 1.1 ad * Redistribution and use in source and binary forms, with or without 8 1.1 ad * modification, are permitted provided that the following conditions 9 1.1 ad * are met: 10 1.1 ad * 1. Redistributions of source code must retain the above copyright 11 1.1 ad * notice, this list of conditions and the following disclaimer. 12 1.1 ad * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 ad * notice, this list of conditions and the following disclaimer in the 14 1.1 ad * documentation and/or other materials provided with the distribution. 15 1.1 ad * 16 1.1 ad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 1.1 ad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.1 ad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 ad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.1 ad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.1 ad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.1 ad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 ad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.1 ad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.1 ad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.1 ad * POSSIBILITY OF SUCH DAMAGE. 27 1.1 ad */ 28 1.1 ad 29 1.1 ad /*- 30 1.1 ad * Copyright 1996-1998 John D. Polstra. 31 1.1 ad * All rights reserved. 32 1.1 ad * 33 1.1 ad * Redistribution and use in source and binary forms, with or without 34 1.1 ad * modification, are permitted provided that the following conditions 35 1.1 ad * are met: 36 1.1 ad * 1. Redistributions of source code must retain the above copyright 37 1.1 ad * notice, this list of conditions and the following disclaimer. 38 1.1 ad * 2. Redistributions in binary form must reproduce the above copyright 39 1.1 ad * notice, this list of conditions and the following disclaimer in the 40 1.1 ad * documentation and/or other materials provided with the distribution. 41 1.1 ad * 42 1.1 ad * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 43 1.1 ad * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 44 1.1 ad * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 45 1.1 ad * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 46 1.1 ad * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 47 1.1 ad * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 48 1.1 ad * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 49 1.1 ad * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 50 1.1 ad * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 51 1.1 ad * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 52 1.1 ad */ 53 1.1 ad 54 1.1 ad #include <sys/cdefs.h> 55 1.16 skrll __KERNEL_RCSID(0, "$NetBSD: kobj_machdep.c,v 1.16 2023/04/28 07:33:56 skrll Exp $"); 56 1.1 ad 57 1.1 ad #define ELFSIZE ARCH_ELFSIZE 58 1.1 ad 59 1.1 ad #include <sys/param.h> 60 1.14 skrll 61 1.1 ad #include <sys/exec.h> 62 1.1 ad #include <sys/exec_elf.h> 63 1.10 martin #include <sys/kmem.h> 64 1.14 skrll #include <sys/kobj.h> 65 1.14 skrll #include <sys/kobj_impl.h> 66 1.10 martin #include <sys/ksyms.h> 67 1.14 skrll #include <sys/systm.h> 68 1.1 ad 69 1.1 ad #include <arm/cpufunc.h> 70 1.10 martin #include <arm/locore.h> 71 1.1 ad 72 1.1 ad int 73 1.1 ad kobj_reloc(kobj_t ko, uintptr_t relocbase, const void *data, 74 1.1 ad bool isrela, bool local) 75 1.1 ad { 76 1.1 ad Elf_Addr *where; 77 1.1 ad Elf_Addr addr; 78 1.1 ad Elf_Addr addend; 79 1.1 ad Elf_Word rtype, symidx; 80 1.1 ad const Elf_Rel *rel; 81 1.1 ad const Elf_Rela *rela; 82 1.12 maxv int error; 83 1.1 ad 84 1.1 ad if (isrela) { 85 1.1 ad rela = (const Elf_Rela *)data; 86 1.1 ad where = (Elf_Addr *) (relocbase + rela->r_offset); 87 1.1 ad addend = rela->r_addend; 88 1.1 ad rtype = ELF_R_TYPE(rela->r_info); 89 1.1 ad symidx = ELF_R_SYM(rela->r_info); 90 1.1 ad } else { 91 1.1 ad rel = (const Elf_Rel *)data; 92 1.1 ad where = (Elf_Addr *) (relocbase + rel->r_offset); 93 1.1 ad addend = *where; 94 1.1 ad rtype = ELF_R_TYPE(rel->r_info); 95 1.1 ad symidx = ELF_R_SYM(rel->r_info); 96 1.1 ad } 97 1.1 ad 98 1.16 skrll const Elf_Sym *sym = kobj_symbol(ko, symidx); 99 1.16 skrll 100 1.16 skrll if (!local && ELF_ST_BIND(sym->st_info) == STB_LOCAL) { 101 1.16 skrll return 0; 102 1.16 skrll } 103 1.16 skrll 104 1.1 ad switch (rtype) { 105 1.1 ad case R_ARM_NONE: /* none */ 106 1.4 matt case R_ARM_V4BX: /* none */ 107 1.3 dsl return 0; 108 1.1 ad 109 1.1 ad case R_ARM_ABS32: 110 1.12 maxv error = kobj_sym_lookup(ko, symidx, &addr); 111 1.12 maxv if (error) 112 1.3 dsl break; 113 1.3 dsl *where = addr + addend; 114 1.3 dsl return 0; 115 1.1 ad 116 1.3 dsl case R_ARM_COPY: /* none */ 117 1.3 dsl /* There shouldn't be copy relocations in kernel objects. */ 118 1.1 ad break; 119 1.1 ad 120 1.1 ad case R_ARM_JUMP_SLOT: 121 1.12 maxv error = kobj_sym_lookup(ko, symidx, &addr); 122 1.12 maxv if (error) 123 1.3 dsl break; 124 1.3 dsl *where = addr; 125 1.3 dsl return 0; 126 1.1 ad 127 1.1 ad case R_ARM_RELATIVE: /* A + B */ 128 1.1 ad addr = relocbase + addend; 129 1.1 ad if (*where != addr) 130 1.1 ad *where = addr; 131 1.3 dsl return 0; 132 1.3 dsl 133 1.8 skrll case R_ARM_MOVW_ABS_NC: /* (S + A) | T */ 134 1.4 matt case R_ARM_MOVT_ABS: 135 1.7 matt if ((*where & 0x0fb00000) != 0x03000000) 136 1.7 matt break; 137 1.12 maxv error = kobj_sym_lookup(ko, symidx, &addr); 138 1.12 maxv if (error) 139 1.4 matt break; 140 1.4 matt if (rtype == R_ARM_MOVT_ABS) 141 1.4 matt addr >>= 16; 142 1.4 matt *where = (*where & 0xfff0f000) 143 1.4 matt | ((addr << 4) & 0x000f0000) | (addr & 0x00000fff); 144 1.4 matt return 0; 145 1.4 matt 146 1.8 skrll case R_ARM_CALL: /* ((S + A) | T) - P */ 147 1.4 matt case R_ARM_JUMP24: 148 1.8 skrll case R_ARM_PC24: /* Deprecated */ 149 1.4 matt if (local && (*where & 0x00ffffff) != 0x00fffffe) 150 1.3 dsl return 0; 151 1.3 dsl 152 1.3 dsl /* Remove the instruction from the 24 bit offset */ 153 1.3 dsl addend &= 0x00ffffff; 154 1.3 dsl 155 1.3 dsl /* Sign extend if necessary */ 156 1.3 dsl if (addend & 0x00800000) 157 1.3 dsl addend |= 0xff000000; 158 1.3 dsl 159 1.4 matt addend <<= 2; 160 1.4 matt 161 1.12 maxv error = kobj_sym_lookup(ko, symidx, &addr); 162 1.12 maxv if (error) 163 1.3 dsl break; 164 1.3 dsl 165 1.6 matt addend += (uintptr_t)addr - (uintptr_t)where; 166 1.3 dsl 167 1.4 matt if (addend & 3) { 168 1.4 matt printf ("Relocation %x unaligned @ %p\n", addend, where); 169 1.4 matt return -1; 170 1.4 matt } 171 1.4 matt 172 1.4 matt if ((addend & 0xfe000000) != 0x00000000 && 173 1.4 matt (addend & 0xfe000000) != 0xfe000000) { 174 1.3 dsl printf ("Relocation %x too far @ %p\n", addend, where); 175 1.3 dsl return -1; 176 1.3 dsl } 177 1.4 matt *where = (*where & 0xff000000) | ((addend >> 2) & 0x00ffffff); 178 1.3 dsl return 0; 179 1.1 ad 180 1.8 skrll case R_ARM_REL32: /* ((S + A) | T) - P */ 181 1.8 skrll /* T = 0 for now */ 182 1.12 maxv error = kobj_sym_lookup(ko, symidx, &addr); 183 1.12 maxv if (error) 184 1.8 skrll break; 185 1.8 skrll 186 1.8 skrll addend += (uintptr_t)addr - (uintptr_t)where; 187 1.8 skrll *where = addend; 188 1.8 skrll return 0; 189 1.8 skrll 190 1.8 skrll case R_ARM_PREL31: /* ((S + A) | T) - P */ 191 1.8 skrll /* Sign extend if necessary */ 192 1.8 skrll if (addend & 0x40000000) 193 1.8 skrll addend |= 0xc0000000; 194 1.8 skrll /* T = 0 for now */ 195 1.12 maxv error = kobj_sym_lookup(ko, symidx, &addr); 196 1.12 maxv if (error) 197 1.8 skrll break; 198 1.8 skrll 199 1.8 skrll addend += (uintptr_t)addr - (uintptr_t)where; 200 1.8 skrll 201 1.8 skrll if ((addend & 0x80000000) != 0x00000000 && 202 1.8 skrll (addend & 0x80000000) != 0x80000000) { 203 1.8 skrll printf ("Relocation %x too far @ %p\n", addend, where); 204 1.8 skrll return -1; 205 1.8 skrll } 206 1.8 skrll 207 1.8 skrll *where = (*where & 0x80000000) | (addend & 0x7fffffff); 208 1.8 skrll 209 1.1 ad default: 210 1.3 dsl break; 211 1.1 ad } 212 1.3 dsl 213 1.3 dsl printf("kobj_reloc: unexpected/invalid relocation type %d @ %p symidx %u\n", 214 1.3 dsl rtype, where, symidx); 215 1.3 dsl return -1; 216 1.1 ad } 217 1.1 ad 218 1.15 rin #ifdef _ARM_ARCH_BE8 219 1.10 martin 220 1.10 martin enum be8_magic_sym_type { 221 1.10 martin Other, ArmStart, ThumbStart, DataStart 222 1.10 martin }; 223 1.10 martin 224 1.10 martin struct be8_marker { 225 1.10 martin enum be8_magic_sym_type type; 226 1.10 martin void *addr; 227 1.10 martin }; 228 1.10 martin 229 1.10 martin struct be8_marker_list { 230 1.10 martin size_t cnt; 231 1.10 martin struct be8_marker *markers; 232 1.10 martin }; 233 1.10 martin 234 1.10 martin /* 235 1.10 martin * See ELF for the ARM Architecture, Section 4.5.5: Mapping Symbols 236 1.10 martin * ARM reserves $a/$d/$t (and variants like $a.2) to mark start of 237 1.10 martin * arm/thumb code sections to allow conversion from ARM32-EB to -BE8 238 1.10 martin * format. 239 1.10 martin */ 240 1.10 martin static enum be8_magic_sym_type 241 1.10 martin be8_sym_type(const char *name, int info) 242 1.10 martin { 243 1.10 martin if (ELF_ST_BIND(info) != STB_LOCAL) 244 1.10 martin return Other; 245 1.10 martin if (ELF_ST_TYPE(info) != STT_NOTYPE) 246 1.10 martin return Other; 247 1.10 martin if (name[0] != '$' || name[1] == '\0' || 248 1.10 martin (name[2] != '\0' && name[2] != '.')) 249 1.10 martin return Other; 250 1.10 martin 251 1.10 martin switch (name[1]) { 252 1.10 martin case 'a': 253 1.10 martin return ArmStart; 254 1.10 martin case 'd': 255 1.10 martin return DataStart; 256 1.10 martin case 't': 257 1.10 martin return ThumbStart; 258 1.10 martin default: 259 1.10 martin return Other; 260 1.10 martin } 261 1.10 martin } 262 1.10 martin 263 1.10 martin static int 264 1.10 martin be8_ksym_count(const char *name, int symindex, void *value, uint32_t size, 265 1.10 martin int info, void *cookie) 266 1.10 martin { 267 1.10 martin size_t *res = cookie; 268 1.10 martin enum be8_magic_sym_type t = be8_sym_type(name, info); 269 1.10 martin 270 1.10 martin if (t != Other) 271 1.10 martin (*res)++; 272 1.10 martin return 0; 273 1.10 martin } 274 1.10 martin 275 1.10 martin static int 276 1.10 martin be8_ksym_add(const char *name, int symindex, void *value, uint32_t size, 277 1.10 martin int info, void *cookie) 278 1.10 martin { 279 1.10 martin size_t ndx; 280 1.10 martin struct be8_marker_list *list = cookie; 281 1.10 martin enum be8_magic_sym_type t = be8_sym_type(name, info); 282 1.10 martin 283 1.10 martin if (t == Other) 284 1.10 martin return 0; 285 1.10 martin 286 1.10 martin ndx = list->cnt++; 287 1.10 martin list->markers[ndx].type = t; 288 1.10 martin list->markers[ndx].addr = value; 289 1.10 martin 290 1.10 martin return 0; 291 1.10 martin } 292 1.10 martin 293 1.10 martin static int 294 1.10 martin be8_ksym_comp(const void *a, const void *b) 295 1.10 martin { 296 1.10 martin const struct be8_marker *ma = a, *mb = b; 297 1.10 martin uintptr_t va = (uintptr_t)ma->addr, vb = (uintptr_t)mb->addr; 298 1.10 martin 299 1.10 martin if (va == vb) 300 1.10 martin return 0; 301 1.10 martin if (va < vb) 302 1.10 martin return -1; 303 1.10 martin return 1; 304 1.10 martin } 305 1.10 martin 306 1.10 martin static void 307 1.10 martin be8_ksym_swap(void *start, size_t size, const struct be8_marker_list *list) 308 1.10 martin { 309 1.10 martin uintptr_t va_end = (uintptr_t)start + size; 310 1.10 martin size_t i; 311 1.10 martin uint32_t *p32, *p32_end, v32; 312 1.10 martin uint16_t *p16, *p16_end, v16; 313 1.10 martin 314 1.10 martin /* find first relevant list entry */ 315 1.10 martin for (i = 0; i < list->cnt; i++) 316 1.10 martin if (start <= list->markers[i].addr) 317 1.10 martin break; 318 1.10 martin 319 1.10 martin /* swap all arm and thumb code parts of this section */ 320 1.10 martin for ( ; i < list->cnt; i++) { 321 1.10 martin switch (list->markers[i].type) { 322 1.10 martin case ArmStart: 323 1.10 martin p32 = (uint32_t*)list->markers[i].addr; 324 1.10 martin p32_end = (uint32_t*)va_end; 325 1.10 martin if (i+1 < list->cnt) { 326 1.10 martin if ((uintptr_t)list->markers[i+1].addr 327 1.10 martin < va_end) 328 1.10 martin p32_end = (uint32_t*) 329 1.10 martin list->markers[i+1].addr; 330 1.10 martin } 331 1.10 martin while (p32 < p32_end) { 332 1.10 martin v32 = bswap32(*p32); 333 1.10 martin *p32++ = v32; 334 1.10 martin } 335 1.10 martin break; 336 1.10 martin case ThumbStart: 337 1.10 martin p16 = (uint16_t*)list->markers[i].addr; 338 1.10 martin p16_end = (uint16_t*)va_end; 339 1.10 martin if (i+1 < list->cnt) { 340 1.10 martin if ((uintptr_t)list->markers[i+1].addr 341 1.10 martin < va_end) 342 1.10 martin p16_end = (uint16_t*) 343 1.10 martin list->markers[i+1].addr; 344 1.10 martin } 345 1.10 martin while (p16 < p16_end) { 346 1.10 martin v16 = bswap16(*p16); 347 1.10 martin *p16++ = v16; 348 1.10 martin } 349 1.10 martin break; 350 1.10 martin default: 351 1.10 martin break; 352 1.10 martin } 353 1.10 martin } 354 1.10 martin } 355 1.13 skrll 356 1.10 martin static void 357 1.10 martin kobj_be8_fixup(kobj_t ko) 358 1.10 martin { 359 1.10 martin size_t relsym_cnt = 0, i, msize; 360 1.10 martin struct be8_marker_list list; 361 1.10 martin struct be8_marker tmp; 362 1.10 martin 363 1.10 martin /* 364 1.10 martin * Count all special relocations symbols 365 1.10 martin */ 366 1.10 martin ksyms_mod_foreach(ko->ko_name, be8_ksym_count, &relsym_cnt); 367 1.10 martin 368 1.10 martin /* 369 1.10 martin * Provide storage for the address list and add the symbols 370 1.10 martin */ 371 1.10 martin list.cnt = 0; 372 1.10 martin msize = relsym_cnt*sizeof(*list.markers); 373 1.10 martin list.markers = kmem_alloc(msize, KM_SLEEP); 374 1.10 martin ksyms_mod_foreach(ko->ko_name, be8_ksym_add, &list); 375 1.10 martin KASSERT(list.cnt == relsym_cnt); 376 1.10 martin 377 1.10 martin /* 378 1.10 martin * Sort symbols by ascending address 379 1.10 martin */ 380 1.10 martin if (kheapsort(list.markers, relsym_cnt, sizeof(*list.markers), 381 1.10 martin be8_ksym_comp, &tmp) != 0) 382 1.10 martin panic("could not sort be8 marker symbols"); 383 1.10 martin 384 1.10 martin /* 385 1.10 martin * Apply swaps to the .text section (XXX we do not have the 386 1.10 martin * section header available any more, it has been jetisoned 387 1.10 martin * already, so we can not check for all PROGBIT sections). 388 1.10 martin */ 389 1.10 martin for (i = 0; i < ko->ko_nprogtab; i++) { 390 1.10 martin if (strcmp(ko->ko_progtab[i].name, ".text") != 0) 391 1.10 martin continue; 392 1.10 martin be8_ksym_swap(ko->ko_progtab[i].addr, 393 1.10 martin (size_t)ko->ko_progtab[i].size, 394 1.10 martin &list); 395 1.10 martin } 396 1.10 martin 397 1.10 martin /* 398 1.10 martin * Done, free list 399 1.10 martin */ 400 1.10 martin kmem_free(list.markers, msize); 401 1.10 martin } 402 1.10 martin #endif 403 1.10 martin 404 1.1 ad int 405 1.1 ad kobj_machdep(kobj_t ko, void *base, size_t size, bool load) 406 1.1 ad { 407 1.1 ad 408 1.1 ad if (load) { 409 1.15 rin #ifdef _ARM_ARCH_BE8 410 1.15 rin if (base == (void*)ko->ko_text_address) 411 1.10 martin kobj_be8_fixup(ko); 412 1.10 martin #endif 413 1.5 matt #ifndef _RUMPKERNEL 414 1.7 matt cpu_idcache_wbinv_range((vaddr_t)base, size); 415 1.1 ad cpu_tlb_flushID(); 416 1.5 matt #endif 417 1.1 ad } 418 1.1 ad 419 1.1 ad return 0; 420 1.1 ad } 421