#include <stddef.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/param.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include "image.h"
#include "boot.h"
+#include <machine/multiboot.h>
+#include <machine/elf.h>
+
+
static int block_size = 0;
static int verboseboot = VERBOSEBOOT_QUIET;
extern u16_t vid_port; /* Video i/o port. */
extern u32_t vid_mem_base; /* Video memory base address. */
extern u32_t vid_mem_size; /* Video memory size. */
+extern u32_t mbdev; /* Device number in multiboot format */
#define click_shift clck_shft /* 7 char clash with click_size. */
#define P_SIZ_OFF 0 /* Process' sizes into kernel data. */
#define P_INIT_OFF 4 /* Init cs & sizes into fs data. */
+/* Where multiboot info struct goes in memory */
+#define MULTIBOOT_INFO_ADDR 0x9500
#define between(a, c, z) ((unsigned) ((c) - (a)) <= ((z) - (a)))
+char *select_image(char *image);
+size_t strspn(const char *string, const char *in);
+char * strpbrk(register const char *string, register const char *brk);
+char * strtok(register char *string, const char *separators);
+char * strdup(const char *s1);
+
void pretty_image(const char *image)
/* Pretty print the name of the image to load. Translate '/' and '_' to
* space, first letter goes uppercase. An 'r' before a digit prints as
unsigned click_size; /* click_size = Smallest kernel memory object. */
unsigned k_flags; /* Not all kernels are created equal. */
u32_t reboot_code; /* Obsolete reboot code return pointer. */
+int do_multiboot;
int params2params(char *params, size_t psize)
/* Repackage the environment settings for the kernel. */
return len >> SECTOR_SHIFT;
}
-off_t image_off, image_size;
+off_t image_off, image_sectors, image_bytes;
u32_t (*vir2sec)(u32_t vsec); /* Where is a sector on disk? */
u32_t file_vir2sec(u32_t vsec)
cnt= SECTOR_SIZE;
}
if (*addr + click_size > limit)
- {
+ {
DEBUGEXTRA(("get_segment: out of memory; "
"addr=0x%lx; limit=0x%lx; size=%lx\n",
*addr, limit, size));
}
}
+int split_module_list(char *modules)
+{
+ int i;
+ char *c, *s;
+
+ for (s= modules, i= 1; (c= strrchr(s, ' ')) != NULL; i++) {
+ *c = '\0';
+ }
+
+ return i;
+}
+
+void exec_mb(char *kernel, char* modules)
+/* Get a Minix image into core, patch it up and execute. */
+{
+ int i;
+ static char hdr[SECTOR_SIZE];
+ char *buf;
+ u32_t vsec, addr, limit, n, totalmem = 0;
+ u16_t kmagic, mode;
+ char *console;
+ char params[SECTOR_SIZE];
+ extern char *sbrk(int);
+ char *verb;
+ u32_t text_vaddr, text_paddr, text_filebytes, text_membytes;
+ u32_t data_vaddr, data_paddr, data_filebytes, data_membytes;
+ u32_t pc;
+ u32_t text_offset, data_offset;
+ i32_t segsize;
+ int r;
+ u32_t cs, ds;
+ char *modstring, *mod;
+ multiboot_info_t *mbinfo;
+ multiboot_module_t *mbmodinfo;
+ u32_t mbinfo_size, mbmodinfo_size;
+ char *memvar;
+ memory *mp;
+ u32_t mod_cmdline_start, kernel_cmdline_start;
+ u32_t modstringlen;
+ int modnr;
+
+ /* The stack is pretty deep here, so check if heap and stack collide. */
+ (void) sbrk(0);
+
+ if ((verb= b_value(VERBOSEBOOTVARNAME)) != nil)
+ verboseboot = a2l(verb);
+
+ printf("\nLoading %s\n", kernel);
+
+ vsec= 0; /* Load this sector from kernel next. */
+ addr= mem[0].base; /* Into this memory block. */
+ limit= mem[0].base + mem[0].size;
+ if (limit > caddr) limit= caddr;
+
+ /* set click size for get_segment */
+ click_size = PAGE_SIZE;
+
+ k_flags = K_KHIGH|K_BRET|K_MEML|K_INT86|K_RET|K_HDR
+ |K_HIGH|K_CHMEM|K_I386;
+
+ /* big kernels must be loaded into extended memory */
+ addr= mem[1].base;
+ limit= mem[1].base + mem[1].size;
+
+ /* Get first sector */
+ DEBUGEXTRA(("get_sector\n"));
+ if ((buf= get_sector(vsec++)) == nil) {
+ DEBUGEXTRA(("get_sector failed\n"));
+ return;
+ }
+ memcpy(hdr, buf, SECTOR_SIZE);
+
+ /* Get ELF header */
+ DEBUGEXTRA(("read_header_elf\n"));
+ r = read_header_elf(hdr, &text_vaddr, &text_paddr,
+ &text_filebytes, &text_membytes,
+ &data_vaddr, &data_paddr,
+ &data_filebytes, &data_membytes,
+ &pc, &text_offset, &data_offset);
+ if (r < 0) { errno= ENOEXEC; return; }
+
+ /* Read the text segment. */
+ addr = text_paddr;
+ segsize = (i32_t) text_filebytes;
+ vsec = text_offset / SECTOR_SIZE;
+ DEBUGEXTRA(("get_segment(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
+ vsec, segsize, addr, limit));
+ if (!get_segment(&vsec, &segsize, &addr, limit)) return;
+ DEBUGEXTRA(("get_segment done vsec=0x%lx size=0x%lx "
+ "addr=0x%lx\n",
+ vsec, segsize, addr));
+
+ /* Read the data segment. */
+ addr = data_paddr;
+ segsize = (i32_t) data_filebytes;
+ vsec = data_offset / SECTOR_SIZE;
+
+ DEBUGEXTRA(("get_segment(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
+ vsec, segsize, addr, limit));
+ if (!get_segment(&vsec, &segsize, &addr, limit)) return;
+ DEBUGEXTRA(("get_segment done vsec=0x%lx size=0x%lx "
+ "addr=0x%lx\n",
+ vsec, segsize, addr));
+
+ n = data_membytes - align(data_filebytes, click_size);
+
+ /* Zero out bss. */
+ DEBUGEXTRA(("\nraw_clear(0x%lx, 0x%lx); limit=0x%lx... ", addr, n, limit));
+ if (addr + n > limit) { errno= ENOMEM; return; }
+ raw_clear(addr, n);
+ DEBUGEXTRA(("done\n"));
+ addr+= n;
+
+ /* Check the kernel magic number. */
+ raw_copy(mon2abs(&kmagic),
+ data_paddr + MAGIC_OFF, sizeof(kmagic));
+ if (kmagic != KERNEL_D_MAGIC) {
+ printf("Kernel magic number is incorrect (0x%x@0x%lx)\n",
+ kmagic, data_paddr + MAGIC_OFF);
+ errno= 0;
+ return;
+ }
+
+ /* Translate the boot parameters to what Minix likes best. */
+ DEBUGEXTRA(("params2params(0x%x, 0x%x)... ", params, sizeof(params)));
+ if (!params2params(params, sizeof(params))) { errno= 0; return; }
+ DEBUGEXTRA(("done\n"));
+
+ /* Create multiboot info struct */
+ mbinfo = malloc(sizeof(multiboot_info_t));
+ if (mbinfo == nil) { errno= ENOMEM; return; }
+ memset(mbinfo, 0, sizeof(multiboot_info_t));
+
+ /* Module info structs start where kernel ends */
+ mbinfo->mods_addr = addr;
+
+ modstring = strdup(modules);
+ if (modstring == nil) {errno = ENOMEM; return; }
+ modstringlen = strlen(modules);
+ mbinfo->mods_count = split_module_list(modules);
+
+ mbmodinfo_size = sizeof(multiboot_module_t) * mbinfo->mods_count;
+ mbmodinfo = malloc(mbmodinfo_size);
+ if (mbmodinfo == nil) { errno= ENOMEM; return; }
+ addr+= mbmodinfo_size;
+ addr= align(addr, click_size);
+
+ mod_cmdline_start = mbinfo->mods_addr + sizeof(multiboot_module_t) *
+ mbinfo->mods_count;
+
+ raw_copy(mod_cmdline_start, mon2abs(modules),
+ modstringlen+1);
+
+ mbmodinfo[0].cmdline = mod_cmdline_start;
+ modnr = 1;
+ for (i= 0; i < modstringlen; ++i) {
+ if (modules[i] == '\0') {
+ mbmodinfo[modnr].cmdline = mod_cmdline_start + i + 1;
+ ++modnr;
+ }
+ }
+
+ kernel_cmdline_start = mod_cmdline_start + modstringlen + 1;
+ mbinfo->cmdline = kernel_cmdline_start;
+ raw_copy(kernel_cmdline_start, mon2abs(kernel),
+ strlen(kernel)+1);
+
+ mbinfo->flags = MULTIBOOT_INFO_MODS|MULTIBOOT_INFO_CMDLINE|
+ MULTIBOOT_INFO_BOOTDEV|MULTIBOOT_INFO_MEMORY;
+
+ mbinfo->boot_device = mbdev;
+ mbinfo->mem_lower = mem[0].size/1024;
+ mbinfo->mem_upper = mem[1].size/1024;
+
+ for (i = 0, mod = strtok(modstring, " "); mod != nil;
+ mod = strtok(nil, " "), i++) {
+
+ mod = select_image(mod);
+ if (mod == nil) {errno = 0; return; }
+
+ mbmodinfo[i].mod_start = addr;
+ mbmodinfo[i].mod_end = addr + image_bytes;
+ mbmodinfo[i].pad = 0;
+
+ segsize= image_bytes;
+ vsec= 0;
+ DEBUGEXTRA(("get_segment(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
+ vsec, segsize, addr, limit));
+ if (!get_segment(&vsec, &segsize, &addr, limit)) return;
+ DEBUGEXTRA(("get_segment done vsec=0x%lx size=0x%lx "
+ "addr=0x%lx\n",
+ vsec, segsize, addr));
+ addr+= segsize;
+ addr= align(addr, click_size);
+ }
+ free(modstring);
+
+ DEBUGEXTRA(("modinfo raw_copy: dst 0x%lx src 0x%lx sz 0x%lx\n",
+ mbinfo->mods_addr, mon2abs(mbmodinfo),
+ mbmodinfo_size));
+ raw_copy(mbinfo->mods_addr, mon2abs(mbmodinfo),
+ mbmodinfo_size);
+ free(mbmodinfo);
+
+ raw_copy(MULTIBOOT_INFO_ADDR, mon2abs(mbinfo),
+ sizeof(multiboot_info_t));
+ free(mbinfo);
+
+ /* Run the trailer function just before starting Minix. */
+ DEBUGEXTRA(("run_trailer()... "));
+ if (!run_trailer()) { errno= 0; return; }
+ DEBUGEXTRA(("done\n"));
+
+ /* Set the video to the required mode. */
+ if ((console= b_value("console")) == nil || (mode= a2x(console)) == 0) {
+ mode= strcmp(b_value("chrome"), "color") == 0 ? COLOR_MODE :
+ MONO_MODE;
+ }
+ DEBUGEXTRA(("set_mode(%d)... ", mode));
+ set_mode(mode);
+ DEBUGEXTRA(("done\n"));
+
+ /* Close the disk. */
+ DEBUGEXTRA(("dev_close()... "));
+ (void) dev_close();
+ DEBUGEXTRA(("done\n"));
+
+ /* Minix. */
+ cs = ds = text_paddr;
+ DEBUGEXTRA(("minix(0x%lx, 0x%lx, 0x%lx, 0x%x, 0x%x, 0x%lx)\n",
+ pc, cs, ds, params, sizeof(params), 0));
+ minix(pc, cs, ds, params, sizeof(params), 0);
+
+ if (!(k_flags & K_BRET)) {
+ extern u32_t reboot_code;
+ raw_copy(mon2abs(params), reboot_code, sizeof(params));
+ }
+ parse_code(params);
+
+ /* Return from Minix. Things may have changed, so assume nothing. */
+ fsok= -1;
+ errno= 0;
+
+ /* Read leftover character, if any. */
+ scan_keyboard();
+
+ /* Restore screen contents. */
+ restore_screen();
+}
+
void exec_image(char *image)
/* Get a Minix image into core, patch it up and execute. */
{
raw_clear(aout, PROCESS_MAX * A_MINHDR);
/* Read the many different processes: */
- for (i= 0; vsec < image_size; i++) {
+ for (i= 0; vsec < image_sectors; i++) {
u32_t startaddr;
startaddr = addr;
if (i == PROCESS_MAX) {
&& numeric(size)) {
vir2sec= flat_vir2sec;
image_off= a2l(image);
- image_size= a2l(size);
+ image_sectors= a2l(size);
strcpy(image, "Minix");
return image;
}
}
r_stat(image_ino, &st);
+ image_bytes = st.st_size;
+
if (!S_ISREG(st.st_mode)) {
char *version= image + strlen(image);
char dots[NAME_MAX + 1];
r_stat(image_ino, &st);
}
vir2sec= file_vir2sec;
- image_size= (st.st_size + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
+ image_sectors= (st.st_size + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
return image;
bail_out:
free(image);
*/
{
char *image;
+ char *mb;
+ char *kernel;
+ /* FIXME: modules should come from environment */
+ char modules[] = "boot/ds boot/rs boot/pm boot/sched boot/vfs boot/memory boot/log boot/tty boot/mfs boot/vm boot/pfs boot/init";
+
+ if ((mb = b_value("mb")) != nil) {
+ do_multiboot = a2l(mb);
+ kernel = b_value("kernel");
+ if (kernel == nil) {
+ printf("kernel not set\n");
+ return;
+ }
+ }
- if ((image= select_image(b_value("image"))) == nil) return;
+ if (do_multiboot) {
+ if ((kernel= select_image(b_value("kernel"))) == nil) return;
+ } else {
+ if ((image= select_image(b_value("image"))) == nil) return;
+ }
if(serial_line >= 0) {
char linename[2];
b_setvar(E_VAR, SERVARNAME, linename);
}
- exec_image(image);
+ if (do_multiboot)
+ exec_mb(kernel, modules);
+ else
+ exec_image(image);
switch (errno) {
case ENOEXEC:
- printf("%s contains a bad program header\n", image);
+ printf("%s contains a bad program header\n",
+ do_multiboot ? kernel : image);
break;
case ENOMEM:
- printf("Not enough memory to load %s\n", image);
+ printf("Not enough memory to load %s\n",
+ do_multiboot ? kernel : image);
break;
case EIO:
- printf("Unexpected EOF on %s\n", image);
+ printf("Unexpected EOF on %s\n",
+ do_multiboot ? kernel : image);
case 0:
/* No error or error already reported. */;
}
- free(image);
+
+ if (do_multiboot)
+ free(kernel);
+ else
+ free(image);
if(serial_line >= 0)
b_unset(SERVARNAME);
}
+size_t
+strspn(const char *string, const char *in)
+{
+ register const char *s1, *s2;
+
+ for (s1 = string; *s1; s1++) {
+ for (s2 = in; *s2 && *s2 != *s1; s2++)
+ /* EMPTY */ ;
+ if (*s2 == '\0')
+ break;
+ }
+ return s1 - string;
+}
+
+char *
+strpbrk(register const char *string, register const char *brk)
+{
+ register const char *s1;
+
+ while (*string) {
+ for (s1 = brk; *s1 && *s1 != *string; s1++)
+ /* EMPTY */ ;
+ if (*s1)
+ return (char *)string;
+ string++;
+ }
+ return (char *)NULL;
+}
+
+char *
+strtok(register char *string, const char *separators)
+{
+ register char *s1, *s2;
+ static char *savestring = NULL;
+
+ if (string == NULL) {
+ string = savestring;
+ if (string == NULL) return (char *)NULL;
+ }
+
+ s1 = string + strspn(string, separators);
+ if (*s1 == '\0') {
+ savestring = NULL;
+ return (char *)NULL;
+ }
+
+ s2 = strpbrk(s1, separators);
+ if (s2 != NULL)
+ *s2++ = '\0';
+ savestring = s2;
+ return s1;
+}
+
+char *
+strdup(const char *s1)
+{
+ size_t len;
+ char *s2;
+
+ len= strlen(s1)+1;
+
+ s2= malloc(len);
+ if (s2 == NULL)
+ return NULL;
+ strcpy(s2, s1);
+
+ return s2;
+}
+
/*
* $PchId: bootimage.c,v 1.10 2002/02/27 19:39:09 philip Exp $
*/
--- /dev/null
+/*
+ * Update physical addresses of boot services
+ */
+
+#include <sys/param.h>
+
+#include <err.h>
+#include <fcntl.h>
+
+#include <gelf.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#define BOOTPROG_LOAD_START 0x05000000ULL
+
+int nflag = 0;
+
+int stack_kbytes[] = {
+ /* ds rs pm sched vfs memory log tty mfs vm pfs init */
+ 16, 8125, 32, 32, 16, 8, 32, 16, 128, 128, 128, 64
+};
+
+static void usage(void);
+
+GElf_Addr
+update_paddr(int nr, char *fname, GElf_Addr startaddr)
+{
+ int i, fd;
+ Elf *e;
+ size_t n;
+
+ GElf_Phdr phdr;
+ GElf_Addr endaddr = 0;
+
+ if ((fd = open(fname, O_RDWR, 0)) < 0)
+ err(EX_NOINPUT, "open \"%s\" failed", fname);
+
+ if ((e = elf_begin(fd, ELF_C_RDWR, NULL)) == NULL)
+ errx(EX_SOFTWARE, "elf_begin() failed: %s.", elf_errmsg(-1));
+
+ if (elf_kind(e) != ELF_K_ELF)
+ errx(EX_DATAERR, "\"%s\" is not an ELF object.", fname);
+
+ if (elf_getphdrnum(e, &n) != 0)
+ errx(EX_DATAERR, "elf_getphdrnum() failed: %s.", elf_errmsg(-1));
+
+ for (i = 0; i < n; i++) {
+ if (gelf_getphdr(e, i, &phdr) != &phdr)
+ errx(EX_SOFTWARE, "getphdr() failed: %s.",
+ elf_errmsg(-1));
+
+ if (phdr.p_type == PT_LOAD) {
+ phdr.p_paddr = startaddr + phdr.p_vaddr;
+
+ endaddr = round_page(phdr.p_paddr + phdr.p_memsz)
+ + round_page(stack_kbytes[nr] * 1024);
+
+ if (gelf_update_phdr(e, i, &phdr) < 0)
+ errx(EX_SOFTWARE,
+ "gelf_update_phdr failed: %s.",
+ elf_errmsg(-1));
+ }
+
+ }
+
+ if (elf_update(e, ELF_C_WRITE) < 0)
+ errx(EX_SOFTWARE, "elf_update failed: %s.", elf_errmsg(-1));
+
+ (void) elf_end(e);
+ (void) close(fd);
+
+ return endaddr;
+
+}
+
+int
+main(int argc, char **argv)
+{
+ int i, ch;
+ GElf_Addr startaddr, endaddr;
+
+ startaddr = BOOTPROG_LOAD_START;
+
+ while ((ch = getopt(argc, argv, "n")) != -1) {
+ switch (ch) {
+ case 'n':
+ nflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ exit(EX_USAGE);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1)
+ usage();
+
+ if (elf_version(EV_CURRENT) == EV_NONE)
+ errx(EX_SOFTWARE, "ELF library intialization failed: %s",
+ elf_errmsg(-1));
+
+ startaddr = BOOTPROG_LOAD_START;
+ for (i = 0; i < argc; i++) {
+ startaddr = update_paddr(i, argv[i], startaddr);
+ }
+
+ exit(EX_OK);
+}
+
+static void
+usage(void)
+{
+ (void) fprintf(stderr, "usage: %s [-n] elf1 elf2...\n", getprogname());
+}
/* Support only 32-bit ELF objects */
#define __ELF_WORD_SIZE 32
+#define SECTOR_SIZE 512
+
static int __elfN(check_header)(const Elf_Ehdr *hdr);
int read_header_elf(
unsigned long seg_filebytes, seg_membytes;
int i = 0;
- assert(exec_hdr != NULL);
-
*text_vaddr = *text_paddr = 0;
*text_filebytes = *text_membytes = 0;
*data_vaddr = *data_paddr = 0;
return ENOEXEC;
}
- if ((hdr->e_phoff > PAGE_SIZE) ||
- (hdr->e_phoff + hdr->e_phentsize * hdr->e_phnum) > PAGE_SIZE) {
+ if ((hdr->e_phoff > SECTOR_SIZE) ||
+ (hdr->e_phoff + hdr->e_phentsize * hdr->e_phnum) > SECTOR_SIZE) {
return ENOEXEC;
}
#ifdef __NBSD_LIBC
rounddown((uintptr_t)phdr, sizeof(Elf_Addr)) != (uintptr_t)phdr
#else
- !_minix_aligned(phdr, Elf_Addr)
+ !_minix_aligned(hdr->e_phoff, Elf_Addr)
#endif
) {
return ENOEXEC;
}
#if ELF_DEBUG
- printf("Program header file offset (phoff): %d\n", hdr->e_phoff);
- printf("Section header file offset (shoff): %d\n", hdr->e_shoff);
+ printf("Program header file offset (phoff): %ld\n", hdr->e_phoff);
+ printf("Section header file offset (shoff): %ld\n", hdr->e_shoff);
printf("Program header entry size (phentsize): %d\n", hdr->e_phentsize);
printf("Program header entry num (phnum): %d\n", hdr->e_phnum);
printf("Section header entry size (shentsize): %d\n", hdr->e_shentsize);
printf("Section header entry num (shnum): %d\n", hdr->e_shnum);
printf("Section name strings index (shstrndx): %d\n", hdr->e_shstrndx);
- printf("Entry Point: 0x%x\n", hdr->e_entry);
+ printf("Entry Point: 0x%lx\n", hdr->e_entry);
#endif
for (i = 0; i < hdr->e_phnum; i++) {
}
#if ELF_DEBUG
- printf("Text vaddr: 0x%x\n", *text_vaddr);
- printf("Text paddr: 0x%x\n", *text_paddr);
- printf("Text filebytes: 0x%x\n", *text_filebytes);
- printf("Text membytes: 0x%x\n", *text_membytes);
- printf("Data vaddr: 0x%x\n", *data_vaddr);
- printf("Data paddr: 0x%x\n", *data_paddr);
- printf("Data filebyte: 0x%x\n", *data_filebytes);
- printf("Data membytes: 0x%x\n", *data_membytes);
- printf("Tot bytes: 0x%x\n", *tot_bytes);
- printf("PC: 0x%x\n", *pc);
- printf("Text offset: 0x%x\n", *text_offset);
- printf("Data offset: 0x%x\n", *data_offset);
+ printf("Text vaddr: 0x%lx\n", *text_vaddr);
+ printf("Text paddr: 0x%lx\n", *text_paddr);
+ printf("Text filebytes: 0x%lx\n", *text_filebytes);
+ printf("Text membytes: 0x%lx\n", *text_membytes);
+ printf("Data vaddr: 0x%lx\n", *data_vaddr);
+ printf("Data paddr: 0x%lx\n", *data_paddr);
+ printf("Data filebyte: 0x%lx\n", *data_filebytes);
+ printf("Data membytes: 0x%lx\n", *data_membytes);
+ printf("PC: 0x%lx\n", *pc);
+ printf("Text offset: 0x%lx\n", *text_offset);
+ printf("Data offset: 0x%lx\n", *data_offset);
#endif
return OK;