From 0cca5d3d9051161e8f90ac65f731b7e57826bc67 Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Sun, 3 Apr 2011 22:31:51 +0000 Subject: [PATCH] Add 2 new archsw interfaces: 1. arch_loadaddr - used by platform code to adjust the address at which the object gets loaded. Implement PC98 using this new interface instead of using conditional compilation. For ELF objects the ELF header is passed as the data pointer. For raw files it's the filename. Note that ELF objects are first considered as raw files. 2. arch_loadseg - used by platform code to keep track of actual segments, so that (instruction) caches can be flushed or translations can be created. Both the ELF header as well as the program header are passed to allow platform code to treat the kernel proper differently from any additional modules and to have all the relevant details of the loaded segment (e.g. protection). --- sys/boot/common/bootstrap.h | 18 ++++++++++++++++++ sys/boot/common/load_elf.c | 19 ++++++++++--------- sys/boot/common/load_elf_obj.c | 6 ++++-- sys/boot/common/module.c | 25 ++++++------------------- sys/boot/pc98/loader/main.c | 17 +++++++++++++++++ 5 files changed, 55 insertions(+), 30 deletions(-) diff --git a/sys/boot/common/bootstrap.h b/sys/boot/common/bootstrap.h index bf3f9622b6ba..d8b45514cfdc 100644 --- a/sys/boot/common/bootstrap.h +++ b/sys/boot/common/bootstrap.h @@ -296,6 +296,24 @@ struct arch_switch /* Perform ISA byte port I/O (only for systems with ISA) */ 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. + */ +#ifdef __elfN + void (*arch_loadseg)(Elf_Ehdr *eh, Elf_Phdr *ph, uint64_t delta); +#else + void (*arch_loadseg)(void *eh, void *ph, uint64_t delta); +#endif }; extern struct arch_switch archsw; diff --git a/sys/boot/common/load_elf.c b/sys/boot/common/load_elf.c index f0880b1eaa3c..ee6389fec1ff 100644 --- a/sys/boot/common/load_elf.c +++ b/sys/boot/common/load_elf.c @@ -97,7 +97,6 @@ __elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result) struct elf_file ef; Elf_Ehdr *ehdr; int err; - u_int pad; ssize_t bytes_read; fp = NULL; @@ -157,12 +156,6 @@ __elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result) /* Looks OK, got ahead */ ef.kernel = 0; - /* Page-align the load address */ - pad = (u_int)dest & PAGE_MASK; - if (pad != 0) { - pad = PAGE_SIZE - pad; - dest += pad; - } } else if (ehdr->e_type == ET_EXEC) { /* Looks like a kernel */ if (kfp != NULL) { @@ -173,7 +166,7 @@ __elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result) /* * Calculate destination address based on kernel entrypoint */ - dest = ehdr->e_entry; + dest = (ehdr->e_entry & ~PAGE_MASK); if (dest == 0) { printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: not a kernel (maybe static binary?)\n"); err = EPERM; @@ -186,6 +179,11 @@ __elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result) goto oerr; } + if (archsw.arch_loadaddr != NULL) + dest = archsw.arch_loadaddr(LOAD_ELF, ehdr, dest); + else + dest = roundup(dest, PAGE_SIZE); + /* * Ok, we think we should handle this. */ @@ -202,7 +200,7 @@ __elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result) #ifdef ELF_VERBOSE if (ef.kernel) - printf("%s entry at 0x%jx\n", filename, (uintmax_t)dest); + printf("%s entry at 0x%jx\n", filename, (uintmax_t)ehdr->e_entry); #else printf("%s ", filename); #endif @@ -362,6 +360,9 @@ __elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off) printf("\n"); #endif + if (archsw.arch_loadseg != NULL) + archsw.arch_loadseg(ehdr, phdr + i, off); + if (firstaddr == 0 || firstaddr > (phdr[i].p_vaddr + off)) firstaddr = phdr[i].p_vaddr + off; if (lastaddr == 0 || lastaddr < (phdr[i].p_vaddr + off + phdr[i].p_memsz)) diff --git a/sys/boot/common/load_elf_obj.c b/sys/boot/common/load_elf_obj.c index 6f3b3493aa3d..dcd71efff386 100644 --- a/sys/boot/common/load_elf_obj.c +++ b/sys/boot/common/load_elf_obj.c @@ -144,8 +144,10 @@ __elfN(obj_loadfile)(char *filename, u_int64_t dest, goto oerr; } - /* Page-align the load address */ - dest = roundup(dest, PAGE_SIZE); + if (archsw.arch_loadaddr != NULL) + dest = archsw.arch_loadaddr(LOAD_ELF, hdr, dest); + else + dest = roundup(dest, PAGE_SIZE); /* * Ok, we think we should handle this. diff --git a/sys/boot/common/module.c b/sys/boot/common/module.c index 063fcdfb7dcb..728992d040d0 100644 --- a/sys/boot/common/module.c +++ b/sys/boot/common/module.c @@ -275,6 +275,9 @@ file_load(char *filename, vm_offset_t dest, struct preloaded_file **result) int error; int i; + if (archsw.arch_loadaddr != NULL) + dest = archsw.arch_loadaddr(LOAD_RAW, filename, dest); + error = EFTYPE; for (i = 0, fp = NULL; file_formats[i] && fp == NULL; i++) { error = (file_formats[i]->l_load)(filename, loadaddr, &fp); @@ -352,9 +355,6 @@ file_loadraw(char *type, char *name) char *cp; int fd, got; vm_offset_t laddr; -#ifdef PC98 - struct stat st; -#endif /* We can't load first */ if ((file_findfile(NULL, NULL)) == NULL) { @@ -369,20 +369,15 @@ file_loadraw(char *type, char *name) return(CMD_ERROR); } name = cp; - + if ((fd = open(name, O_RDONLY)) < 0) { sprintf(command_errbuf, "can't open '%s': %s", name, strerror(errno)); free(name); return(CMD_ERROR); } -#ifdef PC98 - /* We cannot use 15M-16M area on pc98. */ - if (loadaddr < 0x1000000 && - fstat(fd, &st) == 0 && - (st.st_size == -1 || loadaddr + st.st_size > 0xf00000)) - loadaddr = 0x1000000; -#endif + if (archsw.arch_loadaddr != NULL) + loadaddr = archsw.arch_loadaddr(LOAD_RAW, name, loadaddr); laddr = loadaddr; for (;;) { @@ -489,14 +484,6 @@ mod_loadkld(const char *kldname, int argc, char *argv[]) ; do { -#ifdef PC98 - /* We cannot use 15M-16M area on pc98. */ - struct stat st; - if (loadaddr < 0x1000000 && - stat(filename, &st) == 0 && - (st.st_size == -1 || loadaddr + st.st_size > 0xf00000)) - loadaddr = 0x1000000; -#endif err = file_load(filename, loadaddr, &fp); if (err) break; diff --git a/sys/boot/pc98/loader/main.c b/sys/boot/pc98/loader/main.c index da14d0bcf8ff..391c5e9bc86c 100644 --- a/sys/boot/pc98/loader/main.c +++ b/sys/boot/pc98/loader/main.c @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include "bootstrap.h" @@ -77,6 +78,21 @@ extern char end[]; static void *heap_top; static void *heap_bottom; +static uint64_t +pc98_loadaddr(u_int type, void *data, uint64_t addr) +{ + struct stat st; + + if (type == LOAD_ELF) + return (roundup(addr, PAGE_SIZE)); + + /* We cannot use 15M-16M area on pc98. */ + if (type == LOAD_RAW && addr < 0x1000000 && stat(data, &st) == 0 && + (st.st_size == -1 || addr + st.st_size > 0xf00000)) + addr = 0x1000000; + return (addr); +} + int main(void) { @@ -160,6 +176,7 @@ main(void) archsw.arch_readin = i386_readin; archsw.arch_isainb = isa_inb; archsw.arch_isaoutb = isa_outb; + archsw.arch_loadaddr = pc98_loadaddr; /* * March through the device switch probing for things.