char *select_image(char *image) /* Look image up on the filesystem, if it is a file then we're done, but * if its a directory then we want the newest file in that directory. If * it doesn't exist at all, then see if it is 'number:number' and get the * image from that absolute offset off the disk. */ { ino_t image_ino; struct stat st; image= strcpy(malloc((strlen(image) + 1 + NAME_MAX + 1) * sizeof(char)), image); fsok= r_super(&block_size) != 0; if (!fsok || (image_ino= r_lookup(ROOT_INO, image)) == 0) { char *size; if (numprefix(image, &size) && *size++ == ':' && numeric(size)) { vir2sec= flat_vir2sec; image_off= a2l(image); image_sectors= a2l(size); strcpy(image, "Minix"); return image; } if (!fsok) printf("No image selected\n"); else printf("Can't load %s: %s\n", image, unix_err(errno)); goto bail_out; } 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]; if (!S_ISDIR(st.st_mode)) { printf("%s: %s\n", image, unix_err(ENOTDIR)); goto bail_out; } (void) r_readdir(dots); (void) r_readdir(dots); /* "." & ".." */ *version++= '/'; *version= 0; if ((image_ino= latest_version(version, &st)) == 0) { printf("There are no images in %s\n", image); goto bail_out; } r_stat(image_ino, &st); } vir2sec= file_vir2sec; image_sectors= (st.st_size + SECTOR_SIZE - 1) >> SECTOR_SHIFT; return image; bail_out: free(image); return nil; }
void exec_image(char *image) /* Get a Minix image into core, patch it up and execute. */ { int i; struct image_header hdr; char *buf; u32_t vsec, addr, limit, aout, n, totalmem = 0; struct process *procp; /* Process under construction. */ long a_text, a_data, a_bss, a_stack; int banner= 0; long processor= a2l(b_value("processor")); u16_t kmagic, mode; char *console; char params[SECTOR_SIZE]; extern char *sbrk(int); char *verb; /* 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 "); pretty_image(image); printf(".\n"); vsec= 0; /* Load this sector from image next. */ addr= mem[0].base; /* Into this memory block. */ limit= mem[0].base + mem[0].size; if (limit > caddr) limit= caddr; /* Allocate and clear the area where the headers will be placed. */ aout = (limit -= PROCESS_MAX * A_MINHDR); /* Clear the area where the headers will be placed. */ raw_clear(aout, PROCESS_MAX * A_MINHDR); /* Read the many different processes: */ for (i= 0; vsec < image_size; i++) { u32_t startaddr; startaddr = addr; if (i == PROCESS_MAX) { printf("There are more then %d programs in %s\n", PROCESS_MAX, image); errno= 0; return; } procp= &process[i]; /* Read header. */ DEBUGEXTRA(("Reading header... ")); for (;;) { if ((buf= get_sector(vsec++)) == nil) return; memcpy(&hdr, buf, sizeof(hdr)); if (BADMAG(hdr.process)) { errno= ENOEXEC; return; } /* Check the optional label on the process. */ if (selected(hdr.name)) break; /* Bad label, skip this process. */ vsec+= proc_size(&hdr); } DEBUGEXTRA(("done\n")); /* Sanity check: an 8086 can't run a 386 kernel. */ if (hdr.process.a_cpu == A_I80386 && processor < 386) { printf("You can't run a 386 kernel on this 80%ld\n", processor); errno= 0; return; } /* Get the click shift from the kernel text segment. */ if (i == KERNEL_IDX) { if (!get_clickshift(vsec, &hdr)) return; addr= align(addr, click_size); /* big kernels must be loaded into extended memory */ if (k_flags & K_KHIGH) { addr= mem[1].base; limit= mem[1].base + mem[1].size; } } /* Save a copy of the header for the kernel, with a_syms * misused as the address where the process is loaded at. */ DEBUGEXTRA(("raw_copy(0x%x, 0x%lx, 0x%x)... ", aout + i * A_MINHDR, mon2abs(&hdr.process), A_MINHDR)); hdr.process.a_syms= addr; raw_copy(aout + i * A_MINHDR, mon2abs(&hdr.process), A_MINHDR); DEBUGEXTRA(("done\n")); if (!banner) { DEBUGBASIC((" cs ds text data bss")); if (k_flags & K_CHMEM) DEBUGBASIC((" stack")); DEBUGBASIC(("\n")); banner= 1; } /* Segment sizes. */ DEBUGEXTRA(("a_text=0x%lx; a_data=0x%lx; a_bss=0x%lx; a_flags=0x%x)\n", hdr.process.a_text, hdr.process.a_data, hdr.process.a_bss, hdr.process.a_flags)); a_text= hdr.process.a_text; a_data= hdr.process.a_data; a_bss= hdr.process.a_bss; if (k_flags & K_CHMEM) { a_stack= hdr.process.a_total - a_data - a_bss; if (!(hdr.process.a_flags & A_SEP)) a_stack-= a_text; } else { a_stack= 0; } /* Collect info about the process to be. */ procp->cs= addr; /* Process may be page aligned so that the text segment contains * the header, or have an unmapped zero page against vaxisms. */ procp->entry= hdr.process.a_entry; if (hdr.process.a_flags & A_PAL) a_text+= hdr.process.a_hdrlen; if (hdr.process.a_flags & A_UZP) procp->cs-= click_size; /* Separate I&D: two segments. Common I&D: only one. */ if (hdr.process.a_flags & A_SEP) { /* Read the text segment. */ DEBUGEXTRA(("get_segment(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n", vsec, a_text, addr, limit)); if (!get_segment(&vsec, &a_text, &addr, limit)) return; DEBUGEXTRA(("get_segment done vsec=0x%lx a_text=0x%lx " "addr=0x%lx\n", vsec, a_text, addr)); /* The data segment follows. */ procp->ds= addr; if (hdr.process.a_flags & A_UZP) procp->ds-= click_size; procp->data= addr; } else { /* Add text to data to form one segment. */ procp->data= addr + a_text; procp->ds= procp->cs; a_data+= a_text; } /* Read the data segment. */ DEBUGEXTRA(("get_segment(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n", vsec, a_data, addr, limit)); if (!get_segment(&vsec, &a_data, &addr, limit)) return; DEBUGEXTRA(("get_segment done vsec=0x%lx a_data=0x%lx " "addr=0x%lx\n", vsec, a_data, addr)); /* Make space for bss and stack unless... */ if (i != KERNEL_IDX && (k_flags & K_CLAIM)) a_bss= a_stack= 0; DEBUGBASIC(("%07lx %07lx %8ld %8ld %8ld", procp->cs, procp->ds, hdr.process.a_text, hdr.process.a_data, hdr.process.a_bss)); if (k_flags & K_CHMEM) DEBUGBASIC((" %8ld", a_stack)); /* Note that a_data may be negative now, but we can look at it * as -a_data bss bytes. */ /* Compute the number of bss clicks left. */ a_bss+= a_data; n= align(a_bss, click_size); a_bss-= n; /* 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; /* And the number of stack clicks. */ a_stack+= a_bss; n= align(a_stack, click_size); a_stack-= n; /* Add space for the stack. */ addr+= n; /* Process endpoint. */ procp->end= addr; if (verboseboot >= VERBOSEBOOT_BASIC) printf(" %s\n", hdr.name); else { u32_t mem; mem = addr-startaddr; printf("%s ", hdr.name); totalmem += mem; } if (i == 0 && (k_flags & (K_HIGH | K_KHIGH)) == K_HIGH) { /* Load the rest in extended memory. */ addr= mem[1].base; limit= mem[1].base + mem[1].size; } } if (verboseboot < VERBOSEBOOT_BASIC) printf("(%dk)\n", totalmem/1024); if ((n_procs= i) == 0) { printf("There are no programs in %s\n", image); errno= 0; return; } /* Check the kernel magic number. */ raw_copy(mon2abs(&kmagic), process[KERNEL_IDX].data + MAGIC_OFF, sizeof(kmagic)); if (kmagic != KERNEL_D_MAGIC) { printf("Kernel magic number is incorrect (0x%x@0x%lx)\n", kmagic, process[KERNEL_IDX].data + MAGIC_OFF); errno= 0; return; } /* Patch sizes, etc. into kernel data. */ DEBUGEXTRA(("patch_sizes()... ")); patch_sizes(); DEBUGEXTRA(("done\n")); #if !DOS if (!(k_flags & K_MEML)) { /* Copy the a.out headers to the old place. */ raw_copy(HEADERPOS, aout, PROCESS_MAX * A_MINHDR); } #endif /* Run the trailer function just before starting Minix. */ DEBUGEXTRA(("run_trailer()... ")); if (!run_trailer()) { errno= 0; return; } DEBUGEXTRA(("done\n")); /* 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")); /* 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. */ DEBUGEXTRA(("minix(0x%lx, 0x%lx, 0x%lx, 0x%x, 0x%x, 0x%lx)\n", process[KERNEL_IDX].entry, process[KERNEL_IDX].cs, process[KERNEL_IDX].ds, params, sizeof(params), aout)); minix(process[KERNEL_IDX].entry, process[KERNEL_IDX].cs, process[KERNEL_IDX].ds, params, sizeof(params), aout); 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_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 bootminix(void) /* Load Minix and run it. (Given the size of this program it is surprising * that it ever gets to that.) */ { 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 (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]; linename[0] = serial_line + '0'; linename[1] = '\0'; b_setvar(E_VAR, SERVARNAME, linename); } if (do_multiboot) exec_mb(kernel, modules); else exec_image(image); switch (errno) { case ENOEXEC: printf("%s contains a bad program header\n", do_multiboot ? kernel : image); break; case ENOMEM: printf("Not enough memory to load %s\n", do_multiboot ? kernel : image); break; case EIO: printf("Unexpected EOF on %s\n", do_multiboot ? kernel : image); case 0: /* No error or error already reported. */; } if (do_multiboot) free(kernel); else free(image); if(serial_line >= 0) b_unset(SERVARNAME); }