Index: head/sys/boot/efi/boot1/Makefile =================================================================== --- head/sys/boot/efi/boot1/Makefile +++ head/sys/boot/efi/boot1/Makefile @@ -8,8 +8,11 @@ PROG= boot1.sym INTERNALPROG= -WARNS?= 6 +WARNS?= 3 +# Include bcache code. +HAVE_BCACHE= yes + # We implement a slightly non-standard %S in that it always takes a # CHAR16 that's common in UEFI-land instead of a wchar_t. This only # seems to matter on arm64 where wchar_t defaults to an int instead @@ -18,13 +21,15 @@ CWARNFLAGS.boot1.c+= -Wno-format # Disable warnings that are currently incompatible with the zfs boot code -CWARNFLAGS.zfs_module.c += -Wno-array-bounds -CWARNFLAGS.zfs_module.c += -Wno-cast-align -CWARNFLAGS.zfs_module.c += -Wno-cast-qual -CWARNFLAGS.zfs_module.c += -Wno-missing-prototypes -CWARNFLAGS.zfs_module.c += -Wno-sign-compare -CWARNFLAGS.zfs_module.c += -Wno-unused-parameter -CWARNFLAGS.zfs_module.c += -Wno-unused-function +CWARNFLAGS.zfs.c += -Wno-incompatible-pointer-types-discards-qualifiers +CWARNFLAGS.zfs.c += -Wno-missing-variable-declarations +CWARNFLAGS.zfs.c += -Wno-array-bounds +CWARNFLAGS.zfs.c += -Wno-cast-align +CWARNFLAGS.zfs.c += -Wno-cast-qual +CWARNFLAGS.zfs.c += -Wno-missing-prototypes +CWARNFLAGS.zfs.c += -Wno-sign-compare +CWARNFLAGS.zfs.c += -Wno-unused-parameter +CWARNFLAGS.zfs.c += -Wno-unused-function CWARNFLAGS.skein.c += -Wno-cast-align .if ${COMPILER_TYPE} == "clang" CWARNFLAGS.skein.c += -Wno-missing-variable-declarations @@ -33,19 +38,27 @@ .endif # architecture-specific loader code -SRCS= boot1.c self_reloc.c start.S ufs_module.c +SRCS= boot1.c self_reloc.c start.S .if ${MK_ZFS} != "no" -SRCS+= zfs_module.c +.PATH: ${.CURDIR}/../../../crypto/skein SRCS+= skein.c skein_block.c # Do not unroll skein loops, reduce code size CFLAGS+= -DSKEIN_LOOP=111 -.PATH: ${.CURDIR}/../../../crypto/skein +.PATH: ${.CURDIR}/../../zfs +SRCS+= zfs.c .endif .if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} > 40201 CWARNFLAGS.self_reloc.c+= -Wno-error=maybe-uninitialized .endif +# Always add MI sources +.PATH: ${.CURDIR}/../../common +.include "${.CURDIR}/../../common/Makefile.inc" +CFLAGS+= -I${.CURDIR}/../../common + +.PATH: ${.CURDIR}/arch/${MACHINE} + CFLAGS+= -I. CFLAGS+= -I${.CURDIR}/../include CFLAGS+= -I${.CURDIR}/../include/${MACHINE} @@ -117,7 +130,7 @@ SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH} \ ${OBJCOPY} -j .peheader -j .text -j .sdata -j .data \ -j .dynamic -j .dynsym -j .rel.dyn \ - -j .rela.dyn -j .reloc -j .eh_frame \ + -j .rela.dyn -j .reloc -j .eh_frame -j set_Xcommand_set \ --output-target=${EFI_TARGET} ${.ALLSRC} ${.TARGET} boot1.o: ${SASRC}/ufsread.c Index: head/sys/boot/efi/boot1/boot1.c =================================================================== --- head/sys/boot/efi/boot1/boot1.c +++ head/sys/boot/efi/boot1/boot1.c @@ -23,61 +23,179 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include #include +#include #include +#include +#include #include +#ifdef EFI_ZFS_BOOT +#include +#endif typedef CHAR16 efi_char; #include -#include "boot_module.h" +#include + +#include "efi_drivers.h" +#include "efizfs.h" #include "paths.h" static void efi_panic(EFI_STATUS s, const char *fmt, ...) __dead2 __printflike(2, 3); +#ifdef EFI_DEBUG +#define DPRINTF(fmt, args...) printf(fmt, ##args) +#define DSTALL(d) BS->Stall(d) +#else +#define DPRINTF(fmt, ...) {} +#define DSTALL(d) {} +#endif -static const boot_module_t *boot_modules[] = -{ +struct arch_switch archsw; /* MI/MD interface boundary */ + +static const efi_driver_t *efi_drivers[] = { + NULL +}; + +extern struct console efi_console; +#if defined(__amd64__) || defined(__i386__) +extern struct console comconsole; +extern struct console nullconsole; +#endif + #ifdef EFI_ZFS_BOOT - &zfs_module, +uint64_t pool_guid; #endif + +struct fs_ops *file_system[] = { +#ifdef EFI_ZFS_BOOT + &zfs_fsops, +#endif + &dosfs_fsops, #ifdef EFI_UFS_BOOT - &ufs_module + &ufs_fsops, #endif + &cd9660_fsops, + &nfs_fsops, + &gzipfs_fsops, + &bzipfs_fsops, + NULL }; -#define NUM_BOOT_MODULES nitems(boot_modules) +struct devsw *devsw[] = { + &efipart_hddev, + &efipart_fddev, + &efipart_cddev, +#ifdef EFI_ZFS_BOOT + &zfs_dev, +#endif + NULL +}; + +struct console *consoles[] = { + &efi_console, + NULL +}; + +static EFI_LOADED_IMAGE *boot_image; +static EFI_DEVICE_PATH *imgpath; +static EFI_DEVICE_PATH *imgprefix; + +/* Definitions we don't actually need for boot, but we need to define + * to make the linker happy. + */ +struct file_format *file_formats[] = { NULL }; + +struct netif_driver *netif_drivers[] = { NULL }; + +static int +efi_autoload(void) +{ + printf("******** Boot block should not call autoload\n"); + return (-1); +} + +static ssize_t +efi_copyin(const void *src __unused, vm_offset_t dest __unused, + const size_t len __unused) +{ + printf("******** Boot block should not call copyin\n"); + return (-1); +} + +static ssize_t +efi_copyout(vm_offset_t src __unused, void *dest __unused, + const size_t len __unused) +{ + printf("******** Boot block should not call copyout\n"); + return (-1); +} + +static ssize_t +efi_readin(int fd __unused, vm_offset_t dest __unused, + const size_t len __unused) +{ + printf("******** Boot block should not call readin\n"); + return (-1); +} + /* The initial number of handles used to query EFI for partitions. */ #define NUM_HANDLES_INIT 24 -static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; -static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; static EFI_GUID FreeBSDBootVarGUID = FREEBSD_BOOT_VAR_GUID; -/* - * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures - * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from - * EFI methods. - */ -void * -Malloc(size_t len, const char *file __unused, int line __unused) +static EFI_STATUS +do_load(const char *filepath, void **bufp, size_t *bufsize) { - void *out; + struct stat st; + void *buf = NULL; + int fd, err; + size_t fsize, remaining; + ssize_t readsize; - if (BS->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS) - return (out); + if ((fd = open(filepath, O_RDONLY)) < 0) { + return (ENOTSUP); + } - return (NULL); -} + if ((err = fstat(fd, &st)) != 0) { + goto close_file; + } -void -Free(void *buf, const char *file __unused, int line __unused) -{ - if (buf != NULL) - (void)BS->FreePool(buf); + fsize = st.st_size; + + if ((buf = malloc(fsize)) == NULL) { + err = ENOMEM; + goto close_file; + } + + remaining = fsize; + + do { + if ((readsize = read(fd, buf, fsize)) < 0) { + err = (-readsize); + goto free_buf; + } + + remaining -= readsize; + } while(remaining != 0); + + close(fd); + *bufsize = st.st_size; + *bufp = buf; + + close_file: + close(fd); + + return errno_to_efi_status(err); + + free_buf: + free(buf); + goto close_file; } static EFI_STATUS @@ -97,98 +215,275 @@ return (rv); } -/* - * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match, - * FALSE otherwise. - */ -static BOOLEAN -nodes_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath) +static int +probe_fs(const char *filepath) { - size_t len; + int fd; - if (imgpath == NULL || imgpath->Type != devpath->Type || - imgpath->SubType != devpath->SubType) - return (FALSE); + if ((fd = open(filepath, O_RDONLY)) < 0) { + return (ENOTSUP); + } - len = DevicePathNodeLength(imgpath); - if (len != DevicePathNodeLength(devpath)) - return (FALSE); + close(fd); - return (memcmp(imgpath, devpath, (size_t)len) == 0); + return (0); } -/* - * device_paths_match returns TRUE if the imgpath isn't NULL and all nodes - * in imgpath and devpath match up to their respective occurrences of a - * media node, FALSE otherwise. - */ -static BOOLEAN -device_paths_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath) +static int +probe_dev(struct devsw *dev, int unit, const char *filepath) { + struct devdesc currdev; + char *devname; + int err; - if (imgpath == NULL) - return (FALSE); + currdev.d_dev = dev; + currdev.d_type = currdev.d_dev->dv_type; + currdev.d_unit = unit; + currdev.d_opendata = NULL; + devname = efi_fmtdev(&currdev); - while (!IsDevicePathEnd(imgpath) && !IsDevicePathEnd(devpath)) { - if (IsDevicePathType(imgpath, MEDIA_DEVICE_PATH) && - IsDevicePathType(devpath, MEDIA_DEVICE_PATH)) - return (TRUE); + env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev, + env_nounset); - if (!nodes_match(imgpath, devpath)) - return (FALSE); + err = probe_fs(filepath); - imgpath = NextDevicePathNode(imgpath); - devpath = NextDevicePathNode(devpath); - } + return (err); +} - return (FALSE); +static bool +check_preferred(EFI_HANDLE *h) +{ + EFI_DEVICE_PATH *path = efi_lookup_devpath(h); + bool out; + + if ((path = efi_lookup_devpath(h)) == NULL) + return (false); + + out = efi_devpath_is_prefix(imgpath, path) || + efi_devpath_is_prefix(imgprefix, path); + + return (out); } -/* - * devpath_last returns the last non-path end node in devpath. - */ -static EFI_DEVICE_PATH * -devpath_last(EFI_DEVICE_PATH *devpath) +bool +efi_zfs_is_preferred(EFI_HANDLE *h) { + return (check_preferred(h)); +} - while (!IsDevicePathEnd(NextDevicePathNode(devpath))) - devpath = NextDevicePathNode(devpath); +static int +load_preferred(EFI_LOADED_IMAGE *img, const char *filepath, void **bufp, + size_t *bufsize, EFI_HANDLE *handlep) +{ + pdinfo_list_t *pdi_list; + pdinfo_t *dp, *pp; + char *devname; - return (devpath); +#ifdef EFI_ZFS_BOOT + /* Did efi_zfs_probe() detect the boot pool? */ + if (pool_guid != 0) { + struct zfs_devdesc currdev; + + currdev.d_dev = &zfs_dev; + currdev.d_unit = 0; + currdev.d_type = currdev.d_dev->dv_type; + currdev.d_opendata = NULL; + currdev.pool_guid = pool_guid; + currdev.root_guid = 0; + devname = efi_fmtdev(&currdev); + + env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev, + env_nounset); + + if (probe_fs(filepath) == 0 && + do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { + *handlep = efizfs_get_handle_by_guid(pool_guid); + return (0); + } + } +#endif /* EFI_ZFS_BOOT */ + + /* We have device lists for hd, cd, fd, walk them all. */ + pdi_list = efiblk_get_pdinfo_list(&efipart_hddev); + STAILQ_FOREACH(dp, pdi_list, pd_link) { + struct disk_devdesc currdev; + + currdev.d_dev = &efipart_hddev; + currdev.d_type = currdev.d_dev->dv_type; + currdev.d_unit = dp->pd_unit; + currdev.d_opendata = NULL; + currdev.d_slice = -1; + currdev.d_partition = -1; + devname = efi_fmtdev(&currdev); + + env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev, + env_nounset); + + if (check_preferred(dp->pd_handle) && + probe_fs(filepath) == 0 && + do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { + *handlep = dp->pd_handle; + return (0); + } + + /* Assuming GPT partitioning. */ + STAILQ_FOREACH(pp, &dp->pd_part, pd_link) { + if (check_preferred(pp->pd_handle)) { + currdev.d_slice = pp->pd_unit; + currdev.d_partition = 255; + devname = efi_fmtdev(&currdev); + + env_setenv("currdev", EV_VOLATILE, devname, + efi_setcurrdev, env_nounset); + + if (probe_fs(filepath) == 0 && + do_load(filepath, bufp, bufsize) == + EFI_SUCCESS) { + *handlep = pp->pd_handle; + return (0); + } + } + } + } + + pdi_list = efiblk_get_pdinfo_list(&efipart_cddev); + STAILQ_FOREACH(dp, pdi_list, pd_link) { + if ((dp->pd_handle == img->DeviceHandle || + dp->pd_alias == img->DeviceHandle || + check_preferred(dp->pd_handle)) && + probe_dev(&efipart_cddev, dp->pd_unit, filepath) == 0 && + do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { + *handlep = dp->pd_handle; + return (0); + } + } + + pdi_list = efiblk_get_pdinfo_list(&efipart_fddev); + STAILQ_FOREACH(dp, pdi_list, pd_link) { + if ((dp->pd_handle == img->DeviceHandle || + check_preferred(dp->pd_handle)) && + probe_dev(&efipart_cddev, dp->pd_unit, filepath) == 0 && + do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { + *handlep = dp->pd_handle; + return (0); + } + } + + return (ENOENT); } -/* - * load_loader attempts to load the loader image data. - * - * It tries each module and its respective devices, identified by mod->probe, - * in order until a successful load occurs at which point it returns EFI_SUCCESS - * and EFI_NOT_FOUND otherwise. - * - * Only devices which have preferred matching the preferred parameter are tried. - */ -static EFI_STATUS -load_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp, - size_t *bufsize, BOOLEAN preferred) +static int +load_all(const char *filepath, void **bufp, size_t *bufsize, + EFI_HANDLE *handlep) { - UINTN i; - dev_info_t *dev; - const boot_module_t *mod; + pdinfo_list_t *pdi_list; + pdinfo_t *dp, *pp; + zfsinfo_list_t *zfsi_list; + zfsinfo_t *zi; + char *devname; - for (i = 0; i < NUM_BOOT_MODULES; i++) { - mod = boot_modules[i]; - for (dev = mod->devices(); dev != NULL; dev = dev->next) { - if (dev->preferred != preferred) - continue; +#ifdef EFI_ZFS_BOOT + zfsi_list = efizfs_get_zfsinfo_list(); + STAILQ_FOREACH(zi, zfsi_list, zi_link) { + struct zfs_devdesc currdev; - if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) == - EFI_SUCCESS) { - *devinfop = dev; - *modp = mod; - return (EFI_SUCCESS); + currdev.d_dev = &zfs_dev; + currdev.d_unit = 0; + currdev.d_type = currdev.d_dev->dv_type; + currdev.d_opendata = NULL; + currdev.pool_guid = zi->zi_pool_guid; + currdev.root_guid = 0; + devname = efi_fmtdev(&currdev); + + env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev, + env_nounset); + + if (probe_fs(filepath) == 0 && + do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { + *handlep = zi->zi_handle; + + return (0); + } + } +#endif /* EFI_ZFS_BOOT */ + + /* We have device lists for hd, cd, fd, walk them all. */ + pdi_list = efiblk_get_pdinfo_list(&efipart_hddev); + STAILQ_FOREACH(dp, pdi_list, pd_link) { + struct disk_devdesc currdev; + + currdev.d_dev = &efipart_hddev; + currdev.d_type = currdev.d_dev->dv_type; + currdev.d_unit = dp->pd_unit; + currdev.d_opendata = NULL; + currdev.d_slice = -1; + currdev.d_partition = -1; + devname = efi_fmtdev(&currdev); + + env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev, + env_nounset); + + if (probe_fs(filepath) == 0 && + do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { + *handlep = dp->pd_handle; + + return (0); + } + + /* Assuming GPT partitioning. */ + STAILQ_FOREACH(pp, &dp->pd_part, pd_link) { + currdev.d_slice = pp->pd_unit; + currdev.d_partition = 255; + devname = efi_fmtdev(&currdev); + + env_setenv("currdev", EV_VOLATILE, devname, + efi_setcurrdev, env_nounset); + + if (probe_fs(filepath) == 0 && + do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { + *handlep = pp->pd_handle; + + return (0); } } } + pdi_list = efiblk_get_pdinfo_list(&efipart_cddev); + STAILQ_FOREACH(dp, pdi_list, pd_link) { + if (probe_dev(&efipart_cddev, dp->pd_unit, filepath) == 0 && + do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { + *handlep = dp->pd_handle; + + return (0); + } + } + + pdi_list = efiblk_get_pdinfo_list(&efipart_fddev); + STAILQ_FOREACH(dp, pdi_list, pd_link) { + if (probe_dev(&efipart_fddev, dp->pd_unit, filepath) == 0 && + do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { + *handlep = dp->pd_handle; + + return (0); + } + } + + return (ENOENT); +} + +static EFI_STATUS +load_loader(EFI_HANDLE *handlep, void **bufp, size_t *bufsize) +{ + /* Try the preferred handles first, then all the handles */ + if (load_preferred(boot_image, PATH_LOADER_EFI, bufp, bufsize, + handlep) == 0) { + return (0); + } + + if (load_all(PATH_LOADER_EFI, bufp, bufsize, handlep) == 0) { + return (0); + } + return (EFI_NOT_FOUND); } @@ -202,20 +497,27 @@ size_t bufsize, loadersize, cmdsize; void *buf, *loaderbuf; char *cmd; - dev_info_t *dev; - const boot_module_t *mod; + EFI_HANDLE fshandle; EFI_HANDLE loaderhandle; EFI_LOADED_IMAGE *loaded_image; EFI_STATUS status; + EFI_DEVICE_PATH *fspath; - status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE); - if (status != EFI_SUCCESS) { - status = load_loader(&mod, &dev, &loaderbuf, &loadersize, - FALSE); + status = load_loader(&fshandle, &loaderbuf, &loadersize); + + if (status != EFI_SUCCESS) { + return (status); + } + + fspath = NULL; + if (status == EFI_SUCCESS) { + status = BS->OpenProtocol(fshandle, &DevicePathGUID, + (void **)&fspath, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (status != EFI_SUCCESS) { - printf("Failed to load '%s'\n", PATH_LOADER_EFI); - return (status); - } + DPRINTF("Failed to get image DevicePath (%lu)\n", + EFI_ERROR_CODE(status)); + } + DPRINTF("filesystem device path: %s\n", devpath_str(fspath)); } /* @@ -230,9 +532,9 @@ */ cmd = NULL; cmdsize = 0; - status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize); + status = do_load(PATH_DOTCONFIG, &buf, &bufsize); if (status == EFI_NOT_FOUND) - status = mod->load(PATH_CONFIG, dev, &buf, &bufsize); + status = do_load(PATH_CONFIG, &buf, &bufsize); if (status == EFI_SUCCESS) { cmdsize = bufsize + 1; cmd = malloc(cmdsize); @@ -244,24 +546,25 @@ buf = NULL; } - if ((status = BS->LoadImage(TRUE, IH, devpath_last(dev->devpath), + if ((status = BS->LoadImage(TRUE, IH, efi_devpath_last_node(fspath), loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) { - printf("Failed to load image provided by %s, size: %zu, (%lu)\n", - mod->name, loadersize, EFI_ERROR_CODE(status)); + printf("Failed to load image, size: %zu, (%lu)\n", + loadersize, EFI_ERROR_CODE(status)); goto errout; } - if ((status = BS->HandleProtocol(loaderhandle, &LoadedImageGUID, - (VOID**)&loaded_image)) != EFI_SUCCESS) { - printf("Failed to query LoadedImage provided by %s (%lu)\n", - mod->name, EFI_ERROR_CODE(status)); + if ((status = BS->OpenProtocol(loaderhandle, &LoadedImageGUID, + (VOID**)&loaded_image, IH, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL)) != EFI_SUCCESS) { + printf("Failed to query LoadedImage (%lu)\n", + EFI_ERROR_CODE(status)); goto errout; } if (cmd != NULL) printf(" command args: %s\n", cmd); - loaded_image->DeviceHandle = dev->devhandle; + loaded_image->DeviceHandle = fshandle; loaded_image->LoadOptionsSize = cmdsize; loaded_image->LoadOptions = cmd; @@ -279,8 +582,8 @@ if ((status = BS->StartImage(loaderhandle, NULL, NULL)) != EFI_SUCCESS) { - printf("Failed to start image provided by %s (%lu)\n", - mod->name, EFI_ERROR_CODE(status)); + printf("Failed to start image (%lu)\n", + EFI_ERROR_CODE(status)); loaded_image->LoadOptionsSize = 0; loaded_image->LoadOptions = NULL; } @@ -296,142 +599,37 @@ return (status); } -/* - * probe_handle determines if the passed handle represents a logical partition - * if it does it uses each module in order to probe it and if successful it - * returns EFI_SUCCESS. - */ -static EFI_STATUS -probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred) +EFI_STATUS +main(int argc __unused, CHAR16 *argv[] __unused) { - dev_info_t *devinfo; - EFI_BLOCK_IO *blkio; - EFI_DEVICE_PATH *devpath; - EFI_STATUS status; - UINTN i; + EFI_STATUS status; - /* Figure out if we're dealing with an actual partition. */ - status = BS->HandleProtocol(h, &DevicePathGUID, (void **)&devpath); - if (status == EFI_UNSUPPORTED) - return (status); + SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; + UINTN i, max_dim, best_mode, cols, rows; + CHAR16 *text; - if (status != EFI_SUCCESS) { - DPRINTF("\nFailed to query DevicePath (%lu)\n", - EFI_ERROR_CODE(status)); - return (status); - } -#ifdef EFI_DEBUG - { - CHAR16 *text = efi_devpath_name(devpath); - DPRINTF("probing: %S\n", text); - efi_free_devpath_name(text); - } + archsw.arch_autoload = efi_autoload; + archsw.arch_getdev = efi_getdev; + archsw.arch_copyin = efi_copyin; + archsw.arch_copyout = efi_copyout; + archsw.arch_readin = efi_readin; +#ifdef EFI_ZFS_BOOT + /* Note this needs to be set before ZFS init. */ + archsw.arch_zfs_probe = efi_zfs_probe; #endif - status = BS->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio); - if (status == EFI_UNSUPPORTED) - return (status); - if (status != EFI_SUCCESS) { - DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n", - EFI_ERROR_CODE(status)); - return (status); - } + /* Init the time source */ + efi_time_init(); + cons_probe(); - if (!blkio->Media->LogicalPartition) - return (EFI_UNSUPPORTED); - - *preferred = device_paths_match(imgpath, devpath); - - /* Run through each module, see if it can load this partition */ - for (i = 0; i < NUM_BOOT_MODULES; i++) { - devinfo = malloc(sizeof(*devinfo)); - if (devinfo == NULL) { - DPRINTF("\nFailed to allocate devinfo\n"); - continue; - } - devinfo->dev = blkio; - devinfo->devpath = devpath; - devinfo->devhandle = h; - devinfo->devdata = NULL; - devinfo->preferred = *preferred; - devinfo->next = NULL; - - status = boot_modules[i]->probe(devinfo); - if (status == EFI_SUCCESS) - return (EFI_SUCCESS); - free(devinfo); - } - - return (EFI_UNSUPPORTED); -} - -/* - * probe_handle_status calls probe_handle and outputs the returned status - * of the call. - */ -static void -probe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath) -{ - EFI_STATUS status; - BOOLEAN preferred; - - preferred = FALSE; - status = probe_handle(h, imgpath, &preferred); - - DPRINTF("probe: "); - switch (status) { - case EFI_UNSUPPORTED: - printf("."); - DPRINTF(" not supported\n"); - break; - case EFI_SUCCESS: - if (preferred) { - printf("%c", '*'); - DPRINTF(" supported (preferred)\n"); - } else { - printf("%c", '+'); - DPRINTF(" supported\n"); - } - break; - default: - printf("x"); - DPRINTF(" error (%lu)\n", EFI_ERROR_CODE(status)); - break; - } - DSTALL(500000); -} - -EFI_STATUS -efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) -{ - EFI_HANDLE *handles; - EFI_LOADED_IMAGE *img; - EFI_DEVICE_PATH *imgpath; - EFI_STATUS status; - EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; - SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; - UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles; - CHAR16 *text; - - /* Basic initialization*/ - ST = Xsystab; - IH = Ximage; - BS = ST->BootServices; - RS = ST->RuntimeServices; - - /* Set up the console, so printf works. */ - status = BS->LocateProtocol(&ConsoleControlGUID, NULL, - (VOID **)&ConsoleControl); - if (status == EFI_SUCCESS) - (void)ConsoleControl->SetMode(ConsoleControl, - EfiConsoleControlScreenText); /* * Reset the console and find the best text mode. */ conout = ST->ConOut; conout->Reset(conout, TRUE); max_dim = best_mode = 0; - for (i = 0; ; i++) { + + for (i = 0; ; i++) { status = conout->QueryMode(conout, i, &cols, &rows); if (EFI_ERROR(status)) break; @@ -440,31 +638,37 @@ best_mode = i; } } - if (max_dim > 0) + + if (max_dim > 0) conout->SetMode(conout, best_mode); + conout->EnableCursor(conout, TRUE); conout->ClearScreen(conout); + /* Print this here, so people know it's at least starting. */ printf("\n>> FreeBSD EFI boot block\n"); printf(" Loader path: %s\n\n", PATH_LOADER_EFI); - printf(" Initializing modules:"); - for (i = 0; i < NUM_BOOT_MODULES; i++) { - printf(" %s", boot_modules[i]->name); - if (boot_modules[i]->init != NULL) - boot_modules[i]->init(); + + /* Get the image path and trim it to get the disk on which we + * found this loader. + */ + if ((status = BS->OpenProtocol(IH, &LoadedImageGUID, + (VOID**)&boot_image, IH, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL)) != EFI_SUCCESS) { + panic("Failed to query LoadedImage (%lu)\n", + EFI_ERROR_CODE(status)); } - putchar('\n'); /* Determine the devpath of our image so we can prefer it. */ - status = BS->HandleProtocol(IH, &LoadedImageGUID, (VOID**)&img); + status = BS->HandleProtocol(IH, &LoadedImageGUID, (VOID**)&boot_image); imgpath = NULL; if (status == EFI_SUCCESS) { - text = efi_devpath_name(img->FilePath); + text = efi_devpath_name(boot_image->FilePath); printf(" Load Path: %S\n", text); efi_setenv_freebsd_wcs("Boot1Path", text); efi_free_devpath_name(text); - status = BS->HandleProtocol(img->DeviceHandle, &DevicePathGUID, + status = BS->HandleProtocol(boot_image->DeviceHandle, &DevicePathGUID, (void **)&imgpath); if (status != EFI_SUCCESS) { DPRINTF("Failed to get image DevicePath (%lu)\n", @@ -478,49 +682,36 @@ } - /* Get all the device handles */ - hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE); - handles = malloc(hsize); - if (handles == NULL) { - printf("Failed to allocate %d handles\n", NUM_HANDLES_INIT); - } + /* The loaded image device path ends with a partition, then a + * file path. Trim them both to get the actual disk. + */ + if ((imgprefix = efi_devpath_trim(imgpath)) == NULL || + (imgprefix = efi_devpath_trim(imgprefix)) == NULL) { + panic("Couldn't trim device path"); + } - status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL, - &hsize, handles); - switch (status) { - case EFI_SUCCESS: - break; - case EFI_BUFFER_TOO_SMALL: - free(handles); - handles = malloc(hsize); - if (handles == NULL) - efi_panic(EFI_OUT_OF_RESOURCES, "Failed to allocate %d handles\n", - NUM_HANDLES_INIT); - status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, - NULL, &hsize, handles); - if (status != EFI_SUCCESS) - efi_panic(status, "Failed to get device handles\n"); - break; - default: - efi_panic(status, "Failed to get device handles\n"); - break; - } + /* + * Initialize the block cache. Set the upper limit. + */ + bcache_init(32768, 512); - /* Scan all partitions, probing with all modules. */ - nhandles = hsize / sizeof(*handles); - printf(" Probing %zu block devices...", nhandles); - DPRINTF("\n"); + printf("\n Initializing modules:"); - for (i = 0; i < nhandles; i++) - probe_handle_status(handles[i], imgpath); - printf(" done\n"); - - /* Status summary. */ - for (i = 0; i < NUM_BOOT_MODULES; i++) { - printf(" "); - boot_modules[i]->status(); + for (i = 0; efi_drivers[i] != NULL; i++) { + printf(" %s", efi_drivers[i]->name); + if (efi_drivers[i]->init != NULL) + efi_drivers[i]->init(); } + for (i = 0; devsw[i] != NULL; i++) { + if (devsw[i]->dv_init != NULL) { + printf(" %s", devsw[i]->dv_name); + (devsw[i]->dv_init)(); + } + } + + putchar('\n'); + try_boot(); /* If we get here, we're out of luck... */ @@ -528,53 +719,19 @@ } /* - * add_device adds a device to the passed devinfo list. - */ -void -add_device(dev_info_t **devinfop, dev_info_t *devinfo) -{ - dev_info_t *dev; - - if (*devinfop == NULL) { - *devinfop = devinfo; - return; - } - - for (dev = *devinfop; dev->next != NULL; dev = dev->next) - ; - - dev->next = devinfo; -} - -/* * OK. We totally give up. Exit back to EFI with a sensible status so * it can try the next option on the list. */ static void efi_panic(EFI_STATUS s, const char *fmt, ...) { - va_list ap; + va_list ap; - printf("panic: "); - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - printf("\n"); + printf("panic: "); + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + printf("\n"); - BS->Exit(IH, s, 0, NULL); -} - -void -putchar(int c) -{ - CHAR16 buf[2]; - - if (c == '\n') { - buf[0] = '\r'; - buf[1] = 0; - ST->ConOut->OutputString(ST->ConOut, buf); - } - buf[0] = c; - buf[1] = 0; - ST->ConOut->OutputString(ST->ConOut, buf); + BS->Exit(IH, s, 0, NULL); } Index: head/sys/boot/efi/boot1/boot_module.h =================================================================== --- head/sys/boot/efi/boot1/boot_module.h +++ head/sys/boot/efi/boot1/boot_module.h @@ -1,109 +0,0 @@ -/*- - * Copyright (c) 2015 Eric McCorkle - * 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$ - */ - -#ifndef _BOOT_MODULE_H_ -#define _BOOT_MODULE_H_ - -#include - -#include -#include -#include - -#ifdef EFI_DEBUG -#define DPRINTF(fmt, args...) printf(fmt, ##args) -#define DSTALL(d) BS->Stall(d) -#else -#define DPRINTF(fmt, ...) {} -#define DSTALL(d) {} -#endif - -/* EFI device info */ -typedef struct dev_info -{ - EFI_BLOCK_IO *dev; - EFI_DEVICE_PATH *devpath; - EFI_HANDLE *devhandle; - void *devdata; - BOOLEAN preferred; - struct dev_info *next; -} dev_info_t; - -/* - * A boot loader module. - * - * This is a standard interface for filesystem modules in the EFI system. - */ -typedef struct boot_module_t -{ - const char *name; - - /* init is the optional initialiser for the module. */ - void (*init)(void); - - /* - * probe checks to see if the module can handle dev. - * - * Return codes: - * EFI_SUCCESS = The module can handle the device. - * EFI_NOT_FOUND = The module can not handle the device. - * Other = The module encountered an error. - */ - EFI_STATUS (*probe)(dev_info_t* dev); - - /* - * load should select the best out of a set of devices that probe - * indicated were loadable and load the specified file. - * - * Return codes: - * EFI_SUCCESS = The module can handle the device. - * EFI_NOT_FOUND = The module can not handle the device. - * Other = The module encountered an error. - */ - EFI_STATUS (*load)(const char *filepath, dev_info_t *devinfo, - void **buf, size_t *bufsize); - - /* status outputs information about the probed devices. */ - void (*status)(void); - - /* valid devices as found by probe. */ - dev_info_t *(*devices)(void); -} boot_module_t; - -/* Standard boot modules. */ -#ifdef EFI_UFS_BOOT -extern const boot_module_t ufs_module; -#endif -#ifdef EFI_ZFS_BOOT -extern const boot_module_t zfs_module; -#endif - -/* Functions available to modules. */ -extern void add_device(dev_info_t **devinfop, dev_info_t *devinfo); -extern int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap); -#endif Index: head/sys/boot/efi/boot1/ufs_module.c =================================================================== --- head/sys/boot/efi/boot1/ufs_module.c +++ head/sys/boot/efi/boot1/ufs_module.c @@ -1,185 +0,0 @@ -/*- - * Copyright (c) 1998 Robert Nordier - * All rights reserved. - * Copyright (c) 2001 Robert Drehmel - * All rights reserved. - * Copyright (c) 2014 Nathan Whitehorn - * All rights reserved. - * Copyright (c) 2015 Eric McCorkle - * All rights reverved. - * - * 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 -#include -#include -#include -#include - -#include "boot_module.h" - -static dev_info_t *devinfo; -static dev_info_t *devices; - -static int -dskread(void *buf, u_int64_t lba, int nblk) -{ - int size; - EFI_STATUS status; - - lba = lba / (devinfo->dev->Media->BlockSize / DEV_BSIZE); - size = nblk * DEV_BSIZE; - - status = devinfo->dev->ReadBlocks(devinfo->dev, - devinfo->dev->Media->MediaId, lba, size, buf); - - if (status != EFI_SUCCESS) { - DPRINTF("dskread: failed dev: %p, id: %u, lba: %ju, size: %d, " - "status: %lu\n", devinfo->dev, - devinfo->dev->Media->MediaId, (uintmax_t)lba, size, - EFI_ERROR_CODE(status)); - return (-1); - } - - return (0); -} - -#include "ufsread.c" - -static struct dmadat __dmadat; - -static int -init_dev(dev_info_t* dev) -{ - - devinfo = dev; - dmadat = &__dmadat; - - return fsread(0, NULL, 0); -} - -static EFI_STATUS -probe(dev_info_t* dev) -{ - - if (init_dev(dev) < 0) - return (EFI_UNSUPPORTED); - - add_device(&devices, dev); - - return (EFI_SUCCESS); -} - -static EFI_STATUS -load(const char *filepath, dev_info_t *dev, void **bufp, size_t *bufsize) -{ - ufs_ino_t ino; - EFI_STATUS status; - size_t size; - ssize_t read; - void *buf; - -#ifdef EFI_DEBUG - { - CHAR16 *text = efi_devpath_name(dev->devpath); - DPRINTF("Loading '%s' from %S\n", filepath, text); - efi_free_devpath_name(text); - } -#endif - if (init_dev(dev) < 0) { - DPRINTF("Failed to init device\n"); - return (EFI_UNSUPPORTED); - } - - if ((ino = lookup(filepath)) == 0) { - DPRINTF("Failed to lookup '%s' (file not found?)\n", filepath); - return (EFI_NOT_FOUND); - } - - if (fsread_size(ino, NULL, 0, &size) < 0 || size <= 0) { - printf("Failed to read size of '%s' ino: %d\n", filepath, ino); - return (EFI_INVALID_PARAMETER); - } - - if ((status = BS->AllocatePool(EfiLoaderData, size, &buf)) != - EFI_SUCCESS) { - printf("Failed to allocate read buffer %zu for '%s' (%lu)\n", - size, filepath, EFI_ERROR_CODE(status)); - return (status); - } - - read = fsread(ino, buf, size); - if ((size_t)read != size) { - printf("Failed to read '%s' (%zd != %zu)\n", filepath, read, - size); - (void)BS->FreePool(buf); - return (EFI_INVALID_PARAMETER); - } - - DPRINTF("Load complete\n"); - - *bufp = buf; - *bufsize = size; - - return (EFI_SUCCESS); -} - -static void -status(void) -{ - int i; - dev_info_t *dev; - - for (dev = devices, i = 0; dev != NULL; dev = dev->next, i++) - ; - - printf("%s found ", ufs_module.name); - switch (i) { - case 0: - printf("no partitions\n"); - break; - case 1: - printf("%d partition\n", i); - break; - default: - printf("%d partitions\n", i); - } -} - -static dev_info_t * -_devices(void) -{ - - return (devices); -} - -const boot_module_t ufs_module = -{ - .name = "UFS", - .probe = probe, - .load = load, - .status = status, - .devices = _devices -}; Index: head/sys/boot/efi/boot1/zfs_module.c =================================================================== --- head/sys/boot/efi/boot1/zfs_module.c +++ head/sys/boot/efi/boot1/zfs_module.c @@ -1,248 +0,0 @@ -/*- - * Copyright (c) 2015 Eric McCorkle - * 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 -#include -#include -#include -#include -#include -#include - -#include "boot_module.h" - -#include "libzfs.h" -#include "zfsimpl.c" - -static dev_info_t *devices; - -uint64_t -ldi_get_size(void *priv) -{ - dev_info_t *devinfo = priv; - - return (devinfo->dev->Media->BlockSize * - (devinfo->dev->Media->LastBlock + 1)); -} - -static int -vdev_read(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes) -{ - dev_info_t *devinfo; - uint64_t lba; - size_t size, remainder, rb_size, blksz; - char *bouncebuf = NULL, *rb_buf; - EFI_STATUS status; - - devinfo = (dev_info_t *)priv; - lba = off / devinfo->dev->Media->BlockSize; - remainder = off % devinfo->dev->Media->BlockSize; - - rb_buf = buf; - rb_size = bytes; - - /* - * If we have remainder from off, we need to add remainder part. - * Since buffer must be multiple of the BlockSize, round it all up. - */ - size = roundup2(bytes + remainder, devinfo->dev->Media->BlockSize); - blksz = size; - if (remainder != 0 || size != bytes) { - rb_size = devinfo->dev->Media->BlockSize; - bouncebuf = malloc(rb_size); - if (bouncebuf == NULL) { - printf("vdev_read: out of memory\n"); - return (-1); - } - rb_buf = bouncebuf; - blksz = rb_size - remainder; - } - - while (bytes > 0) { - status = devinfo->dev->ReadBlocks(devinfo->dev, - devinfo->dev->Media->MediaId, lba, rb_size, rb_buf); - if (EFI_ERROR(status)) - goto error; - if (bytes < blksz) - blksz = bytes; - if (bouncebuf != NULL) - memcpy(buf, rb_buf + remainder, blksz); - buf = (void *)((uintptr_t)buf + blksz); - bytes -= blksz; - lba++; - remainder = 0; - blksz = rb_size; - } - - free(bouncebuf); - return (0); - -error: - free(bouncebuf); - DPRINTF("vdev_read: failed dev: %p, id: %u, lba: %ju, size: %zu," - " rb_size: %zu, status: %lu\n", devinfo->dev, - devinfo->dev->Media->MediaId, (uintmax_t)lba, bytes, rb_size, - EFI_ERROR_CODE(status)); - return (-1); -} - -static EFI_STATUS -probe(dev_info_t *dev) -{ - spa_t *spa; - dev_info_t *tdev; - EFI_STATUS status; - - /* ZFS consumes the dev on success so we need a copy. */ - if ((status = BS->AllocatePool(EfiLoaderData, sizeof(*dev), - (void**)&tdev)) != EFI_SUCCESS) { - DPRINTF("Failed to allocate tdev (%lu)\n", - EFI_ERROR_CODE(status)); - return (status); - } - memcpy(tdev, dev, sizeof(*dev)); - - if (vdev_probe(vdev_read, tdev, &spa) != 0) { - (void)BS->FreePool(tdev); - return (EFI_UNSUPPORTED); - } - - dev->devdata = spa; - add_device(&devices, dev); - - return (EFI_SUCCESS); -} - -static EFI_STATUS -load(const char *filepath, dev_info_t *devinfo, void **bufp, size_t *bufsize) -{ - spa_t *spa; - struct zfsmount zfsmount; - dnode_phys_t dn; - struct stat st; - int err; - void *buf; - EFI_STATUS status; - - spa = devinfo->devdata; - -#ifdef EFI_DEBUG - { - CHAR16 *text = efi_devpath_name(devinfo->devpath); - DPRINTF("load: '%s' spa: '%s', devpath: %S\n", filepath, - spa->spa_name, text); - efi_free_devpath_name(text); - } -#endif - if ((err = zfs_spa_init(spa)) != 0) { - DPRINTF("Failed to load pool '%s' (%d)\n", spa->spa_name, err); - return (EFI_NOT_FOUND); - } - - if ((err = zfs_mount(spa, 0, &zfsmount)) != 0) { - DPRINTF("Failed to mount pool '%s' (%d)\n", spa->spa_name, err); - return (EFI_NOT_FOUND); - } - - if ((err = zfs_lookup(&zfsmount, filepath, &dn)) != 0) { - if (err == ENOENT) { - DPRINTF("Failed to find '%s' on pool '%s' (%d)\n", - filepath, spa->spa_name, err); - return (EFI_NOT_FOUND); - } - printf("Failed to lookup '%s' on pool '%s' (%d)\n", filepath, - spa->spa_name, err); - return (EFI_INVALID_PARAMETER); - } - - if ((err = zfs_dnode_stat(spa, &dn, &st)) != 0) { - printf("Failed to stat '%s' on pool '%s' (%d)\n", filepath, - spa->spa_name, err); - return (EFI_INVALID_PARAMETER); - } - - if ((status = BS->AllocatePool(EfiLoaderData, (UINTN)st.st_size, &buf)) - != EFI_SUCCESS) { - printf("Failed to allocate load buffer %jd for pool '%s' for '%s' " - "(%lu)\n", (intmax_t)st.st_size, spa->spa_name, filepath, EFI_ERROR_CODE(status)); - return (EFI_INVALID_PARAMETER); - } - - if ((err = dnode_read(spa, &dn, 0, buf, st.st_size)) != 0) { - printf("Failed to read node from %s (%d)\n", spa->spa_name, - err); - (void)BS->FreePool(buf); - return (EFI_INVALID_PARAMETER); - } - - *bufsize = st.st_size; - *bufp = buf; - - return (EFI_SUCCESS); -} - -static void -status(void) -{ - spa_t *spa; - - spa = STAILQ_FIRST(&zfs_pools); - if (spa == NULL) { - printf("%s found no pools\n", zfs_module.name); - return; - } - - printf("%s found the following pools:", zfs_module.name); - STAILQ_FOREACH(spa, &zfs_pools, spa_link) - printf(" %s", spa->spa_name); - - printf("\n"); -} - -static void -init(void) -{ - - zfs_init(); -} - -static dev_info_t * -_devices(void) -{ - - return (devices); -} - -const boot_module_t zfs_module = -{ - .name = "ZFS", - .init = init, - .probe = probe, - .load = load, - .status = status, - .devices = _devices -}; Index: head/sys/boot/efi/libefi/Makefile =================================================================== --- head/sys/boot/efi/libefi/Makefile +++ head/sys/boot/efi/libefi/Makefile @@ -11,8 +11,9 @@ INTERNALLIB= WARNS?= 2 -SRCS= delay.c devpath.c efi_console.c efichar.c efinet.c efipart.c env.c errno.c \ - handles.c wchar.c libefi.c efi_driver_utils.c efizfs.c devicename.c +SRCS= delay.c devpath.c efi_console.c efichar.c efinet.c efipart.c env.c \ + errno.c handles.c wchar.c libefi.c efi_driver_utils.c efizfs.c \ + devicename.c efi_main.c .if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" SRCS+= time.c Index: head/sys/boot/efi/libefi/efi_main.c =================================================================== --- head/sys/boot/efi/libefi/efi_main.c +++ head/sys/boot/efi/libefi/efi_main.c @@ -0,0 +1,188 @@ +/*- + * Copyright (c) 2000 Doug Rabson + * 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$"); + +#include +#include +#include +#include + +static EFI_PHYSICAL_ADDRESS heap; +static UINTN heapsize; + +void +efi_exit(EFI_STATUS exit_code) +{ + + BS->FreePages(heap, EFI_SIZE_TO_PAGES(heapsize)); + BS->Exit(IH, exit_code, 0, NULL); +} + +void +exit(int status) +{ + + efi_exit(EFI_LOAD_ERROR); +} + +static CHAR16 * +arg_skipsep(CHAR16 *argp) +{ + + while (*argp == ' ' || *argp == '\t' || *argp == '\n') + argp++; + return (argp); +} + +static CHAR16 * +arg_skipword(CHAR16 *argp) +{ + + while (*argp && *argp != ' ' && *argp != '\t' && *argp != '\n') + argp++; + return (argp); +} + +EFI_STATUS +efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table) +{ + static EFI_GUID image_protocol = LOADED_IMAGE_PROTOCOL; + static EFI_GUID console_control_protocol = + EFI_CONSOLE_CONTROL_PROTOCOL_GUID; + EFI_CONSOLE_CONTROL_PROTOCOL *console_control = NULL; + EFI_LOADED_IMAGE *img; + CHAR16 *argp, *args, **argv; + EFI_STATUS status; + int argc, addprog; + + IH = image_handle; + ST = system_table; + BS = ST->BootServices; + RS = ST->RuntimeServices; + + status = BS->LocateProtocol(&console_control_protocol, NULL, + (VOID **)&console_control); + if (status == EFI_SUCCESS) + (void)console_control->SetMode(console_control, + EfiConsoleControlScreenText); + + heapsize = 64 * 1024 * 1024; + status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, + EFI_SIZE_TO_PAGES(heapsize), &heap); + if (status != EFI_SUCCESS) + BS->Exit(IH, status, 0, NULL); + + setheap((void *)(uintptr_t)heap, (void *)(uintptr_t)(heap + heapsize)); + + /* Use efi_exit() from here on... */ + + status = BS->HandleProtocol(IH, &image_protocol, (VOID**)&img); + if (status != EFI_SUCCESS) + efi_exit(status); + + /* + * Pre-process the (optional) load options. If the option string + * is given as an ASCII string, we use a poor man's ASCII to + * Unicode-16 translation. The size of the option string as given + * to us includes the terminating null character. We assume the + * string is an ASCII string if strlen() plus the terminating + * '\0' is less than LoadOptionsSize. Even if all Unicode-16 + * characters have the upper 8 bits non-zero, the terminating + * null character will cause a one-off. + * If the string is already in Unicode-16, we make a copy so that + * we know we can always modify the string. + */ + if (img->LoadOptionsSize > 0 && img->LoadOptions != NULL) { + if (img->LoadOptionsSize == strlen(img->LoadOptions) + 1) { + args = malloc(img->LoadOptionsSize << 1); + for (argc = 0; argc < (int)img->LoadOptionsSize; argc++) + args[argc] = ((char*)img->LoadOptions)[argc]; + } else { + args = malloc(img->LoadOptionsSize); + memcpy(args, img->LoadOptions, img->LoadOptionsSize); + } + } else + args = NULL; + + /* + * Use a quick and dirty algorithm to build the argv vector. We + * first count the number of words. Then, after allocating the + * vector, we split the string up. We don't deal with quotes or + * other more advanced shell features. + * The EFI shell will pass the name of the image as the first + * word in the argument list. This does not happen if we're + * loaded by the boot manager. This is not so easy to figure + * out though. The ParentHandle is not always NULL, because + * there can be a function (=image) that will perform the task + * for the boot manager. + */ + /* Part 1: Figure out if we need to add our program name. */ + addprog = (args == NULL || img->ParentHandle == NULL || + img->FilePath == NULL) ? 1 : 0; + if (!addprog) { + addprog = + (DevicePathType(img->FilePath) != MEDIA_DEVICE_PATH || + DevicePathSubType(img->FilePath) != MEDIA_FILEPATH_DP || + DevicePathNodeLength(img->FilePath) <= + sizeof(FILEPATH_DEVICE_PATH)) ? 1 : 0; + if (!addprog) { + /* XXX todo. */ + } + } + /* Part 2: count words. */ + argc = (addprog) ? 1 : 0; + argp = args; + while (argp != NULL && *argp != 0) { + argp = arg_skipsep(argp); + if (*argp == 0) + break; + argc++; + argp = arg_skipword(argp); + } + /* Part 3: build vector. */ + argv = malloc((argc + 1) * sizeof(CHAR16*)); + argc = 0; + if (addprog) + argv[argc++] = (CHAR16 *)L"loader.efi"; + argp = args; + while (argp != NULL && *argp != 0) { + argp = arg_skipsep(argp); + if (*argp == 0) + break; + argv[argc++] = argp; + argp = arg_skipword(argp); + /* Terminate the words. */ + if (*argp != 0) + *argp++ = 0; + } + argv[argc] = NULL; + + status = main(argc, argv); + efi_exit(status); + return (status); +} Index: head/sys/boot/efi/loader/Makefile =================================================================== --- head/sys/boot/efi/loader/Makefile +++ head/sys/boot/efi/loader/Makefile @@ -16,7 +16,6 @@ bootinfo.c \ conf.c \ copy.c \ - efi_main.c \ main.c \ self_reloc.c \ smbios.c \ Index: head/sys/boot/efi/loader/efi_main.c =================================================================== --- head/sys/boot/efi/loader/efi_main.c +++ head/sys/boot/efi/loader/efi_main.c @@ -1,188 +0,0 @@ -/*- - * Copyright (c) 2000 Doug Rabson - * 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$"); - -#include -#include -#include -#include - -static EFI_PHYSICAL_ADDRESS heap; -static UINTN heapsize; - -void -efi_exit(EFI_STATUS exit_code) -{ - - BS->FreePages(heap, EFI_SIZE_TO_PAGES(heapsize)); - BS->Exit(IH, exit_code, 0, NULL); -} - -void -exit(int status) -{ - - efi_exit(EFI_LOAD_ERROR); -} - -static CHAR16 * -arg_skipsep(CHAR16 *argp) -{ - - while (*argp == ' ' || *argp == '\t' || *argp == '\n') - argp++; - return (argp); -} - -static CHAR16 * -arg_skipword(CHAR16 *argp) -{ - - while (*argp && *argp != ' ' && *argp != '\t' && *argp != '\n') - argp++; - return (argp); -} - -EFI_STATUS -efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table) -{ - static EFI_GUID image_protocol = LOADED_IMAGE_PROTOCOL; - static EFI_GUID console_control_protocol = - EFI_CONSOLE_CONTROL_PROTOCOL_GUID; - EFI_CONSOLE_CONTROL_PROTOCOL *console_control = NULL; - EFI_LOADED_IMAGE *img; - CHAR16 *argp, *args, **argv; - EFI_STATUS status; - int argc, addprog; - - IH = image_handle; - ST = system_table; - BS = ST->BootServices; - RS = ST->RuntimeServices; - - status = BS->LocateProtocol(&console_control_protocol, NULL, - (VOID **)&console_control); - if (status == EFI_SUCCESS) - (void)console_control->SetMode(console_control, - EfiConsoleControlScreenText); - - heapsize = 64 * 1024 * 1024; - status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, - EFI_SIZE_TO_PAGES(heapsize), &heap); - if (status != EFI_SUCCESS) - BS->Exit(IH, status, 0, NULL); - - setheap((void *)(uintptr_t)heap, (void *)(uintptr_t)(heap + heapsize)); - - /* Use efi_exit() from here on... */ - - status = BS->HandleProtocol(IH, &image_protocol, (VOID**)&img); - if (status != EFI_SUCCESS) - efi_exit(status); - - /* - * Pre-process the (optional) load options. If the option string - * is given as an ASCII string, we use a poor man's ASCII to - * Unicode-16 translation. The size of the option string as given - * to us includes the terminating null character. We assume the - * string is an ASCII string if strlen() plus the terminating - * '\0' is less than LoadOptionsSize. Even if all Unicode-16 - * characters have the upper 8 bits non-zero, the terminating - * null character will cause a one-off. - * If the string is already in Unicode-16, we make a copy so that - * we know we can always modify the string. - */ - if (img->LoadOptionsSize > 0 && img->LoadOptions != NULL) { - if (img->LoadOptionsSize == strlen(img->LoadOptions) + 1) { - args = malloc(img->LoadOptionsSize << 1); - for (argc = 0; argc < (int)img->LoadOptionsSize; argc++) - args[argc] = ((char*)img->LoadOptions)[argc]; - } else { - args = malloc(img->LoadOptionsSize); - memcpy(args, img->LoadOptions, img->LoadOptionsSize); - } - } else - args = NULL; - - /* - * Use a quick and dirty algorithm to build the argv vector. We - * first count the number of words. Then, after allocating the - * vector, we split the string up. We don't deal with quotes or - * other more advanced shell features. - * The EFI shell will pass the name of the image as the first - * word in the argument list. This does not happen if we're - * loaded by the boot manager. This is not so easy to figure - * out though. The ParentHandle is not always NULL, because - * there can be a function (=image) that will perform the task - * for the boot manager. - */ - /* Part 1: Figure out if we need to add our program name. */ - addprog = (args == NULL || img->ParentHandle == NULL || - img->FilePath == NULL) ? 1 : 0; - if (!addprog) { - addprog = - (DevicePathType(img->FilePath) != MEDIA_DEVICE_PATH || - DevicePathSubType(img->FilePath) != MEDIA_FILEPATH_DP || - DevicePathNodeLength(img->FilePath) <= - sizeof(FILEPATH_DEVICE_PATH)) ? 1 : 0; - if (!addprog) { - /* XXX todo. */ - } - } - /* Part 2: count words. */ - argc = (addprog) ? 1 : 0; - argp = args; - while (argp != NULL && *argp != 0) { - argp = arg_skipsep(argp); - if (*argp == 0) - break; - argc++; - argp = arg_skipword(argp); - } - /* Part 3: build vector. */ - argv = malloc((argc + 1) * sizeof(CHAR16*)); - argc = 0; - if (addprog) - argv[argc++] = (CHAR16 *)L"loader.efi"; - argp = args; - while (argp != NULL && *argp != 0) { - argp = arg_skipsep(argp); - if (*argp == 0) - break; - argv[argc++] = argp; - argp = arg_skipword(argp); - /* Terminate the words. */ - if (*argp != 0) - *argp++ = 0; - } - argv[argc] = NULL; - - status = main(argc, argv); - efi_exit(status); - return (status); -}