Index: sys/boot/efi/boot1/Makefile =================================================================== --- sys/boot/efi/boot1/Makefile +++ sys/boot/efi/boot1/Makefile @@ -8,17 +8,23 @@ PROG= boot1.sym INTERNALPROG= -WARNS?= 6 +WARNS?= 3 + +# Include bcache code. +HAVE_BCACHE= yes .if ${MK_ZFS} != "no" # 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.boot1.c += -Wno-missing-variable-declarations +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 @@ -27,20 +33,29 @@ .endif .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} @@ -64,6 +79,17 @@ .PATH: ${.CURDIR}/../../common CFLAGS+= -I${.CURDIR}/../../common +# make buildenv doesn't set DESTDIR, this means LIBSTAND +# will be wrong when crossbuilding. +.if exists(${.OBJDIR}/../../../../lib/libstand/libstand.a) +LIBSTAND= ${.OBJDIR}/../../../../lib/libstand/libstand.a +.endif + +# Add libefi +.PATH: ${.CURDIR}/../libefi +LIBEFI= ${.OBJDIR}/../libefi/libefi.a + + FILES= boot1.efi boot1.efifat FILESMODE_boot1.efi= ${BINMODE} @@ -83,8 +109,8 @@ # __aeabi_* (arm) or __divdi3 (i386). # as well as required string and memory functions for all platforms. # -DPADD+= ${LIBSTAND} -LDADD+= -lstand +DPADD+= ${LIBEFI} ${LIBSTAND} +LDADD+= ${LIBEFI} ${LIBSTAND} DPADD+= ${LDSCRIPT} @@ -110,7 +136,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: ${.CURDIR}/../../common/ufsread.c @@ -119,7 +145,7 @@ # created by generate-fat.sh .include "${.CURDIR}/Makefile.fat" -BOOT1_MAXSIZE?= 131072 +BOOT1_MAXSIZE?= 524288 boot1.efifat: boot1.efi @set -- `ls -l ${.ALLSRC}`; \ Index: sys/boot/efi/boot1/boot1.c =================================================================== --- sys/boot/efi/boot1/boot1.c +++ sys/boot/efi/boot1/boot1.c @@ -23,64 +23,124 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include #include +#include #include +#include +#include #include +#ifdef EFI_ZFS_BOOT +#include +#endif -#include "boot_module.h" +#include + +#include "efi_drivers.h" +#include "efizfs.h" #include "paths.h" -static const boot_module_t *boot_modules[] = -{ +#ifdef EFI_DEBUG +#define DPRINTF(fmt, args...) printf(fmt, ##args) +#define DSTALL(d) BS->Stall(d) +#else +#define DPRINTF(fmt, ...) {} +#define DSTALL(d) {} +#endif + +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 +uint64_t pool_guid; +#endif + +struct fs_ops *file_system[] = { #ifdef EFI_ZFS_BOOT - &zfs_module, + &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) -/* The initial number of handles used to query EFI for partitions. */ -#define NUM_HANDLES_INIT 24 +struct devsw *devsw[] = { + &efipart_hddev, + &efipart_fddev, + &efipart_cddev, +#ifdef EFI_ZFS_BOOT + &zfs_dev, +#endif + NULL +}; -EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab); +struct console *consoles[] = { + &efi_console, + NULL +}; -EFI_SYSTEM_TABLE *systab; -EFI_BOOT_SERVICES *bs; -static EFI_HANDLE *image; +/* Definitions we don't actually need for boot, but we need to define + * to make the linker happy. + */ +struct file_format *file_formats[] = { NULL }; -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; +struct netif_driver *netif_drivers[] = { NULL }; -/* - * 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 int +efi_autoload(void) { - void *out; + printf("******** Boot block should not call autoload\n"); + return (-1); +} - if (bs->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS) - return (out); +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); +} - return (NULL); +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); } -void -Free(void *buf, const char *file __unused, int line __unused) +static ssize_t +efi_readin(int fd __unused, vm_offset_t dest __unused, + const size_t len __unused) { - if (buf != NULL) - (void)bs->FreePool(buf); + 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 DevicePathGUID = DEVICE_PATH_PROTOCOL; +static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; + /* * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match, * FALSE otherwise. @@ -141,6 +201,7 @@ return (devpath); } +#ifdef EFI_DEBUG /* * devpath_node_str is a basic output method for a devpath node which * only understands a subset of the available sub types. @@ -272,7 +333,7 @@ * devpath_strlcat appends a text description of devpath to buf but not more * than size - 1 characters followed by NUL-terminator. */ -int +static int devpath_strlcat(char *buf, size_t size, EFI_DEVICE_PATH *devpath) { size_t len, used; @@ -303,48 +364,366 @@ * devpath_str is convenience method which returns the text description of * devpath using a static buffer, so it isn't thread safe! */ -char * +static char * devpath_str(EFI_DEVICE_PATH *devpath) { static char buf[256]; devpath_strlcat(buf, sizeof(buf), devpath); - return buf; + return (buf); } +#endif -/* - * 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) +do_load(const char *filepath, void **bufp, size_t *bufsize) { - UINTN i; - dev_info_t *dev; - const boot_module_t *mod; - - 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; - - if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) == - EFI_SUCCESS) { - *devinfop = dev; - *modp = mod; - return (EFI_SUCCESS); + struct stat st; + void *buf = NULL; + int fd, err; + size_t fsize, remaining; + ssize_t readsize; + + if ((fd = open(filepath, O_RDONLY)) < 0) { + return (ENOTSUP); + } + + if ((err = fstat(fd, &st)) != 0) { + goto close_file; + } + + 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 int +probe_fs(const char *filepath) +{ + int fd; + + if ((fd = open(filepath, O_RDONLY)) < 0) { + return (ENOTSUP); + } + + close(fd); + + return (0); +} + +static int +probe_dev(struct devsw *dev, int unit, const char *filepath) +{ + struct devdesc currdev; + char *devname; + int err; + + currdev.d_dev = dev; + currdev.d_type = currdev.d_dev->dv_type; + currdev.d_unit = unit; + currdev.d_opendata = NULL; + devname = efi_fmtdev(&currdev); + + env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev, + env_nounset); + + err = probe_fs(filepath); + + return (err); +} + +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; + EFI_DEVICE_PATH *devpath, *copy; + EFI_HANDLE h; + struct devsw *dev; + int unit; + uint64_t extra; + char *devname; + +#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 = img->DeviceHandle; + 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 (dp->pd_handle == img->DeviceHandle && + probe_fs(filepath) == 0 && + do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { + *handlep = img->DeviceHandle; + return (0); + } + + /* Assuming GPT partitioning. */ + STAILQ_FOREACH(pp, &dp->pd_part, pd_link) { + if (pp->pd_handle == img->DeviceHandle) { + 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 = img->DeviceHandle; + 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) && + probe_dev(&efipart_cddev, dp->pd_unit, filepath) == 0 && + do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { + *handlep = img->DeviceHandle; + return (0); + } + } + + pdi_list = efiblk_get_pdinfo_list(&efipart_fddev); + STAILQ_FOREACH(dp, pdi_list, pd_link) { + if (dp->pd_handle == img->DeviceHandle && + probe_dev(&efipart_cddev, dp->pd_unit, filepath) == 0 && + do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { + *handlep = img->DeviceHandle; + return (0); + } + } + + /* + * Try the device handle from our loaded image first. If that + * fails, use the device path from the loaded image and see if + * any of the nodes in that path match one of the enumerated + * handles. + */ + if (efi_handle_lookup(img->DeviceHandle, &dev, &unit, &extra) == 0 && + probe_dev(dev, dp->pd_unit, filepath) == 0 && + do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { + *handlep = img->DeviceHandle; + return (0); + } + + copy = NULL; + devpath = efi_lookup_image_devpath(IH); + while (devpath != NULL) { + h = efi_devpath_handle(devpath); + if (h == NULL) + break; + + free(copy); + copy = NULL; + + if (efi_handle_lookup(h, &dev, &unit, &extra) == 0 && + probe_dev(dev, dp->pd_unit, filepath) == 0 && + do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { + *handlep = img->DeviceHandle; + return (0); + } + + devpath = efi_lookup_devpath(h); + if (devpath != NULL) { + copy = efi_devpath_trim(devpath); + devpath = copy; + } + } + free(copy); + + return (ENOENT); +} + +static int +load_all(const char *filepath, void **bufp, size_t *bufsize, + EFI_HANDLE *handlep) +{ + pdinfo_list_t *pdi_list; + pdinfo_t *dp, *pp; + zfsinfo_list_t *zfsi_list; + zfsinfo_t *zi; + char *devname; + +#ifdef EFI_ZFS_BOOT + zfsi_list = efizfs_get_zfsinfo_list(); + STAILQ_FOREACH(zi, zfsi_list, zi_link) { + 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 = 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; + printf("Succeeded\n"); + + 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) +{ + EFI_LOADED_IMAGE *boot_image; + EFI_STATUS status; + + 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)); + } + + /* 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); } @@ -358,20 +737,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(&fshandle, &loaderbuf, &loadersize); + + if (status != EFI_SUCCESS) { + return (status); + } - status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE); - if (status != EFI_SUCCESS) { - status = load_loader(&mod, &dev, &loaderbuf, &loadersize, - FALSE); + 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)); } /* @@ -386,9 +772,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); @@ -400,24 +786,25 @@ buf = NULL; } - if ((status = bs->LoadImage(TRUE, image, devpath_last(dev->devpath), + if ((status = BS->LoadImage(TRUE, IH, devpath_last(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; @@ -433,10 +820,10 @@ DSTALL(1000000); DPRINTF(".\n"); - if ((status = bs->StartImage(loaderhandle, NULL, NULL)) != + 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; } @@ -452,135 +839,33 @@ 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); - - if (status != EFI_SUCCESS) { - DPRINTF("\nFailed to query DevicePath (%lu)\n", - EFI_ERROR_CODE(status)); - return (status); - } + SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; + UINTN i, max_dim, best_mode, cols, rows; - DPRINTF("probing: %s\n", devpath_str(devpath)); - - 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); - } - - if (!blkio->Media->LogicalPartition) - return (EFI_UNSUPPORTED); - - *preferred = device_paths_match(imgpath, devpath); + 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 - /* Run through each module, see if it can load this partition */ - for (i = 0; i < NUM_BOOT_MODULES; i++) { - if ((status = bs->AllocatePool(EfiLoaderData, - sizeof(*devinfo), (void **)&devinfo)) != - EFI_SUCCESS) { - DPRINTF("\nFailed to allocate devinfo (%lu)\n", - EFI_ERROR_CODE(status)); - 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); - (void)bs->FreePool(devinfo); - } + /* Init the time source */ + efi_time_init(); - return (EFI_UNSUPPORTED); -} + cons_probe(); -/* - * 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; - - /* Basic initialization*/ - systab = Xsystab; - image = Ximage; - bs = Xsystab->BootServices; - - /* 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 = systab->ConOut; + conout = ST->ConOut; conout->Reset(conout, TRUE); max_dim = best_mode = 0; for (i = 0; ; i++) { @@ -597,123 +882,39 @@ conout->EnableCursor(conout, TRUE); conout->ClearScreen(conout); - 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(); - } - putchar('\n'); + /* + * Initialise the block cache. Set the upper limit. + */ + bcache_init(32768, 512); - /* Get all the device handles */ - hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE); - if ((status = bs->AllocatePool(EfiLoaderData, hsize, (void **)&handles)) - != EFI_SUCCESS) - panic("Failed to allocate %d handles (%lu)", NUM_HANDLES_INIT, - EFI_ERROR_CODE(status)); + printf("\n>> FreeBSD EFI boot block\n"); - status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL, - &hsize, handles); - switch (status) { - case EFI_SUCCESS: - break; - case EFI_BUFFER_TOO_SMALL: - (void)bs->FreePool(handles); - if ((status = bs->AllocatePool(EfiLoaderData, hsize, - (void **)&handles)) != EFI_SUCCESS) { - panic("Failed to allocate %zu handles (%lu)", hsize / - sizeof(*handles), EFI_ERROR_CODE(status)); - } - status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID, - NULL, &hsize, handles); - if (status != EFI_SUCCESS) - panic("Failed to get device handles (%lu)\n", - EFI_ERROR_CODE(status)); - break; - default: - panic("Failed to get device handles (%lu)", - EFI_ERROR_CODE(status)); - } + 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; - /* Scan all partitions, probing with all modules. */ - nhandles = hsize / sizeof(*handles); - printf(" Probing %zu block devices...", nhandles); - DPRINTF("\n"); + printf(" Loader path: %s\n\n", PATH_LOADER_EFI); + printf(" Initializing modules:"); - /* Determine the devpath of our image so we can prefer it. */ - status = bs->HandleProtocol(image, &LoadedImageGUID, (VOID**)&img); - imgpath = NULL; - if (status == EFI_SUCCESS) { - status = bs->HandleProtocol(img->DeviceHandle, &DevicePathGUID, - (void **)&imgpath); - if (status != EFI_SUCCESS) - DPRINTF("Failed to get image DevicePath (%lu)\n", - EFI_ERROR_CODE(status)); - DPRINTF("boot1 imagepath: %s\n", devpath_str(imgpath)); + 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; i < nhandles; i++) - probe_handle_status(handles[i], imgpath); - printf(" done\n"); + for (i = 0; devsw[i] != NULL; i++) { + if (devsw[i]->dv_init != NULL) { + printf(" %s", devsw[i]->dv_name); + (devsw[i]->dv_init)(); + } + } - /* Status summary. */ - for (i = 0; i < NUM_BOOT_MODULES; i++) { - printf(" "); - boot_modules[i]->status(); - } + putchar('\n'); try_boot(); /* If we get here, we're out of luck... */ panic("No bootable partitions found!"); } - -/* - * 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; -} - -void -panic(const char *fmt, ...) -{ - va_list ap; - - printf("panic: "); - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - printf("\n"); - - while (1) {} -} - -void -putchar(int c) -{ - CHAR16 buf[2]; - - if (c == '\n') { - buf[0] = '\r'; - buf[1] = 0; - systab->ConOut->OutputString(systab->ConOut, buf); - } - buf[0] = c; - buf[1] = 0; - systab->ConOut->OutputString(systab->ConOut, buf); -} Index: sys/boot/efi/boot1/boot_module.h =================================================================== --- sys/boot/efi/boot1/boot_module.h +++ /dev/null @@ -1,115 +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); - -extern EFI_SYSTEM_TABLE *systab; -extern EFI_BOOT_SERVICES *bs; - -extern int devpath_strlcat(char *buf, size_t size, EFI_DEVICE_PATH *devpath); -extern char *devpath_str(EFI_DEVICE_PATH *devpath); -#endif Index: sys/boot/efi/boot1/ufs_module.c =================================================================== --- sys/boot/efi/boot1/ufs_module.c +++ /dev/null @@ -1,180 +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; - - DPRINTF("Loading '%s' from %s\n", filepath, devpath_str(dev->devpath)); - - 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: sys/boot/efi/boot1/zfs_module.c =================================================================== --- sys/boot/efi/boot1/zfs_module.c +++ /dev/null @@ -1,243 +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; - - DPRINTF("load: '%s' spa: '%s', devpath: %s\n", filepath, spa->spa_name, - devpath_str(devinfo->devpath)); - - 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 -};