summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/boot/common/bootstrap.h18
-rw-r--r--sys/boot/common/load_elf.c19
-rw-r--r--sys/boot/common/load_elf_obj.c6
-rw-r--r--sys/boot/common/module.c25
-rw-r--r--sys/boot/pc98/loader/main.c17
5 files changed, 55 insertions, 30 deletions
diff --git a/sys/boot/common/bootstrap.h b/sys/boot/common/bootstrap.h
index bf3f962..d8b4551 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 f0880b1..ee6389f 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 6f3b349..dcd71ef 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 063fcdf..728992d 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 da14d0b..391c5e9 100644
--- a/sys/boot/pc98/loader/main.c
+++ b/sys/boot/pc98/loader/main.c
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <machine/bootinfo.h>
#include <machine/psl.h>
+#include <sys/param.h>
#include <sys/reboot.h>
#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.
OpenPOWER on IntegriCloud