Index: lib/libstand/Makefile =================================================================== --- lib/libstand/Makefile +++ lib/libstand/Makefile @@ -41,7 +41,7 @@ .PATH: ${LIBC_SRC}/string SRCS+= bcmp.c bcopy.c bzero.c ffs.c fls.c \ memccpy.c memchr.c memcmp.c memcpy.c memmove.c memset.c \ - qdivrem.c strcat.c strchr.c strcmp.c strcpy.c \ + qdivrem.c strcat.c strchr.c strcmp.c strcpy.c stpcpy.c stpncpy.c \ strcspn.c strlcat.c strlcpy.c strlen.c strncat.c strncmp.c strncpy.c \ strpbrk.c strrchr.c strsep.c strspn.c strstr.c strtok.c swab.c .if ${MACHINE_CPUARCH} == "arm" Index: lib/libstand/stand.h =================================================================== --- lib/libstand/stand.h +++ lib/libstand/stand.h @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD$ - * From $NetBSD: stand.h,v 1.22 1997/06/26 19:17:40 drochner Exp $ + * From $NetBSD: stand.h,v 1.22 1997/06/26 19:17:40 drochner Exp $ */ /*- @@ -131,7 +131,7 @@ #define SEEK_CUR 1 /* set file offset to current plus offset */ #define SEEK_END 2 /* set file offset to EOF plus offset */ -/* +/* * Device switch */ struct devsw { @@ -166,8 +166,9 @@ #define DEVT_NONE 0 #define DEVT_DISK 1 #define DEVT_NET 2 -#define DEVT_CD 3 +#define DEVT_CD 3 #define DEVT_ZFS 4 +#define DEVT_EFI 5 int d_unit; void *d_opendata; }; @@ -279,7 +280,7 @@ extern void srandom(u_long seed); extern u_long random(void); - + /* imports from stdlib, locally modified */ extern long strtol(const char *, char **, int); extern unsigned long strtoul(const char *, char **, int); @@ -368,9 +369,9 @@ extern int null_readdir(struct open_file *f, struct dirent *d); -/* - * Machine dependent functions and data, must be provided or stubbed by - * the consumer +/* + * Machine dependent functions and data, must be provided or stubbed by + * the consumer */ extern int getchar(void); extern int ischar(void); Index: sys/boot/efi/Makefile =================================================================== --- sys/boot/efi/Makefile +++ sys/boot/efi/Makefile @@ -15,7 +15,7 @@ .if ${MACHINE_CPUARCH} == "aarch64" || \ ${MACHINE_CPUARCH} == "amd64" || \ ${MACHINE_CPUARCH} == "arm" -SUBDIR+= libefi loader boot1 +SUBDIR+= libefi drivers loader boot1 .endif .endif # ${COMPILER_TYPE} != "gcc" || ${COMPILER_VERSION} >= 40500 Index: sys/boot/efi/boot1/Makefile =================================================================== --- sys/boot/efi/boot1/Makefile +++ sys/boot/efi/boot1/Makefile @@ -8,34 +8,50 @@ 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 CWARNFLAGS.skein.c += -Wno-missing-variable-declarations .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 +# 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} +CFLAGS+= -I${.CURDIR}/../drivers/ CFLAGS+= -I${.CURDIR}/../../../contrib/dev/acpica/include CFLAGS+= -I${.CURDIR}/../../.. CFLAGS+= -DEFI_UFS_BOOT @@ -56,6 +72,20 @@ .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 + +.PATH: ${.CURDIR}/../drivers +LIBEFI_DRIVERS= ${.OBJDIR}/../drivers/libefi_drivers.a + + FILES= boot1.efi boot1.efifat FILESMODE_boot1.efi= ${BINMODE} @@ -75,8 +105,8 @@ # __aeabi_* (arm) or __divdi3 (i386). # as well as required string and memory functions for all platforms. # -DPADD+= ${LIBSTAND} -LDADD+= -lstand +DPADD+= ${LIBEFI_DRIVERS} ${LIBEFI} ${LIBSTAND} +LDADD+= ${LIBEFI_DRIVERS} ${LIBEFI} ${LIBSTAND} DPADD+= ${LDSCRIPT} @@ -102,7 +132,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 @@ -111,7 +141,7 @@ # created by generate-fat.sh .include "${.CURDIR}/Makefile.fat" -BOOT1_MAXSIZE?= 131072 +BOOT1_MAXSIZE?= 524288 boot1.efifat: boot1.efi @set -- `ls -l boot1.efi`; \ Index: sys/boot/efi/boot1/Makefile.fat =================================================================== --- sys/boot/efi/boot1/Makefile.fat +++ sys/boot/efi/boot1/Makefile.fat @@ -1,4 +1,4 @@ # This file autogenerated by generate-fat.sh - DO NOT EDIT # $FreeBSD$ BOOT1_OFFSET=0x2d -BOOT1_MAXSIZE=131072 +BOOT1_MAXSIZE=524288 Index: sys/boot/efi/boot1/boot1.c =================================================================== --- sys/boot/efi/boot1/boot1.c +++ sys/boot/efi/boot1/boot1.c @@ -26,62 +26,118 @@ #include #include #include +#include #include +#include +#include #include +#ifdef EFI_ZFS_BOOT +#include +#endif + +#include -#include "boot_module.h" +#include "efi_drivers.h" #include "paths.h" -static const boot_module_t *boot_modules[] = -{ -#ifdef EFI_ZFS_BOOT - &zfs_module, -#endif -#ifdef EFI_UFS_BOOT - &ufs_module +#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[] = { + &fs_driver, + NULL }; -#define NUM_BOOT_MODULES nitems(boot_modules) -/* The initial number of handles used to query EFI for partitions. */ -#define NUM_HANDLES_INIT 24 +extern struct console efi_console; +#if defined(__amd64__) || defined(__i386__) +extern struct console comconsole; +extern struct console nullconsole; +#endif -void putchar(int c); -EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab); +struct fs_ops *file_system[] = { + &dosfs_fsops, + &ufs_fsops, + &cd9660_fsops, + &nfs_fsops, + &gzipfs_fsops, + &bzipfs_fsops, + NULL +}; -EFI_SYSTEM_TABLE *systab; -EFI_BOOT_SERVICES *bs; -static EFI_HANDLE *image; +struct devsw *devsw[] = { + &efipart_dev, +#ifdef EFI_ZFS_BOOT + &zfs_dev, +#endif + 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 console *consoles[] = { + &efi_console, + NULL +}; -/* - * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures - * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from - * EFI methods. +/* Definitions we don't actually need for boot, but we need to define + * to make the linker happy. */ -void * -Malloc(size_t len, const char *file __unused, int line __unused) +struct file_format *file_formats[] = { NULL }; + +struct netif_driver *netif_drivers[] = { NULL }; + +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 int efi_getdev(void **vdev __unused, const char *devspec __unused, + const char **path __unused) +{ + printf("******** Boot block should not call getdev\n"); + return (-1); +} - return (NULL); +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); } -void -Free(void *buf, const char *file __unused, int line __unused) +static ssize_t +efi_copyout(vm_offset_t src __unused, void *dest __unused, + const size_t len __unused) { - if (buf != NULL) - (void)bs->FreePool(buf); + 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 DevicePathGUID = DEVICE_PATH_PROTOCOL; +static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; +static EFI_GUID SimpleFileSystemProtocolGUID = SIMPLE_FILE_SYSTEM_PROTOCOL; +static EFI_GUID FileInfoGUID = EFI_FILE_INFO_ID;; + /* * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match, * FALSE otherwise. @@ -142,6 +198,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. @@ -273,7 +330,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; @@ -304,48 +361,207 @@ * 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 + +static EFI_STATUS +efi_load(EFI_HANDLE dev, const char *filepath, void **bufp, size_t *bufsize) +{ + UINTN infosize = sizeof(EFI_FILE_INFO) + + ((strlen(filepath) + 1) * sizeof(CHAR16)); + EFI_FILE_INFO *finfo; + EFI_STATUS status; + EFI_FILE_IO_INTERFACE *iface; + EFI_FILE_HANDLE root; + EFI_FILE_HANDLE target; + CHAR16 path16[strlen(filepath) + 1]; + void *buf; + + finfo = malloc(infosize); + + if (finfo == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + status = BS->OpenProtocol(dev, &SimpleFileSystemProtocolGUID, + (void **)&iface, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (status != EFI_SUCCESS) { + free(finfo); + printf("Open protocol failed! %ld\n", EFI_ERROR_CODE(status)); + return (status); + } + + status = iface->OpenVolume(iface, &root); + + if (status != EFI_SUCCESS) { + BS->CloseProtocol(dev, &SimpleFileSystemProtocolGUID, IH, NULL); + free(finfo); + printf("Open volume failed! %ld\n", EFI_ERROR_CODE(status)); + return (status); + } + + strcpy_to_16(path16, filepath); + status = root->Open(root, &target, path16, EFI_FILE_MODE_READ, 0); + + if (status != EFI_SUCCESS) { + BS->CloseProtocol(dev, &SimpleFileSystemProtocolGUID, IH, NULL); + free(finfo); + + return (status); + } + + *bufsize = infosize; + status = target->GetInfo(target, &FileInfoGUID, bufsize, finfo); + + if (status != EFI_SUCCESS) { + BS->CloseProtocol(dev, &SimpleFileSystemProtocolGUID, IH, NULL); + free(finfo); + printf("Get info failed! %ld\n", EFI_ERROR_CODE(status)); + return (status); + } + + *bufsize = finfo->FileSize; + + if ((buf = malloc(finfo->FileSize)) == NULL) { + BS->CloseProtocol(dev, &SimpleFileSystemProtocolGUID, IH, NULL); + free(finfo); + printf("Failed to allocate load buffer %zd for '%s' " + "(%lu)\n", finfo->FileSize, filepath, EFI_ERROR_CODE(status)); + return (EFI_OUT_OF_RESOURCES); + } + + *bufp = buf; + status = target->Read(target, bufsize, buf); + BS->CloseProtocol(dev, &SimpleFileSystemProtocolGUID, IH, NULL); + free(finfo); + + if (status != EFI_SUCCESS) { + printf("Read failed! %ld\n", EFI_ERROR_CODE(status)); + return (status); + } + + return (EFI_SUCCESS); } /* * 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. + * This tries all handles which support the EFI_SIMPLE_FILE_SYSTEM interface. + * It is expected that the drivers will have installed this interface on every + * handle representing a device containing a supported file system. + * + * Note: In the future, this may be altered to use the EFI_LOAD_FILE interface, + * which should work transparently with network booting. * * 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) +load_loader(EFI_HANDLE *handlep, 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); - } + EFI_DEVICE_PATH *imgpath; + EFI_DEVICE_PATH *devpath; + EFI_LOADED_IMAGE *boot_image; + EFI_HANDLE *boot_handle; + EFI_HANDLE *preferred; + EFI_HANDLE *handles; + EFI_STATUS status; + UINTN i, hsize, nhandles, npreferred; + + 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)); + } + + boot_handle = boot_image->DeviceHandle; + + if ((status = BS->OpenProtocol(boot_handle, &DevicePathGUID, + (void **)&imgpath, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL))) { + panic("Failed to get image DevicePath (%lu)\n", + EFI_ERROR_CODE(status)); + } + DPRINTF("boot1 imagepath: %s\n", devpath_str(imgpath)); + + /* Allocate space for the handles */ + hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE); + if ((handles = malloc(hsize)) == NULL) + panic("Failed to allocate %d handles (%lu)", NUM_HANDLES_INIT, + EFI_ERROR_CODE(status)); + + status = BS->LocateHandle(ByProtocol, &SimpleFileSystemProtocolGUID, NULL, + &hsize, handles); + + switch (status) { + case EFI_SUCCESS: + break; + case EFI_BUFFER_TOO_SMALL: + (void)BS->FreePool(handles); + if ((handles = malloc(hsize)) == NULL) { + panic("Failed to allocate %zu handles (%lu)", hsize / + sizeof(*handles), EFI_ERROR_CODE(status)); } + status = BS->LocateHandle(ByProtocol, + &SimpleFileSystemProtocolGUID, 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)); } + if ((preferred = malloc(hsize)) == NULL) + panic("Failed to allocate %d handles (%lu)", NUM_HANDLES_INIT, + EFI_ERROR_CODE(status)); + + npreferred = 0; + nhandles = hsize / sizeof(*handles); + + /* Figure out which handles are preferred */ + for (i = 0; i < nhandles; i++) { + if (BS->OpenProtocol(handles[i], &DevicePathGUID, + (void **)&devpath, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL) == + EFI_SUCCESS) { + if (device_paths_match(imgpath, devpath)) { + preferred[npreferred] = handles[i]; + npreferred++; + } + BS->CloseProtocol(handles[i], &DevicePathGUID, IH, NULL); + } + } + + BS->CloseProtocol(boot_handle, &DevicePathGUID, IH, NULL); + + /* Try the preferred handles first, then all the handles */ + for (i = 0; i < npreferred; i++) { + if (efi_load(preferred[i], PATH_LOADER_EFI, bufp, bufsize) == + EFI_SUCCESS) { + *handlep = preferred[i]; + return (EFI_SUCCESS); + } + } + + for (i = 0; i < nhandles; i++) { + if (efi_load(handles[i], PATH_LOADER_EFI, bufp, bufsize) == + EFI_SUCCESS) { + *handlep = handles[i]; + return (EFI_SUCCESS); + } + } + + printf("Failed to load %s from any device!\n", PATH_LOADER_EFI); + return (EFI_NOT_FOUND); } @@ -359,20 +575,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); - status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE); - if (status != EFI_SUCCESS) { - status = load_loader(&mod, &dev, &loaderbuf, &loadersize, - FALSE); + 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)); } /* @@ -387,9 +610,9 @@ */ cmd = NULL; cmdsize = 0; - status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize); + status = efi_load(fshandle, PATH_DOTCONFIG, &buf, &bufsize); if (status == EFI_NOT_FOUND) - status = mod->load(PATH_CONFIG, dev, &buf, &bufsize); + status = efi_load(fshandle, PATH_CONFIG, &buf, &bufsize); if (status == EFI_SUCCESS) { cmdsize = bufsize + 1; cmd = malloc(cmdsize); @@ -401,24 +624,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; @@ -434,10 +658,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; } @@ -453,134 +677,19 @@ 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) -{ - dev_info_t *devinfo; - EFI_BLOCK_IO *blkio; - EFI_DEVICE_PATH *devpath; - EFI_STATUS status; - UINTN i; - - /* 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); - } - - 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); - - /* 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); - } - - 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; - - 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) +main(int argc __unused, CHAR16 *argv[] __unused) { - 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); + UINTN i, max_dim, best_mode, cols, rows; + + cons_probe(); + /* * 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 +706,31 @@ 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'); - - /* 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)); - - 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)); - } + /* + * Initialise 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>> FreeBSD EFI boot block\n"); - /* 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)); - } + 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; - for (i = 0; i < nhandles; i++) - probe_handle_status(handles[i], imgpath); - printf(" done\n"); + printf(" Loader path: %s\n\n", PATH_LOADER_EFI); + printf(" Initializing modules:"); - /* 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(); } + 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,117 +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)(); - - /* - * 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)(); - - /* valid devices as found by probe. */ - dev_info_t *(*devices)(); -} 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 void panic(const char *fmt, ...) __dead2; -extern int printf(const char *fmt, ...); -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/fat-amd64.tmpl.bz2.uu =================================================================== --- sys/boot/efi/boot1/fat-amd64.tmpl.bz2.uu +++ sys/boot/efi/boot1/fat-amd64.tmpl.bz2.uu @@ -2,25 +2,50 @@ DO NOT EDIT $FreeBSD$ begin 644 fat-amd64.tmpl.bz2 -M0EIH.3%!62936?$)3$,`&U9_____Z^KJZ_^N_^O^Z_^[ON_NK^JJ^KZNKNNJ -MZNKNZOJ^P`+\#$!0$#1D-,@#)DT#1B&AIDQ,AD:#1HTR`-#)D80Q!D:,)D`` -M#1@F30```&@`$JJ9!_HU4:",3!,F0&C(83`F30T`T!B&!,F`(P3`"#0,@`/2 -M::`#0!D`,C1`T9#3(`R9-`T8AH:9,3(9&@T:-,@#0R9&$,09&C"9```T8)DT -M```!H``JBD@_2B:FF9)IHQ/1#:@-`:`R#(T`&@:-`!H8FAH:::'J::-`9&1Z -MFF!'HAB8U/1/*8---3EV+*PZ5:L^\19>>T2K3OA>TUS8M>VJ_;9P7"8;&7&8R51N>F -M1E%A#6+F9*H@$(9J%%%%%%%$>!!!!!!!!! -M!!!!!!!#76C@OM;-N%^W[!<=H[<-1 -MRR"SVLL>LG*Z1G+K%N;);>IIYL-7L*D[Q-SH;5D;RU_+ZK.+TEMX%K(QQ813V:GS1ZT;"R\!H$K/Z:=%386M -MPJL..`X;BN0SS2,I;U*I;;.]O5ZMI9CMV -MY(;8*\CXX-SPW(^Z5WIWPW0V@?7DLGZ@QJQHC6!J-\U[>@T$2F)3"7UM2V+: -M+YMFW;MO6^<-@L)R7+XU0JB(L,KI:F[OD%ZUC=-0WB\7C? -M."P'%83CL1BM$RLHD):&7,DOSLY1=2Y,H_EOG`<%YS0,!Q&$XS]')8CXEXP_ -MFX2-7*,#%P;!Q]V)E#BO"83#?\V3C..Y#E,1?L5S&,NC%DQI>;+`DS>NQL5? -?+6IF915V$0"$)@`M+"Q)@(_9+!?^+N2*<*$AXA*8A@`` +M0EIH.3%!629363$"%&\`'YA______________^O^Z_^[_N[^J^NK^KZOKONJ +MZNK^ZN[^X`C_%-``HH`%41"1(*)`BJ!H:```?M5```#0````````-`:-#0`` +M`````````````555$_2@!O_U2J/_TJA_JJ>4!H````T``````&@`````:``` +M!H``>H`&@!HR`0,F3(!DR``TP0T`:``#0Q#30#(``-`-`R&@&@!D!H&FC$&C +M0``&@`#0@9,F0#)D`!I@AH`T``&AB&F@&0``:`:!D-`-`#(#0--&(-&@``-` +M`&A`R9,@&3(`#3!#0!H``-#$--`,@``T`T#(:`:`&0&@::,0:-```:``-`55 +M(_23]"13-3TIZJ?[*D:$_]5-3TVBFU-J;1&3)A'H0\F2/4Q&GJ!ZF`3U#U'E +M/031B8U#$9'J!ZAM(\*#R#0,4S4_5,U/0VJ>$\B*9O7.9HQ&K@F!RV88885S +M,&#####&POFPP!@?ILGJGM'9/CNX=\\1]7S2JJJJJJJ7IE7 +M7(9UEEEEEDI2E*4I2LJLAG6666662E*4I2E*RJR&=999999?K++++++++)9* +MLD,ZRRRRRS*JJJJJJJJ5U5W@=3BHR9,F3)DY555555554M*K2AG6666662E* +M4I2E*RJR&=999999*RJR&=999999M]ST6EDR8Z75L[4S8=BSC1D=PZ]J#RWA +M*>XSS+OI9+,OP:!G,`[#(RG-'!93*8`$4]KF#`!H][S_R?Y_E]3FG`P`>;;6UBVMK0VMK:VMK:VMK:VMK +M:VMK:VMK:Z^ZZZZZZZZZZZZZZZZZZZZZZZ[+MSB;FU1#B/J/_7C^C55555552ZG]E9V3I_)YDL6IJ:FIJ:DI2E*4I2TJM+G^S^# +MFT,6EI:6EI:4I2E*4I2TJM+^;^[%1DR9,F3)*4I2E*4LE62&=999999*4I2E +M*4K*K(9UEEEEEDI2E*4I2LJL^[1"ZZZZZZ4I2E*4I7570SK+++++/R*KK+H9 +MUUUUUUUE55G3M,9UIK<&G/7:>^5EGWHT*,&#!$1$1$<#@<#@=(_=',TM+2TO\J***,:***(0A"$(0O1C,9C,3$Q,3,,'G/3> +MP]YDOJ9]^;^6Z(B(B(B(B(B(Y=WCP6;9%EEEEEEEEEEEEEEEFEQ$1$:0B(B( +MB(LLLXG%111WF+U'JX['EU555=UW6+%BQ<_U&K0T-#0M1111^K^EBQ8L7*Z' +MJNBLU,.M?M.S=NIP]AGYSL.W_;U+ZLF3)DA"$.D]GIK*4I0A"'*HHH +MHA"$(0A#_-W+NW>N^>`^L^RYKQ7CORG#PN%PN%PL&#!@P8,&#!@P>,\UY3/* +M4I2E*4I2E*4I2(B(B(B(B(B*4IL=_XF+%BQ0A"$(0A"$(0A"'F>UQ8L6+O>X +M=L_D=VA"$(0A#]BBBBB$(0A"$(0A#F^%\(9\,,-#0T-"$(0^$^>Z5TKZSPV? +M?D_1H&B?XB(B(B(B(B(CC6=?"R5*4I2E*4I2E*;/99@P8,&#!@X7"X7"X7"X +M7`X'$XG$XD(0A"$(0A"'6T444>51111"$(?]._?2?30A"'K****/-!1111"$ +M(;J***/O44440A"$(0A]=X3JWV'-?;>,[I]YSGQ'H'B]MK:VMK:VMK:VMK:V +MMK:VMK>"\-]ET[8V-C8V-C8V-C8V-C8V*4B(B(B(B(B(BE*4Q,3$A\&BBBB$ +M(0A"$/^_(_3T-#0T(0A#[G?O$>Q0\EY;@<#@1$1$1$1$1F6A=*T2E*4I2E*4I2E*4B(B(B(B +M(B(BFQL;'@T4440A"'E4444>BHHHH\.BBBB$(0ZCKO*YSG.+%B +MQ=;11113L;YQY+#P?@66666KA@888#-AA@`>5H:&AH:****(?:4440>6S/_G ++WQ=R13A0D#$"%&\` ` end Index: sys/boot/efi/boot1/fat-arm.tmpl.bz2.uu =================================================================== --- sys/boot/efi/boot1/fat-arm.tmpl.bz2.uu +++ sys/boot/efi/boot1/fat-arm.tmpl.bz2.uu @@ -2,25 +2,50 @@ DO NOT EDIT $FreeBSD$ begin 644 fat-arm.tmpl.bz2 -M0EIH.3%!62936>#67)H`&U9_____Z^KJZ_ZN_^O^J_^[OJ[NK^JJ^KZNKNNJ -MZNKNZOJ^P`+\```"``:`T::-`:8@P@&1D-!H:808)B:#0`T``,$T#!,@PC09 -M#33"9,0`T(`!H#1IHT!IB#"`9&0T&AIA!@F)H-`#0``P30,$R#"-!D--,)DQ -M`#0@`&@-&FC0&F(,(!D9#0:&F$&"8F@T`-``#!-`P3(,(T&0TTPF3$`-`522 -M$_(H2-DT0T:8C(T!H!ZC30R-&@-`,@&C1H:`:#1M3(T,@:::/1#331FII@)@ -M)Z:)RK5N6<7,O<%[)S4ZD(ODD1"*2"(B(+E99)"P2A$"$.#(((0Z^BHO)97* -MKNTS2;//!6_,:)5IVI>LPGUM8_)MV&_QO'$Y;`J/TETR.=50:\2B`0AF9 -M<_.ME;:;0N<9%D%\Q['*&6B4*U:JM6K5JUQ12I)1111116K45I*TJU:M6K<: -MZ424444448Y-1)111111[F<_6R+%BQ8L6+$X3333333333333333=7Z\E2M6 -MK5JU:M--------->R44444447N#[%BQ8L6+%BQ-M)*******,!0HHHHHHHY[ -M-RR5757;.MS?HE)GL[:M-Q)&/TG09Q6MZ%)XJ4>^]M6W8C@..T= -MV&HOX\@T$`%JWHY$`-/ZV!A?)K>YEEZ1`#*,&#,]G484F/7/RDR%Y4Q?U[J:^S$]EPK -MD81)^D"%H^>2OU:FLC31KK??,_$ES74S%+)U7JU5D:VQD)R-2U3"7[FWW -M-DPVV;ANV^9-R&"T;G,A>6EJ3:=EVE6ENKC#PZG.]=9:75*G=>-4N\OA]'=- -M`L[RN\MM/>Z'8:6Q.RAWU+=HOHDCZ6H?8_!^+:-JVS^6Z;UP'#>T*HB+3GM+4VVS(NQ)&K?`_9IW\,PS#$;QOG"<-QV*QFB8^2)!)H). -M7(_@P9(R$G)DCMYF,_-.ITH]0;4 +M`#0-&@VIZFFF:FC0:>IHVH>H!IHWHIH>2::#U/4]3#4]&3:FD[$4T=T[;+$: +MN:8'3:!AAA70P8,,,,,;"^A@#`N-'Q-`PPPP'K:M)GVO:LZ/HDN[1WS1^6_` +M:?U'@N_>Z>(\)[YX[_!_T\EYCYC5@>EXZ7BZ.V8;VEA@PPP'IM'5[.SK*.LZ +MRKK.L[UP<'!P<'!P<'!P<'!P<'!U'9MCN7.VGI<-#>T-[>EO;U6].]O;V]O; +MV]O;V]O;V]O;W,VNC:AM;5&UM;6UM;6UM;6UM;6UM;6UM;6UO;&]SM[M*-[0 +MHT;'3:W*U/-R5:%555557!J5:FA?#0NNNNNN]K]=XU\+KKKKKKIXS>M??OTGN7]#X#RWP_2*J +MJJJJJI>L5=ZAI6666662E*4I2E*RJS5R#PV';_R52Y7*Y7*Y7*E*4I2E*7*J +MY4-*RRRRRSFJJJJJJJJE=5=WE$+KKKKKLZJJJJJJJI9JLWP:(777777=UTK+ +M++++++)X]59]#/KOP:)G,`]MV>'L#N\,,`"*?E:`P +M`>T]KU?=^%[SNM$X&`#M'S;[=Q6<7%Q<7%Q<7%Q<7%Q<7%Q<7%Q<70[YL?-- +MS5555 +M55552S59H:5EEEEEDI2E*4I2LJLAI666666>[JJJJJJJJE=5=Z9RUT/G>TJE +MJ:FI5J:DM2K4AI6666662]@]H_??S/?OA/BO/^H55555552[K\A9W[U/R^WE +MBU-34U-34E*4I2E*7(JY'5]QBHS9LV;-FE*4I2E*6:K-#2LLLLLLE*4I2E*5 +ME5D-*RRRRRR4I2E*4I6560TK+++++)2E*4I2E959\FB%UUUUUTI2E*4I2NJN +MAI666666?3U7670TKKKKKKK,LRS+NK:QL;&QL;&QL;&QL;&QL;& +MQO;V]OWY'(Y'(_LHHHHA"$(0A"$(0O1111"$ +M(=DUOZGO77?Y/@O^7E/C/.?4N9S.9$1$1$1$1'-N^>(\EJM[++++++++++++ +M+++,O$1$1IB(B(B(CH=#H=#HHHH\7%]5];'LNG5555U^OBQ8L75]5JR9,F2V +M>+%BQ?@^OQ8L6+E[7[/YRS[AX3]5XC7^+S=.4I2\#G_&\3V6I?5FS9LT(0A] +M]G.3)DR0A"&VBBBB$(0A"$/>O?/%>,_T?ZO]WE/_7F//>N:];6UM;!@P8,&# +M!@P8,&#RG7/-9Y2E*4I2E*4I2E*1$1$1$1$1$12G.YWD>7BQ8L4(0A"$(0A" +M$(0AV3#J^!DR9,F3X'];W3P7C(0A"$(0A"$/PJ***(0A"$(0Y^CVXTX889,F +M3)"$(>W>.S;-OG?4^UH7Y-$T;_$1$1$1$1$1$<>]YGV@4I2E*4I2E*4IDS3- +M,&#!@UM;6UM;6UM;6UN9S-C8V-B$(0A"$(0A#[:BBBCT:***(0A#_-X[X3X: +M$(0]=1111"$(>D"BBBC?\C%BQ8O.HHHHA"$(0A#R7_;[5_X^*^.\U[%YSY3W +M#U+_[W/2=)TG2=)BQ8L6+%BQ8L6+['W-"VQ2E*4I2E*4I2E*1$1$1$1$1$12 +ME.="$(>VHHHHA"$.%%%%'E]CU^3)DR0A"'7\A\1WKXR$(0A"$(0A"E%%%$(0 +MA"$(0A"$(0AUWF/Z7FOD/DO/?*>.[#Y;_D1$1$1$1$1$7:-T[^E*4I2E*4I2 +ME*4I$1$1$1$1',YG,YW.YW.\FBBBB$(0]&BBBCK4444>51111"$(>J^[]'T' +MH/0>@A"$/[GI\6+%B[RBBBBGL<6+%BICA@888#1AA@`>CDR9,F5%%%$/CJ** +1(/F-#S7_XNY(IPH2!C]4XX`` ` end Index: sys/boot/efi/boot1/fat-arm64.tmpl.bz2.uu =================================================================== --- sys/boot/efi/boot1/fat-arm64.tmpl.bz2.uu +++ sys/boot/efi/boot1/fat-arm64.tmpl.bz2.uu @@ -2,25 +2,49 @@ DO NOT EDIT $FreeBSD$ begin 644 fat-arm64.tmpl.bz2 -M0EIH.3%!629364C65#T`&U;_____Z^KJZ_^N_^O^J_^[OJ[NK^JJ^KZNKNNJ -MZNKNZOJ^P`+\#0``0`#0#)D&@TR8AD`,0!D--&`@:!H&@`!B#)IHR:--#(9, -MAA`8F@Q,0,#52`_U4?J@`&AH```:`:``````T-`T&@R&@T``````````$``T -M`R9!H-,F(9`#$`9#31@(&@:!H``8@R::,FC30R&3(80&)H,3$#`521(]I1I) -MF*:8C1Z`F0:`TR,@:&C30:`R!HTT,$!DTT-J:&@R&C)IA,:F33(S4]-3`--$ -MZ--B6=6F1M!<28FJA"+E)$0B<@B(B"TK+:2%L)0B!"'(D$$(9F:@LRO+Q;TL -MNJ9YY2QZK1*-0US5+UM6R;E?-T_QQG*=-<9#J:#>R[!&-40;(2B`0AE9=956 -MO+"IH&,8M=KEBF(3,A$H5JU%:M6K5K1-.A)------6K35I*TJU:M6K[LK*RLK*RLK*INY)IIIIIIL6F3333 -M333=7VLL91VEN[UP[M$I,5X--+@R1:XKTL?G%LL>,D\Y*-*DU+6MB^YMF\7S -MB,!S6CMPUEU'H'B0`4V-'(@!JKN]^?Z<]*UB`&/9J#*9N@O9.H6FYDN5AT,L -MS-UAW-A;:O3J61R=".=)EY-(TK3M8US8NM;1N&\<%Q%^Y3"9%=8Z-AUMYA;W -MPYKK)5;?@6D;$DWL"J0LE*.Q]RA>Q[,;.QH%VDM/KGE)[.JBX4T=56_.0JD: -MUL&Q73$OR;=NF^?PXKCL%SF=:1FKO&W%A1)O,YWU&FM;1N]W0QW=6U*UDS]Q -M0M\CN\G:L^KT%O2U%G0;335JJYFAG8I,5$D?:UC\'Z/U;QO7`<)_3CL!R7/= -M%B=L<+`H+J1;6??%$1%*H8[34M_N$+V0O6O;YJ7!95E7%<9?L%R7-83#:)BY -M(D$F?DZ4B^,W)%W)SY(X;B/[<9?L\P'_-*YCPGRLLY=[?HU\D?[A\BDOL -MP)20P6A]5```````````````````` +M``````````*JJDT`&G_^J2I_^I4_RJGJ``!H``-````````&@-`````````& +M@#0`&AH!`:!H!H`:#30R`&FA@F@T-!IB!H#(#3$``9```:`#",`@`,@:```` +M0&@:`:`&@TT,@!IH8)H-#0:8@:`R`TQ``&0``&@`PC`(`#(&@```$!H&@&@! +MH--#(`::&":#0T&F(&@,@-,0`!D``!H`,(P"``R!H````*JD?I'H1*;293/% +M*FVJ;?JJ?JFGM2&F0VB`/4'J`>2&@R:#0#1H-'H3)IY0'J'I`T:&@TTT_1(T +MVIFH'I-I/334]&3)E/-BFK[5U\L1LVS`Z+4,,,*ZF#!AAAAC87U88`P+CQM8 +MPPPP';U:S/K=9G1]*EW*/6M7YKUS7^J[U[-W[^I_$]^\)V'B/BO(>>V8':L. +MF[3K4>#JPPP888`5#1,2SH&`V!@,!X#`8(,$"!`@0($"!`@0($"=FZ;LW.[A +MS-QZ'#4X-3@X)<'!5P3P<'!P<'!P<'!P<'!P<'!R-SLMR&YN4;FYN;FYN;FY +MN;FYN;FYN;FYN;G!SN#F<':4<&I1JYW1;70;'DY*M2JJJJJKLVQ5L:E\-2ZZ +MZZZ[]?[#X%\+KKKKKKI:*M$8:UEEEEEDI2E*4I2LJLZ_L]3%1FS9LV;-*4I2 +ME*4LU6:&M999999R\GU'MLPP];FS9LV;-FS2V*MB&M99 +M9999*RJR&M999999U/8=KHS9L='=,NS#1,MG'.,NCMG7,CR7@*>V]-F7T,\N +M^]H'/8!V'4P_+.YPPP`(I^9J#`![;J>Y_A_D^TU98&`#T+M'WM[>WM[>WM[>WM[>WM[*93*7777 +M777777777777777777=-TW9-[G;V]1#G=%M=!HS2E*4I2E*ZJZ&M999999.$ +MI2E*4I656>DHA======ZJJJJJJJJJ6:K-#6LLLLLLE*4I2E*5E5D-:RRRRRS +MW-55555554KJKNLZ%=3T2631HT2T:):*M$-:RRRRRR7Y3VCOG\[L/]WR'E^I +M55555552[C\A9W;TOS>O+%L;&QL;&Q*4I2E*4M%6CJ=YVV3%KT:-&C1H]3AA +M99555555+8JV+^C^BR8M&C1HT:)2E*4I2EHJT0UK+++++)2E*4I2E959#6LL +MLLLLE*4I2E*5E5GRZ(7777772E*4I2E*ZJZ&M999999LJNLNAK7777776556 +M>R7?OLW;-'OVQX;H/CN1Y;D;6UM4^LNZN+%BQ=#K?;^BL[IW[NWN +MW)Z_ER9,F3N^CZ_W?L=%],V;-FA"$/P,YR9,F2$(0Z=%%%$(0A"$(?WO?/`> +M"_U>&_Z>*\9Y#RWV3;M;6#!@P8,&#!@P8,&#!XSJGD/54I2E*4I2E*4I2D1$ +M1$1$1$1$%_[BQ8L4(0A"$(0A"$(0A\Y[3%BQ8O@>\=\[QX"$(0A"$ +M/>T444?XT4440A"$(0AS=EWHUX889,F3)"$(=Z^$Z[8GS,^^U^+\V@:%_B(B +M(B(B(B(B.-9E\#/*4I2E*4I2E*4V;%BP8,&#:VMK:VMK:VMK:Y'(YW.YW.A" +M$(0A"$(0^ZHHHH\ZBBBB$(0_T?"?#>&A"$/L:***(0A#JA1111PHHHH\JBBB +MCQZ***(0A#_M\5]P^,\9\EY+L/*?,?N/3/([[E+YOX.3)DR0 +MA"'RO"=5]Z^0A"$(0A"$(0I1111"$(0A"$(0A"$(?)>0\%Y+Y3Y;RWS'A/-? +M->>B(B(B(B(B(B[0ND?TI2E*4I2E*4I2E(B(B(B(B(CD(;UG$,HJ0@""#-QRL -MK%;U%@U#)LDM5=:+-(N(1@I4IJ5*E2I54DID4DDDDDE*E)2BI1I4J5*EU;!) -M%))))))CE"2*222222VAMLQPP,#`P,#`P(X"!`@0($"!`@0($"!"A0[?7Q3* -M5*E2I4J5"A0H4*%"A04*%"A0H4+.ST&QK*RLK*RLK*RA>Q22222226J1)))) -M)))E.[CDIL[6:1_==<1)HM-I)YW&BA1::S+:)65-0B]%&'M(M0NH;>IIW;(JNVEFI;>C')YXV5+]XBB)\ -M[ZEVKL@W3>-^_IQW*(%VV;@O/<5F69*8X9GXH9&+#BAR'^.4Y;FM,Y[HL!@OY8;$?8S;J7G.0^F*'/Q;^A`$$ -7$8`%A.GB7Z'$1=)_XNY(IPH2`GA(C"`` +M0EIH.3%!62936=SO#C@`'YC______________^O^J_^[OJ[^J^NK^KZOKONJ +MZNK^ZN[^X`C_*``&B@`4"0D2(B0&I*````````#0```````#(-``R``````` +M```````"JJE'ZH`:?_ZDJG_ZJ>JG_JJ````````````````#0``T```````# +M0:&AZ@$!H&@&@!H--#(`::&":#0T&F(&@,@-,0`!D``!H`,(P"``R!H```!` +M:!H!H`:#30R`&FA@F@T-!IB!H#(#3$``9```:`#",`@`,@:````0&@:`:`&@ +MTT,@!IH8)H-#0:8@:`R`TQ``&0``&@`PC`(`#(&@````JJ1^E'Z:22>E-/U3 +MU*?_I2GM2)_ZJF3TVJ>H>IH:,C0,T@:;4'J&@:#U--`:`9`>H!ZC30:`>H`> +MU3U&3TCU--&AZ3T33#4]J:3M1;5],[S;L'-SS`ZK4,LLKZF3)EEEELH8U99` +MR/+U#+++(9CZ.Z#/T/H6=GI$O6OLUGWK[5KIA8"H%V,<7HTANC4'..@>0_@A +MKX(FK!2V=#7*(0A"$(`%PKSW6IUUG7==AUW7>"Z72Z72Z72Z72Z72Z72Z72Z +M7K=N^0//Y:G%J<7%+BXKN*>+BXN+BXN+BXN+BXN+BXM[O]'1HLT:+-& +MC1HT:-&C1HT:-&C1HT:-'6<'6=NXN5G%J6:N#JN=U',^%M7:EUUUUUW=.9=S +M-3#4PPPPPP_-]37^&K+######"6Y=N1EK4I2E*2E*4I2E*EU.Q^3J;%F;-FS +M9LTI2E*4I2S79H:U*4I2G;;_3^TS9LV;-FS9IY>^?Z]TNNNNNNNEZA=X*&M2E*4I*4I2E*4 +MJ74AK4I2E*2E*4I2E*EU(:U*4I2F/JZ4I2E*4EFNS0UJ4I2E,[KKKKKKKI87 +M8>3S>KVMCM:W,U9>R>P:"CMW8,'DLXI[;TV+Z7QKOP9]SE@S>HY7-G +M"965E`$6]AJ#(!^7UO;>U_<[_5MR,@'H'R+ZIR4Y.3DY.3DY.3DY.3DY.3DY +M.3DY.X>N<'=-&C8T:-K1HT:-&C1HT:-&C1HT:-&CN7O]M2E*4I2DLUV;T3??4[ +MNTMK[>_>9Z5=======+O_"4_&?,?&[ +M$MCFF960PPPPPPNNPIA#6PPPG###"E-(=.TEWK2FVLT]9FGRM+9U'\HLLL +MB(B(C>WM[>WNP]DZKNWT'7>)T.AT.AT.AT.AT.AT.AT.AT.AZ#L=KQ_6<'!P +M<'!P<'!P<'!P<'!P<'6=9UG6=3O=.UJE*4H]J:EEEG^60K4.N=,I2E"$(0A" +M'T7X>QL;&QWV7L*_H>,]P_S?[O*?`?%>H;V]O;V]$1$1$1$\ +M>4\M\%YCU3GYW.YW.YW.LLLLLLLLLL\5YCR'J*4I2E*4I2E*4I2(B(B(B(B( +MB*4I3R/?;&QL;$(0A"$(0A"$(0AY[VFQL;&QX_BO$>&[*$(0A"$*LLLLA"$( +M0A"$(0\OWOZ`UY99;6UM;4(0A[%[IWCO'O'_#RGY,\S[,?XB(B(B(B(B(CC6 +M;?"^12E*4I2E*4I2FS9;+66666666<[G<[G<[G;V]P<'!P0A"$(0A"$(>!99 +M99YUEEED(0A[AY#R7NT(0AZJRRRSN@LLLLA"$.-EEEGQ;+++(0A"$,C(^I]C +M@WW/Q9Y^SUW\,QW+!^G>8,&#!@P8,&#!@P8,&#!];[6=;.I2E*4I2E*4I2E( +MB(B(B(B(B(I2E,C(R,CP[+++(0A"$(0_Z[7KMK:VMJ$(0^'Y#_MX+WZ$(0A" +M$(0A"UEEED(0A"$(0A"$(0A_X^"\=\)\-\1YC_Y[IVGQGQV]O;V]$1$1$1$1 +M=F.F?TI2E*4I2E*4I2E(B(B(B(B(B(I3MW;O>V6660A"'G6666=]9999_S99 +M99"$(>D^N\[S7FO->:A"$/['H]C8V-CP+++++?@[&QL;%MF61EED-6660!YV +A<#S[+FVTI2&VRRRR'P%EED'QVI_Z__%W)%.%"0W.\..` ` end Index: sys/boot/efi/boot1/generate-fat.sh =================================================================== --- sys/boot/efi/boot1/generate-fat.sh +++ sys/boot/efi/boot1/generate-fat.sh @@ -13,7 +13,7 @@ FAT_SIZE=1600 #Size in 512-byte blocks of the produced image -BOOT1_SIZE=128k +BOOT1_SIZE=512k # # Known filenames 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,196 +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; - -static int -vdev_read(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes) -{ - dev_info_t *devinfo; - off_t lba; - EFI_STATUS status; - - devinfo = (dev_info_t *)priv; - lba = off / devinfo->dev->Media->BlockSize; - - status = devinfo->dev->ReadBlocks(devinfo->dev, - devinfo->dev->Media->MediaId, lba, bytes, buf); - if (status != EFI_SUCCESS) { - DPRINTF("vdev_read: failed dev: %p, id: %u, lba: %jd, size: %zu," - " status: %lu\n", devinfo->dev, - devinfo->dev->Media->MediaId, (intmax_t)lba, bytes, - EFI_ERROR_CODE(status)); - return (-1); - } - - return (0); -} - -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 %zd for pool '%s' for '%s' " - "(%lu)\n", 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: sys/boot/efi/drivers/Makefile =================================================================== --- /dev/null +++ sys/boot/efi/drivers/Makefile @@ -0,0 +1,34 @@ +# $FreeBSD$ + +.include + +LIB= efi_drivers +INTERNALLIB= +WARNS?= 2 + +SRCS= efipart.c fs_driver.c + +.if ${MACHINE_CPUARCH} == "aarch64" +CFLAGS+= -msoft-float -mgeneral-regs-only +.endif +.if ${MACHINE_ARCH} == "amd64" +CFLAGS+= -fPIC -mno-red-zone +.endif +.if ${MK_ZFS} != "no" +CFLAGS+= -I${.CURDIR}/../../zfs +CFLAGS+= -I${.CURDIR}/../../../cddl/boot/zfs +CFLAGS+= -DEFI_ZFS_BOOT +.endif + +CFLAGS+= -I${.CURDIR}/../include +CFLAGS+= -I${.CURDIR}/../include/${MACHINE} +CFLAGS+= -I${.CURDIR}/../../../../lib/libstand + +# Pick up the bootstrap header for some interface items +CFLAGS+= -I${.CURDIR}/../../common + +# Handle FreeBSD specific %b and %D printf format specifiers +CFLAGS+= ${FORMAT_EXTENSIONS} +CFLAGS+= -DTERM_EMU + +.include Index: sys/boot/efi/drivers/efi_drivers.h =================================================================== --- /dev/null +++ sys/boot/efi/drivers/efi_drivers.h @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 2016 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 _EFI_DRIVERS_H_ +#define _EFI_DRIVERS_H_ + +#include + +typedef struct efi_driver_t { + const char *name; + void (*init)(void); +} efi_driver_t; + +extern struct devsw efipart_dev; +extern int efipart_getdesc(struct devdesc *dev, char **out); + +/* EFI drivers. */ +extern const efi_driver_t fs_driver; + +#endif Index: sys/boot/efi/drivers/efipart.c =================================================================== --- sys/boot/efi/drivers/efipart.c +++ sys/boot/efi/drivers/efipart.c @@ -72,94 +72,129 @@ #define PD(dev) (pdinfo[(dev)->d_unit]) +static EFI_STATUS +efipart_supported(EFI_DRIVER_BINDING *This, EFI_HANDLE handle, + EFI_DEVICE_PATH *RemainingDevicePath __unused) +{ + return BS->OpenProtocol(handle, &blkio_guid, + NULL, IH, handle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL); +} + +static EFI_STATUS +efipart_start(EFI_DRIVER_BINDING *This, EFI_HANDLE handle, + EFI_DEVICE_PATH *RemainingDevicePath __unused, + u_int* ndisk, uint* nrdisk) +{ + EFI_BLOCK_IO *blkio; + EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node; + EFI_STATUS status; + EFI_HANDLE alias; + + devpath = efi_lookup_devpath(handle); + + if (devpath == NULL) { + return (EFI_DEVICE_ERROR); + } + + status = BS->HandleProtocol(handle, &blkio_guid, + (void**)&blkio); + if (EFI_ERROR(status)) + return (status); + + if (!blkio->Media->LogicalPartition) { + *nrdisk++; + return (EFI_UNSUPPORTED); + } + + /* + * If we come across a logical partition of subtype CDROM + * it doesn't refer to the CD filesystem itself, but rather + * to any usable El Torito boot image on it. In this case + * we try to find the parent device and add that instead as + * that will be the CD filesystem. + */ + node = efi_devpath_last_node(devpath); + if (DevicePathType(node) == MEDIA_DEVICE_PATH && + DevicePathSubType(node) == MEDIA_CDROM_DP) { + devpathcpy = efi_devpath_trim(devpath); + tmpdevpath = devpathcpy; + status = BS->LocateDevicePath(&blkio_guid, &tmpdevpath, + &alias); + free(devpathcpy); + + if (EFI_ERROR(status)) + return (status); + + efi_register_handle(&efipart_dev, handle, alias); + } else + efi_register_handle(&efipart_dev, handle, NULL); + + pdinfo[npdinfo].pd_open = 0; + pdinfo[npdinfo].pd_bcache = NULL; + pdinfo[npdinfo].pd_unit = npdinfo; + npdinfo++; + *ndisk++; + + return (EFI_SUCCESS); +} + static int -efipart_init(void) +efipart_init(void) { - EFI_BLOCK_IO *blkio; - EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node; - EFI_HANDLE *hin, *hout, *aliases, handle; + EFI_HANDLE *handles; EFI_STATUS status; UINTN sz; - u_int n, nin, nout, nrdisk; + u_int n, nin, ndisk, nrdisk; int err; sz = 0; - hin = NULL; + handles = NULL; status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, 0); if (status == EFI_BUFFER_TOO_SMALL) { - hin = (EFI_HANDLE *)malloc(sz * 3); + handles = (EFI_HANDLE *)malloc(sz); status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, - hin); + handles); if (EFI_ERROR(status)) - free(hin); + free(handles); } if (EFI_ERROR(status)) return (efi_status_to_errno(status)); /* Filter handles to only include FreeBSD partitions. */ nin = sz / sizeof(EFI_HANDLE); - hout = hin + nin; - aliases = hout + nin; - nout = 0; - nrdisk = 0; - - bzero(aliases, nin * sizeof(EFI_HANDLE)); pdinfo = malloc(nin * sizeof(*pdinfo)); - if (pdinfo == NULL) - return (ENOMEM); + ndisk = 0; + nrdisk = 0; for (n = 0; n < nin; n++) { - devpath = efi_lookup_devpath(hin[n]); - if (devpath == NULL) { - continue; - } - - status = BS->HandleProtocol(hin[n], &blkio_guid, - (void**)&blkio); - if (EFI_ERROR(status)) - continue; - if (!blkio->Media->LogicalPartition) { - nrdisk++; - continue; - } - - /* - * If we come across a logical partition of subtype CDROM - * it doesn't refer to the CD filesystem itself, but rather - * to any usable El Torito boot image on it. In this case - * we try to find the parent device and add that instead as - * that will be the CD filesystem. - */ - node = efi_devpath_last_node(devpath); - if (DevicePathType(node) == MEDIA_DEVICE_PATH && - DevicePathSubType(node) == MEDIA_CDROM_DP) { - devpathcpy = efi_devpath_trim(devpath); - tmpdevpath = devpathcpy; - status = BS->LocateDevicePath(&blkio_guid, &tmpdevpath, - &handle); - free(devpathcpy); - if (EFI_ERROR(status)) - continue; - hout[nout] = handle; - aliases[nout] = hin[n]; - } else - hout[nout] = hin[n]; - nout++; - pdinfo[npdinfo].pd_open = 0; - pdinfo[npdinfo].pd_bcache = NULL; - pdinfo[npdinfo].pd_unit = npdinfo; - npdinfo++; + efipart_start(NULL, handles[n], NULL, &ndisk, &nrdisk); } bcache_add_dev(npdinfo); - err = efi_register_handles(&efipart_dev, hout, aliases, nout); - free(hin); + free(handles); - if (nout == 0 && nrdisk > 0) + if (ndisk == 0 && nrdisk > 0) printf("Found %d disk(s) but no logical partition\n", nrdisk); return (err); } +int +efipart_getdesc(struct devdesc *dev, char **out) +{ + int namelen = strlen(efipart_dev.dv_name) + 21; + char* devname = malloc(namelen); + + if (devname == NULL) { + return (ENOMEM); + } + + snprintf(devname, namelen, "%s%d", efipart_dev.dv_name, dev->d_unit); + *out = devname; + + return (0); +} + static int efipart_print(int verbose) { Index: sys/boot/efi/drivers/fs_driver.c =================================================================== --- /dev/null +++ sys/boot/efi/drivers/fs_driver.c @@ -0,0 +1,991 @@ +/*- + * Copyright (c) 2016 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 +#include +#include +#ifdef EFI_ZFS_BOOT +#include +#endif +#include + +#include "efi_drivers.h" + +static EFI_GUID SimpleFileSystemProtocolGUID = SIMPLE_FILE_SYSTEM_PROTOCOL; +static EFI_GUID ComponentNameGUID = COMPONENT_NAME2_PROTOCOL; + +static struct fs_ops *backend_file_system[] = { + &ufs_fsops, + &cd9660_fsops, + &tftp_fsops, + &nfs_fsops, + &gzipfs_fsops, + &bzipfs_fsops, + NULL +}; + +static struct devsw *backend_devsw[] = { + &efipart_dev, +#ifdef EFI_ZFS_BOOT + &zfs_dev, +#endif + NULL +}; + +typedef struct volinfo_t { + struct fs_ops *fsops; + struct devdesc *dev; +} volinfo_t; + +typedef struct fileinfo_t { + const volinfo_t* vinfo; + struct open_file fdata; + char path[]; +} fileinfo_t; + +typedef struct nameinfo_t { + CHAR16 *devname; +} nameinfo_t; + +static EFI_GUID FileInfoGUID = EFI_FILE_INFO_ID;; + +static EFIAPI EFI_STATUS +file_open_impl(EFI_FILE_HANDLE File, EFI_FILE_HANDLE *NewHandle, + CHAR16 *FileName, UINT64 OpenMode, UINT64 Attributes); + +static EFIAPI EFI_STATUS +file_close_impl(EFI_FILE_HANDLE File); + +static EFIAPI EFI_STATUS +file_delete_impl(EFI_FILE_HANDLE File); + +static EFIAPI EFI_STATUS +dir_read_impl(EFI_FILE_HANDLE File, UINTN *BufferSize, VOID *Buffer); + +static EFIAPI EFI_STATUS +dir_write_impl(EFI_FILE_HANDLE File, UINTN *BufferSize, + VOID *Buffer); + +static EFIAPI EFI_STATUS +file_read_impl(EFI_FILE_HANDLE File, UINTN *BufferSize, VOID *Buffer); + +static EFIAPI EFI_STATUS +file_write_impl(EFI_FILE_HANDLE File, UINTN *BufferSize, + VOID *Buffer); + +static EFIAPI EFI_STATUS +file_set_position_impl(EFI_FILE_HANDLE File, UINT64 Position); + +static EFIAPI EFI_STATUS +file_get_position_impl(EFI_FILE_HANDLE File, UINT64 *Position); + +static EFIAPI EFI_STATUS +file_get_info_impl(EFI_FILE_HANDLE File, EFI_GUID *InformationType, + UINTN *BufferSize, VOID *Buffer); + +static EFIAPI EFI_STATUS +file_set_info_impl(EFI_FILE_HANDLE File, EFI_GUID *InformationType, + UINTN BufferSize, VOID *Buffer); + +static EFIAPI EFI_STATUS +file_flush_impl(EFI_FILE_HANDLE File); + +static struct devdesc* +clone_devdesc(struct devdesc *dev) +{ + struct devdesc *out; + + switch(dev->d_dev->dv_type) { + case DEVT_ZFS: + out = malloc(sizeof(struct zfs_devdesc)); + + if (out == NULL) { + return NULL; + } + + memcpy(out, dev, sizeof(struct zfs_devdesc)); + + return out; + + default: + out = malloc(sizeof(struct devdesc)); + + if (out == NULL) { + return NULL; + } + + memcpy(out, dev, sizeof(struct devdesc)); + + return out; + } +} + +static EFI_STATUS +do_file_open(const volinfo_t *vinfo, const char filepath[], + int mode, EFI_FILE_HANDLE *out) +{ + EFI_FILE_HANDLE fhandle; + fileinfo_t *finfo; + struct stat st; + struct devdesc *tmpdev; + int err; + + memset(&st, 0, sizeof(struct stat)); + fhandle = malloc(sizeof(EFI_FILE) + sizeof(fileinfo_t) + + strlen(filepath) + 1); + + if (fhandle == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + tmpdev = clone_devdesc(vinfo->dev); + + if (tmpdev == NULL) { + free(fhandle); + return (EFI_OUT_OF_RESOURCES); + } + + finfo = (fileinfo_t*)(fhandle + 1); + finfo->fdata.f_flags = mode + 1; + finfo->fdata.f_dev = NULL; + finfo->fdata.f_ops = NULL; + finfo->fdata.f_offset = 0; + finfo->fdata.f_devdata = NULL; + + if ((err = vinfo->dev->d_dev->dv_open(&(finfo->fdata), tmpdev)) != 0) { + free(fhandle); + return (errno_to_efi_status(err)); + } + + finfo->fdata.f_dev = vinfo->dev->d_dev; + + if ((err = vinfo->fsops->fo_open(filepath, &(finfo->fdata))) != 0) { + free(fhandle); + return (errno_to_efi_status(err)); + } + + finfo->fdata.f_ops = vinfo->fsops; + + if ((err = vinfo->fsops->fo_stat(&(finfo->fdata), &st)) != 0) { + free(fhandle); + return (errno_to_efi_status(err)); + } + + strcpy(finfo->path, filepath); + finfo->vinfo = vinfo; + fhandle->Revision = EFI_FILE_HANDLE_REVISION; + fhandle->Open = file_open_impl; + fhandle->Close = file_close_impl; + fhandle->Delete = file_delete_impl; + fhandle->SetPosition = file_set_position_impl; + fhandle->GetPosition = file_get_position_impl; + fhandle->GetInfo = file_get_info_impl; + fhandle->SetInfo = file_set_info_impl; + fhandle->Flush = file_flush_impl; + + if (S_ISDIR(st.st_mode)) { + fhandle->Read = dir_read_impl; + fhandle->Write = dir_write_impl; + } else { + fhandle->Read = file_read_impl; + fhandle->Write = file_write_impl; + } + + *out = fhandle; + + return (EFI_SUCCESS); +} + +static int +mode_from_efi(UINT64 efi_mode) +{ + int mode = 0; + + if (efi_mode & EFI_FILE_MODE_WRITE) { + mode |= O_WRONLY; + } else if (efi_mode & EFI_FILE_MODE_READ) { + mode |= O_RDONLY; + } else if (efi_mode & EFI_FILE_MODE_READ && + efi_mode & EFI_FILE_MODE_WRITE) { + mode |= O_RDWR; + } + + return mode; +} + +static UINT64 +mode_to_efi(int mode) +{ + UINT64 efi_mode = 0; + + if (mode & O_WRONLY) { + efi_mode |= EFI_FILE_MODE_WRITE; + } else if (mode & O_RDONLY) { + efi_mode |= EFI_FILE_MODE_READ; + } else if (mode & O_RDWR) { + efi_mode |= EFI_FILE_MODE_READ; + efi_mode |= EFI_FILE_MODE_WRITE; + } + + return (efi_mode); +} + +static EFIAPI EFI_STATUS +file_open_impl(EFI_FILE_HANDLE File, EFI_FILE_HANDLE *NewHandle, + CHAR16 *FileName, UINT64 OpenMode, UINT64 Attributes) +{ + fileinfo_t *finfo = (fileinfo_t*)(File + 1); + char buf[strlen(finfo->path) + strlen16(FileName) + 1]; + + strcpy_from_16(stpcpy(buf, finfo->path), FileName); + + return do_file_open(finfo->vinfo, buf, + mode_from_efi(OpenMode), NewHandle); +} + +static EFIAPI EFI_STATUS +file_close_impl(EFI_FILE_HANDLE File) +{ + fileinfo_t *finfo = (fileinfo_t*)(File + 1); + int res; + + if ((res = finfo->fdata.f_ops->fo_close(&(finfo->fdata))) != 0) { + return (errno_to_efi_status(res)); + } + + if ((res = finfo->vinfo->dev->d_dev->dv_close(&(finfo->fdata))) != 0) { + return (errno_to_efi_status(res)); + } + + free(File); + return (EFI_SUCCESS); +} + +static EFIAPI EFI_STATUS +file_delete_impl(EFI_FILE_HANDLE File) +{ + file_close_impl(File); + + return (EFI_WARN_DELETE_FAILURE); +} + +static EFIAPI EFI_STATUS +dir_read_impl(EFI_FILE_HANDLE File, UINTN *BufferSize, VOID *Buffer) +{ + fileinfo_t *finfo = (fileinfo_t*)(File + 1); + fileinfo_t *entinfo; + struct dirent d; + struct stat st; + int err; + UINTN currsize = *BufferSize; + UINTN reqsize; + EFI_FILE_INFO *out = (EFI_FILE_INFO*)Buffer; + EFI_FILE_HANDLE enthandle; + EFI_STATUS status; + off_t currpos; + + /* Record teh current position so we can rewind if we have to */ + if ((currpos = finfo->fdata.f_ops->fo_seek(&(finfo->fdata), + 0, SEEK_CUR)) < 0) { + return (errno_to_efi_status(errno)); + } + + if ((err = finfo->fdata.f_ops->fo_readdir(&(finfo->fdata), &d)) != 0) { + return (errno_to_efi_status(errno)); + } + + reqsize = sizeof(EFI_FILE_INFO) + + ((strlen(d.d_name) + 1) * sizeof(CHAR16)); + + if (Buffer == NULL || currsize < reqsize) { + finfo->fdata.f_ops->fo_seek(&(finfo->fdata), currpos, SEEK_SET); + *BufferSize = reqsize; + + return (EFI_BUFFER_TOO_SMALL); + } + + // We have to actually open the file, since EFI directory + // reads are supposed to return stat information. + CHAR16 buf[d.d_namlen]; + strcpy_to_16(buf, d.d_name); + status = file_open_impl(File, &enthandle, buf, EFI_FILE_READ_ONLY, 0); + + if (EFI_ERROR(status)) { + finfo->fdata.f_ops->fo_seek(&(finfo->fdata), currpos, SEEK_SET); + return (status); + } + + entinfo = (fileinfo_t*)(enthandle + 1); + + if ((err = finfo->fdata.f_ops->fo_stat(&(entinfo->fdata), &st)) != 0) { + finfo->fdata.f_ops->fo_seek(&(finfo->fdata), currpos, SEEK_SET); + return (errno_to_efi_status(errno)); + } + + status = file_close_impl(enthandle); + + if (EFI_ERROR(status)) { + finfo->fdata.f_ops->fo_seek(&(finfo->fdata), currpos, SEEK_SET); + return (status); + } + + // We're good at this point, copy everything into place. + out->Size = reqsize; + out->FileSize = st.st_size; + out->PhysicalSize = st.st_blocks * st.st_blksize; + out->Attribute = mode_to_efi(st.st_mode); + to_efi_time(&(out->LastAccessTime), st.st_atime); + to_efi_time(&(out->ModificationTime), st.st_mtime); + to_efi_time(&(out->CreateTime), st.st_ctime); + + if (S_ISDIR(st.st_mode)) { + out->Attribute |= EFI_FILE_DIRECTORY; + } + + strcpy_to_16(out->FileName, d.d_name); + *BufferSize = reqsize; + + return (EFI_SUCCESS); +} + +static EFIAPI EFI_STATUS +dir_write_impl(EFI_FILE_HANDLE File __unused, UINTN *BufferSize __unused, + VOID *Buffer __unused) +{ + // EFI API doesn't allow writing to directories + return (EFI_UNSUPPORTED); +} + +static EFIAPI EFI_STATUS +file_read_impl(EFI_FILE_HANDLE File, UINTN *BufferSize, VOID *Buffer) +{ + fileinfo_t *finfo = (fileinfo_t*)(File + 1); + size_t readsize = *BufferSize; + size_t resid; + int err; + + if ((err = finfo->fdata.f_ops->fo_read(&(finfo->fdata), Buffer, + readsize, &resid)) != 0) { + return (errno_to_efi_status(errno)); + } + + *BufferSize = readsize - resid; + + return (EFI_SUCCESS); +} + +static EFIAPI EFI_STATUS +file_write_impl(EFI_FILE_HANDLE File, UINTN *BufferSize, VOID *Buffer) +{ + fileinfo_t *finfo = (fileinfo_t*)(File + 1); + size_t writesize = *BufferSize; + size_t resid; + int err; + + if ((err = finfo->fdata.f_ops->fo_write(&(finfo->fdata), Buffer, + writesize, &resid)) != 0) { + return (errno_to_efi_status(errno)); + } + + *BufferSize = writesize - resid; + + return (EFI_SUCCESS); +} + +static EFIAPI EFI_STATUS +file_set_position_impl(EFI_FILE_HANDLE File, UINT64 Position) +{ + fileinfo_t *finfo = (fileinfo_t*)(File + 1); + int res; + + if (Position != 0xffffffffffffffffLL) { + res = finfo->fdata.f_ops->fo_seek(&(finfo->fdata), + Position, SEEK_SET); + } else { + res = finfo->fdata.f_ops->fo_seek(&(finfo->fdata), + 0, SEEK_END); + } + + if (res > 0) { + return (EFI_SUCCESS); + } else { + return (errno_to_efi_status(res)); + } +} + + +static EFIAPI EFI_STATUS +file_get_position_impl(EFI_FILE_HANDLE File, UINT64 *Position) +{ + fileinfo_t *finfo = (fileinfo_t*)(File + 1); + off_t res; + + res = finfo->fdata.f_ops->fo_seek(&(finfo->fdata), 0, SEEK_CUR); + + if (res > 0) { + *Position = res; + + return (EFI_SUCCESS); + } else { + return (errno_to_efi_status(errno)); + } +} + +static EFIAPI EFI_STATUS +file_get_info_impl(EFI_FILE_HANDLE File, EFI_GUID *InformationType, + UINTN *BufferSize, VOID *Buffer) +{ + fileinfo_t *finfo = (fileinfo_t*)(File + 1); + + if (!memcmp(InformationType, &FileInfoGUID, sizeof(EFI_GUID))) { + EFI_FILE_INFO *out = (EFI_FILE_INFO*)Buffer; + UINTN str16len =(strlen(finfo->path) + 1) * sizeof(CHAR16); + UINTN currsize = *BufferSize; + UINTN reqsize = sizeof(EFI_FILE_INFO) + str16len; + struct stat st; + int err; + + memset(&st, 0, sizeof(struct stat)); + *BufferSize = reqsize; + + if (Buffer == NULL || + currsize < sizeof(EFI_FILE_INFO) + str16len) { + *BufferSize = sizeof(EFI_FILE_INFO) + str16len; + return (EFI_BUFFER_TOO_SMALL); + } + + if ((err = finfo->fdata.f_ops->fo_stat(&(finfo->fdata), + &st)) != 0) { + return (errno_to_efi_status(errno)); + } + + out->Size = sizeof(EFI_FILE_INFO) + str16len; + out->FileSize = st.st_size; + out->PhysicalSize = st.st_blocks * st.st_blksize; + to_efi_time(&(out->LastAccessTime), st.st_atime); + to_efi_time(&(out->ModificationTime), st.st_mtime); + to_efi_time(&(out->CreateTime), st.st_ctime); + out->Attribute = mode_to_efi(st.st_mode); + + if (S_ISDIR(st.st_mode)) { + out->Attribute |= EFI_FILE_DIRECTORY; + } + + strcpy_to_16(out->FileName, finfo->path); + } else { + return (EFI_UNSUPPORTED); + } + + return (EFI_SUCCESS); +} + +static EFIAPI EFI_STATUS +file_set_info_impl(EFI_FILE_HANDLE File __unused, + EFI_GUID *InformationType __unused, + UINTN BufferSize __unused, VOID *Buffer __unused) +{ + return (EFI_WRITE_PROTECTED); +} + +static EFIAPI EFI_STATUS +file_flush_impl(EFI_FILE_HANDLE File __unused) +{ + return (EFI_SUCCESS); +} + +static EFIAPI EFI_STATUS +open_volume_impl(EFI_FILE_IO_INTERFACE *This, EFI_FILE_HANDLE *Root) +{ + volinfo_t *vinfo = (volinfo_t*)(This + 1); + + return do_file_open(vinfo, "", O_RDONLY, Root); +} + +static struct fs_ops* +fs_probe(struct devdesc *dev) +{ + struct open_file f; + int err, i; + + f.f_flags = O_RDONLY + 1; + f.f_dev = (struct devsw *)0; + f.f_ops = (struct fs_ops *)0; + f.f_offset = 0; + f.f_devdata = dev; + + if ((err = dev->d_dev->dv_open(&f, dev)) != 0) { + return NULL; + } + + for (i = 0; backend_file_system[i] != NULL; i++) { + f.f_ops = backend_file_system[i]; + + if ((err = f.f_ops->fo_open("/", &f)) == 0) { + return backend_file_system[i]; + } + } + + return NULL; +} + +static EFI_STATUS +make_fs_file_io_iface(struct devdesc *dev, EFI_FILE_IO_INTERFACE **out) +{ + static struct fs_ops* fsops; + EFI_FILE_IO_INTERFACE* fiface; + volinfo_t *vinfo; + + switch (dev->d_type) { +#ifdef EFI_ZFS_BOOT + case DEVT_ZFS: + fsops = &zfs_fsops; + break; +#endif + default: + fsops = fs_probe(dev); + break; + } + + if (fsops == NULL) { + return (EFI_UNSUPPORTED); + } + + fiface = malloc(sizeof(EFI_FILE_IO_INTERFACE) + sizeof(volinfo_t)); + + if (fiface == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + vinfo = (volinfo_t*)(fiface + 1); + + fiface->Revision = EFI_FILE_IO_INTERFACE_REVISION; + fiface->OpenVolume = open_volume_impl; + vinfo->dev = dev; + vinfo->fsops = fsops; + + *out = fiface; + + return (EFI_SUCCESS); +} + +static EFIAPI EFI_STATUS +get_driver_name_impl(EFI_COMPONENT_NAME2 *this, CHAR8 *lang __unused, + CHAR16 **out) +{ + static const char driver_name[] = "fs_driver"; + static const size_t namelen = + sizeof driver_name / sizeof driver_name[0]; + CHAR16 *name16 = malloc(sizeof(CHAR16) * namelen); + + if (name16 == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + strcpy_to_16(name16, driver_name); + *out = name16; + + return (EFI_SUCCESS); +} + +static EFIAPI EFI_STATUS +get_controller_name_impl(EFI_COMPONENT_NAME2 *this, EFI_HANDLE controller, + EFI_HANDLE child __unused, CHAR8 *lang __unused, CHAR16 **out) +{ + nameinfo_t *ninfo = (nameinfo_t*)(this + 1); + CHAR16 *name16 = malloc(sizeof(CHAR16) * strlen16(ninfo->devname)); + + if (name16 == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + strcpy16(name16, ninfo->devname); + *out = name16; + + return (EFI_SUCCESS); +} + + + +static EFI_STATUS +make_cname_iface(struct devdesc *dev, EFI_COMPONENT_NAME2 **out) +{ + static CHAR8* langs[] = { "en" }; + EFI_COMPONENT_NAME2 *iface; + nameinfo_t *ninfo; + char *devname; + + /* Generate a device name based on the underlying device type */ + switch (dev->d_type) { +#ifdef EFI_ZFS_BOOT + case DEVT_ZFS: { + int err = zfs_dev_getdesc((struct zfs_devdesc *)dev, &devname); + + if (err) { + return (errno_to_efi_status(err)); + } + } break; +#endif + case DEVT_DISK: { + int err = efipart_getdesc(dev, &devname); + + if (err) { + return (errno_to_efi_status(err)); + } + } break; + default: + devname = NULL; + break; + } + + iface = malloc(sizeof(EFI_COMPONENT_NAME2) + sizeof(nameinfo_t)); + + if (iface == NULL) { + free(devname); + + return (EFI_OUT_OF_RESOURCES); + } + + /* Convert the device name to CHAR16s */ + if (devname != NULL) { + ninfo = (nameinfo_t*)(iface + 1); + ninfo->devname = malloc(sizeof(CHAR16) * (strlen(devname) + 1)); + + if (ninfo->devname == NULL) { + free(iface); + free(devname); + + return (EFI_OUT_OF_RESOURCES); + } + + strcpy_to_16(ninfo->devname, devname); + free(devname); + } else { + ninfo->devname = NULL; + } + + /* Set up the functions */ + iface->SupportedLanguages = langs; + iface->GetDriverName = get_driver_name_impl; + iface->GetControllerName = get_controller_name_impl; + + *out = iface; + + return (EFI_SUCCESS); +} + +static EFIAPI EFI_STATUS +bind_fs_iface(EFI_HANDLE handle, struct devdesc *dev) +{ + EFI_STATUS status; + EFI_FILE_IO_INTERFACE *iface; + + // Check if there is already a filesystem interface + status = BS->OpenProtocol(handle, &SimpleFileSystemProtocolGUID, + NULL, IH, handle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL); + + if (!EFI_ERROR(status)) { + return (EFI_ACCESS_DENIED); + } else if (status != EFI_UNSUPPORTED) { + return (status); + } + + status = make_fs_file_io_iface(dev, &iface); + + if (EFI_ERROR(status)) { + return (status); + } + + status = BS->InstallMultipleProtocolInterfaces(&handle, + &SimpleFileSystemProtocolGUID, iface, + NULL); + + if (EFI_ERROR(status)) { + free(iface); + } + + return (status); +} + +static EFIAPI void +bind_cname_iface(EFI_HANDLE handle, struct devdesc *dev) +{ + EFI_STATUS status; + EFI_COMPONENT_NAME2 *cname; + + status = make_cname_iface(dev, &cname); + + if (EFI_ERROR(status)) { + return; + } + + status = BS->InstallMultipleProtocolInterfaces(&handle, + &ComponentNameGUID, cname, NULL); + + if (EFI_ERROR(status)) { + free(cname); + + return; + } +} + +static EFIAPI EFI_STATUS +bind_ifaces(EFI_HANDLE handle, struct devdesc *dev) +{ + bind_cname_iface(handle, dev); + + return bind_fs_iface(handle, dev); +} + +static EFIAPI EFI_STATUS +stop_impl(EFI_DRIVER_BINDING *This __unused, EFI_HANDLE ControllerHandle __unused, + UINTN NumberOfChildren __unused, EFI_HANDLE *ChildHandleBuffer __unused) +{ + // Get the protocol inteface, uninstall it, and free it + return (EFI_SUCCESS); +} + +#ifdef EFI_ZFS_BOOT +static void +efi_zfs_probe(void) +{ + EFI_HANDLE h; + u_int unit; + int i; + char dname[SPECNAMELEN + 1]; + uint64_t guid; + + unit = 0; + h = efi_find_handle(&efipart_dev, 0); + for (i = 0; h != NULL; h = efi_find_handle(&efipart_dev, ++i)) { + snprintf(dname, sizeof(dname), "%s%d:", efipart_dev.dv_name, i); + if (zfs_probe_dev(dname, &guid) == 0) { + (void)efi_handle_update_dev(h, &zfs_dev, unit++, guid); + } + } +} +#endif + +static int +backend_parsedev(struct devdesc **dev, const char *devspec, const char **path) +{ + struct devdesc *idev; + struct devsw *dv; + char *cp; + const char *np; + int i; + + /* minimum length check */ + if (strlen(devspec) < 2) + return (EINVAL); + + /* look for a device that matches */ + for (i = 0; backend_devsw[i] != NULL; i++) { + dv = backend_devsw[i]; + if (!strncmp(devspec, dv->dv_name, strlen(dv->dv_name))) + break; + } + if (backend_devsw[i] == NULL) { + return (ENOENT); + } + + np = devspec + strlen(dv->dv_name); + +#ifdef EFI_ZFS_BOOT + if (dv->dv_type == DEVT_ZFS) { + int err; + + idev = malloc(sizeof(struct zfs_devdesc)); + if (idev == NULL) + return (ENOMEM); + + err = zfs_parsedev((struct zfs_devdesc*)idev, np, path); + if (err != 0) { + free(idev); + return (err); + } + *dev = idev; + cp = strchr(np + 1, ':'); + } else +#endif + { + idev = malloc(sizeof(struct devdesc)); + if (idev == NULL) + return (ENOMEM); + + idev->d_dev = dv; + idev->d_type = dv->dv_type; + idev->d_unit = -1; + if (*np != '\0' && *np != ':') { + idev->d_unit = strtol(np, &cp, 0); + if (cp == np) { + idev->d_unit = -1; + free(idev); + return (EUNIT); + } + } + } + + if (*cp != '\0' && *cp != ':') { + free(idev); + return (EINVAL); + } + + if (path != NULL) + *path = (*cp == 0) ? cp : cp + 1; + if (dev != NULL) + *dev = idev; + else + free(idev); + return (0); +} + +static int +backend_getdev(void **vdev, const char *devspec, const char **path) +{ + struct devdesc **dev = (struct devdesc **)vdev; + int rv; + + /* + * If it looks like this is just a path and no device, then + * use the current device instead. + */ + if (devspec == NULL || *devspec == '/' || !strchr(devspec, ':')) { + rv = backend_parsedev(dev, getenv("currdev"), NULL); + if (rv == 0 && path != NULL) + *path = devspec; + return (rv); + } + + /* Parse the device name off the beginning of the devspec. */ + return (backend_parsedev(dev, devspec, path)); +} + +static void +init(void) +{ + EFI_HANDLE h; + EFI_STATUS status; + u_int unit; + int i; + struct devsw *dev; + uint64_t pool_guid; + int (*old_getdev)(void **, const char *, const char **) = + archsw.arch_getdev; + + archsw.arch_getdev = backend_getdev; +#ifdef EFI_ZFS_BOOT + /* Note this needs to be set before ZFS init. */ + archsw.arch_zfs_probe = efi_zfs_probe; +#endif + + /* Initialize all the backend drivers */ + for (i = 0; backend_devsw[i] != NULL; i++) { + if (backend_devsw[i]->dv_init != NULL) + (backend_devsw[i]->dv_init)(); + } + + /* Attach SIMPLE_FILE_SYSTEM interfaces to all efipart devices */ + unit = 0; + h = efi_find_handle(&efipart_dev, 0); + for (i = 0; h != NULL; h = efi_find_handle(&efipart_dev, ++i)) { + struct devdesc *currdev; + + currdev = malloc(sizeof(struct devdesc)); + + if (currdev == NULL) { + continue; + } + + if (efi_handle_lookup(h, &dev, &unit, &pool_guid) != 0) { + free(currdev); + continue; + } + + currdev->d_dev = dev; + currdev->d_unit = unit; + currdev->d_opendata = NULL; + currdev->d_type = currdev->d_dev->dv_type; + + status = bind_ifaces(h, currdev); + + if (EFI_ERROR(status) && status != EFI_UNSUPPORTED && + status != EFI_ACCESS_DENIED) { + printf("Failed to attach filesystem interface to efipart%u (%ld)\n", + unit, EFI_ERROR_CODE(status)); + free(currdev); + } + } + + /* Attach SIMPLE_FILE_SYSTEM interface to all ZFS devices */ +#ifdef EFI_ZFS_BOOT + unit = 0; + h = efi_find_handle(&zfs_dev, 0); + for (i = 0; h != NULL; h = efi_find_handle(&zfs_dev, ++i)) { + struct zfs_devdesc *currdev; + + currdev = malloc(sizeof(struct zfs_devdesc)); + + if (currdev == NULL) { + continue; + } + + if (efi_handle_lookup(h, &dev, &unit, &pool_guid) != 0) { + free(currdev); + continue; + } + + currdev->d_dev = dev; + currdev->d_unit = unit; + currdev->d_opendata = NULL; + currdev->d_type = currdev->d_dev->dv_type; + currdev->pool_guid = pool_guid; + currdev->root_guid = 0; + + status = bind_ifaces(h, (struct devdesc*)currdev); + + if (EFI_ERROR(status)) { + printf("Failed to attach filesystem interface to zfs%u (%ld)\n", + unit, EFI_ERROR_CODE(status)); + } + } +#endif + archsw.arch_getdev = old_getdev; +} + +const efi_driver_t fs_driver = +{ + .name = "FS Backend", + .init = init, +}; Index: sys/boot/efi/include/efidevp.h =================================================================== --- sys/boot/efi/include/efidevp.h +++ sys/boot/efi/include/efidevp.h @@ -148,8 +148,8 @@ // bits[31:16] - binary number // Compressed ASCII is 5 bits per character 0b00001 = 'A' 0b11010 = 'Z' // -#define PNP_EISA_ID_CONST 0x41d0 -#define EISA_ID(_Name, _Num) ((UINT32) ((_Name) | (_Num) << 16)) +#define PNP_EISA_ID_CONST 0x41d0 +#define EISA_ID(_Name, _Num) ((UINT32) ((_Name) | (_Num) << 16)) #define EISA_PNP_ID(_PNPId) (EISA_ID(PNP_EISA_ID_CONST, (_PNPId))) #define EFI_PNP_ID(_PNPId) (EISA_ID(PNP_EISA_ID_CONST, (_PNPId))) @@ -158,7 +158,7 @@ /* * */ -#define MESSAGING_DEVICE_PATH 0x03 +#define MESSAGING_DEVICE_PATH 0x03 #define MSG_ATAPI_DP 0x01 typedef struct _ATAPI_DEVICE_PATH { @@ -172,7 +172,7 @@ typedef struct _SCSI_DEVICE_PATH { EFI_DEVICE_PATH Header; UINT16 Pun; - UINT16 Lun; + UINT16 Lun; } SCSI_DEVICE_PATH; #define MSG_FIBRECHANNEL_DP 0x03 @@ -279,7 +279,7 @@ #define DEVICE_PATH_MESSAGING_VT_100_PLUS \ { 0x7baec70b, 0x57e0, 0x4c76, {0x8e, 0x87, 0x2f, 0x9e, 0x28, 0x08, 0x83, 0x43} } - + #define DEVICE_PATH_MESSAGING_VT_UTF8 \ { 0xad15a0d6, 0x8bec, 0x4acf, {0xa0, 0x73, 0xd0, 0x1d, 0xe7, 0x7e, 0x2d, 0x88} } @@ -361,7 +361,7 @@ PCCARD_DEVICE_PATH PcCard; MEMMAP_DEVICE_PATH MemMap; VENDOR_DEVICE_PATH Vendor; - UNKNOWN_DEVICE_VENDOR_DEVICE_PATH UnknownVendor; + UNKNOWN_DEVICE_VENDOR_DEVICE_PATH UnknownVendor; CONTROLLER_DEVICE_PATH Controller; ACPI_HID_DEVICE_PATH Acpi; @@ -395,7 +395,7 @@ PCCARD_DEVICE_PATH *PcCard; MEMMAP_DEVICE_PATH *MemMap; VENDOR_DEVICE_PATH *Vendor; - UNKNOWN_DEVICE_VENDOR_DEVICE_PATH *UnknownVendor; + UNKNOWN_DEVICE_VENDOR_DEVICE_PATH *UnknownVendor; CONTROLLER_DEVICE_PATH *Controller; ACPI_HID_DEVICE_PATH *Acpi; ACPI_EXTENDED_HID_DEVICE_PATH *ExtendedAcpi; @@ -424,5 +424,35 @@ } EFI_DEV_PATH_PTR; +/* Device path to text protocol */ + +#define EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID \ + { 0xbc62157e, 0x3e33, 0x4fec, { 0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf } } + +#define EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID \ + { 0x8b843e20, 0x8132, 0x4852, { 0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c } } + +INTERFACE_DECL(_EFI_DEVICE_PATH_PROTOCOL); + +typedef +CHAR16* +(EFIAPI *EFI_DEVICE_PATH_TO_TEXT_NODE) ( + IN struct _EFI_DEVICE_PATH *This, + IN BOOLEAN DisplayOnly, + IN BOOLEAN AllowShortCuts + ); + +typedef +CHAR16* +(EFIAPI *EFI_DEVICE_PATH_TO_TEXT_PATH) ( + IN struct _EFI_DEVICE_PATH *This, + IN BOOLEAN DisplayOnly, + IN BOOLEAN AllowShortCuts + ); + +typedef struct _EFI_DEVICE_PATH_TO_TEXT_PROTOCOL { + EFI_DEVICE_PATH_TO_TEXT_NODE ConvertDeviceNodeToText; + EFI_DEVICE_PATH_TO_TEXT_PATH ConvertDevicePathToText; +} EFI_DEVICE_PATH_TO_TEXT_PROTOCOL; #endif Index: sys/boot/efi/include/efilib.h =================================================================== --- sys/boot/efi/include/efilib.h +++ sys/boot/efi/include/efilib.h @@ -31,22 +31,26 @@ #define _LOADER_EFILIB_H #include +#include extern EFI_HANDLE IH; -extern EFI_SYSTEM_TABLE *ST; +extern EFI_SYSTEM_TABLE *ST; extern EFI_BOOT_SERVICES *BS; extern EFI_RUNTIME_SERVICES *RS; -extern struct devsw efipart_dev; +extern struct devsw efifs_dev; extern struct devsw efinet_dev; +extern struct fs_ops efifs_fsops; extern struct netif_driver efinetif; void *efi_get_table(EFI_GUID *tbl); int efi_register_handles(struct devsw *, EFI_HANDLE *, EFI_HANDLE *, int); +int efi_register_handle(struct devsw *, EFI_HANDLE, EFI_HANDLE); EFI_HANDLE efi_find_handle(struct devsw *, int); int efi_handle_lookup(EFI_HANDLE, struct devsw **, int *, uint64_t *); int efi_handle_update_dev(EFI_HANDLE, struct devsw *, int, uint64_t); +int efi_handle_remove_dev(EFI_HANDLE); EFI_DEVICE_PATH *efi_lookup_image_devpath(EFI_HANDLE); EFI_DEVICE_PATH *efi_lookup_devpath(EFI_HANDLE); @@ -57,6 +61,7 @@ void efi_free_devpath_name(CHAR16 *); int efi_status_to_errno(EFI_STATUS); +EFI_STATUS errno_to_efi_status(int errno); void efi_time_init(void); void efi_time_fini(void); @@ -65,4 +70,7 @@ void exit(EFI_STATUS status); void delay(int usecs); +time_t from_efi_time(EFI_TIME *efi_time); +void to_efi_time(EFI_TIME *efi_time, time_t time); + #endif /* _LOADER_EFILIB_H */ Index: sys/boot/efi/include/efiprot.h =================================================================== --- sys/boot/efi/include/efiprot.h +++ sys/boot/efi/include/efiprot.h @@ -27,6 +27,8 @@ --*/ +#include + // // Device Path protocol // @@ -307,9 +309,9 @@ // // The FileName field of the EFI_FILE_INFO data structure is variable length. // Whenever code needs to know the size of the EFI_FILE_INFO data structure, it needs to -// be the size of the data structure without the FileName field. The following macro +// be the size of the data structure without the FileName field. The following macro // computes this size correctly no matter how big the FileName array is declared. -// This is required to make the EFI_FILE_INFO data structure ANSI compilant. +// This is required to make the EFI_FILE_INFO data structure ANSI compilant. // #define SIZE_OF_EFI_FILE_INFO EFI_FIELD_OFFSET(EFI_FILE_INFO,FileName) @@ -329,9 +331,9 @@ // // The VolumeLabel field of the EFI_FILE_SYSTEM_INFO data structure is variable length. // Whenever code needs to know the size of the EFI_FILE_SYSTEM_INFO data structure, it needs -// to be the size of the data structure without the VolumeLable field. The following macro +// to be the size of the data structure without the VolumeLable field. The following macro // computes this size correctly no matter how big the VolumeLable array is declared. -// This is required to make the EFI_FILE_SYSTEM_INFO data structure ANSI compilant. +// This is required to make the EFI_FILE_SYSTEM_INFO data structure ANSI compilant. // #define SIZE_OF_EFI_FILE_SYSTEM_INFO EFI_FIELD_OFFSET(EFI_FILE_SYSTEM_INFO,VolumeLabel) @@ -411,7 +413,7 @@ EFI_DEVICE_IO Write; } EFI_IO_ACCESS; -typedef +typedef EFI_STATUS (EFIAPI *EFI_PCI_DEVICE_PATH) ( IN struct _EFI_DEVICE_IO_INTERFACE *This, @@ -555,4 +557,80 @@ CHAR8 *SupportedLanguages; } EFI_UNICODE_COLLATION_INTERFACE; +// +// Driver Binding protocol +// + +#define DRIVER_BINDING_PROTOCOL \ + { 0x18a031ab, 0xb443, 0x4d1a, {0xa5, 0xc0, 0x0c, 0x09, 0x26, 0x1e, 0x9f, 0x71} } + +INTERFACE_DECL(_EFI_DRIVER_BINDING); + +typedef +EFI_STATUS +(EFIAPI *EFI_DRIVER_BINDING_SUPPORTED) ( + IN struct _EFI_DRIVER_BINDING *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH *RemainingPath + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_DRIVER_BINDING_START) ( + IN struct _EFI_DRIVER_BINDING *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH *RemainingPath + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_DRIVER_BINDING_STOP) ( + IN struct _EFI_DRIVER_BINDING *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +typedef struct _EFI_DRIVER_BINDING { + EFI_DRIVER_BINDING_SUPPORTED Supported; + EFI_DRIVER_BINDING_START Start; + EFI_DRIVER_BINDING_STOP Stop; + UINT32 Version; + EFI_HANDLE ImageHandle; + EFI_HANDLE DriverBindingHandle; +} EFI_DRIVER_BINDING; + +// +// Component Name Protocol 2 +// + +#define COMPONENT_NAME2_PROTOCOL \ + { 0x6a7a5cff, 0xe8d9, 0x4f70, {0xba, 0xda, 0x75, 0xab, 0x30, 0x25, 0xce, 0x14 } } + +INTERFACE_DECL(_EFI_COMPONENT_NAME2); + +typedef +EFI_STATUS +(EFIAPI *EFI_COMPONENT_NAME_GET_DRIVER_NAME) ( + IN struct _EFI_COMPONENT_NAME2 *This, + IN CHAR8 * Language, + OUT CHAR16 **DriverName + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_COMPONENT_NAME_GET_CONTROLLER_NAME) ( + IN struct _EFI_COMPONENT_NAME2 *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +typedef struct _EFI_COMPONENT_NAME2 { + EFI_COMPONENT_NAME_GET_DRIVER_NAME GetDriverName; + EFI_COMPONENT_NAME_GET_CONTROLLER_NAME GetControllerName; + CHAR8 **SupportedLanguages; +} EFI_COMPONENT_NAME2; + #endif Index: sys/boot/efi/include/string16.h =================================================================== --- /dev/null +++ sys/boot/efi/include/string16.h @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 2016 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 _STRING16_H_ +#define _STRING16_H_ + +#include +#include + +/* + * These are 16-bit variants of string,h functions for use with EFI code. + */ + +extern size_t strlen16(const CHAR16 *str); +extern CHAR16* strdup16(CHAR16 *str); +extern CHAR16* strcpy16(CHAR16 *dst, const CHAR16 *src); +extern CHAR16* stpcpy16(CHAR16 *dst, const CHAR16 *src); +extern CHAR16* strcpy_to_16(CHAR16 *dst, const char *src); +extern char* strcpy_from_16(char *dst, const CHAR16 *src); + +#endif Index: sys/boot/efi/libefi/Makefile =================================================================== --- sys/boot/efi/libefi/Makefile +++ sys/boot/efi/libefi/Makefile @@ -10,8 +10,8 @@ INTERNALLIB= WARNS?= 2 -SRCS= delay.c devpath.c efi_console.c efinet.c efipart.c errno.c \ - handles.c libefi.c +SRCS= delay.c devpath.c efi_console.c efifs.c efinet.c env.c errno.c \ + handles.c libefi.c string16.c .if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" SRCS+= time.c Index: sys/boot/efi/libefi/devpath.c =================================================================== --- sys/boot/efi/libefi/devpath.c +++ sys/boot/efi/libefi/devpath.c @@ -30,35 +30,7 @@ #include #include -/* XXX: This belongs in an efifoo.h header. */ -#define EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID \ - { 0xbc62157e, 0x3e33, 0x4fec, { 0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf } } - -#define EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID \ - { 0x8b843e20, 0x8132, 0x4852, { 0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c } } - -INTERFACE_DECL(_EFI_DEVICE_PATH_PROTOCOL); - -typedef -CHAR16* -(EFIAPI *EFI_DEVICE_PATH_TO_TEXT_NODE) ( - IN struct _EFI_DEVICE_PATH *This, - IN BOOLEAN DisplayOnly, - IN BOOLEAN AllowShortCuts - ); - -typedef -CHAR16* -(EFIAPI *EFI_DEVICE_PATH_TO_TEXT_PATH) ( - IN struct _EFI_DEVICE_PATH *This, - IN BOOLEAN DisplayOnly, - IN BOOLEAN AllowShortCuts - ); - -typedef struct _EFI_DEVICE_PATH_TO_TEXT_PROTOCOL { - EFI_DEVICE_PATH_TO_TEXT_NODE ConvertDeviceNodeToText; - EFI_DEVICE_PATH_TO_TEXT_PATH ConvertDevicePathToText; -} EFI_DEVICE_PATH_TO_TEXT_PROTOCOL; +#include "efidevp.h" static EFI_GUID ImageDevicePathGUID = EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID; Index: sys/boot/efi/libefi/efifs.c =================================================================== --- /dev/null +++ sys/boot/efi/libefi/efifs.c @@ -0,0 +1,524 @@ +/*- + * Copyright (c) 2016 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 + +static EFI_GUID FileInfoGUID = EFI_FILE_INFO_ID;; +static EFI_GUID SimpleFileSystemProtocolGUID = SIMPLE_FILE_SYSTEM_PROTOCOL; +static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; +static EFI_GUID ComponentNameGUID = COMPONENT_NAME2_PROTOCOL; + +static int efifs_open(const char *path, struct open_file *f); +static int efifs_write(struct open_file *f, void *buf, size_t size, size_t *resid); +static int efifs_close(struct open_file *f); +static int efifs_read(struct open_file *f, void *buf, size_t size, size_t *resid); +static off_t efifs_seek(struct open_file *f, off_t offset, int where); +static int efifs_stat(struct open_file *f, struct stat *sb); +static int efifs_readdir(struct open_file *f, struct dirent *d); + +static int efifs_dev_init(void); +static int efifs_dev_strategy(void *, int, daddr_t, size_t, char *, size_t *); +static int efifs_dev_open(struct open_file *, ...); +static int efifs_dev_close(struct open_file *); +static int efifs_dev_print(int); + +struct devsw efifs_dev = { + .dv_name = "EFI", + .dv_type = DEVT_EFI, + .dv_init = efifs_dev_init, + .dv_strategy = efifs_dev_strategy, + .dv_open = efifs_dev_open, + .dv_close = efifs_dev_close, + .dv_ioctl = noioctl, + .dv_print = efifs_dev_print, + .dv_cleanup = NULL +}; + +struct fs_ops efifs_fsops = { + "EFI", + efifs_open, + efifs_close, + efifs_read, + efifs_write, + efifs_seek, + efifs_stat, + efifs_readdir +}; + +static int +efifs_dev_init(void) +{ + EFI_HANDLE *hin; + EFI_STATUS status; + UINTN sz; + u_int n, nin, unit; + int err; + + sz = 0; + hin = NULL; + status = BS->LocateHandle(ByProtocol, &SimpleFileSystemProtocolGUID, + 0, &sz, 0); + if (status == EFI_BUFFER_TOO_SMALL) { + hin = (EFI_HANDLE *)malloc(sz); + status = BS->LocateHandle(ByProtocol, + &SimpleFileSystemProtocolGUID, 0, &sz, hin); + if (EFI_ERROR(status)) + free(hin); + } + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + /* Filter handles to only include FreeBSD partitions. */ + nin = sz / sizeof(EFI_HANDLE); + unit = 0; + + for (n = 0; n < nin; n++) { + status = BS->OpenProtocol(hin[n], &SimpleFileSystemProtocolGUID, + NULL, IH, NULL, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL); + if (EFI_ERROR(status)) + continue; + + efi_handle_update_dev(hin[n], &efifs_dev, unit++, 0); + } + + free(hin); + return (err); +} + + +static int +efifs_dev_print(int verbose) +{ + char line[80]; + CHAR16 *name16; + EFI_COMPONENT_NAME2 *compname; + EFI_DEVICE_PATH *devpath; + EFI_HANDLE h; + EFI_STATUS status; + u_int unit; + + for (unit = 0, h = efi_find_handle(&efifs_dev, 0); + h != NULL; h = efi_find_handle(&efifs_dev, ++unit)) { + sprintf(line, " %s%d:", efifs_dev.dv_name, unit); + pager_output(line); + pager_output(" EFI("); + + /* Try looking up the component name protocol name */ + if(!EFI_ERROR(BS->HandleProtocol(h, &ComponentNameGUID, + (void**)&compname)) && + !EFI_ERROR(compname->GetControllerName(compname, h, NULL, + "en", &name16))) { + char buf[strlen16(name16) + 1]; + + strcpy_from_16(buf, name16); + pager_output(buf); + } else { + pager_output("SIMPLE_FILE_SYSTEM"); + } + + if (verbose) { + status = BS->HandleProtocol(h, &DevicePathGUID, + (void **)&devpath); + if (!EFI_ERROR(status)) { + name16 = efi_devpath_name(devpath); + char buf[strlen16(name16) + 1]; + strcpy_from_16(buf, name16); + + /* Print out the device path if we have one */ + pager_output(", devpath = "); + pager_output(buf); + } + } + + pager_output(")\n"); + } + return (0); +} + +static int +efifs_dev_open(struct open_file *f, ...) +{ + va_list args; + struct devdesc *dev; + EFI_FILE_IO_INTERFACE *fsiface; + EFI_HANDLE h; + EFI_STATUS status; + + va_start(args, f); + dev = va_arg(args, struct devdesc*); + va_end(args); + + h = efi_find_handle(&efifs_dev, dev->d_unit); + + if (h == NULL) + return (EINVAL); + + status = BS->OpenProtocol(h, &SimpleFileSystemProtocolGUID, + (void**)&fsiface, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (EFI_ERROR(status)) { + return (efi_status_to_errno(status)); + } + + dev->d_opendata = fsiface; + return (0); +} + +static int +efifs_dev_close(struct open_file *f) +{ + struct devdesc *dev; + EFI_HANDLE h; + EFI_STATUS status; + + dev = (struct devdesc *)(f->f_devdata); + h = efi_find_handle(&efifs_dev, dev->d_unit); + + if (h == NULL) + return (EINVAL); + + if (dev->d_opendata == NULL) + return (EINVAL); + + status = BS->CloseProtocol(h, &SimpleFileSystemProtocolGUID, IH, NULL); + + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + dev->d_opendata = NULL; + return (0); +} + + +/* Raw I/O isn't supported on EFI FS devices, as they talk through + * SIMPLE_FILE_SYSTEM_INTERFACE. + */ +static int +efifs_dev_strategy(void *devdata __unused, int rw __unused, daddr_t blk __unused, + size_t size __unused, char *buf __unused, + size_t *rsize __unused) +{ + printf("Raw I/O not supported on EFI FS interface\n"); + return ENOTSUP; +} + +/* + * Open a file. + */ +static int +efifs_open(const char *upath, struct open_file *f) +{ + struct devdesc *dev; + EFI_FILE_IO_INTERFACE *fsiface; + EFI_FILE_HANDLE root; + EFI_STATUS status; + CHAR16 path[strlen(upath) + 1]; + + dev = (struct devdesc *)(f->f_devdata); + fsiface = dev->d_opendata; + + if (!strcmp(upath, "") || !strcmp(upath, "/")) { + return (fsiface->OpenVolume(fsiface, + (EFI_FILE_HANDLE*)&(f->f_fsdata))); + } else { + status = fsiface->OpenVolume(fsiface, &root); + + if (EFI_ERROR(status)) { + return (efi_status_to_errno(status)); + } + + strcpy_to_16(path, upath); + status = root->Open(root, (EFI_FILE_HANDLE*)&(f->f_fsdata), path, + EFI_FILE_MODE_READ, 0); + + root->Close(root); + + if (EFI_ERROR(status)) { + return (efi_status_to_errno(status)); + } + + return 0; + } +} + +static int +efifs_close(struct open_file *f) +{ + EFI_FILE_HANDLE file = (EFI_FILE_HANDLE)f->f_fsdata; + EFI_STATUS status; + + status = file->Close(file); + + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + return (0); +} + +static int +efifs_read(struct open_file *f, void *start, size_t size, size_t *resid /* out */) +{ + EFI_FILE_HANDLE file = (EFI_FILE_HANDLE)f->f_fsdata; + UINTN readsize = size; + EFI_STATUS status; + + status = file->Read(file, &readsize, start); + + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + if (resid) + *resid = size - readsize; + + return (0); +} + +static int +efifs_write(struct open_file *f, void *start, size_t size, + size_t *resid /* out */) +{ + EFI_FILE_HANDLE file = (EFI_FILE_HANDLE)f->f_fsdata; + UINTN writesize = size; + EFI_STATUS status; + + status = file->Write(file, &writesize, start); + + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + if (resid) + *resid = size - writesize; + + return (0); +} + +static off_t +efifs_seek(struct open_file *f, off_t offset, int where) +{ + EFI_FILE_HANDLE file = (EFI_FILE_HANDLE)f->f_fsdata; + UINT64 pos; + EFI_STATUS status; + + switch (where) { + case SEEK_SET: + status = file->SetPosition(file, offset); + + if (status != EFI_SUCCESS) { + errno = (efi_status_to_errno(status)); + return -1; + } + + break; + case SEEK_CUR: + status = file->GetPosition(file, &pos); + + if (status != EFI_SUCCESS) { + errno = (efi_status_to_errno(status)); + return -1; + } + + status = file->SetPosition(file, pos + offset); + + if (status != EFI_SUCCESS) { + errno = (efi_status_to_errno(status)); + return -1; + } + + break; + case SEEK_END: + status = file->SetPosition(file, 0xffffffffffffffff); + + if (status != EFI_SUCCESS) { + errno = (efi_status_to_errno(status)); + return -1; + } + default: + errno = EINVAL; + return (-1); + } + + status = file->GetPosition(file, &pos); + + if (status != EFI_SUCCESS) { + errno = (efi_status_to_errno(status)); + return -1; + } + + return (pos); +} + +/* SIMPLE_FILE_SYSTEM_PROTOCOL is geared towards FAT, so we can't + * reproduce stat with absolute fidelity. + */ +static int +efifs_stat(struct open_file *f, struct stat *sb) +{ + EFI_FILE_HANDLE file; + UINTN size = 0; + EFI_FILE_INFO *finfo; + EFI_STATUS status; + + file = (EFI_FILE_HANDLE)f->f_fsdata; + status = file->GetInfo(file, &FileInfoGUID, &size, NULL); + + if (status != EFI_BUFFER_TOO_SMALL) { + errno = (efi_status_to_errno(status)); + return -1; + } + + finfo = malloc(size); + status = file->GetInfo(file, &FileInfoGUID, &size, finfo); + + if (status != EFI_SUCCESS) { + errno = (efi_status_to_errno(status)); + return -1; + } + + /* We can't properly fill these in... */ + sb->st_ino = 0; + sb->st_nlink = 0; + sb->st_uid = 0; + sb->st_gid = 0; + sb->st_blksize = 512; + /* Build the mode field */ + if (finfo->Attribute & EFI_FILE_DIRECTORY) { + sb->st_mode = S_IFDIR; + } else { + sb->st_mode = S_IFREG; + } + + if (finfo->Attribute & EFI_FILE_MODE_READ) { + sb->st_mode = S_IRUSR | S_IXUSR | S_IRGRP | + S_IXGRP | S_IROTH | S_IXOTH; + } + + if (finfo->Attribute & EFI_FILE_MODE_READ) { + sb->st_mode = S_IWUSR | S_IWGRP | S_IWOTH; + } + /* This may or may not be supported, depending on the FS driver */ + sb->st_blocks = finfo->PhysicalSize / 512; + /* These fields we can get right */ + sb->st_size = finfo->FileSize; + sb->st_atime = from_efi_time(&(finfo->LastAccessTime)); + sb->st_mtime = from_efi_time(&(finfo->ModificationTime)); + sb->st_ctime = from_efi_time(&(finfo->CreateTime)); + + free(finfo); + + return (0); +} + +static int +efifs_readdir(struct open_file *f, struct dirent *d) +{ + EFI_FILE_HANDLE dir; + EFI_FILE_HANDLE entry; + UINTN size = 0; + EFI_FILE_INFO *finfo; + EFI_STATUS status; + + dir = (EFI_FILE_HANDLE)f->f_fsdata; + status = dir->Read(dir, &size, NULL); + + if (status != EFI_BUFFER_TOO_SMALL) { + errno = (efi_status_to_errno(status)); + return -1; + } + + if (size == 0) { + return (ENOENT); + } + + finfo = malloc(size); + status = dir->Read(dir, &size, finfo); + + if (status != EFI_SUCCESS) { + errno = (efi_status_to_errno(status)); + return -1; + } + + strcpy_from_16(d->d_name, finfo->FileName); + d->d_namlen = strlen(d->d_name); + d->d_reclen = sizeof(struct dirent); + /* We can't faithfully reproduce this due to the limitations + * of the SIMPLE_FILE_SYSTEM interface */ + d->d_fileno = 0; + + /* The FAT-style interface here forces us to open the file to + * get its attributes. + */ + status = dir->Open(dir, &entry, finfo->FileName, + EFI_FILE_MODE_READ, 0); + free(finfo); + + if (EFI_ERROR(status)) { + printf("Open directory entry failed\n"); + errno = (efi_status_to_errno(status)); + return -1; + } + + size = 0; + status = entry->GetInfo(entry, &FileInfoGUID, &size, NULL); + + if (status != EFI_BUFFER_TOO_SMALL) { + printf("Get finfo size failed\n"); + errno = (efi_status_to_errno(status)); + return -1; + } + + finfo = malloc(size); + status = entry->GetInfo(entry, &FileInfoGUID, &size, finfo); + + if (status != EFI_SUCCESS) { + printf("Get finfo failed\n"); + free(finfo); + errno = (efi_status_to_errno(status)); + return -1; + } + + /* There is some information loss here due to the FAT-based + * EFI_SIMPLE_FILE_SYSTEM interface + */ + if (finfo->Attribute & EFI_FILE_DIRECTORY) { + d->d_type = DT_DIR; + } else { + d->d_type = DT_REG; + } + + free(finfo); + entry->Close(entry); + + return (0); +} Index: sys/boot/efi/libefi/errno.c =================================================================== --- sys/boot/efi/libefi/errno.c +++ sys/boot/efi/libefi/errno.c @@ -30,6 +30,69 @@ #include #include +EFI_STATUS +errno_to_efi_status(int errno) +{ + EFI_STATUS status; + + switch (errno) { + case EPERM: + status = EFI_ACCESS_DENIED; + break; + + case EOVERFLOW: + status = EFI_BUFFER_TOO_SMALL; + break; + + case EIO: + status = EFI_DEVICE_ERROR; + break; + + case EINVAL: + status = EFI_INVALID_PARAMETER; + break; + + case ESTALE: + status = EFI_MEDIA_CHANGED; + break; + + case ENXIO: + status = EFI_NO_MEDIA; + break; + + case ENOENT: + status = EFI_NOT_FOUND; + break; + + case ENOMEM: + status = EFI_OUT_OF_RESOURCES; + break; + + case ENOTSUP: + case ENODEV: + status = EFI_UNSUPPORTED; + break; + + case ENOSPC: + status = EFI_VOLUME_FULL; + break; + + case EACCES: + status = EFI_WRITE_PROTECTED; + break; + + case 0: + status = EFI_SUCCESS; + break; + + default: + status = EFI_DEVICE_ERROR; + break; + } + + return (status); +} + int efi_status_to_errno(EFI_STATUS status) { Index: sys/boot/efi/libefi/handles.c =================================================================== --- sys/boot/efi/libefi/handles.c +++ sys/boot/efi/libefi/handles.c @@ -41,21 +41,36 @@ struct entry *entry; int nentries; +static int +get_next_unit(struct devsw *sw) +{ + int i, idx; + + for (i = 0, idx = 0; i < nentries; i++) { + if (entry[i].dev == sw) { + idx++; + } + } + + return (idx); +} + int efi_register_handles(struct devsw *sw, EFI_HANDLE *handles, EFI_HANDLE *aliases, int count) { size_t sz; - int idx, unit; + int idx, unit, i; idx = nentries; nentries += count; sz = nentries * sizeof(struct entry); + unit = get_next_unit(sw); entry = (entry == NULL) ? malloc(sz) : realloc(entry, sz); - for (unit = 0; idx < nentries; idx++, unit++) { - entry[idx].handle = handles[unit]; + for (i = 0; idx < nentries; idx++, unit++, i++) { + entry[idx].handle = handles[i]; if (aliases != NULL) - entry[idx].alias = aliases[unit]; + entry[idx].alias = aliases[i]; else entry[idx].alias = NULL; entry[idx].dev = sw; @@ -64,6 +79,16 @@ return (0); } +int +efi_register_handle(struct devsw *sw, EFI_HANDLE handle, EFI_HANDLE alias) +{ + if (alias == NULL) { + return efi_register_handles(sw, &handle, NULL, 1); + } else { + return efi_register_handles(sw, &handle, &alias, 1); + } +} + EFI_HANDLE efi_find_handle(struct devsw *dev, int unit) { @@ -116,3 +141,29 @@ return (ENOENT); } + +int +efi_handle_remove_dev(EFI_HANDLE h) +{ + int idx; + + /* Find the entry */ + for (idx = 0; idx < nentries; idx++) { + if (entry[idx].handle != h) + continue; + } + + if (idx >= nentries) + return (ENOENT); + else if (idx == nentries - 1) { + nentries--; + entry = realloc(entry, nentries * sizeof(struct entry)); + } else { + memcpy(entry + idx, entry + idx + 1, + sizeof(struct entry) * (nentries - (idx + 1))); + nentries--; + entry = realloc(entry, nentries * sizeof(struct entry)); + } + + return (0); +} Index: sys/boot/efi/libefi/string16.c =================================================================== --- /dev/null +++ sys/boot/efi/libefi/string16.c @@ -0,0 +1,88 @@ +/*- + * Copyright (c) 2016 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 "string16.h" +#include + +size_t +strlen16(const CHAR16 *str) +{ + size_t i; + + for (i = 0; str[i] != 0; i++); + + return i; +} + +CHAR16 * +strcpy16(CHAR16 *dst, const CHAR16 *src) +{ + stpcpy16(dst, src); + + return (dst); +} + +CHAR16 * +stpcpy16(CHAR16 *dst, const CHAR16 *src) +{ + for (; *src != 0; src++, dst++) { + *dst = *src; + } + + *dst = *src; + + return dst; +} + +char * +strcpy_from_16(char *dst, const CHAR16 *src) +{ + int i; + + for (i = 0; src[i] != 0; i++) { + dst[i] = src[i]; + } + + dst[i] = 0; + + return (dst); +} + +CHAR16 * +strcpy_to_16(CHAR16 *dst, const char *src) +{ + int i; + + for (i = 0; src[i] != 0; i++) { + dst[i] = src[i]; + } + + dst[i] = 0; + + return (dst); +} Index: sys/boot/efi/libefi/time.c =================================================================== --- sys/boot/efi/libefi/time.c +++ sys/boot/efi/libefi/time.c @@ -2,28 +2,28 @@ * Copyright (c) 1999, 2000 * Intel Corporation. * 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. - * + * * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * + * * This product includes software developed by Intel Corporation and * its contributors. - * + * * 4. Neither the name of Intel Corporation or its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION 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 @@ -35,7 +35,7 @@ * 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 @@ -58,6 +58,41 @@ #define SECSPERHOUR ( 60*60 ) #define SECSPERDAY (24 * SECSPERHOUR) +/* +// These arrays give the cumulative number of days up to the first of the +// month number used as the index (1 -> 12) for regular and leap years. +// The value at index 13 is for the whole year. +*/ +static const time_t CumulativeDays[2][14] = { + {0, + 0, + 31, + 31 + 28, + 31 + 28 + 31, + 31 + 28 + 31 + 30, + 31 + 28 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 }, + {0, + 0, + 31, + 31 + 29, + 31 + 29 + 31, + 31 + 29 + 31 + 30, + 31 + 29 + 31 + 30 + 31, + 31 + 29 + 31 + 30 + 31 + 30, + 31 + 29 + 31 + 30 + 31 + 30 + 31, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 }}; + void efi_time_init(void) { @@ -68,45 +103,46 @@ { } -static time_t -efi_time(EFI_TIME *ETime) +void +to_efi_time(EFI_TIME *efi_time, time_t time) { - /* - // These arrays give the cumulative number of days up to the first of the - // month number used as the index (1 -> 12) for regular and leap years. - // The value at index 13 is for the whole year. - */ - static time_t CumulativeDays[2][14] = { - {0, - 0, - 31, - 31 + 28, - 31 + 28 + 31, - 31 + 28 + 31 + 30, - 31 + 28 + 31 + 30 + 31, - 31 + 28 + 31 + 30 + 31 + 30, - 31 + 28 + 31 + 30 + 31 + 30 + 31, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 }, - {0, - 0, - 31, - 31 + 29, - 31 + 29 + 31, - 31 + 29 + 31 + 30, - 31 + 29 + 31 + 30 + 31, - 31 + 29 + 31 + 30 + 31 + 30, - 31 + 29 + 31 + 30 + 31 + 30 + 31, - 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31, - 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30, - 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, - 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, - 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 }}; - - time_t UTime; + if (time >= 0) { + for (efi_time->Year = 1970; + time > CumulativeDays[isleap(efi_time->Year)][13] * SECSPERDAY; + time -= CumulativeDays[isleap(efi_time->Year)][13] * SECSPERDAY, + efi_time->Year++); + + for (efi_time->Month = 0; + time > CumulativeDays[isleap(efi_time->Year)][efi_time->Month] * + SECSPERDAY; + efi_time->Month++); + + time -= CumulativeDays[isleap(efi_time->Year)][efi_time->Month - 1] * + SECSPERDAY; + + for (efi_time->Day = 0; time > SECSPERDAY; + time -= SECSPERDAY, efi_time->Day++); + + for (efi_time->Hour = 0; time > SECSPERHOUR; + time -= SECSPERHOUR, efi_time->Hour++); + + for (efi_time->Minute = 0; time > 60; + time -= 60, efi_time->Minute++); + + efi_time->Second = time; + efi_time->Nanosecond = 0; + efi_time->TimeZone = 0; + efi_time->Daylight = 0; + } else { + memset(efi_time, 0, sizeof(EFI_TIME)); + } +} + +time_t +from_efi_time(EFI_TIME *ETime) +{ + + time_t UTime; int Year; /* @@ -134,7 +170,7 @@ /* // UTime should now be set to 00:00:00 on Jan 1 of the file's year. // - // Months + // Months */ UTime += (CumulativeDays[isleap(ETime->Year)][ETime->Month] * SECSPERDAY); @@ -170,7 +206,7 @@ */ UTime += (ETime->TimeZone * 60); } - + return UTime; } @@ -196,7 +232,7 @@ // Convert to UNIX time (ie seconds since the epoch */ - tp->tv_sec = efi_time( &EfiTime ); + tp->tv_sec = from_efi_time( &EfiTime ); tp->tv_usec = 0; /* EfiTime.Nanosecond * 1000; */ /* @@ -221,7 +257,7 @@ { struct timeval tv; EFI_GetTimeOfDay(&tv, 0); - + if (tloc) *tloc = tv.tv_sec; return tv.tv_sec; Index: sys/boot/efi/loader/Makefile =================================================================== --- sys/boot/efi/loader/Makefile +++ sys/boot/efi/loader/Makefile @@ -50,6 +50,7 @@ CFLAGS+= -I${.CURDIR} CFLAGS+= -I${.CURDIR}/arch/${MACHINE} CFLAGS+= -I${.CURDIR}/../include +CFLAGS+= -I${.CURDIR}/../drivers CFLAGS+= -I${.CURDIR}/../include/${MACHINE} CFLAGS+= -I${.CURDIR}/../../../contrib/dev/acpica/include CFLAGS+= -I${.CURDIR}/../../.. @@ -68,6 +69,8 @@ LIBSTAND= ${.OBJDIR}/../../../../lib/libstand/libstand.a .endif +LIBEFI_DRIVERS= ${.OBJDIR}/../drivers/libefi_drivers.a + .if !defined(BOOT_HIDE_SERIAL_NUMBERS) # Export serial numbers, UUID, and asset tag from loader. CFLAGS+= -DSMBIOS_SERIAL_NUMBERS @@ -147,9 +150,10 @@ LIBEFI= ${.OBJDIR}/../libefi/libefi.a -DPADD= ${LIBFICL} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBSTAND} \ - ${LDSCRIPT} -LDADD= ${LIBFICL} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBSTAND} +DPADD= ${LIBFICL} ${LIBEFI} ${LIBEFI_DRIVERS} ${LIBFDT} ${LIBEFI_FDT} \ + ${LIBSTAND} ${LDSCRIPT} +LDADD= ${LIBFICL} ${LIBEFI} ${LIBEFI_DRIVERS} ${LIBFDT} ${LIBEFI_FDT} \ + ${LIBSTAND} .include Index: sys/boot/efi/loader/conf.c =================================================================== --- sys/boot/efi/loader/conf.c +++ sys/boot/efi/loader/conf.c @@ -31,30 +31,22 @@ #include #include #include -#ifdef EFI_ZFS_BOOT -#include -#endif + +#include "efi_drivers.h" + +const efi_driver_t *efi_drivers[] = { + &fs_driver, + NULL +}; struct devsw *devsw[] = { - &efipart_dev, + &efifs_dev, &efinet_dev, -#ifdef EFI_ZFS_BOOT - &zfs_dev, -#endif NULL }; struct fs_ops *file_system[] = { -#ifdef EFI_ZFS_BOOT - &zfs_fsops, -#endif - &dosfs_fsops, - &ufs_fsops, - &cd9660_fsops, - &tftp_fsops, - &nfs_fsops, - &gzipfs_fsops, - &bzipfs_fsops, + &efifs_fsops, NULL }; Index: sys/boot/efi/loader/loader_efi.h =================================================================== --- sys/boot/efi/loader/loader_efi.h +++ sys/boot/efi/loader/loader_efi.h @@ -33,6 +33,10 @@ #include +#include "efi_drivers.h" + +extern const efi_driver_t *efi_drivers[]; + int efi_autoload(void); int efi_getdev(void **vdev, const char *devspec, const char **path); Index: sys/boot/efi/loader/main.c =================================================================== --- sys/boot/efi/loader/main.c +++ sys/boot/efi/loader/main.c @@ -84,10 +84,6 @@ EFI_GUID fdtdtb = FDT_TABLE_GUID; EFI_GUID inputid = SIMPLE_TEXT_INPUT_PROTOCOL; -#ifdef EFI_ZFS_BOOT -static void efi_zfs_probe(void); -#endif - /* * cpy8to16 copies a traditional C string into a CHAR16 string and * 0 terminates it. len is the size of *dst in bytes. @@ -122,7 +118,7 @@ EFI_HANDLE *hin, *hin_end, *walker; UINTN sz; int retval = 0; - + /* * Find all the handles that support the SIMPLE_TEXT_INPUT_PROTOCOL and * do the typical dance to get the right sized buffer. @@ -179,7 +175,7 @@ } else if (DevicePathType(path) == MESSAGING_DEVICE_PATH && DevicePathSubType(path) == MSG_USB_CLASS_DP) { USB_CLASS_DEVICE_PATH *usb; - + usb = (USB_CLASS_DEVICE_PATH *)(void *)path; if (usb->DeviceClass == 3 && /* HID */ usb->DeviceSubClass == 1 && /* Boot devices */ @@ -260,10 +256,6 @@ 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 /* Init the time source */ efi_time_init(); @@ -388,6 +380,10 @@ /* * March through the device switch probing for things. */ + for (i = 0; efi_drivers[i] != NULL; i++) + if (efi_drivers[i]->init != NULL) + (efi_drivers[i]->init)(); + for (i = 0; devsw[i] != NULL; i++) if (devsw[i]->dv_init != NULL) (devsw[i]->dv_init)(); @@ -422,6 +418,7 @@ if (find_currdev(img, &dev, &unit, &pool_guid) != 0) return (EFI_NOT_FOUND); + printf("Found efi device under %s\n", dev->dv_name); switch (dev->dv_type) { #ifdef EFI_ZFS_BOOT case DEVT_ZFS: { @@ -1088,23 +1085,3 @@ COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); #endif - -#ifdef EFI_ZFS_BOOT -static void -efi_zfs_probe(void) -{ - EFI_HANDLE h; - u_int unit; - int i; - char dname[SPECNAMELEN + 1]; - uint64_t guid; - - unit = 0; - h = efi_find_handle(&efipart_dev, 0); - for (i = 0; h != NULL; h = efi_find_handle(&efipart_dev, ++i)) { - snprintf(dname, sizeof(dname), "%s%d:", efipart_dev.dv_name, i); - if (zfs_probe_dev(dname, &guid) == 0) - (void)efi_handle_update_dev(h, &zfs_dev, unit++, guid); - } -} -#endif Index: sys/boot/zfs/libzfs.h =================================================================== --- sys/boot/zfs/libzfs.h +++ sys/boot/zfs/libzfs.h @@ -67,6 +67,7 @@ int zfs_bootenv(const char *name); int zfs_belist_add(const char *name, uint64_t __unused); int zfs_set_env(void); +int zfs_dev_getdesc(struct zfs_devdesc *dev, char** out); extern struct devsw zfs_dev; extern struct fs_ops zfs_fsops; Index: sys/boot/zfs/zfs.c =================================================================== --- sys/boot/zfs/zfs.c +++ sys/boot/zfs/zfs.c @@ -511,6 +511,31 @@ return (ret); } +int +zfs_dev_getdesc(struct zfs_devdesc *dev, char **out) +{ + char *devname; + spa_t *spa; + int len; + + spa = spa_find_by_guid(dev->pool_guid); + + if (!spa) + return (ENXIO); + + len = strlen(spa->spa_name) + 5; + devname = malloc(len); + + if (devname == NULL) { + return (ENOMEM); + } + + snprintf(devname, len, "zfs:%s", spa->spa_name); + *out = devname; + + return (0); +} + /* * Print information about ZFS pools */ @@ -858,7 +883,7 @@ ctr++; continue; } - + snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index); snprintf(envval, sizeof(envval), "%s", zfs_be->name); rv = setenv(envname, envval, 1); @@ -891,7 +916,7 @@ } } - + for (; zfs_env_index <= ZFS_BE_LAST; zfs_env_index++) { snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index); (void)unsetenv(envname);