Index: sys/boot/efi/boot1/Makefile =================================================================== --- sys/boot/efi/boot1/Makefile +++ sys/boot/efi/boot1/Makefile @@ -3,6 +3,7 @@ MAN= .include +.include # In-tree GCC does not support __attribute__((ms_abi)). .if ${COMPILER_TYPE} != "gcc" @@ -13,13 +14,21 @@ INTERNALPROG= # architecture-specific loader code -SRCS= boot1.c self_reloc.c start.S +SRCS= boot1.c self_reloc.c start.S ufs_module.c +.if ${MK_ZFS} != "no" +SRCS+= zfs_module.c +.endif CFLAGS+= -I. CFLAGS+= -I${.CURDIR}/../include CFLAGS+= -I${.CURDIR}/../include/${MACHINE} CFLAGS+= -I${.CURDIR}/../../../contrib/dev/acpica/include CFLAGS+= -I${.CURDIR}/../../.. +.if ${MK_ZFS} != "no" +CFLAGS+= -I${.CURDIR}/../../zfs/ +CFLAGS+= -I${.CURDIR}/../../../cddl/boot/zfs/ +CFLAGS+= -DZFS_EFI_BOOT +.endif # Always add MI sources and REGULAR efi loader bits .PATH: ${.CURDIR}/../loader/arch/${MACHINE} Index: sys/boot/efi/boot1/boot1.c =================================================================== --- sys/boot/efi/boot1/boot1.c +++ sys/boot/efi/boot1/boot1.c @@ -5,6 +5,8 @@ * 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 are freely * permitted provided that the above copyright notice and this @@ -21,13 +23,14 @@ __FBSDID("$FreeBSD$"); #include -#include #include #include #include #include +#include "boot_module.h" + #define _PATH_LOADER "/boot/loader.efi" #define _PATH_KERNEL "/boot/kernel/kernel" @@ -41,13 +44,19 @@ u_int sp_size; }; -static const char digits[] = "0123456789abcdef"; +static const boot_module_t* const boot_modules[] = +{ +#ifdef ZFS_EFI_BOOT + &zfs_module, +#endif +#ifdef UFS_EFI_BOOT + &ufs_module +#endif +}; -static void panic(const char *fmt, ...) __dead2; -static int printf(const char *fmt, ...); -static int putchar(char c, void *arg); -static int vprintf(const char *fmt, va_list ap); -static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap); +#define NUM_BOOT_MODULES (sizeof(boot_modules) / sizeof(boot_module_t*)) + +static const char digits[] = "0123456789abcdef"; static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap); static int __putc(char c, void *arg); @@ -58,11 +67,112 @@ static int domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet); static void load(const char *fname); +static void try_load(const boot_module_t* mod, const dev_info_t devs[], + size_t ndevs); static EFI_SYSTEM_TABLE *systab; static EFI_HANDLE *image; -static void +void * +Malloc(size_t len, const char *file, int line) +{ + void *out; + + if (systab->BootServices->AllocatePool(EfiLoaderData, + len, &out) != EFI_SUCCESS) { + return (NULL); + } + + return (out); +} + +char * +strcpy(char *dst, const char *src) +{ + int i; + + for (i = 0; src[i]; i++) + dst[i] = src[i]; + dst[i] = '\0'; + + return (dst); +} + +char * +strchr(const char *s, int c) +{ + int i; + + for (i = 0; s[i]; i++) + if (s[i] == c) + return ((char*)(s + i)); + + return (NULL); +} + +int +strncmp(const char *a, const char *b, size_t len) +{ + int i; + + for (i = 0; i < len; i++) { + if (a[i] == '\0' && b[i] == '\0') + return (0); + else if (a[i] < b[i]) + return (-1); + else if (a[i] > b[i]) + return (1); + } + + return (0); +} + +size_t +strlen(const char *s) +{ + size_t len = 0; + + for (; *s != '\0'; s++, len++) + ; + + return (len); +} + +char * +strdup(const char *s) +{ + char *out; + + out = malloc(strlen(s) + 1); + if (out == NULL) + return (NULL); + + strcpy(out, s); + + return (out); +} + +int +bcmp(const void *a, const void *b, size_t len) +{ + const char *sa = a; + const char *sb = b; + int i; + + for (i = 0; i < len; i++) + if (sa[i] != sb[i]) + return (1); + + return (0); +} + +int +memcmp(const void *a, const void *b, size_t len) +{ + return bcmp(a, b, len); +} + +void bcopy(const void *src, void *dst, size_t len) { const char *s = src; @@ -72,22 +182,27 @@ *d++ = *s++; } -static void +void * memcpy(void *dst, const void *src, size_t len) { + bcopy(src, dst, len); + + return (dst); } -static void -bzero(void *b, size_t len) +void * +memset(void *b, int val, size_t len) { char *p = b; while (len-- != 0) - *p++ = 0; + *p++ = val; + + return (b); } -static int +int strcmp(const char *s1, const char *s2) { for (; *s1 == *s2 && *s1; s1++, s2++) @@ -95,30 +210,86 @@ return ((u_char)*s1 - (u_char)*s2); } +int +putchr(char c, void *arg) +{ + 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); + + return (1); +} + static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; -static EFI_BLOCK_IO *bootdev; -static EFI_DEVICE_PATH *bootdevpath; -static EFI_HANDLE *bootdevhandle; +#define MAX_DEVS 128 -EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab) +/* + * This function only returns if it fails to load the kernel. If it + * succeeds, it simply boots the kernel. + */ +void +try_load(const boot_module_t *mod, const dev_info_t devs[], size_t ndevs) { - EFI_HANDLE handles[128]; + int idx; + size_t bufsize; + void *buffer; + EFI_HANDLE loaderhandle; + EFI_LOADED_IMAGE *loaded_image; + + buffer = mod->load(devs, ndevs, _PATH_LOADER, &idx, &bufsize); + if (buffer == NULL) { + printf("Could not load file\n"); + return; + } + + if (systab->BootServices->LoadImage(TRUE, image, devs[idx].devpath, + buffer, bufsize, &loaderhandle) != EFI_SUCCESS) + return; + + if (systab->BootServices->HandleProtocol(loaderhandle, + &LoadedImageGUID, (VOID**)&loaded_image) != EFI_SUCCESS) + return; + + loaded_image->DeviceHandle = devs[idx].devhandle; + + if (systab->BootServices->StartImage(loaderhandle, NULL, NULL) != + EFI_SUCCESS) + return; +} + +void +efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) +{ + EFI_HANDLE handles[MAX_DEVS]; + dev_info_t module_devs[NUM_BOOT_MODULES][MAX_DEVS]; + size_t dev_offsets[NUM_BOOT_MODULES]; EFI_BLOCK_IO *blkio; - UINTN i, nparts = sizeof(handles), cols, rows, max_dim, best_mode; EFI_STATUS status; EFI_DEVICE_PATH *devpath; EFI_BOOT_SERVICES *BS; EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; - char *path = _PATH_LOADER; + UINTN i, j, max_dim, best_mode, cols, rows, nparts; + /* Basic initialization*/ + nparts = sizeof(handles); systab = Xsystab; image = Ximage; + memset(dev_offsets, 0, NUM_BOOT_MODULES * sizeof(size_t)); + + /* Set up the console, so printf works. */ BS = systab->BootServices; status = BS->LocateProtocol(&ConsoleControlGUID, NULL, (VOID **)&ConsoleControl); @@ -132,8 +303,7 @@ conout->Reset(conout, TRUE); max_dim = best_mode = 0; for (i = 0; ; i++) { - status = conout->QueryMode(conout, i, - &cols, &rows); + status = conout->QueryMode(conout, i, &cols, &rows); if (EFI_ERROR(status)) break; if (cols * rows > max_dim) { @@ -146,15 +316,27 @@ conout->EnableCursor(conout, TRUE); conout->ClearScreen(conout); - printf("\n" - ">> FreeBSD EFI boot block\n"); - printf(" Loader path: %s\n", path); + printf("\n>> FreeBSD EFI boot block\n"); + printf(" Loader path: %s\n\n", _PATH_LOADER); + printf(" Initializing modules:"); + for (i = 0; i < NUM_BOOT_MODULES; i++) { + if (boot_modules[i] != NULL) { + printf(" %s", boot_modules[i]->name); + boot_modules[i]->init(image, systab, BS); + } + } + putchr('\n', NULL); + /* Get all the device handles */ status = systab->BootServices->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL, &nparts, handles); nparts /= sizeof(handles[0]); + /* Scan all partitions, probing with all modules. */ for (i = 0; i < nparts; i++) { + dev_info_t devinfo; + + /* Figure out if we're dealing with an actual partition. */ status = systab->BootServices->HandleProtocol(handles[i], &DevicePathGUID, (void **)&devpath); if (EFI_ERROR(status)) @@ -171,180 +353,35 @@ if (!blkio->Media->LogicalPartition) continue; - if (domount(devpath, blkio, 1) >= 0) - break; - } - - if (i == nparts) - panic("No bootable partition found"); - - bootdevhandle = handles[i]; - load(path); - - panic("Load failed"); - - return EFI_SUCCESS; -} - -static int -dskread(void *buf, u_int64_t lba, int nblk) -{ - EFI_STATUS status; - int size; - - lba = lba / (bootdev->Media->BlockSize / DEV_BSIZE); - size = nblk * DEV_BSIZE; - status = bootdev->ReadBlocks(bootdev, bootdev->Media->MediaId, lba, - size, buf); - - if (EFI_ERROR(status)) - return (-1); - - return (0); -} - -#include "ufsread.c" - -static ssize_t -fsstat(ufs_ino_t inode) -{ -#ifndef UFS2_ONLY - static struct ufs1_dinode dp1; - ufs1_daddr_t addr1; -#endif -#ifndef UFS1_ONLY - static struct ufs2_dinode dp2; -#endif - static struct fs fs; - static ufs_ino_t inomap; - char *blkbuf; - void *indbuf; - size_t n, nb, size, off, vboff; - ufs_lbn_t lbn; - ufs2_daddr_t addr2, vbaddr; - static ufs2_daddr_t blkmap, indmap; - u_int u; - - blkbuf = dmadat->blkbuf; - indbuf = dmadat->indbuf; - if (!dsk_meta) { - inomap = 0; - for (n = 0; sblock_try[n] != -1; n++) { - if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE, - SBLOCKSIZE / DEV_BSIZE)) - return -1; - memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); - if (( -#if defined(UFS1_ONLY) - fs.fs_magic == FS_UFS1_MAGIC -#elif defined(UFS2_ONLY) - (fs.fs_magic == FS_UFS2_MAGIC && - fs.fs_sblockloc == sblock_try[n]) -#else - fs.fs_magic == FS_UFS1_MAGIC || - (fs.fs_magic == FS_UFS2_MAGIC && - fs.fs_sblockloc == sblock_try[n]) -#endif - ) && - fs.fs_bsize <= MAXBSIZE && - fs.fs_bsize >= sizeof(struct fs)) - break; - } - if (sblock_try[n] == -1) { - printf("Not ufs\n"); - return -1; + /* Setup devinfo */ + devinfo.dev = blkio; + devinfo.devpath = devpath; + devinfo.devhandle = handles[i]; + devinfo.devdata = NULL; + + /* Run through each module, see if it can load this partition */ + for (j = 0; j < NUM_BOOT_MODULES; j++ ) { + if (boot_modules[j] != NULL && + boot_modules[j]->probe(&devinfo)) { + module_devs[j][dev_offsets[j]++] = devinfo; + } } - dsk_meta++; - } else - memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); - if (!inode) - return 0; - if (inomap != inode) { - n = IPERVBLK(&fs); - if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK)) - return -1; - n = INO_TO_VBO(n, inode); -#if defined(UFS1_ONLY) - memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, - sizeof(struct ufs1_dinode)); -#elif defined(UFS2_ONLY) - memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, - sizeof(struct ufs2_dinode)); -#else - if (fs.fs_magic == FS_UFS1_MAGIC) - memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, - sizeof(struct ufs1_dinode)); - else - memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, - sizeof(struct ufs2_dinode)); -#endif - inomap = inode; - fs_off = 0; - blkmap = indmap = 0; - } - size = DIP(di_size); - n = size - fs_off; - return (n); -} - -static struct dmadat __dmadat; - -static int -domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet) -{ - - dmadat = &__dmadat; - bootdev = blkio; - bootdevpath = device; - if (fsread(0, NULL, 0)) { - if (!quiet) - printf("domount: can't read superblock\n"); - return (-1); } - if (!quiet) - printf("Succesfully mounted UFS filesystem\n"); - return (0); -} - -static void -load(const char *fname) -{ - ufs_ino_t ino; - EFI_STATUS status; - EFI_HANDLE loaderhandle; - EFI_LOADED_IMAGE *loaded_image; - void *buffer; - size_t bufsize; - if ((ino = lookup(fname)) == 0) { - printf("File %s not found\n", fname); - return; + /* + * Select a partition to boot by trying each module in order. + */ + for (i = 0; i < NUM_BOOT_MODULES; i++) { + if (boot_modules[i] == NULL) + continue; + try_load(boot_modules[i], module_devs[i], dev_offsets[i]); } - bufsize = fsstat(ino); - status = systab->BootServices->AllocatePool(EfiLoaderData, - bufsize, &buffer); - fsread(ino, buffer, bufsize); - - /* XXX: For secure boot, we need our own loader here */ - status = systab->BootServices->LoadImage(TRUE, image, bootdevpath, - buffer, bufsize, &loaderhandle); - if (EFI_ERROR(status)) - printf("LoadImage failed with error %lx\n", status); - - status = systab->BootServices->HandleProtocol(loaderhandle, - &LoadedImageGUID, (VOID**)&loaded_image); - if (EFI_ERROR(status)) - printf("HandleProtocol failed with error %lx\n", status); - - loaded_image->DeviceHandle = bootdevhandle; - - status = systab->BootServices->StartImage(loaderhandle, NULL, NULL); - if (EFI_ERROR(status)) - printf("StartImage failed with error %lx\n", status); + /* If we get here, we're out of luck... */ + panic("No bootable partitions found!"); } -static void +void panic(const char *fmt, ...) { char buf[128]; @@ -358,7 +395,7 @@ while (1) {} } -static int +int printf(const char *fmt, ...) { va_list ap; @@ -369,38 +406,17 @@ return 0; va_start(ap, fmt); - ret = vprintf(fmt, ap); + ret = __printf(fmt, putchr, 0, ap); va_end(ap); return (ret); } -static int -putchar(char c, void *arg) -{ - 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); - return (1); -} - -static int -vprintf(const char *fmt, va_list ap) +void vprintf(const char *fmt, va_list ap) { - int ret; - - ret = __printf(fmt, putchar, 0, ap); - return (ret); + __printf(fmt, putchr, 0, ap); } -static int -vsnprintf(char *str, size_t sz, const char *fmt, va_list ap) +int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap) { struct sp_data sp; int ret; @@ -416,15 +432,10 @@ __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap) { char buf[(sizeof(long) * 8) + 1]; - char *nbuf; + char *nbuf, *s; u_long ul; u_int ui; - int lflag; - int sflag; - char *s; - int pad; - int ret; - int c; + int lflag, sflag, pad, ret, c; nbuf = &buf[sizeof buf - 1]; ret = 0; Index: sys/boot/efi/include/efilib.h =================================================================== --- sys/boot/efi/include/efilib.h +++ sys/boot/efi/include/efilib.h @@ -43,7 +43,8 @@ int efi_register_handles(struct devsw *, EFI_HANDLE *, EFI_HANDLE *, int); EFI_HANDLE efi_find_handle(struct devsw *, int); -int efi_handle_lookup(EFI_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_status_to_errno(EFI_STATUS); time_t efi_time(EFI_TIME *); Index: sys/boot/efi/libefi/handles.c =================================================================== --- sys/boot/efi/libefi/handles.c +++ sys/boot/efi/libefi/handles.c @@ -35,6 +35,7 @@ EFI_HANDLE alias; struct devsw *dev; int unit; + uint64_t extra; }; struct entry *entry; @@ -79,7 +80,7 @@ } int -efi_handle_lookup(EFI_HANDLE h, struct devsw **dev, int *unit) +efi_handle_lookup(EFI_HANDLE h, struct devsw **dev, int *unit, uint64_t *extra) { int idx; @@ -90,7 +91,28 @@ *dev = entry[idx].dev; if (unit != NULL) *unit = entry[idx].unit; + if (extra != NULL) + *extra = entry[idx].extra; return (0); } return (ENOENT); } + +int +efi_handle_update_dev(EFI_HANDLE h, struct devsw *dev, int unit, + uint64_t guid) +{ + int idx; + + for (idx = 0; idx < nentries; idx++) { + if (entry[idx].handle != h) + continue; + entry[idx].dev = dev; + entry[idx].unit = unit; + entry[idx].alias = NULL; + entry[idx].extra = guid; + return (0); + } + + return (ENOENT); +} Index: sys/boot/efi/loader/Makefile =================================================================== --- sys/boot/efi/loader/Makefile +++ sys/boot/efi/loader/Makefile @@ -23,6 +23,10 @@ smbios.c \ vers.c +.if ${MK_ZFS} != "no" +SRCS+= ${.CURDIR}/../../zfs/zfs.c +.endif + .PATH: ${.CURDIR}/arch/${MACHINE} # For smbios.c .PATH: ${.CURDIR}/../../i386/libi386 @@ -35,6 +39,11 @@ CFLAGS+= -I${.CURDIR}/../../../contrib/dev/acpica/include CFLAGS+= -I${.CURDIR}/../../.. CFLAGS+= -I${.CURDIR}/../../i386/libi386 +.if ${MK_ZFS} != "no" +CFLAGS+= -I${.CURDIR}/../../zfs +CFLAGS+= -I${.CURDIR}/../../../cddl/boot/zfs +CFLAGS+= -DZFS_EFI_BOOT +.endif CFLAGS+= -DNO_PCI -DEFI # make buildenv doesn't set DESTDIR, this means LIBSTAND @@ -67,7 +76,7 @@ CFLAGS+= -DEFI_STAGING_SIZE=${EFI_STAGING_SIZE} .endif -# Always add MI sources +# Always add MI sources .PATH: ${.CURDIR}/../../common .include "${.CURDIR}/../../common/Makefile.inc" CFLAGS+= -I${.CURDIR}/../../common Index: sys/boot/efi/loader/conf.c =================================================================== --- sys/boot/efi/loader/conf.c +++ sys/boot/efi/loader/conf.c @@ -31,14 +31,23 @@ #include #include #include +#ifdef ZFS_EFI_BOOT +#include "../zfs/libzfs.h" +#endif struct devsw *devsw[] = { &efipart_dev, &efinet_dev, +#ifdef ZFS_EFI_BOOT + &zfs_dev, +#endif NULL }; struct fs_ops *file_system[] = { +#ifdef ZFS_EFI_BOOT + &zfs_fsops, +#endif &dosfs_fsops, &ufs_fsops, &cd9660_fsops, Index: sys/boot/efi/loader/devicename.c =================================================================== --- sys/boot/efi/loader/devicename.c +++ sys/boot/efi/loader/devicename.c @@ -31,14 +31,18 @@ #include #include #include +#include #include "bootstrap.h" +#ifdef ZFS_EFI_BOOT +#include "libzfs.h" +#endif #include #include static int efi_parsedev(struct devdesc **, const char *, const char **); -/* +/* * Point (dev) at an allocated device specifier for the device matching the * path in (devspec). If it contains an explicit device specification, * use that. If not, use the default device. @@ -84,7 +88,7 @@ struct devsw *dv; char *cp; const char *np; - int i, err; + int i; /* minimum length check */ if (strlen(devspec) < 2) @@ -99,24 +103,44 @@ if (devsw[i] == NULL) return (ENOENT); - idev = malloc(sizeof(struct devdesc)); - if (idev == NULL) - return (ENOMEM); - - idev->d_dev = dv; - idev->d_type = dv->dv_type; - idev->d_unit = -1; - - err = 0; np = devspec + strlen(dv->dv_name); - if (*np != '\0' && *np != ':') { - idev->d_unit = strtol(np, &cp, 0); - if (cp == np) { - idev->d_unit = -1; + +#ifdef ZFS_EFI_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 (EUNIT); + 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); + } + } +#ifdef ZFS_EFI_BOOT } +#endif + if (*cp != '\0' && *cp != ':') { free(idev); return (EINVAL); @@ -135,9 +159,13 @@ efi_fmtdev(void *vdev) { struct devdesc *dev = (struct devdesc *)vdev; - static char buf[32]; /* XXX device length constant? */ + static char buf[SPECNAMELEN + 1]; switch(dev->d_type) { +#ifdef ZFS_EFI_BOOT + case DEVT_ZFS: + return (zfs_fmtdev(dev)); +#endif case DEVT_NONE: strcpy(buf, "(no device)"); break; @@ -147,7 +175,7 @@ break; } - return(buf); + return (buf); } /* @@ -161,7 +189,7 @@ rv = efi_parsedev(&ncurr, value, NULL); if (rv != 0) - return(rv); + return (rv); free(ncurr); env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); Index: sys/boot/efi/loader/main.c =================================================================== --- sys/boot/efi/loader/main.c +++ sys/boot/efi/loader/main.c @@ -28,6 +28,7 @@ #include __FBSDID("$FreeBSD$"); +#include #include #include #include @@ -39,13 +40,13 @@ #include #include "loader_efi.h" +#include "libzfs.h" extern char bootprog_name[]; extern char bootprog_rev[]; extern char bootprog_date[]; extern char bootprog_maker[]; -struct devdesc currdev; /* our current device */ struct arch_switch archsw; /* MI/MD interface boundary */ EFI_GUID acpi = ACPI_TABLE_GUID; @@ -61,13 +62,41 @@ EFI_GUID debugimg = DEBUG_IMAGE_INFO_TABLE_GUID; EFI_GUID fdtdtb = FDT_TABLE_GUID; +static void efi_zfs_probe(void); + +/* + * Need this because EFI uses UTF-16 unicode string constants, but we + * use UTF-8. We can't use printf due to the possiblity of \0 and we + * don't support support wide characters either. + */ +static void +print_str16(const CHAR16 *str) +{ + int i; + + for (i = 0; str[i]; i++) + printf("%c", (char)str[i]); +} + EFI_STATUS main(int argc, CHAR16 *argv[]) { char vendor[128]; EFI_LOADED_IMAGE *img; EFI_GUID *guid; - int i; + int i, unit; + struct devsw *dev; + uint64_t pool_guid; + + archsw.arch_autoload = efi_autoload; + archsw.arch_getdev = efi_getdev; + archsw.arch_copyin = efi_copyin; + archsw.arch_copyout = efi_copyout; + archsw.arch_readin = efi_readin; +#ifdef ZFS_EFI_BOOT + /* Note this needs to be set before ZFS init. */ + archsw.arch_zfs_probe = efi_zfs_probe; +#endif /* * XXX Chicken-and-egg problem; we want to have console output @@ -92,6 +121,13 @@ /* Get our loaded image protocol interface structure. */ BS->HandleProtocol(IH, &imgid, (VOID**)&img); + printf("Command line arguments:"); + for (i = 0; i < argc; i++) { + printf(" "); + print_str16(argv[i]); + } + printf("\n"); + printf("Image base: 0x%lx\n", (u_long)img->ImageBase); printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff); @@ -105,9 +141,6 @@ printf("%s, Revision %s\n", bootprog_name, bootprog_rev); printf("(%s, %s)\n", bootprog_maker, bootprog_date); - efi_handle_lookup(img->DeviceHandle, &currdev.d_dev, &currdev.d_unit); - currdev.d_type = currdev.d_dev->dv_type; - /* * Disable the watchdog timer. By default the boot manager sets * the timer to 5 minutes before invoking a boot option. If we @@ -119,18 +152,43 @@ */ BS->SetWatchdogTimer(0, 0, 0, NULL); - env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev), - efi_setcurrdev, env_nounset); - env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset, - env_nounset); + if (efi_handle_lookup(img->DeviceHandle, &dev, &unit, &pool_guid) != 0) + return (EFI_NOT_FOUND); - setenv("LINES", "24", 1); /* optional */ + switch (dev->dv_type) { +#ifdef ZFS_EFI_BOOT + case DEVT_ZFS: { + struct zfs_devdesc currdev; + + currdev.d_dev = dev; + currdev.d_unit = unit; + currdev.d_type = currdev.d_dev->dv_type; + currdev.d_opendata = NULL; + currdev.pool_guid = pool_guid; + currdev.root_guid = 0; + env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev), + efi_setcurrdev, env_nounset); + env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset, + env_nounset); + break; + } +#endif + default: { + struct devdesc currdev; - 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; + currdev.d_dev = dev; + currdev.d_unit = unit; + currdev.d_opendata = NULL; + currdev.d_type = currdev.d_dev->dv_type; + env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev), + efi_setcurrdev, env_nounset); + env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset, + env_nounset); + break; + } + } + + setenv("LINES", "24", 1); /* optional */ for (i = 0; i < ST->NumberOfTableEntries; i++) { guid = &ST->ConfigurationTable[i].VendorGuid; @@ -204,50 +262,47 @@ status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver); if (status != EFI_BUFFER_TOO_SMALL) { printf("Can't determine memory map size\n"); - return CMD_ERROR; + return (CMD_ERROR); } map = malloc(sz); status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver); if (EFI_ERROR(status)) { printf("Can't read memory map\n"); - return CMD_ERROR; + return (CMD_ERROR); } ndesc = sz / dsz; printf("%23s %12s %12s %8s %4s\n", - "Type", "Physical", "Virtual", "#Pages", "Attr"); + "Type", "Physical", "Virtual", "#Pages", "Attr"); for (i = 0, p = map; i < ndesc; - i++, p = NextMemoryDescriptor(p, dsz)) { - printf("%23s %012lx %012lx %08lx ", - types[p->Type], - p->PhysicalStart, - p->VirtualStart, - p->NumberOfPages); - if (p->Attribute & EFI_MEMORY_UC) - printf("UC "); - if (p->Attribute & EFI_MEMORY_WC) - printf("WC "); - if (p->Attribute & EFI_MEMORY_WT) - printf("WT "); - if (p->Attribute & EFI_MEMORY_WB) - printf("WB "); - if (p->Attribute & EFI_MEMORY_UCE) - printf("UCE "); - if (p->Attribute & EFI_MEMORY_WP) - printf("WP "); - if (p->Attribute & EFI_MEMORY_RP) - printf("RP "); - if (p->Attribute & EFI_MEMORY_XP) - printf("XP "); - printf("\n"); + i++, p = NextMemoryDescriptor(p, dsz)) { + printf("%23s %012lx %012lx %08lx ", types[p->Type], + p->PhysicalStart, p->VirtualStart, p->NumberOfPages); + if (p->Attribute & EFI_MEMORY_UC) + printf("UC "); + if (p->Attribute & EFI_MEMORY_WC) + printf("WC "); + if (p->Attribute & EFI_MEMORY_WT) + printf("WT "); + if (p->Attribute & EFI_MEMORY_WB) + printf("WB "); + if (p->Attribute & EFI_MEMORY_UCE) + printf("UCE "); + if (p->Attribute & EFI_MEMORY_WP) + printf("WP "); + if (p->Attribute & EFI_MEMORY_RP) + printf("RP "); + if (p->Attribute & EFI_MEMORY_XP) + printf("XP "); + printf("\n"); } - return CMD_OK; + return (CMD_OK); } -COMMAND_SET(configuration, "configuration", - "print configuration tables", command_configuration); +COMMAND_SET(configuration, "configuration", "print configuration tables", + command_configuration); static const char * guid_to_string(EFI_GUID *guid) @@ -295,7 +350,7 @@ printf(" at %p\n", ST->ConfigurationTable[i].VendorTable); } - return CMD_OK; + return (CMD_OK); } @@ -370,20 +425,17 @@ status = RS->GetNextVariableName(&varsz, NULL, NULL); for (; status != EFI_NOT_FOUND; ) { - status = RS->GetNextVariableName(&varsz, var, - &varguid); + status = RS->GetNextVariableName(&varsz, var, &varguid); //if (EFI_ERROR(status)) //break; conout->OutputString(conout, var); printf("="); datasz = 0; - status = RS->GetVariable(var, &varguid, NULL, &datasz, - NULL); + status = RS->GetVariable(var, &varguid, NULL, &datasz, NULL); /* XXX: check status */ data = malloc(datasz); - status = RS->GetVariable(var, &varguid, NULL, &datasz, - data); + status = RS->GetVariable(var, &varguid, NULL, &datasz, data); if (EFI_ERROR(status)) printf(""); else { @@ -402,6 +454,27 @@ return (CMD_OK); } +COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset", + command_lszfs); + +static int +command_lszfs(int argc, char *argv[]) +{ + int err; + + if (argc != 2) { + command_errmsg = "wrong number of arguments"; + return (CMD_ERROR); + } + + err = zfs_list(argv[1]); + if (err != 0) { + command_errmsg = strerror(err); + return (CMD_ERROR); + } + return (CMD_OK); +} + #ifdef LOADER_FDT_SUPPORT extern int command_fdt_internal(int argc, char *argv[]); @@ -415,8 +488,27 @@ command_fdt(int argc, char *argv[]) { + return (command_fdt_internal(argc, argv)); } COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); #endif + +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); + } +} Index: sys/boot/zfs/zfs.c =================================================================== --- sys/boot/zfs/zfs.c +++ sys/boot/zfs/zfs.c @@ -140,7 +140,7 @@ n = size; if (fp->f_seekp + n > sb.st_size) n = sb.st_size - fp->f_seekp; - + rc = dnode_read(spa, &fp->f_dnode, fp->f_seekp, start, n); if (rc) return (rc); @@ -493,7 +493,7 @@ } } close(pa.fd); - return (0); + return (ret); } /*