diff --git a/stand/common/bootstrap.h b/stand/common/bootstrap.h --- a/stand/common/bootstrap.h +++ b/stand/common/bootstrap.h @@ -351,14 +351,6 @@ int (*arch_isainb)(int port); void (*arch_isaoutb)(int port, int value); - /* - * Interface to adjust the load address according to the "object" - * being loaded. - */ - uint64_t (*arch_loadaddr)(u_int type, void *data, uint64_t addr); -#define LOAD_ELF 1 /* data points to the ELF header. */ -#define LOAD_RAW 2 /* data points to the file name. */ - /* * Interface to inform MD code about a loaded (ELF) segment. This * can be used to flush caches and/or set up translations. diff --git a/stand/common/load_elf.c b/stand/common/load_elf.c --- a/stand/common/load_elf.c +++ b/stand/common/load_elf.c @@ -403,6 +403,7 @@ * in the elf header (an ARM kernel can be loaded at any 2MB * boundary), so we leave dest set to the value calculated by * archsw.arch_loadaddr() and passed in to this function. + * XXX This comment is obsolete, but it still seems to work */ #ifndef __arm__ if (ehdr->e_type == ET_EXEC) @@ -445,10 +446,7 @@ goto oerr; } - if (archsw.arch_loadaddr != NULL) - dest = archsw.arch_loadaddr(LOAD_ELF, ehdr, dest); - else - dest = roundup(dest, PAGE_SIZE); + dest = md_align(dest); /* * Ok, we think we should handle this. diff --git a/stand/common/load_elf_obj.c b/stand/common/load_elf_obj.c --- a/stand/common/load_elf_obj.c +++ b/stand/common/load_elf_obj.c @@ -157,10 +157,7 @@ goto oerr; } - if (archsw.arch_loadaddr != NULL) - dest = archsw.arch_loadaddr(LOAD_ELF, hdr, dest); - else - dest = roundup(dest, PAGE_SIZE); + dest = md_align(dest); /* * Ok, we think we should handle this. diff --git a/stand/common/modinfo.c b/stand/common/modinfo.c --- a/stand/common/modinfo.c +++ b/stand/common/modinfo.c @@ -202,7 +202,7 @@ * platform. * * XXX For the moment, it's just PAGE_SIZE to make the refactoring go faster, - * but needs to hook-in arch_loadaddr (or its replacement) functionality. + * but needs to hook-in the replacement of arch_loadaddr. * * Also, we may need other logical things when dealing with different types of * page sizes and/or masking or sizes. This works well for addr and sizes, but diff --git a/stand/common/module.c b/stand/common/module.c --- a/stand/common/module.c +++ b/stand/common/module.c @@ -43,6 +43,7 @@ #endif #include "bootstrap.h" +#include "modinfo.h" #define MDIR_REMOVED 0x0001 #define MDIR_NOHINTS 0x0002 @@ -562,8 +563,7 @@ int i; TSENTER2(filename); - if (archsw.arch_loadaddr != NULL) - dest = archsw.arch_loadaddr(LOAD_RAW, filename, dest); + dest = md_align(dest); error = EFTYPE; for (i = last_file_format, fp = NULL; @@ -713,8 +713,7 @@ #endif #endif - if (archsw.arch_loadaddr != NULL) - loadaddr = archsw.arch_loadaddr(LOAD_RAW, name, loadaddr); + loadaddr = md_align(loadaddr); if (module_verbose > MODULE_VERBOSE_SILENT) printf("%s ", name); @@ -1015,9 +1014,7 @@ } /* Figure out where to load the data. */ - dest = loadaddr; - if (archsw.arch_loadaddr != NULL) - dest = archsw.arch_loadaddr(LOAD_RAW, (void *)name, dest); + dest = md_align(loadaddr); /* Create & populate control structure */ fp = file_alloc(); diff --git a/stand/kboot/kboot/arch/aarch64/exec.c b/stand/kboot/kboot/arch/aarch64/exec.c --- a/stand/kboot/kboot/arch/aarch64/exec.c +++ b/stand/kboot/kboot/arch/aarch64/exec.c @@ -188,9 +188,9 @@ /* * Figure out where to put it. * - * Linux does not allow us to kexec_load into any part of memory. Ask - * arch_loadaddr to resolve the first available chunk of physical memory - * where loading is possible (load_addr). + * Linux does not allow us to kexec_load into any part of memory. Find + * the first available chunk of physical memory where loading is + * possible (staging). * * The kernel is loaded at the 'base' address in continguous physical * memory. We use the 2MB in front of the kernel as a place to put our diff --git a/stand/kboot/kboot/arch/amd64/elf64_freebsd.c b/stand/kboot/kboot/arch/amd64/elf64_freebsd.c --- a/stand/kboot/kboot/arch/amd64/elf64_freebsd.c +++ b/stand/kboot/kboot/arch/amd64/elf64_freebsd.c @@ -179,8 +179,8 @@ * Figure out where to put it. * * Linux does not allow to do kexec_load into any part of memory. Ask - * arch_loadaddr to resolve the first available chunk of physical memory - * where loading is possible (load_addr). + * kboot_get_phys_load_segment resolve the first available chunk of + * physical memory where loading is possible (staging). * * The kernel is loaded at the 'base' address in continguous physical * pages (using 2MB super pages). The first such page is unused by the diff --git a/stand/kboot/kboot/arch/powerpc64/ppc64_elf_freebsd.c b/stand/kboot/kboot/arch/powerpc64/ppc64_elf_freebsd.c --- a/stand/kboot/kboot/arch/powerpc64/ppc64_elf_freebsd.c +++ b/stand/kboot/kboot/arch/powerpc64/ppc64_elf_freebsd.c @@ -89,21 +89,18 @@ /* * Figure out where to put it. * - * Linux does not allow to do kexec_load into - * any part of memory. Ask arch_loadaddr to - * resolve the first available chunk of physical - * memory where loading is possible (load_addr). + * Linux does not allow to do kexec_load into any part of memory. Ask + * kboot_get_phys_load_segment resolve the first available chunk of + * physical memory where loading is possible (load_addr). * - * Memory organization is shown below. - * It is assumed, that text segment offset of - * kernel ELF (KERNPHYSADDR) is non-zero, - * which is true for PPC/PPC64 architectures, - * where default is 0x100000. + * Memory organization is shown below. It is assumed, that text segment + * offset of kernel ELF (KERNPHYSADDR) is non-zero, which is true for + * PPC/PPC64 architectures, where default is 0x100000. * * load_addr: trampoline code * load_addr + KERNPHYSADDR: kernel text segment */ - trampolinebase = archsw.arch_loadaddr(LOAD_RAW, NULL, 0); + trampolinebase = kboot_get_phys_load_segment(); printf("Load address at %#jx\n", (uintmax_t)trampolinebase); printf("Relocation offset is %#jx\n", (uintmax_t)elf64_relocation_offset); diff --git a/stand/uboot/copy.c b/stand/uboot/copy.c --- a/stand/uboot/copy.c +++ b/stand/uboot/copy.c @@ -1,6 +1,6 @@ /*- * Copyright (c) 1998 Michael Smith - * Copyright (c) 2007 Semihalf, Rafal Jaworowski + * Copyright (c) 2007 Semihalf, Rafal Jaworowski * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,7 +35,7 @@ #include "libuboot.h" /* - * MD primitives supporting placement of module data + * MD primitives supporting placement of module data */ #ifdef __arm__ @@ -51,6 +51,9 @@ extern void _start(void); /* ubldr entry point address. */ +uint64_t loadbase; +bool loadbase_set = false; + /* * This is called for every object loaded (kernel, module, dtb file, etc). The * expected return value is the next address at or after the given addr which is @@ -63,8 +66,8 @@ * On subsequent calls the addr will be non-zero, and we just round it up so * that each object begins on a page boundary. */ -uint64_t -uboot_loadaddr(u_int type, void *data, uint64_t addr) +static uint64_t +uboot_loadaddr() { struct sys_info *si; uint64_t sblock, eblock, subldr, eubldr; @@ -73,87 +76,89 @@ int i; char *envstr; - if (addr == 0) { - /* - * If the loader_kernaddr environment variable is set, blindly - * honor it. It had better be right. We force interpretation - * of the value in base-16 regardless of any leading 0x prefix, - * because that's the U-Boot convention. - */ - envstr = ub_env_get("loader_kernaddr"); - if (envstr != NULL) - return (strtoul(envstr, NULL, 16)); - - /* - * Find addr/size of largest DRAM block. Carve our own address - * range out of the block, because loading the kernel over the - * top ourself is a poor memory-conservation strategy. Avoid - * memory at beginning of the first block of physical ram, - * since u-boot likes to pass args and data there. Assume that - * u-boot has moved itself to the very top of ram and - * optimistically assume that we won't run into it up there. - */ - if ((si = ub_get_sys_info()) == NULL) - panic("could not retrieve system info"); - - biggest_block = 0; - biggest_size = 0; - subldr = rounddown2((uintptr_t)_start, KERN_ALIGN); - eubldr = roundup2((uint64_t)uboot_heap_end, KERN_ALIGN); - for (i = 0; i < si->mr_no; i++) { - if (si->mr[i].flags != MR_ATTR_DRAM) - continue; - sblock = roundup2((uint64_t)si->mr[i].start, - KERN_ALIGN); - eblock = rounddown2((uint64_t)si->mr[i].start + - si->mr[i].size, KERN_ALIGN); - if (biggest_size == 0) - sblock += KERN_MINADDR; - if (subldr >= sblock && subldr < eblock) { - if (subldr - sblock > eblock - eubldr) { - this_block = sblock; - this_size = subldr - sblock; - } else { - this_block = eubldr; - this_size = eblock - eubldr; - } - } else if (subldr < sblock && eubldr < eblock) { - /* Loader is below or engulfs the sblock */ - this_block = (eubldr < sblock) ? sblock : eubldr; - this_size = eblock - this_block; + /* + * If the loader_kernaddr environment variable is set, blindly + * honor it. It had better be right. We force interpretation + * of the value in base-16 regardless of any leading 0x prefix, + * because that's the U-Boot convention. + */ + envstr = ub_env_get("loader_kernaddr"); + if (envstr != NULL) + return (strtoul(envstr, NULL, 16)); + + /* + * Find addr/size of largest DRAM block. Carve our own address + * range out of the block, because loading the kernel over the + * top ourself is a poor memory-conservation strategy. Avoid + * memory at beginning of the first block of physical ram, + * since u-boot likes to pass args and data there. Assume that + * u-boot has moved itself to the very top of ram and + * optimistically assume that we won't run into it up there. + */ + if ((si = ub_get_sys_info()) == NULL) + panic("could not retrieve system info"); + + biggest_block = 0; + biggest_size = 0; + subldr = rounddown2((uintptr_t)_start, KERN_ALIGN); + eubldr = roundup2((uint64_t)uboot_heap_end, KERN_ALIGN); + for (i = 0; i < si->mr_no; i++) { + if (si->mr[i].flags != MR_ATTR_DRAM) + continue; + sblock = roundup2((uint64_t)si->mr[i].start, + KERN_ALIGN); + eblock = rounddown2((uint64_t)si->mr[i].start + + si->mr[i].size, KERN_ALIGN); + if (biggest_size == 0) + sblock += KERN_MINADDR; + if (subldr >= sblock && subldr < eblock) { + if (subldr - sblock > eblock - eubldr) { + this_block = sblock; + this_size = subldr - sblock; } else { - this_block = 0; - this_size = 0; - } - if (biggest_size < this_size) { - biggest_block = this_block; - biggest_size = this_size; + this_block = eubldr; + this_size = eblock - eubldr; } + } else if (subldr < sblock && eubldr < eblock) { + /* Loader is below or engulfs the sblock */ + this_block = (eubldr < sblock) ? sblock : eubldr; + this_size = eblock - this_block; + } else { + this_block = 0; + this_size = 0; } - if (biggest_size == 0) - panic("Not enough DRAM to load kernel"); + if (biggest_size < this_size) { + biggest_block = this_block; + biggest_size = this_size; + } + } + if (biggest_size == 0) + panic("Not enough DRAM to load kernel"); #if 0 - printf("Loading kernel into region 0x%08jx-0x%08jx (%ju MiB)\n", - (uintmax_t)biggest_block, - (uintmax_t)biggest_block + biggest_size - 1, - (uintmax_t)biggest_size / 1024 / 1024); + printf("Loading kernel into region 0x%08jx-0x%08jx (%ju MiB)\n", + (uintmax_t)biggest_block, + (uintmax_t)biggest_block + biggest_size - 1, + (uintmax_t)biggest_size / 1024 / 1024); #endif - return (biggest_block); - } - return roundup2(addr, PAGE_SIZE); + return (biggest_block); } ssize_t uboot_copyin(const void *src, vm_offset_t dest, const size_t len) { - bcopy(src, (void *)dest, len); + if (!loadbase_set) { + loadbase = uboot_loadaddr(); + loadbase_set = true; + } + + bcopy(src, (void *)(dest + loadbase), len); return (len); } ssize_t uboot_copyout(const vm_offset_t src, void *dest, const size_t len) { - bcopy((void *)src, dest, len); + bcopy((void *)(src + loadbase), dest, len); return (len); } diff --git a/stand/uboot/libuboot.h b/stand/uboot/libuboot.h --- a/stand/uboot/libuboot.h +++ b/stand/uboot/libuboot.h @@ -57,7 +57,6 @@ extern uintptr_t uboot_heap_start; extern uintptr_t uboot_heap_end; -uint64_t uboot_loadaddr(u_int type, void *data, uint64_t addr); ssize_t uboot_copyin(const void *src, vm_offset_t dest, const size_t len); ssize_t uboot_copyout(const vm_offset_t src, void *dest, const size_t len); ssize_t uboot_readin(readin_handle_t fd, vm_offset_t dest, const size_t len); diff --git a/stand/uboot/main.c b/stand/uboot/main.c --- a/stand/uboot/main.c +++ b/stand/uboot/main.c @@ -41,7 +41,6 @@ struct uboot_devdesc currdev; struct arch_switch archsw = { /* MI/MD interface boundary */ - .arch_loadaddr = uboot_loadaddr, .arch_getdev = uboot_getdev, .arch_copyin = uboot_copyin, .arch_copyout = uboot_copyout,