static int bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev) { struct open_disk *od; int error; if (dev->d_unit >= nbdinfo) { DEBUG("attempt to open nonexistent disk"); return(ENXIO); } od = (struct open_disk *)malloc(sizeof(struct open_disk)); if (!od) { DEBUG("no memory"); return (ENOMEM); } /* Look up BIOS unit number, intialise open_disk structure */ od->od_dkunit = dev->d_unit; od->od_unit = bdinfo[od->od_dkunit].bd_unit; od->od_flags = bdinfo[od->od_dkunit].bd_flags; od->od_boff = 0; error = 0; DEBUG("open '%s', unit 0x%x slice %d partition %d", i386_fmtdev(dev), dev->d_unit, dev->d_kind.biosdisk.slice, dev->d_kind.biosdisk.partition); /* Get geometry for this open (removable device may have changed) */ if (bd_getgeom(od)) { DEBUG("can't get geometry"); error = ENXIO; goto out; } /* Determine disk layout. */ error = bd_open_pc98(od, dev); out: if (error) { free(od); } else { *odp = od; /* return the open disk */ } return(error); }
/* * Load the information expected by the kernel. * * - The kernel environment is copied into kernel space. * - Module metadata are formatted and placed in kernel space. */ int bi_load(struct preloaded_file *fp, uint64_t *bi_addr) { struct bootinfo bi; struct preloaded_file *xp; struct file_metadata *md; struct devdesc *rootdev; char *rootdevname; vm_offset_t addr, ssym, esym; bzero(&bi, sizeof(struct bootinfo)); bi.bi_version = 1; // bi.bi_boothowto = bi_getboothowto(fp->f_args); /* * Allow the environment variable 'rootdev' to override the supplied * device. This should perhaps go to MI code and/or have $rootdev * tested/set by MI code before launching the kernel. */ rootdevname = getenv("rootdev"); i386_getdev((void**)&rootdev, rootdevname, NULL); if (rootdev != NULL) { /* Try reading /etc/fstab to select the root device. */ getrootmount(i386_fmtdev(rootdev)); free(rootdev); } md = file_findmetadata(fp, MODINFOMD_SSYM); ssym = (md != NULL) ? *((vm_offset_t *)&(md->md_data)) : 0; md = file_findmetadata(fp, MODINFOMD_ESYM); esym = (md != NULL) ? *((vm_offset_t *)&(md->md_data)) : 0; if (ssym != 0 && esym != 0) { bi.bi_symtab = ssym; bi.bi_esymtab = esym; } /* Find the last module in the chain. */ addr = 0; for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { if (addr < (xp->f_addr + xp->f_size)) addr = xp->f_addr + xp->f_size; } addr = (addr + 15) & ~15; /* Copy module list and metadata. */ bi.bi_modulep = addr; addr = bi_copymodules(addr); if (addr <= bi.bi_modulep) { addr = bi.bi_modulep; bi.bi_modulep = 0; } addr = (addr + 15) & ~15; /* Copy our environment. */ bi.bi_envp = addr; addr = bi_copyenv(addr); if (addr <= bi.bi_envp) { addr = bi.bi_envp; bi.bi_envp = 0; } addr = (addr + PAGE_MASK) & ~PAGE_MASK; bi.bi_kernend = addr; return (ldr_bootinfo(&bi, bi_addr)); }
/* * Load the information expected by an i386 kernel. * * - The 'boothowto' argument is constructed * - The 'bootdev' argument is constructed * - The 'bootinfo' struct is constructed, and copied into the kernel space. * - The kernel environment is copied into kernel space. * - Module metadata are formatted and placed in kernel space. */ int bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t *modulep, vm_offset_t *kernendp) { struct preloaded_file *xp, *kfp; struct i386_devdesc *rootdev; struct file_metadata *md; vm_offset_t addr; vm_offset_t kernend; vm_offset_t envp; vm_offset_t size; vm_offset_t ssym, esym; char *rootdevname; int bootdevnr, i, howto; char *kernelname; const char *kernelpath; howto = bi_getboothowto(args); /* * Allow the environment variable 'rootdev' to override the supplied device * This should perhaps go to MI code and/or have $rootdev tested/set by * MI code before launching the kernel. */ rootdevname = getenv("rootdev"); i386_getdev((void **)(&rootdev), rootdevname, NULL); if (rootdev == NULL) { /* bad $rootdev/$currdev */ printf("can't determine root device\n"); return(EINVAL); } /* Try reading the /etc/fstab file to select the root device */ getrootmount(i386_fmtdev(rootdev)); /* Do legacy rootdev guessing */ /* XXX - use a default bootdev of 0. Is this ok??? */ bootdevnr = 0; switch(rootdev->d_type) { case DEVT_CD: /* Pass in BIOS device number. */ bi.bi_bios_dev = bc_unit2bios(rootdev->d_kind.bioscd.unit); bootdevnr = bc_getdev(rootdev); break; case DEVT_DISK: /* pass in the BIOS device number of the current disk */ bi.bi_bios_dev = bd_unit2bios(rootdev->d_kind.biosdisk.unit); bootdevnr = bd_getdev(rootdev); break; case DEVT_NET: break; default: printf("WARNING - don't know how to boot from device type %d\n", rootdev->d_type); } if (bootdevnr == -1) { printf("root device %s invalid\n", i386_fmtdev(rootdev)); return (EINVAL); } free(rootdev); /* find the last module in the chain */ addr = 0; for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { if (addr < (xp->f_addr + xp->f_size)) addr = xp->f_addr + xp->f_size; } /* pad to a page boundary */ addr = roundup(addr, PAGE_SIZE); /* copy our environment */ envp = addr; addr = bi_copyenv(addr); /* pad to a page boundary */ addr = roundup(addr, PAGE_SIZE); kfp = file_findfile(NULL, "elf kernel"); if (kfp == NULL) kfp = file_findfile(NULL, "elf32 kernel"); if (kfp == NULL) panic("can't find kernel file"); kernend = 0; /* fill it in later */ file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); bios_addsmapdata(kfp); /* Figure out the size and location of the metadata */ *modulep = addr; size = bi_copymodules32(0); kernend = roundup(addr + size, PAGE_SIZE); *kernendp = kernend; /* patch MODINFOMD_KERNEND */ md = file_findmetadata(kfp, MODINFOMD_KERNEND); bcopy(&kernend, md->md_data, sizeof kernend); /* copy module list and metadata */ (void)bi_copymodules32(addr); ssym = esym = 0; md = file_findmetadata(kfp, MODINFOMD_SSYM); if (md != NULL) ssym = *((vm_offset_t *)&(md->md_data)); md = file_findmetadata(kfp, MODINFOMD_ESYM); if (md != NULL) esym = *((vm_offset_t *)&(md->md_data)); if (ssym == 0 || esym == 0) ssym = esym = 0; /* sanity */ /* legacy bootinfo structure */ kernelname = getenv("kernelname"); i386_getdev(NULL, kernelname, &kernelpath); bi.bi_version = BOOTINFO_VERSION; bi.bi_kernelname = 0; /* XXX char * -> kernel name */ bi.bi_nfs_diskless = 0; /* struct nfs_diskless * */ bi.bi_n_bios_used = 0; /* XXX would have to hook biosdisk driver for these */ for (i = 0; i < N_BIOS_GEOM; i++) bi.bi_bios_geom[i] = bd_getbigeom(i); bi.bi_size = sizeof(bi); bi.bi_memsizes_valid = 1; bi.bi_basemem = bios_basemem / 1024; bi.bi_extmem = bios_extmem / 1024; bi.bi_envp = envp; bi.bi_modulep = *modulep; bi.bi_kernend = kernend; bi.bi_kernelname = VTOP(kernelpath); bi.bi_symtab = ssym; /* XXX this is only the primary kernel symtab */ bi.bi_esymtab = esym; /* legacy boot arguments */ *howtop = howto | RB_BOOTINFO; *bootdevp = bootdevnr; *bip = VTOP(&bi); return(0); }
/* * Load the information expected by an amd64 kernel. * * - The 'boothowto' argument is constructed * - The 'bootdev' argument is constructed * - The 'bootinfo' struct is constructed, and copied into the kernel space. * - The kernel environment is copied into kernel space. * - Module metadata are formatted and placed in kernel space. */ int bi_load64(char *args, vm_offset_t *modulep, vm_offset_t *kernendp) { struct preloaded_file *xp, *kfp; struct i386_devdesc *rootdev; struct file_metadata *md; vm_offset_t addr; u_int64_t kernend; u_int64_t envp; vm_offset_t size; char *rootdevname; int howto; if (!bi_checkcpu()) { printf("CPU doesn't support long mode\n"); return (EINVAL); } howto = bi_getboothowto(args); /* * Allow the environment variable 'rootdev' to override the supplied device * This should perhaps go to MI code and/or have $rootdev tested/set by * MI code before launching the kernel. */ rootdevname = getenv("rootdev"); i386_getdev((void **)(&rootdev), rootdevname, NULL); if (rootdev == NULL) { /* bad $rootdev/$currdev */ printf("can't determine root device\n"); return(EINVAL); } /* Try reading the /etc/fstab file to select the root device */ getrootmount(i386_fmtdev(rootdev)); /* find the last module in the chain */ addr = 0; for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { if (addr < (xp->f_addr + xp->f_size)) addr = xp->f_addr + xp->f_size; } /* pad to a page boundary */ addr = roundup(addr, PAGE_SIZE); /* copy our environment */ envp = addr; addr = bi_copyenv(addr); /* pad to a page boundary */ addr = roundup(addr, PAGE_SIZE); kfp = file_findfile(NULL, "elf kernel"); if (kfp == NULL) kfp = file_findfile(NULL, "elf64 kernel"); if (kfp == NULL) panic("can't find kernel file"); kernend = 0; /* fill it in later */ file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); bios_addsmapdata(kfp); /* Figure out the size and location of the metadata */ *modulep = addr; size = bi_copymodules64(0); kernend = roundup(addr + size, PAGE_SIZE); *kernendp = kernend; /* patch MODINFOMD_KERNEND */ md = file_findmetadata(kfp, MODINFOMD_KERNEND); bcopy(&kernend, md->md_data, sizeof kernend); /* copy module list and metadata */ (void)bi_copymodules64(addr); return(0); }
EFI_STATUS main(int argc, CHAR16 *argv[]) { char vendor[128]; EFI_LOADED_IMAGE *img; int i; /* * XXX Chicken-and-egg problem; we want to have console output * early, but some console attributes may depend on reading from * eg. the boot device, which we can't do yet. We can use * printf() etc. once this is done. */ cons_probe(); /* * March through the device switch probing for things. */ for (i = 0; devsw[i] != NULL; i++) if (devsw[i]->dv_init != NULL) (devsw[i]->dv_init)(); /* Get our loaded image protocol interface structure. */ BS->HandleProtocol(IH, &imgid, (VOID**)&img); printf("Image base: 0x%lx\n", (u_long)img->ImageBase); printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff); printf("EFI Firmware: "); /* printf doesn't understand EFI Unicode */ ST->ConOut->OutputString(ST->ConOut, ST->FirmwareVendor); printf(" (rev %d.%02d)\n", ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff); printf("\n"); printf("%s, Revision %s\n", bootprog_name, bootprog_rev); printf("(%s, %s)\n", bootprog_maker, bootprog_date); efi_handle_lookup(img->DeviceHandle, &currdev.d_dev, &currdev.d_unit); currdev.d_type = currdev.d_dev->dv_type; /* * Disable the watchdog timer. By default the boot manager sets * the timer to 5 minutes before invoking a boot option. If we * want to return to the boot manager, we have to disable the * watchdog timer and since we're an interactive program, we don't * want to wait until the user types "quit". The timer may have * fired by then. We don't care if this fails. It does not prevent * normal functioning in any way... */ BS->SetWatchdogTimer(0, 0, 0, NULL); env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&currdev), i386_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&currdev), env_noset, env_nounset); setenv("LINES", "24", 1); /* optional */ archsw.arch_autoload = i386_autoload; archsw.arch_getdev = i386_getdev; archsw.arch_copyin = i386_copyin; archsw.arch_copyout = i386_copyout; archsw.arch_readin = i386_readin; interact(); /* doesn't return */ return (EFI_SUCCESS); /* keep compiler happy */ }
/* * Set the 'current device' by (if possible) recovering the boot device as * supplied by the initial bootstrap. * * XXX should be extended for netbooting. */ static void extract_currdev(void) { struct i386_devdesc new_currdev; int biosdev = -1; /* Assume we are booting from a BIOS disk by default */ new_currdev.d_dev = &biosdisk; /* new-style boot loaders such as pxeldr and cdldr */ if (kargs->bootinfo == 0) { if ((kargs->bootflags & KARGS_FLAGS_CD) != 0) { /* we are booting from a CD with cdboot */ new_currdev.d_dev = &bioscd; new_currdev.d_unit = bc_bios2unit(initial_bootdev); } else if ((kargs->bootflags & KARGS_FLAGS_PXE) != 0) { /* we are booting from pxeldr */ new_currdev.d_dev = &pxedisk; new_currdev.d_unit = 0; } else { /* we don't know what our boot device is */ new_currdev.d_kind.biosdisk.slice = -1; new_currdev.d_kind.biosdisk.partition = 0; biosdev = -1; } } else if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) { /* The passed-in boot device is bad */ new_currdev.d_kind.biosdisk.slice = -1; new_currdev.d_kind.biosdisk.partition = 0; biosdev = -1; } else { new_currdev.d_kind.biosdisk.slice = B_SLICE(initial_bootdev) - 1; new_currdev.d_kind.biosdisk.partition = B_PARTITION(initial_bootdev); biosdev = initial_bootinfo->bi_bios_dev; /* * If we are booted by an old bootstrap, we have to guess at the BIOS * unit number. We will lose if there is more than one disk type * and we are not booting from the lowest-numbered disk type * (ie. SCSI when IDE also exists). */ if ((biosdev == 0) && (B_TYPE(initial_bootdev) != 2)) /* biosdev doesn't match major */ biosdev = 0x80 + B_UNIT(initial_bootdev); /* assume harddisk */ } new_currdev.d_type = new_currdev.d_dev->dv_type; /* * If we are booting off of a BIOS disk and we didn't succeed in determining * which one we booted off of, just use disk0: as a reasonable default. */ if ((new_currdev.d_type == biosdisk.dv_type) && ((new_currdev.d_unit = bd_bios2unit(biosdev)) == -1)) { printf("Can't work out which disk we are booting from.\n" "Guessed BIOS device 0x%x not found by probes, defaulting to disk0:\n", biosdev); new_currdev.d_unit = 0; } env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev), i386_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), env_noset, env_nounset); }