Index: head/sys/amd64/amd64/machdep.c =================================================================== --- head/sys/amd64/amd64/machdep.c +++ head/sys/amd64/amd64/machdep.c @@ -1508,7 +1508,7 @@ #ifdef DDB ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t); ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t); - db_fetch_ksymtab(ksym_start, ksym_end); + db_fetch_ksymtab(ksym_start, ksym_end, 0); #endif efi_systbl_phys = MD_FETCH(kmdp, MODINFOMD_FW_HANDLE, vm_paddr_t); Index: head/sys/arm/arm/machdep_boot.c =================================================================== --- head/sys/arm/arm/machdep_boot.c +++ head/sys/arm/arm/machdep_boot.c @@ -302,7 +302,7 @@ #ifdef DDB ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t); ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t); - db_fetch_ksymtab(ksym_start, ksym_end); + db_fetch_ksymtab(ksym_start, ksym_end, 0); #endif return lastaddr; } Index: head/sys/arm64/arm64/machdep_boot.c =================================================================== --- head/sys/arm64/arm64/machdep_boot.c +++ head/sys/arm64/arm64/machdep_boot.c @@ -208,7 +208,7 @@ #ifdef DDB ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t); ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t); - db_fetch_ksymtab(ksym_start, ksym_end); + db_fetch_ksymtab(ksym_start, ksym_end, 0); #endif return (lastaddr); } Index: head/sys/ddb/db_main.c =================================================================== --- head/sys/ddb/db_main.c +++ head/sys/ddb/db_main.c @@ -48,6 +48,14 @@ #include #include +struct db_private { + char* strtab; + vm_offset_t relbase; +}; +typedef struct db_private *db_private_t; + +#define DB_PRIVATE(x) ((db_private_t)(x->private)) + SYSCTL_NODE(_debug, OID_AUTO, ddb, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, "DDB settings"); @@ -64,7 +72,8 @@ * the symtab and strtab in memory. This is used when loaded from * boot loaders different than the native one (like Xen). */ -vm_offset_t ksymtab, kstrtab, ksymtab_size; +vm_offset_t ksymtab, kstrtab, ksymtab_size, ksymtab_relbase; +static struct db_private ksymtab_private; bool X_db_line_at_pc(db_symtab_t *symtab, c_db_sym_t sym, char **file, int *line, @@ -86,7 +95,8 @@ sym = (Elf_Sym *)symtab->start; while ((char *)sym < symtab->end) { if (sym->st_name != 0 && - !strcmp(symtab->private + sym->st_name, symbol)) + !strcmp(DB_PRIVATE(symtab)->strtab + + sym->st_name, symbol)) return ((c_db_sym_t)sym); sym++; } @@ -101,7 +111,7 @@ c_linker_sym_t lsym; Elf_Sym *sym, *match; unsigned long diff; - db_addr_t stoffs; + db_addr_t stoffs = off; if (symtab->private == NULL) { if (!linker_ddb_search_symbol((caddr_t)off, &lsym, &diff)) { @@ -110,10 +120,11 @@ } return (NULL); } + else + stoffs -= DB_PRIVATE(symtab)->relbase; diff = ~0UL; match = NULL; - stoffs = DB_STOFFS(off); for (sym = (Elf_Sym*)symtab->start; (char*)sym < symtab->end; sym++) { if (sym->st_name == 0 || sym->st_shndx == SHN_UNDEF) continue; @@ -171,15 +182,17 @@ *valp = (db_expr_t)lval.value; } else { if (namep != NULL) - *namep = (const char *)symtab->private + + *namep = (const char *)DB_PRIVATE(symtab)->strtab + ((const Elf_Sym *)sym)->st_name; if (valp != NULL) - *valp = (db_expr_t)((const Elf_Sym *)sym)->st_value; + *valp = (db_expr_t)((const Elf_Sym *)sym)->st_value + + DB_PRIVATE(symtab)->relbase; } } int -db_fetch_ksymtab(vm_offset_t ksym_start, vm_offset_t ksym_end) +db_fetch_ksymtab(vm_offset_t ksym_start, vm_offset_t ksym_end, + vm_offset_t relbase) { Elf_Size strsz; @@ -190,9 +203,11 @@ kstrtab = ksymtab + ksymtab_size; strsz = *(Elf_Size*)kstrtab; kstrtab += sizeof(Elf_Size); + ksymtab_relbase = relbase; if (kstrtab + strsz > ksym_end) { /* Sizes doesn't match, unset everything. */ - ksymtab = ksymtab_size = kstrtab = 0; + ksymtab = ksymtab_size = kstrtab = ksymtab_relbase + = 0; } } @@ -209,8 +224,10 @@ db_command_init(); if (ksymtab != 0 && kstrtab != 0 && ksymtab_size != 0) { + ksymtab_private.strtab = (char *)kstrtab; + ksymtab_private.relbase = ksymtab_relbase; db_add_symbol_table((char *)ksymtab, - (char *)(ksymtab + ksymtab_size), "elf", (char *)kstrtab); + (char *)(ksymtab + ksymtab_size), "elf", (char *)&ksymtab_private); } db_add_symbol_table(NULL, NULL, "kld", NULL); return (1); /* We're the default debugger. */ Index: head/sys/ddb/ddb.h =================================================================== --- head/sys/ddb/ddb.h +++ head/sys/ddb/ddb.h @@ -72,10 +72,6 @@ #define DB_MAXSCRIPTRECURSION 3 #endif -#ifndef DB_STOFFS -#define DB_STOFFS(offs) (offs) -#endif - #ifndef DB_CALL #define DB_CALL db_fncall_generic #else @@ -87,7 +83,7 @@ * Most users should use db_fetch_symtab in order to set them from the * boot loader provided values. */ -extern vm_offset_t ksymtab, kstrtab, ksymtab_size; +extern vm_offset_t ksymtab, kstrtab, ksymtab_size, ksymtab_relbase; /* * There are three "command tables": @@ -232,7 +228,8 @@ int db_write_bytes(vm_offset_t addr, size_t size, char *data); void db_command_register(struct command_table *, struct command *); void db_command_unregister(struct command_table *, struct command *); -int db_fetch_ksymtab(vm_offset_t ksym_start, vm_offset_t ksym_end); +int db_fetch_ksymtab(vm_offset_t ksym_start, vm_offset_t ksym_end, + vm_offset_t relbase); db_cmdfcn_t db_breakpoint_cmd; db_cmdfcn_t db_capture_cmd; Index: head/sys/dev/ksyms/ksyms.c =================================================================== --- head/sys/dev/ksyms/ksyms.c +++ head/sys/dev/ksyms/ksyms.c @@ -202,7 +202,7 @@ strsz = LINKER_STRTAB_GET(lf, &strtab); symsz = numsyms * sizeof(Elf_Sym); -#ifdef __powerpc__ +#ifdef RELOCATABLE_KERNEL fixup = true; #else fixup = lf->id > 1; Index: head/sys/i386/i386/machdep.c =================================================================== --- head/sys/i386/i386/machdep.c +++ head/sys/i386/i386/machdep.c @@ -2180,7 +2180,7 @@ i386_kdb_init(void) { #ifdef DDB - db_fetch_ksymtab(bootinfo.bi_symtab, bootinfo.bi_esymtab); + db_fetch_ksymtab(bootinfo.bi_symtab, bootinfo.bi_esymtab, 0); #endif kdb_init(); #ifdef KDB Index: head/sys/kern/link_elf.c =================================================================== --- head/sys/kern/link_elf.c +++ head/sys/kern/link_elf.c @@ -389,6 +389,21 @@ } #ifdef RELOCATABLE_KERNEL +/* + * __startkernel and __endkernel are symbols set up as relocation canaries. + * + * They are defined in locore to reference linker script symbols at the + * beginning and end of the LOAD area. This has the desired side effect of + * giving us variables that have relative relocations pointing at them, so + * relocation of the kernel object will cause the variables to be updated + * automatically by the runtime linker when we initialize. + * + * There are two main reasons to relocate the kernel: + * 1) If the loader needed to load the kernel at an alternate load address. + * 2) If the kernel is switching address spaces on machines like POWER9 + * under Radix where the high bits of the effective address are used to + * differentiate between hypervisor, host, guest, and problem state. + */ extern vm_offset_t __startkernel, __endkernel; #endif @@ -427,6 +442,7 @@ ef = (elf_file_t) linker_kernel_file; ef->preloaded = 1; #ifdef RELOCATABLE_KERNEL + /* Compute relative displacement */ ef->address = (caddr_t) (__startkernel - KERNBASE); #else ef->address = 0; Index: head/sys/mips/mips/machdep.c =================================================================== --- head/sys/mips/mips/machdep.c +++ head/sys/mips/mips/machdep.c @@ -447,7 +447,7 @@ kernel_kseg0_end += symtabsize; /* end of .strtab */ ksym_end = kernel_kseg0_end; - db_fetch_ksymtab(ksym_start, ksym_end); + db_fetch_ksymtab(ksym_start, ksym_end, 0); } #endif } Index: head/sys/powerpc/powerpc/machdep.c =================================================================== --- head/sys/powerpc/powerpc/machdep.c +++ head/sys/powerpc/powerpc/machdep.c @@ -251,7 +251,6 @@ #ifdef DDB static void load_external_symtab(void); -static void displace_symbol_table(vm_offset_t, vm_offset_t, vm_offset_t); #endif uintptr_t @@ -360,16 +359,8 @@ ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t); ksym_sz = *(Elf_Size*)ksym_start; - /* - * Loader already handled displacing to the load - * address, but we still need to displace it to the - * DMAP. - */ - displace_symbol_table( - (vm_offset_t)(ksym_start + sizeof(Elf_Size)), - ksym_sz, md_offset); - - db_fetch_ksymtab(ksym_start, ksym_end); + db_fetch_ksymtab(ksym_start, ksym_end, md_offset); + /* Symbols provided by loader. */ symbols_provided = true; #endif } @@ -509,45 +500,22 @@ #ifdef DDB /* - * XXX Figure out where to move this. + * On powernv and some booke systems, we might not have symbols loaded via + * loader. However, if the user passed the kernel in as the initrd as well, + * we can manually load it via reinterpreting the initrd copy of the kernel. + * + * In the BOOKE case, we don't actually have a DMAP yet, so we have to use + * temporary maps to inspect the memory, but write DMAP addresses to the + * configuration variables. */ static void -displace_symbol_table(vm_offset_t ksym_start, - vm_offset_t ksym_sz, vm_offset_t displacement) { - Elf_Sym *sym; - - /* - * Relocate the symbol table to our final load address. - */ - for (sym = (Elf_Sym *)ksym_start; - (vm_paddr_t)sym < (ksym_start + ksym_sz); - sym++) { - if (sym->st_name == 0 || - sym->st_shndx == SHN_UNDEF || - sym->st_value == 0) - continue; - if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT && - ELF_ST_TYPE(sym->st_info) != STT_FUNC && - ELF_ST_TYPE(sym->st_info) != STT_NOTYPE) - continue; - /* Skip relocating any implausible symbols */ - if (sym->st_value > KERNBASE) - sym->st_value += displacement; - } -} - -/* - * On powernv, we might not have symbols loaded via loader. However, if the - * user passed the kernel in as the initrd as well, we can manually load it - * via reinterpreting the initrd copy of the kernel. - */ -static void load_external_symtab(void) { phandle_t chosen; vm_paddr_t start, end; pcell_t cell[2]; ssize_t size; - u_char *kernelimg; + u_char *kernelimg; /* Temporary map */ + u_char *kernelimg_final; /* Final location */ int i; @@ -555,7 +523,8 @@ Elf_Phdr *phdr; Elf_Shdr *shdr; - vm_offset_t ksym_start, ksym_sz, kstr_start, kstr_sz; + vm_offset_t ksym_start, ksym_sz, kstr_start, kstr_sz, + ksym_start_final, kstr_start_final; if (!hw_direct_map) return; @@ -587,27 +556,48 @@ if (!(end - start > 0)) return; - kernelimg = (u_char *) PHYS_TO_DMAP(start); - + kernelimg_final = (u_char *) PHYS_TO_DMAP(start); +#ifdef AIM + kernelimg = kernelimg_final; +#else /* BOOKE */ + kernelimg = (u_char *)pmap_early_io_map(start, PAGE_SIZE); +#endif ehdr = (Elf_Ehdr *)kernelimg; - if (!IS_ELF(*ehdr)) + if (!IS_ELF(*ehdr)) { +#ifdef BOOKE + pmap_early_io_unmap(start, PAGE_SIZE); +#endif return; + } +#ifdef BOOKE + pmap_early_io_unmap(start, PAGE_SIZE); + kernelimg = (u_char *)pmap_early_io_map(start, (end - start)); +#endif + phdr = (Elf_Phdr *)(kernelimg + ehdr->e_phoff); shdr = (Elf_Shdr *)(kernelimg + ehdr->e_shoff); ksym_start = 0; ksym_sz = 0; + ksym_start_final = 0; kstr_start = 0; kstr_sz = 0; + kstr_start_final = 0; for (i = 0; i < ehdr->e_shnum; i++) { if (shdr[i].sh_type == SHT_SYMTAB) { ksym_start = (vm_offset_t)(kernelimg + shdr[i].sh_offset); + ksym_start_final = (vm_offset_t) + (kernelimg_final + shdr[i].sh_offset); ksym_sz = (vm_offset_t)(shdr[i].sh_size); kstr_start = (vm_offset_t)(kernelimg + shdr[shdr[i].sh_link].sh_offset); + kstr_start_final = (vm_offset_t) + (kernelimg_final + + shdr[shdr[i].sh_link].sh_offset); + kstr_sz = (vm_offset_t) (shdr[shdr[i].sh_link].sh_size); } @@ -615,13 +605,22 @@ if (ksym_start != 0 && kstr_start != 0 && ksym_sz != 0 && kstr_sz != 0 && ksym_start < kstr_start) { - - displace_symbol_table(ksym_start, ksym_sz, - (__startkernel - KERNBASE)); - ksymtab = ksym_start; + /* + * We can't use db_fetch_ksymtab() here, because we need to + * feed in DMAP addresses that are not mapped yet on booke. + * + * Write the variables directly, where db_init() will pick + * them up later, after the DMAP is up. + */ + ksymtab = ksym_start_final; ksymtab_size = ksym_sz; - kstrtab = kstr_start; + kstrtab = kstr_start_final; + ksymtab_relbase = (__startkernel - KERNBASE); } + +#ifdef BOOKE + pmap_early_io_unmap(start, (end - start)); +#endif }; #endif