diff --git a/stand/i386/libi386/libi386.h b/stand/i386/libi386/libi386.h index a52a1190e7ec..9c7a452a03ad 100644 --- a/stand/i386/libi386/libi386.h +++ b/stand/i386/libi386/libi386.h @@ -1,157 +1,155 @@ /*- * Copyright (c) 1998 Michael Smith * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ +#include "disk.h" +#ifdef LOADER_ZFS_SUPPORT +#include "libzfs.h" +#endif /* * i386 fully-qualified device descriptor. */ -struct i386_devdesc { - struct devdesc dd; /* Must be first. */ - union - { - struct +struct i386_devdesc +{ + union { - int slice; - int partition; - off_t offset; - } biosdisk; - struct - { - uint64_t pool_guid; - uint64_t root_guid; - } zfs; - } d_kind; + struct devdesc dd; + struct disk_devdesc disk; +#ifdef LOADER_ZFS_SUPPORT + struct zfs_devdesc zfs; +#endif + }; }; /* * relocater trampoline support. */ struct relocate_data { uint32_t src; uint32_t dest; uint32_t size; }; extern void relocater(void); /* * The relocater_data[] is fixed size array allocated in relocater_tramp.S */ extern struct relocate_data relocater_data[]; extern uint32_t relocater_size; extern uint16_t relocator_ip; extern uint16_t relocator_cs; extern uint16_t relocator_ds; extern uint16_t relocator_es; extern uint16_t relocator_fs; extern uint16_t relocator_gs; extern uint16_t relocator_ss; extern uint16_t relocator_sp; extern uint32_t relocator_esi; extern uint32_t relocator_eax; extern uint32_t relocator_ebx; extern uint32_t relocator_edx; extern uint32_t relocator_ebp; extern uint16_t relocator_a20_enabled; int i386_getdev(void **vdev, const char *devspec, const char **path); char *i386_fmtdev(void *vdev); int i386_setcurrdev(struct env_var *ev, int flags, const void *value); extern struct devdesc currdev; /* our current device */ #define MAXDEV 31 /* maximum number of distinct devices */ #define MAXBDDEV MAXDEV #include /* exported devices XXX rename? */ extern struct devsw bioscd; extern struct devsw biosfd; extern struct devsw bioshd; extern struct devsw pxedisk; extern struct fs_ops pxe_fsops; int bc_add(int biosdev); /* Register CD booted from. */ uint32_t bd_getbigeom(int bunit); /* return geometry in bootinfo format */ int bd_bios2unit(int biosdev); /* xlate BIOS device -> biosdisk unit */ int bd_unit2bios(struct i386_devdesc *); /* xlate biosdisk -> BIOS device */ int bd_getdev(struct i386_devdesc *dev); /* return dev_t for (dev) */ ssize_t i386_copyin(const void *src, vm_offset_t dest, const size_t len); ssize_t i386_copyout(const vm_offset_t src, void *dest, const size_t len); ssize_t i386_readin(readin_handle_t fd, vm_offset_t dest, const size_t len); struct preloaded_file; void bios_addsmapdata(struct preloaded_file *); void bios_getsmap(void); void bios_getmem(void); extern uint32_t bios_basemem; /* base memory in bytes */ extern uint32_t bios_extmem; /* extended memory in bytes */ extern vm_offset_t memtop; /* last address of physical memory + 1 */ extern vm_offset_t memtop_copyin; /* memtop less heap size for the cases */ /* when heap is at the top of */ /* extended memory; for other cases */ /* just the same as memtop */ extern uint32_t high_heap_size; /* extended memory region available */ extern vm_offset_t high_heap_base; /* for use as the heap */ /* 16KB buffer space for real mode data transfers. */ #define BIO_BUFFER_SIZE 0x4000 void *bio_alloc(size_t size); void bio_free(void *ptr, size_t size); /* * Values for width parameter to biospci_{read,write}_config */ #define BIOSPCI_8BITS 0 #define BIOSPCI_16BITS 1 #define BIOSPCI_32BITS 2 void biospci_detect(void); int biospci_find_devclass(uint32_t class, int index, uint32_t *locator); int biospci_read_config(uint32_t locator, int offset, int width, uint32_t *val); uint32_t biospci_locator(int8_t bus, uint8_t device, uint8_t function); int biospci_write_config(uint32_t locator, int offset, int width, uint32_t val); void biosacpi_detect(void); int i386_autoload(void); void bi_load_vbe_data(struct preloaded_file *kfp); int bi_getboothowto(char *kargs); void bi_setboothowto(int howto); vm_offset_t bi_copyenv(vm_offset_t addr); int bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t *modulep, vm_offset_t *kernend); int bi_load64(char *args, vm_offset_t *modulep, vm_offset_t *kernend, int add_smap); void pxe_enable(void *pxeinfo); diff --git a/stand/i386/loader/main.c b/stand/i386/loader/main.c index cb716d7a9f21..29c40921a85a 100644 --- a/stand/i386/loader/main.c +++ b/stand/i386/loader/main.c @@ -1,468 +1,466 @@ /*- * Copyright (c) 1998 Michael Smith * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * MD bootstrap main() and assorted miscellaneous * commands. */ #include #include #include #include #include #include #include #include #include #include "bootstrap.h" #include "common/bootargs.h" #include "libi386/libi386.h" #include #include "btxv86.h" #ifdef LOADER_ZFS_SUPPORT #include #include "libzfs.h" #endif CTASSERT(sizeof(struct bootargs) == BOOTARGS_SIZE); CTASSERT(offsetof(struct bootargs, bootinfo) == BA_BOOTINFO); CTASSERT(offsetof(struct bootargs, bootflags) == BA_BOOTFLAGS); CTASSERT(offsetof(struct bootinfo, bi_size) == BI_SIZE); /* Arguments passed in from the boot1/boot2 loader */ static struct bootargs *kargs; static uint32_t initial_howto; static uint32_t initial_bootdev; static struct bootinfo *initial_bootinfo; struct arch_switch archsw; /* MI/MD interface boundary */ static void extract_currdev(void); static int isa_inb(int port); static void isa_outb(int port, int value); void exit(int code); #ifdef LOADER_GELI_SUPPORT #include "geliboot.h" struct geli_boot_args *gargs; struct geli_boot_data *gbdata; #endif #ifdef LOADER_ZFS_SUPPORT struct zfs_boot_args *zargs; static void i386_zfs_probe(void); #endif /* XXX debugging */ extern char end[]; static void *heap_top; static void *heap_bottom; caddr_t ptov(uintptr_t x) { return (PTOV(x)); } int main(void) { int i; /* Pick up arguments */ kargs = (void *)__args; initial_howto = kargs->howto; initial_bootdev = kargs->bootdev; initial_bootinfo = kargs->bootinfo ? (struct bootinfo *)PTOV(kargs->bootinfo) : NULL; /* Initialize the v86 register set to a known-good state. */ bzero(&v86, sizeof(v86)); v86.efl = PSL_RESERVED_DEFAULT | PSL_I; /* * Initialise the heap as early as possible. * Once this is done, malloc() is usable. */ bios_getmem(); #if defined(LOADER_BZIP2_SUPPORT) || defined(LOADER_FIREWIRE_SUPPORT) || \ defined(LOADER_GPT_SUPPORT) || defined(LOADER_ZFS_SUPPORT) if (high_heap_size > 0) { heap_top = PTOV(high_heap_base + high_heap_size); heap_bottom = PTOV(high_heap_base); if (high_heap_base < memtop_copyin) memtop_copyin = high_heap_base; } else #endif { heap_top = (void *)PTOV(bios_basemem); heap_bottom = (void *)end; } setheap(heap_bottom, heap_top); /* * Now that malloc is usable, allocate a buffer for tslog and start * logging timestamps during the boot process. */ tslog_init(); /* * detect ACPI for future reference. This may set console to comconsole * if we do have ACPI SPCR table. */ biosacpi_detect(); /* * 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. * If the previous boot stage has requested a serial console, * prefer that. */ bi_setboothowto(initial_howto); if (initial_howto & RB_MULTIPLE) { if (initial_howto & RB_SERIAL) setenv("console", "comconsole vidconsole", 1); else setenv("console", "vidconsole comconsole", 1); } else if (initial_howto & RB_SERIAL) { setenv("console", "comconsole", 1); } else if (initial_howto & RB_MUTE) { setenv("console", "nullconsole", 1); } cons_probe(); /* Set up currdev variable to have hooks in place. */ env_setenv("currdev", EV_VOLATILE | EV_NOHOOK, "", i386_setcurrdev, env_nounset); /* * Initialise the block cache. Set the upper limit. */ bcache_init(32768, 512); /* * Special handling for PXE and CD booting. */ if (kargs->bootinfo == 0) { /* * We only want the PXE disk to try to init itself in the below * walk through devsw if we actually booted off of PXE. */ if (kargs->bootflags & KARGS_FLAGS_PXE) pxe_enable(kargs->pxeinfo ? PTOV(kargs->pxeinfo) : NULL); else if (kargs->bootflags & KARGS_FLAGS_CD) bc_add(initial_bootdev); } 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; archsw.arch_isainb = isa_inb; archsw.arch_isaoutb = isa_outb; archsw.arch_hypervisor = x86_hypervisor; #ifdef LOADER_ZFS_SUPPORT archsw.arch_zfs_probe = i386_zfs_probe; /* * zfsboot and gptzfsboot have always passed KARGS_FLAGS_ZFS, * so if that is set along with KARGS_FLAGS_EXTARG we know we * can interpret the extarg data as a struct zfs_boot_args. */ #define KARGS_EXTARGS_ZFS (KARGS_FLAGS_EXTARG | KARGS_FLAGS_ZFS) if ((kargs->bootflags & KARGS_EXTARGS_ZFS) == KARGS_EXTARGS_ZFS) { zargs = (struct zfs_boot_args *)(kargs + 1); } #endif /* LOADER_ZFS_SUPPORT */ #ifdef LOADER_GELI_SUPPORT /* * If we decided earlier that we have zfs_boot_args extarg data, * and it is big enough to contain the embedded geli data * (the early zfs_boot_args structs weren't), then init the gbdata * pointer accordingly. If there is extarg data which isn't * zfs_boot_args data, determine whether it is geli_boot_args data. * Recent versions of gptboot set KARGS_FLAGS_GELI to indicate that. * Earlier versions didn't, but we presume that's what we * have if the extarg size exactly matches the size of the * geli_boot_args struct during that pre-flag era. */ #define LEGACY_GELI_ARGS_SIZE 260 /* This can never change */ #ifdef LOADER_ZFS_SUPPORT if (zargs != NULL) { if (zargs->size > offsetof(struct zfs_boot_args, gelidata)) { gbdata = &zargs->gelidata; } } else #endif /* LOADER_ZFS_SUPPORT */ if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) { gargs = (struct geli_boot_args *)(kargs + 1); if ((kargs->bootflags & KARGS_FLAGS_GELI) || gargs->size == LEGACY_GELI_ARGS_SIZE) { gbdata = &gargs->gelidata; } } if (gbdata != NULL) import_geli_boot_data(gbdata); #endif /* LOADER_GELI_SUPPORT */ /* * 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)(); printf("BIOS %dkB/%dkB available memory\n", bios_basemem / 1024, bios_extmem / 1024); if (initial_bootinfo != NULL) { initial_bootinfo->bi_basemem = bios_basemem / 1024; initial_bootinfo->bi_extmem = bios_extmem / 1024; } /* detect SMBIOS for future reference */ smbios_detect(NULL); /* detect PCI BIOS for future reference */ biospci_detect(); printf("\n%s", bootprog_info); extract_currdev(); /* set $currdev and $loaddev */ autoload_font(true); bios_getsmap(); interact(); /* if we ever get here, it is an error */ return (1); } /* * 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; #ifdef LOADER_ZFS_SUPPORT char buf[20]; char *bootonce; #endif int biosdev = -1; /* Assume we are booting from a BIOS disk by default */ new_currdev.dd.d_dev = &bioshd; /* 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.dd.d_dev = &bioscd; new_currdev.dd.d_unit = bd_bios2unit(initial_bootdev); } else if ((kargs->bootflags & KARGS_FLAGS_PXE) != 0) { /* we are booting from pxeldr */ new_currdev.dd.d_dev = &pxedisk; new_currdev.dd.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; + new_currdev.disk.d_slice = -1; + new_currdev.disk.d_partition = 0; biosdev = -1; } #ifdef LOADER_ZFS_SUPPORT } else if ((kargs->bootflags & KARGS_FLAGS_ZFS) != 0) { /* * zargs was set in main() if we have new style extended * argument */ if (zargs != NULL && zargs->size >= offsetof(struct zfs_boot_args, primary_pool)) { /* sufficient data is provided */ - new_currdev.d_kind.zfs.pool_guid = zargs->pool; - new_currdev.d_kind.zfs.root_guid = zargs->root; + new_currdev.zfs.pool_guid = zargs->pool; + new_currdev.zfs.root_guid = zargs->root; if (zargs->size >= sizeof(*zargs) && zargs->primary_vdev != 0) { sprintf(buf, "%llu", zargs->primary_pool); setenv("vfs.zfs.boot.primary_pool", buf, 1); sprintf(buf, "%llu", zargs->primary_vdev); setenv("vfs.zfs.boot.primary_vdev", buf, 1); } } else { /* old style zfsboot block */ - new_currdev.d_kind.zfs.pool_guid = kargs->zfspool; - new_currdev.d_kind.zfs.root_guid = 0; + new_currdev.zfs.pool_guid = kargs->zfspool; + new_currdev.zfs.root_guid = 0; } new_currdev.dd.d_dev = &zfs_dev; if ((bootonce = malloc(VDEV_PAD_SIZE)) != NULL) { if (zfs_get_bootonce(&new_currdev, OS_BOOTONCE_USED, bootonce, VDEV_PAD_SIZE) == 0) { setenv("zfs-bootonce", bootonce, 1); } free(bootonce); (void) zfs_attach_nvstore(&new_currdev); } #endif } 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; + new_currdev.disk.d_slice = -1; + new_currdev.disk.d_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); + new_currdev.disk.d_slice = B_SLICE(initial_bootdev) - 1; + new_currdev.disk.d_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, assume harddisk */ biosdev = 0x80 + B_UNIT(initial_bootdev); } } /* * 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.dd.d_dev->dv_type == bioshd.dv_type) && ((new_currdev.dd.d_unit = bd_bios2unit(biosdev)) == -1)) { printf("Can't work out which disk we are booting " "from.\nGuessed BIOS device 0x%x not found by " "probes, defaulting to disk0:\n", biosdev); new_currdev.dd.d_unit = 0; } #ifdef LOADER_ZFS_SUPPORT if (new_currdev.dd.d_dev->dv_type == DEVT_ZFS) init_zfs_boot_options(zfs_fmtdev(&new_currdev)); #endif 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); } COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); static int command_reboot(int argc, char *argv[]) { int i; for (i = 0; devsw[i] != NULL; ++i) if (devsw[i]->dv_cleanup != NULL) (devsw[i]->dv_cleanup)(); printf("Rebooting...\n"); delay(1000000); __exit(0); } /* provide this for panic, as it's not in the startup code */ void exit(int code) { __exit(code); } COMMAND_SET(heap, "heap", "show heap usage", command_heap); static int command_heap(int argc, char *argv[]) { mallocstats(); printf("heap base at %p, top at %p, upper limit at %p\n", heap_bottom, sbrk(0), heap_top); return (CMD_OK); } /* ISA bus access functions for PnP. */ static int isa_inb(int port) { return (inb(port)); } static void isa_outb(int port, int value) { outb(port, value); } #ifdef LOADER_ZFS_SUPPORT static void i386_zfs_probe(void) { char devname[32]; struct i386_devdesc dev; /* * Open all the disks we can find and see if we can reconstruct * ZFS pools from them. */ dev.dd.d_dev = &bioshd; for (dev.dd.d_unit = 0; bd_unit2bios(&dev) >= 0; dev.dd.d_unit++) { snprintf(devname, sizeof(devname), "%s%d:", bioshd.dv_name, dev.dd.d_unit); zfs_probe_dev(devname, NULL); } } #endif diff --git a/stand/i386/zfsboot/zfsboot.c b/stand/i386/zfsboot/zfsboot.c index 8dd3066f15e5..b68d80e802c2 100644 --- a/stand/i386/zfsboot/zfsboot.c +++ b/stand/i386/zfsboot/zfsboot.c @@ -1,721 +1,720 @@ /*- * Copyright (c) 1998 Robert Nordier * All rights reserved. * * Redistribution and use in source and binary forms are freely * permitted provided that the above copyright notice and this * paragraph and the following disclaimer are duplicated in all * such forms. * * This software is provided "AS IS" and without any express or * implied warranties, including, without limitation, the implied * warranties of merchantability and fitness for a particular * purpose. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #ifdef GPT #include #endif #include #include #ifdef LOADER_ZFS_SUPPORT #include #endif #include #include #include #include #include #include #include "bootstrap.h" #include "libi386.h" #include #include "lib.h" #include "rbx.h" #include "cons.h" #include "bootargs.h" #include "disk.h" #include "part.h" #include "paths.h" #include "libzfs.h" #define ARGS 0x900 #define NOPT 14 #define NDEV 3 #define BIOS_NUMDRIVES 0x475 #define DRV_HARD 0x80 #define DRV_MASK 0x7f #define TYPE_AD 0 #define TYPE_DA 1 #define TYPE_MAXHARD TYPE_DA #define TYPE_FD 2 extern uint32_t _end; static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ static const unsigned char flags[NOPT] = { RBX_DUAL, RBX_SERIAL, RBX_ASKNAME, RBX_CDROM, RBX_CONFIG, RBX_KDB, RBX_GDB, RBX_MUTE, RBX_NOINTR, RBX_PAUSE, RBX_QUIET, RBX_DFLTROOT, RBX_SINGLE, RBX_VERBOSE }; uint32_t opts; /* * Paths to try loading before falling back to the boot2 prompt. * * /boot/zfsloader must be tried before /boot/loader in order to remain * backward compatible with ZFS boot environments where /boot/loader exists * but does not have ZFS support, which was the case before FreeBSD 12. * * If no loader is found, try to load a kernel directly instead. */ static const struct string { const char *p; size_t len; } loadpath[] = { { PATH_LOADER_ZFS, sizeof(PATH_LOADER_ZFS) }, { PATH_LOADER, sizeof(PATH_LOADER) }, { PATH_KERNEL, sizeof(PATH_KERNEL) }, }; static const unsigned char dev_maj[NDEV] = {30, 4, 2}; static struct i386_devdesc *bdev; static char cmd[512]; static char cmddup[512]; static char kname[1024]; static int comspeed = SIOSPD; static struct bootinfo bootinfo; static uint32_t bootdev; static struct zfs_boot_args zfsargs; #ifdef LOADER_GELI_SUPPORT static struct geli_boot_args geliargs; #endif extern vm_offset_t high_heap_base; extern uint32_t bios_basemem, bios_extmem, high_heap_size; static char *heap_top; static char *heap_bottom; void exit(int); static void i386_zfs_probe(void); static void load(void); static int parse_cmd(void); #ifdef LOADER_GELI_SUPPORT #include "geliboot.h" static char gelipw[GELI_PW_MAXLEN]; #endif struct arch_switch archsw; /* MI/MD interface boundary */ static char boot_devname[2 * ZFS_MAXNAMELEN + 8]; /* disk or pool:dataset */ struct devsw *devsw[] = { &bioshd, #if defined(LOADER_ZFS_SUPPORT) &zfs_dev, #endif NULL }; struct fs_ops *file_system[] = { #if defined(LOADER_ZFS_SUPPORT) &zfs_fsops, #endif #if defined(LOADER_UFS_SUPPORT) &ufs_fsops, #endif NULL }; caddr_t ptov(uintptr_t x) { return (PTOV(x)); } int main(void); int main(void) { unsigned i; int auto_boot, fd, nextboot = 0; struct disk_devdesc devdesc; bios_getmem(); if (high_heap_size > 0) { heap_top = PTOV(high_heap_base + high_heap_size); heap_bottom = PTOV(high_heap_base); } else { heap_bottom = (char *) (roundup2(__base + (int32_t)&_end, 0x10000) - __base); heap_top = (char *)PTOV(bios_basemem); } setheap(heap_bottom, heap_top); /* * Initialise the block cache. Set the upper limit. */ bcache_init(32768, 512); archsw.arch_autoload = NULL; archsw.arch_getdev = i386_getdev; archsw.arch_copyin = NULL; archsw.arch_copyout = NULL; archsw.arch_readin = NULL; archsw.arch_isainb = NULL; archsw.arch_isaoutb = NULL; archsw.arch_zfs_probe = i386_zfs_probe; bootinfo.bi_version = BOOTINFO_VERSION; bootinfo.bi_size = sizeof(bootinfo); bootinfo.bi_basemem = bios_basemem / 1024; bootinfo.bi_extmem = bios_extmem / 1024; bootinfo.bi_memsizes_valid++; bootinfo.bi_bios_dev = *(uint8_t *)PTOV(ARGS); /* Set up fall back device name. */ snprintf(boot_devname, sizeof (boot_devname), "disk%d:", bd_bios2unit(bootinfo.bi_bios_dev)); /* Set up currdev variable to have hooks in place. */ env_setenv("currdev", EV_VOLATILE, "", i386_setcurrdev, env_nounset); for (i = 0; devsw[i] != NULL; i++) if (devsw[i]->dv_init != NULL) (devsw[i]->dv_init)(); disk_parsedev(&devdesc, boot_devname + 4, NULL); bootdev = MAKEBOOTDEV(dev_maj[DEVT_DISK], devdesc.d_slice + 1, devdesc.dd.d_unit, devdesc.d_partition >= 0 ? devdesc.d_partition : 0xff); /* * zfs_fmtdev() can be called only after dv_init */ if (bdev != NULL && bdev->dd.d_dev->dv_type == DEVT_ZFS) { /* set up proper device name string for ZFS */ strncpy(boot_devname, zfs_fmtdev(bdev), sizeof (boot_devname)); if (zfs_get_bootonce(bdev, OS_BOOTONCE, cmd, sizeof(cmd)) == 0) { nvlist_t *benv; nextboot = 1; memcpy(cmddup, cmd, sizeof(cmd)); if (parse_cmd()) { if (!OPT_CHECK(RBX_QUIET)) printf("failed to parse bootonce " "command\n"); exit(0); } if (!OPT_CHECK(RBX_QUIET)) printf("zfs bootonce: %s\n", cmddup); if (zfs_get_bootenv(bdev, &benv) == 0) { nvlist_add_string(benv, OS_BOOTONCE_USED, cmddup); zfs_set_bootenv(bdev, benv); } /* Do not process this command twice */ *cmd = 0; } } /* now make sure we have bdev on all cases */ free(bdev); i386_getdev((void **)&bdev, boot_devname, NULL); env_setenv("currdev", EV_VOLATILE, boot_devname, i386_setcurrdev, env_nounset); /* Process configuration file */ auto_boot = 1; fd = open(PATH_CONFIG, O_RDONLY); if (fd == -1) fd = open(PATH_DOTCONFIG, O_RDONLY); if (fd != -1) { ssize_t cmdlen; if ((cmdlen = read(fd, cmd, sizeof(cmd))) > 0) cmd[cmdlen] = '\0'; else *cmd = '\0'; close(fd); } if (*cmd) { /* * Note that parse_cmd() is destructive to cmd[] and we also * want to honor RBX_QUIET option that could be present in * cmd[]. */ memcpy(cmddup, cmd, sizeof(cmd)); if (parse_cmd()) auto_boot = 0; if (!OPT_CHECK(RBX_QUIET)) printf("%s: %s\n", PATH_CONFIG, cmddup); /* Do not process this command twice */ *cmd = 0; } /* Do not risk waiting at the prompt forever. */ if (nextboot && !auto_boot) exit(0); if (auto_boot && !*kname) { /* * Iterate through the list of loader and kernel paths, * trying to load. If interrupted by a keypress, or in case of * failure, drop the user to the boot2 prompt. */ for (i = 0; i < nitems(loadpath); i++) { memcpy(kname, loadpath[i].p, loadpath[i].len); if (keyhit(3)) break; load(); } } /* Present the user with the boot2 prompt. */ for (;;) { if (!auto_boot || !OPT_CHECK(RBX_QUIET)) { printf("\nFreeBSD/x86 boot\n"); printf("Default: %s%s\nboot: ", boot_devname, kname); } if (ioctrl & IO_SERIAL) sio_flush(); if (!auto_boot || keyhit(5)) getstr(cmd, sizeof(cmd)); else if (!auto_boot || !OPT_CHECK(RBX_QUIET)) putchar('\n'); auto_boot = 0; if (parse_cmd()) putchar('\a'); else load(); } } /* XXX - Needed for btxld to link the boot2 binary; do not remove. */ void exit(int x) { __exit(x); } static void load(void) { union { struct exec ex; Elf32_Ehdr eh; } hdr; static Elf32_Phdr ep[2]; static Elf32_Shdr es[2]; caddr_t p; uint32_t addr, x; int fd, fmt, i, j; ssize_t size; if ((fd = open(kname, O_RDONLY)) == -1) { printf("\nCan't find %s\n", kname); return; } size = sizeof(hdr); if (read(fd, &hdr, sizeof (hdr)) != size) { close(fd); return; } if (N_GETMAGIC(hdr.ex) == ZMAGIC) { fmt = 0; } else if (IS_ELF(hdr.eh)) { fmt = 1; } else { printf("Invalid %s\n", "format"); close(fd); return; } if (fmt == 0) { addr = hdr.ex.a_entry & 0xffffff; p = PTOV(addr); lseek(fd, PAGE_SIZE, SEEK_SET); size = hdr.ex.a_text; if (read(fd, p, hdr.ex.a_text) != size) { close(fd); return; } p += roundup2(hdr.ex.a_text, PAGE_SIZE); size = hdr.ex.a_data; if (read(fd, p, hdr.ex.a_data) != size) { close(fd); return; } p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); bootinfo.bi_symtab = VTOP(p); memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); p += sizeof(hdr.ex.a_syms); if (hdr.ex.a_syms) { size = hdr.ex.a_syms; if (read(fd, p, hdr.ex.a_syms) != size) { close(fd); return; } p += hdr.ex.a_syms; size = sizeof (int); if (read(fd, p, sizeof (int)) != size) { close(fd); return; } x = *(uint32_t *)p; p += sizeof(int); x -= sizeof(int); size = x; if (read(fd, p, x) != size) { close(fd); return; } p += x; } } else { lseek(fd, hdr.eh.e_phoff, SEEK_SET); for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { size = sizeof (ep[0]); if (read(fd, ep + j, sizeof (ep[0])) != size) { close(fd); return; } if (ep[j].p_type == PT_LOAD) j++; } for (i = 0; i < 2; i++) { p = PTOV(ep[i].p_paddr & 0xffffff); lseek(fd, ep[i].p_offset, SEEK_SET); size = ep[i].p_filesz; if (read(fd, p, ep[i].p_filesz) != size) { close(fd); return; } } p += roundup2(ep[1].p_memsz, PAGE_SIZE); bootinfo.bi_symtab = VTOP(p); if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { lseek(fd, hdr.eh.e_shoff + sizeof (es[0]) * (hdr.eh.e_shstrndx + 1), SEEK_SET); size = sizeof(es); if (read(fd, &es, sizeof (es)) != size) { close(fd); return; } for (i = 0; i < 2; i++) { memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size)); p += sizeof(es[i].sh_size); lseek(fd, es[i].sh_offset, SEEK_SET); size = es[i].sh_size; if (read(fd, p, es[i].sh_size) != size) { close(fd); return; } p += es[i].sh_size; } } addr = hdr.eh.e_entry & 0xffffff; } close(fd); bootinfo.bi_esymtab = VTOP(p); bootinfo.bi_kernelname = VTOP(kname); #ifdef LOADER_GELI_SUPPORT explicit_bzero(gelipw, sizeof(gelipw)); #endif if (bdev->dd.d_dev->dv_type == DEVT_ZFS) { zfsargs.size = sizeof(zfsargs); - zfsargs.pool = bdev->d_kind.zfs.pool_guid; - zfsargs.root = bdev->d_kind.zfs.root_guid; + zfsargs.pool = bdev->zfs.pool_guid; + zfsargs.root = bdev->zfs.root_guid; #ifdef LOADER_GELI_SUPPORT export_geli_boot_data(&zfsargs.gelidata); #endif /* * Note that the zfsargs struct is passed by value, not by * pointer. Code in btxldr.S copies the values from the entry * stack to a fixed location within loader(8) at startup due * to the presence of KARGS_FLAGS_EXTARG. */ __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), bootdev, KARGS_FLAGS_ZFS | KARGS_FLAGS_EXTARG, - (uint32_t)bdev->d_kind.zfs.pool_guid, - (uint32_t)(bdev->d_kind.zfs.pool_guid >> 32), + (uint32_t)bdev->zfs.pool_guid, + (uint32_t)(bdev->zfs.pool_guid >> 32), VTOP(&bootinfo), zfsargs); } else { #ifdef LOADER_GELI_SUPPORT geliargs.size = sizeof(geliargs); export_geli_boot_data(&geliargs.gelidata); #endif /* * Note that the geliargs struct is passed by value, not by * pointer. Code in btxldr.S copies the values from the entry * stack to a fixed location within loader(8) at startup due * to the presence of the KARGS_FLAGS_EXTARG flag. */ __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), bootdev, #ifdef LOADER_GELI_SUPPORT KARGS_FLAGS_GELI | KARGS_FLAGS_EXTARG, 0, 0, VTOP(&bootinfo), geliargs #else 0, 0, 0, VTOP(&bootinfo) #endif ); } } static int mount_root(char *arg) { char *root; struct i386_devdesc *ddesc; uint8_t part; if (asprintf(&root, "%s:", arg) < 0) return (1); if (i386_getdev((void **)&ddesc, root, NULL)) { free(root); return (1); } /* we should have new device descriptor, free old and replace it. */ free(bdev); bdev = ddesc; if (bdev->dd.d_dev->dv_type == DEVT_DISK) { - if (bdev->d_kind.biosdisk.partition == -1) + if (bdev->disk.d_partition == -1) part = 0xff; else - part = bdev->d_kind.biosdisk.partition; + part = bdev->disk.d_partition; bootdev = MAKEBOOTDEV(dev_maj[bdev->dd.d_dev->dv_type], - bdev->d_kind.biosdisk.slice + 1, - bdev->dd.d_unit, part); + bdev->disk.d_slice + 1, bdev->dd.d_unit, part); bootinfo.bi_bios_dev = bd_unit2bios(bdev); } strncpy(boot_devname, root, sizeof (boot_devname)); setenv("currdev", root, 1); free(root); return (0); } static void fs_list(char *arg) { int fd; struct dirent *d; char line[80]; fd = open(arg, O_RDONLY); if (fd < 0) return; pager_open(); while ((d = readdirfd(fd)) != NULL) { sprintf(line, "%s\n", d->d_name); if (pager_output(line)) break; } pager_close(); close(fd); } static int parse_cmd(void) { char *arg = cmd; char *ep, *p, *q; const char *cp; char line[80]; int c, i, j; while ((c = *arg++)) { if (c == ' ' || c == '\t' || c == '\n') continue; for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++) ; ep = p; if (*p) *p++ = 0; if (c == '-') { while ((c = *arg++)) { if (c == 'P') { if (*(uint8_t *)PTOV(0x496) & 0x10) { cp = "yes"; } else { opts |= OPT_SET(RBX_DUAL); opts |= OPT_SET(RBX_SERIAL); cp = "no"; } printf("Keyboard: %s\n", cp); continue; } else if (c == 'S') { j = 0; while ((unsigned int) (i = *arg++ - '0') <= 9) j = j * 10 + i; if (j > 0 && i == -'0') { comspeed = j; break; } /* * Fall through to error below * ('S' not in optstr[]). */ } for (i = 0; c != optstr[i]; i++) if (i == NOPT - 1) return (-1); opts ^= OPT_SET(flags[i]); } ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; if (ioctrl & IO_SERIAL) { if (sio_init(115200 / comspeed) != 0) ioctrl &= ~IO_SERIAL; } } if (c == '?') { printf("\n"); if (*arg == '\0') arg = (char *)"/"; fs_list(arg); zfs_list(arg); return (-1); } else { char *ptr; printf("\n"); arg--; /* * Report pool status if the comment is 'status'. Lets * hope no-one wants to load /status as a kernel. */ if (strcmp(arg, "status") == 0) { pager_open(); for (i = 0; devsw[i] != NULL; i++) { if (devsw[i]->dv_print != NULL) { if (devsw[i]->dv_print(1)) break; } else { snprintf(line, sizeof(line), "%s: (unknown)\n", devsw[i]->dv_name); if (pager_output(line)) break; } } pager_close(); return (-1); } /* * If there is "zfs:" prefix simply ignore it. */ ptr = arg; if (strncmp(ptr, "zfs:", 4) == 0) ptr += 4; /* * If there is a colon, switch pools. */ q = strchr(ptr, ':'); if (q) { *q++ = '\0'; if (mount_root(arg) != 0) { return (-1); } arg = q; } if ((i = ep - arg)) { if ((size_t)i >= sizeof(kname)) return (-1); memcpy(kname, arg, i + 1); } } arg = p; } return (0); } /* * Probe all disks to discover ZFS pools. The idea is to walk all possible * disk devices, however, we also need to identify possible boot pool. * For boot pool detection we have boot disk passed us from BIOS, recorded * in bootinfo.bi_bios_dev. */ static void i386_zfs_probe(void) { char devname[32]; int boot_unit; struct i386_devdesc dev; uint64_t pool_guid = 0; dev.dd.d_dev = &bioshd; /* Translate bios dev to our unit number. */ boot_unit = bd_bios2unit(bootinfo.bi_bios_dev); /* * Open all the disks we can find and see if we can reconstruct * ZFS pools from them. */ for (dev.dd.d_unit = 0; bd_unit2bios(&dev) >= 0; dev.dd.d_unit++) { snprintf(devname, sizeof (devname), "%s%d:", bioshd.dv_name, dev.dd.d_unit); /* If this is not boot disk, use generic probe. */ if (dev.dd.d_unit != boot_unit) zfs_probe_dev(devname, NULL); else zfs_probe_dev(devname, &pool_guid); if (pool_guid != 0 && bdev == NULL) { bdev = malloc(sizeof (struct i386_devdesc)); bzero(bdev, sizeof (struct i386_devdesc)); - bdev->dd.d_dev = &zfs_dev; - bdev->d_kind.zfs.pool_guid = pool_guid; + bdev->zfs.dd.d_dev = &zfs_dev; + bdev->zfs.pool_guid = pool_guid; } } }