From e641a443f45ae058fa697a4cc13eca6725cc0f16 Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Sat, 23 Feb 2008 18:33:50 +0000 Subject: [PATCH] Add __elfN(relocation_offset). It holds the offset between the virtual (link) address and the physical (load) address. Ideally, the mapping between link and load addresses should be abstracted by the copyin(), copyout() and readin() functions, so that we don't have to add kluges in __elfN(loadimage)(). Then, we could also have paged virtual memory for the kernel. This can be important under EFI, where you need to allocate physical memory form the firmware if you want to work in all scenarios. --- sys/boot/common/bootstrap.h | 4 +++- sys/boot/common/load_elf.c | 28 +++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/sys/boot/common/bootstrap.h b/sys/boot/common/bootstrap.h index 6ecd2355188..57982d1e985 100644 --- a/sys/boot/common/bootstrap.h +++ b/sys/boot/common/bootstrap.h @@ -233,13 +233,15 @@ void file_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p) int file_addmodule(struct preloaded_file *fp, char *modname, int version, struct kernel_module **newmp); - /* MI module loaders */ #ifdef __elfN /* Relocation types. */ #define ELF_RELOC_REL 1 #define ELF_RELOC_RELA 2 +/* Relocation offset for some architectures */ +extern u_int64_t __elfN(relocation_offset); + struct elf_file; typedef Elf_Addr (symaddr_fn)(struct elf_file *ef, Elf_Size symidx); diff --git a/sys/boot/common/load_elf.c b/sys/boot/common/load_elf.c index bb070fd9cf0..eabc426922c 100644 --- a/sys/boot/common/load_elf.c +++ b/sys/boot/common/load_elf.c @@ -83,6 +83,8 @@ static char *fake_modname(const char *name); const char *__elfN(kerneltype) = "elf kernel"; const char *__elfN(moduletype) = "elf module"; +u_int64_t __elfN(relocation_offset) = 0; + /* * Attempt to load the file (file) as an ELF module. It will be stored at * (dest), and a pointer to a module structure describing the loaded object @@ -100,7 +102,7 @@ __elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result) fp = NULL; bzero(&ef, sizeof(struct elf_file)); - + /* * Open the image, read and validate the ELF header */ @@ -266,9 +268,33 @@ __elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off) #else off = - (off & 0xff000000u); /* i386 relocates after locore */ #endif +#elif defined(__powerpc__) + /* + * On the purely virtual memory machines like e500, the kernel is + * linked against its final VA range, which is most often not + * available at the loader stage, but only after kernel initializes + * and completes its VM settings. In such cases we cannot use p_vaddr + * field directly to load ELF segments, but put them at some + * 'load-time' locations. + */ + if (off & 0xf0000000u) { + off = -(off & 0xf0000000u); + /* + * XXX the physical load address should not be hardcoded. Note + * that the Book-E kernel assumes that it's loaded at a 16MB + * boundary for now... + */ + off += 0x01000000; + ehdr->e_entry += off; +#ifdef ELF_VERBOSE + printf("Converted entry 0x%08x\n", ehdr->e_entry); +#endif + } else + off = 0; #else off = 0; /* other archs use direct mapped kernels */ #endif + __elfN(relocation_offset) = off; } ef->off = off;