Index: sys/kern/link_elf.c =================================================================== --- sys/kern/link_elf.c (revision 224397) +++ sys/kern/link_elf.c (working copy) @@ -123,6 +123,17 @@ typedef struct elf_file { #endif } *elf_file_t; +#ifdef VIMAGE +struct set_vnet { + uintptr_t vs_start; + uintptr_t vs_stop; + uintptr_t vs_base; + TAILQ_ENTRY(set_vnet) vs_link; +}; + +static TAILQ_HEAD(set_vnet_head, set_vnet) set_vnet_list; +#endif + #include static int link_elf_link_common_finish(linker_file_t); @@ -345,6 +356,9 @@ link_elf_init(void* arg) (void)link_elf_link_common_finish(linker_kernel_file); linker_kernel_file->flags |= LINKER_FILE_LINKED; +#ifdef VIMAGE + TAILQ_INIT(&set_vnet_list); +#endif } SYSINIT(link_elf, SI_SUB_KLD, SI_ORDER_THIRD, link_elf_init, 0); @@ -520,7 +534,89 @@ parse_dpcpu(elf_file_t ef) } #ifdef VIMAGE +static void +set_vnet_insert(struct set_vnet *set) +{ + struct set_vnet *iter; + + TAILQ_FOREACH(iter, &set_vnet_list, vs_link) { + + KASSERT((set->vs_start < iter->vs_start && set->vs_stop < iter->vs_stop) || + (set->vs_start > iter->vs_start && set->vs_stop > iter->vs_stop), + ("vnet sets intersection: to insert: 0x%jx-0x%jx; inserted: 0x%jx-0x%jx", + (uintmax_t)set->vs_start, (uintmax_t)set->vs_stop, + (uintmax_t)iter->vs_start, (uintmax_t)iter->vs_stop)); + + if (iter->vs_start > set->vs_start) { + TAILQ_INSERT_BEFORE(iter, set, vs_link); + break; + } + } + + if (iter == NULL) + TAILQ_INSERT_TAIL(&set_vnet_list, set, vs_link); +} + +static void +set_vnet_remove(struct set_vnet *set) +{ + TAILQ_REMOVE(&set_vnet_list, set, vs_link); +} + +static struct set_vnet * +set_vnet_search(uintptr_t addr) +{ + struct set_vnet *set; + + TAILQ_FOREACH(set, &set_vnet_list, vs_link) { + if (addr < set->vs_start) + return (NULL); + if (addr < set->vs_stop) + return (set); + } + return (NULL); +} + +static void +set_vnet_add(uintptr_t start, uintptr_t stop, uintptr_t base) +{ + struct set_vnet *set; + + set = malloc(sizeof(*set), M_LINKER, M_WAITOK); + set->vs_start = start; + set->vs_stop = stop; + set->vs_base = base; + set_vnet_insert(set); +} + +static void +set_vnet_delete(uintptr_t start) +{ + struct set_vnet *set; + + set = set_vnet_search(start); + KASSERT(set != NULL, ("deleting unknown vnet set (start = 0x%jx)", + (uintmax_t)start)); + set_vnet_remove(set); + free(set, M_LINKER); +} + static int +set_vnet_find(uintptr_t addr, uintptr_t *start, uintptr_t *base) +{ + struct set_vnet *set; + + set = set_vnet_search(addr); + if (set != NULL) { + *start = set->vs_start; + *base = set->vs_base; + return (1); + } else { + return (0); + } +} + +static int parse_vnet(elf_file_t ef) { int count; @@ -544,6 +640,7 @@ parse_vnet(elf_file_t ef) return (ENOSPC); memcpy((void *)ef->vnet_base, (void *)ef->vnet_start, count); vnet_data_copy((void *)ef->vnet_base, count); + set_vnet_add(ef->vnet_start, ef->vnet_stop, ef->vnet_base); return (0); } @@ -1000,6 +1097,7 @@ link_elf_unload_file(linker_file_t file) if (ef->vnet_base != 0) { vnet_data_free((void *)ef->vnet_base, ef->vnet_stop - ef->vnet_start); + set_vnet_delete(ef->vnet_start); } #endif #ifdef GDB @@ -1438,6 +1536,10 @@ elf_lookup(linker_file_t lf, Elf_Size symidx, int elf_file_t ef = (elf_file_t)lf; const Elf_Sym *sym; const char *symbol; + Elf_Addr addr; +#ifdef VIMAGE + uintptr_t vnet_start, vnet_base; +#endif /* Don't even try to lookup the symbol if the index is bogus. */ if (symidx >= ef->nchains) @@ -1469,7 +1571,13 @@ elf_lookup(linker_file_t lf, Elf_Size symidx, int if (*symbol == 0) return (0); - return ((Elf_Addr)linker_file_lookup_symbol(lf, symbol, deps)); + addr = ((Elf_Addr)linker_file_lookup_symbol(lf, symbol, deps)); + +#ifdef VIMAGE + if (set_vnet_find(addr, &vnet_start, &vnet_base)) + addr = addr - vnet_start + vnet_base; +#endif + return addr; } static void