static void start_kernel(char *kernel, char *bootline, void *ofw, int isfloppy, int boothowto) { int fd; u_long marks[MARK_MAX] = {0}; int flags = LOAD_ALL; if (isfloppy) flags &= ~LOAD_BACKWARDS; /* * First, load headers using default allocator and check whether kernel * entry address matches kernel text load address. If yes, this is the * old kernel designed for ofwboot v1.8 and therefore it must be mapped * by PROM. Otherwise, map the kernel with 4MB permanent pages. */ loadfile_set_allocator(LOADFILE_NOP_ALLOCATOR); if ( (fd = loadfile(kernel, marks, LOAD_HDR|COUNT_TEXT)) != -1) { if (COMPAT_BOOT(marks) || compatmode) { (void)printf("[c] "); loadfile_set_allocator(LOADFILE_OFW_ALLOCATOR); } else { loadfile_set_allocator(LOADFILE_MMU_ALLOCATOR); } (void)printf("Loading %s: ", kernel); if (fdloadfile(fd, marks, flags) != -1) { close(fd); jump_to_kernel(marks, kernel, bootline, ofw, boothowto); } } (void)printf("Failed to load '%s'.\n", kernel); }
/* * Open 'filename', read in program and return the opened file * descriptor if ok, or -1 on error. * Fill in marks */ int loadfile(const char *fname, u_long *marks, int flags) { int fd, error; /* Open the file. */ if ((fd = open(fname, 0)) < 0) { WARN(("open %s", fname ? fname : "<default>")); return -1; } /* Load it; save the value of errno across the close() call */ if ((error = fdloadfile(fd, marks, flags)) != 0) { (void)close(fd); errno = error; return -1; } return fd; }
void main(int argc, char *argv[], char *bootargs_start, char *bootargs_end) { unsigned long marks[MARK_MAX]; struct brdprop *brdprop; char *new_argv[MAX_ARGS]; char *bname; ssize_t len; int err, fd, howto, i, n; printf("\n>> %s altboot, revision %s\n", bootprog_name, bootprog_rev); brdprop = brd_lookup(brdtype); printf(">> %s, cpu %u MHz, bus %u MHz, %dMB SDRAM\n", brdprop->verbose, cpuclock / 1000000, busclock / 1000000, bi_mem.memsize >> 20); nata = pcilookup(PCI_CLASS_IDE, lata, 2); if (nata == 0) nata = pcilookup(PCI_CLASS_RAID, lata, 2); if (nata == 0) nata = pcilookup(PCI_CLASS_MISCSTORAGE, lata, 2); if (nata == 0) nata = pcilookup(PCI_CLASS_SCSI, lata, 2); nnif = pcilookup(PCI_CLASS_ETH, lnif, 2); nusb = pcilookup(PCI_CLASS_USB, lusb, 3); #ifdef DEBUG if (nata == 0) printf("No IDE/SATA found\n"); else for (n = 0; n < nata; n++) { int b, d, f, bdf, pvd; bdf = lata[n].bdf; pvd = lata[n].pvd; pcidecomposetag(bdf, &b, &d, &f); printf("%04x.%04x DSK %02d:%02d:%02d\n", PCI_VENDOR(pvd), PCI_PRODUCT(pvd), b, d, f); } if (nnif == 0) printf("no NET found\n"); else for (n = 0; n < nnif; n++) { int b, d, f, bdf, pvd; bdf = lnif[n].bdf; pvd = lnif[n].pvd; pcidecomposetag(bdf, &b, &d, &f); printf("%04x.%04x NET %02d:%02d:%02d\n", PCI_VENDOR(pvd), PCI_PRODUCT(pvd), b, d, f); } if (nusb == 0) printf("no USB found\n"); else for (n = 0; n < nusb; n++) { int b, d, f, bdf, pvd; bdf = lusb[0].bdf; pvd = lusb[0].pvd; pcidecomposetag(bdf, &b, &d, &f); printf("%04x.%04x USB %02d:%02d:%02d\n", PCI_VENDOR(pvd), PCI_PRODUCT(pvd), b, d, f); } #endif pcisetup(); pcifixup(); /* * When argc is too big then it is probably a pointer, which could * indicate that we were launched as a Linux kernel module using * "bootm". */ if (argc > MAX_ARGS) { if (argv != NULL) { /* * initrd image was loaded: * check if it contains a valid altboot command line */ char *p = (char *)argv; if (strncmp(p, "altboot:", 8) == 0) { *p = 0; for (p = p + 8; *p >= ' '; p++); argc = parse_cmdline(new_argv, MAX_ARGS, ((char *)argv) + 8, p); argv = new_argv; } else argc = 0; /* boot default */ } else { /* parse standard Linux bootargs */ argc = parse_cmdline(new_argv, MAX_ARGS, bootargs_start, bootargs_end); argv = new_argv; } } /* look for a PATA drive configuration string under the arguments */ for (n = 1; n < argc; n++) { if (strncmp(argv[n], "ide:", 4) == 0 && argv[n][4] >= '0' && argv[n][4] <= '2') { drive_config = &argv[n][4]; break; } } /* intialize a disk driver */ for (i = 0, n = 0; i < nata; i++) n += dskdv_init(&lata[i]); if (n == 0) printf("IDE/SATA device driver was not found\n"); /* initialize a network interface */ for (n = 0; n < nnif; n++) if (netif_init(&lnif[n]) != 0) break; if (n >= nnif) printf("no NET device driver was found\n"); /* wait 2s for user to enter interactive mode */ for (n = 200; n >= 0; n--) { if (n % 100 == 0) printf("\rHit any key to enter interactive mode: %d", n / 100); if (tstchar()) { #ifdef DEBUG unsigned c; c = toupper(getchar()); if (c == 'C') { /* controller test terminal */ sat_test(); n = 200; continue; } else if (c == 'F') { /* find strings in Flash ROM */ findflash(); n = 200; continue; } #else (void)getchar(); #endif /* enter command line */ argv = new_argv; argc = input_cmdline(argv, MAX_ARGS); break; } delay(10000); } putchar('\n'); howto = RB_AUTOBOOT; /* default is autoboot = 0 */ /* get boot options and determine bootname */ for (n = 1; n < argc; n++) { if (strncmp(argv[n], "ide:", 4) == 0) continue; /* ignore drive configuration argument */ for (i = 0; i < sizeof(bootargs) / sizeof(bootargs[0]); i++) { if (strncasecmp(argv[n], bootargs[i].name, strlen(bootargs[i].name)) == 0) { howto |= bootargs[i].value; break; } } if (i >= sizeof(bootargs) / sizeof(bootargs[0])) break; /* break on first unknown string */ } /* * If no device name is given, we construct a list of drives * which have valid disklabels. */ if (n >= argc) { static const size_t blen = sizeof("wdN:"); n = 0; argc = 0; argv = alloc(MAX_UNITS * (sizeof(char *) + blen)); bname = (char *)(argv + MAX_UNITS); for (i = 0; i < MAX_UNITS; i++) { if (!dlabel_valid(i)) continue; snprintf(bname, blen, "wd%d:", i); argv[argc++] = bname; bname += blen; } /* use default drive if no valid disklabel is found */ if (argc == 0) { argc = 1; argv[0] = BNAME_DEFAULT; } } /* try to boot off kernel from the drive list */ while (n < argc) { bname = argv[n++]; if (check_bootname(bname) == 0) { printf("%s not a valid bootname\n", bname); continue; } if ((fd = open(bname, 0)) < 0) { if (errno == ENOENT) printf("\"%s\" not found\n", bi_path.bootpath); continue; } printf("loading \"%s\" ", bi_path.bootpath); marks[MARK_START] = 0; if (howto == -1) { /* load another altboot binary and replace ourselves */ len = read(fd, (void *)0x100000, 0x1000000 - 0x100000); if (len == -1) goto loadfail; close(fd); netif_shutdown_all(); memcpy((void *)0xf0000, newaltboot, newaltboot_end - newaltboot); __syncicache((void *)0xf0000, newaltboot_end - newaltboot); printf("Restarting...\n"); run((void *)1, argv, (void *)0x100000, (void *)len, (void *)0xf0000); } err = fdloadfile(fd, marks, LOAD_KERNEL); close(fd); if (err < 0) continue; printf("entry=%p, ssym=%p, esym=%p\n", (void *)marks[MARK_ENTRY], (void *)marks[MARK_SYM], (void *)marks[MARK_END]); bootinfo = (void *)0x4000; bi_init(bootinfo); bi_add(&bi_cons, BTINFO_CONSOLE, sizeof(bi_cons)); bi_add(&bi_mem, BTINFO_MEMORY, sizeof(bi_mem)); bi_add(&bi_clk, BTINFO_CLOCK, sizeof(bi_clk)); bi_add(&bi_path, BTINFO_BOOTPATH, sizeof(bi_path)); bi_add(&bi_rdev, BTINFO_ROOTDEVICE, sizeof(bi_rdev)); bi_add(&bi_fam, BTINFO_PRODFAMILY, sizeof(bi_fam)); if (brdtype == BRD_SYNOLOGY || brdtype == BRD_DLINKDSM) { /* need to pass this MAC address to kernel */ bi_add(&bi_net, BTINFO_NET, sizeof(bi_net)); } if (modules_enabled) { if (fsmod != NULL) module_add(fsmod); kmodloadp = marks[MARK_END]; btinfo_modulelist = NULL; module_load(bname); if (btinfo_modulelist != NULL && btinfo_modulelist->num > 0) bi_add(btinfo_modulelist, BTINFO_MODULELIST, btinfo_modulelist_size); } launchfixup(); netif_shutdown_all(); __syncicache((void *)marks[MARK_ENTRY], (u_int)marks[MARK_SYM] - (u_int)marks[MARK_ENTRY]); run((void *)marks[MARK_SYM], (void *)marks[MARK_END], (void *)howto, bootinfo, (void *)marks[MARK_ENTRY]); /* should never come here */ printf("exec returned. Restarting...\n"); _rtt(); } loadfail: printf("load failed. Restarting...\n"); _rtt(); }
static int loadk(char *file, u_long *marks) { int fd, error, flags; vaddr_t va; paddr_t pa; u_long minsize, size; vaddr_t extra; /* * Regardless of the address where we load the kernel, we need to * make sure it has enough valid space to use during pmap_bootstrap. * locore.s tries to map the 512KB following the kernel image, and * we need to make sure this extra room does not overwrite PROM data * (such as the PROM page tables which are immediately below 4MB on * most sun4c). */ extra = 512 * 1024; if ((fd = open(file, O_RDONLY)) < 0) return (errno ? errno : ENOENT); /* * We need to know whether we are booting off a tape or not, * because we can not seek backwards off tapes. */ if (files[fd].f_flags & F_RAW) { flags = (COUNT_KERNEL & ~COUNT_SYM) | (LOAD_KERNEL & ~LOAD_SYM); minsize = FOURMB; va = 0xf8000000; /* KERNBASE */ #ifdef DEBUG printf("Tape boot: expecting a bsd.rd kernel smaller than %p\n", minsize); #endif /* compensate for extra room below */ minsize -= extra; } else { /* * If we did not load a random.seed file yet, try and load * one. */ if (rnd_loaded == 0) { /* * Some PROM do not like having a network device * open()ed twice; better close and reopen after * trying to get randomness. */ close(fd); rnd_loaded = loadrandom(BOOTRANDOM, rnddata, sizeof(rnddata)); if ((fd = open(file, O_RDONLY)) < 0) return (errno ? errno : ENOENT); } flags = LOAD_KERNEL; marks[MARK_START] = 0; /* * Even though we just have opened the file, the gzip code * has tried to read from it. Be sure to reset position in * case the file is not compressed (transparent mode isn't * so transparent...) */ if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { error = errno; goto out; } if ((error = fdloadfile(fd, marks, COUNT_KERNEL)) != 0) goto out; /* rewind file for the actual load operation later */ if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { error = errno; goto out; } minsize = marks[MARK_END] - marks[MARK_START]; /* We want that leading 16K in front of the kernel image */ minsize += PROM_LOADADDR; va = marks[MARK_START] - PROM_LOADADDR; } /* * If the kernel would entirely fit under the boot code, and the * boot code has been loaded 1:1, we do not need to allocate * breathing room after it. */ size = minsize + extra; if (compat != 0) { if (minsize + extra <= RELOC2 - LOWSTACK) size = RELOC2 - LOWSTACK; else compat = 0; } /* Get a physical load address */ #ifdef DEBUG printf("kernel footprint %p, requesting %p\n", minsize, size); #endif pa = getphysmem(size); if (pa == (paddr_t)-1) { /* * The extra bootstrap memory estimate might have been * too much, if physical memory doesn't have any contiguous * large chunks (e.g. on sun4c systems with 4MB regions). * If that increase caused us to cross a 4MB boundary, try * to limit ourselves to a 4MB multiple. */ if (compat == 0 && size / FOURMB != minsize / FOURMB) { size = roundup(minsize, FOURMB); #ifdef DEBUG printf("now trying %p\n", size); #endif pa = getphysmem(size); } if (pa == (paddr_t)-1) { error = EFBIG; goto out; } } printf("Loading at physical address %lx\n", pa); if (pmap_map(va, pa, size) != 0) { error = EFAULT; goto out; } /* try and double-map at VA 0 for compatibility */ if (pa + size > bstart) { #ifdef DEBUG printf("WARNING: %s is too large for compat mode.\n" "If your kernel is too old, it will not run correctly.\n", file); #endif } else { if (pa != 0 && pmap_map(0, pa, size) != 0) { error = EFAULT; goto out; } } marks[MARK_START] = 0; error = fdloadfile(fd, marks, flags); out: close(fd); return (error); }
static int loadk(char *kernel, u_long *marks) { int fd, error; vaddr_t va; paddr_t pa; u_long size; int flags = LOAD_KERNEL; if ((fd = open(kernel, 0)) < 0) return (errno ? errno : ENOENT); marks[MARK_START] = 0; if ((error = fdloadfile(fd, marks, COUNT_KERNEL)) != 0) goto out; size = marks[MARK_END] - marks[MARK_START]; /* We want that leading 16K in front of the kernel image */ size += PROM_LOADADDR; va = marks[MARK_START] - PROM_LOADADDR; /* * Extra space for bootinfo and kernel bootstrap. * In compat mode, we get to re-use the space occupied by the * boot program. Traditionally, we've silently assumed that * is enough for the kernel to work with. */ size += BOOTINFO_SIZE; if (!compatmode) size += 512 * 1024; /* Get a physical load address */ pa = getphysmem(size); if (pa == (paddr_t)-1) { error = EFBIG; goto out; } if (boothowto & AB_VERBOSE) printf("Loading at physical address %lx\n", pa); if (pmap_map(va, pa, size) != 0) { error = EFAULT; goto out; } /* XXX - to do: inspect kernel image and set compat mode */ if (compatmode) { /* Double-map at VA 0 for compatibility */ if (pa + size >= bstart) { printf("%s: too large for compat mode\n", kernel); error = EFBIG; goto out; } if (pa != 0 && pmap_map(0, pa, size) != 0) { error = EFAULT; goto out; } loadaddrmask = 0x07ffffffUL; } if (bootdev_isfloppy(prom_bootdevice)) flags &= ~LOAD_BACKWARDS; marks[MARK_START] = 0; error = fdloadfile(fd, marks, flags); out: close(fd); return (error); }