From owner-freebsd-hackers@FreeBSD.ORG Fri Apr 17 14:50:18 2015 Return-Path: Delivered-To: freebsd-hackers@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id E22C81C9 for ; Fri, 17 Apr 2015 14:50:17 +0000 (UTC) Received: from mail.metricspace.net (mail.metricspace.net [IPv6:2001:470:1f11:617::103]) by mx1.freebsd.org (Postfix) with ESMTP id 80D13CAF for ; Fri, 17 Apr 2015 14:50:17 +0000 (UTC) Received: from [172.16.1.102] (unknown [172.16.1.102]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (Client did not present a certificate) (Authenticated sender: eric) by mail.metricspace.net (Postfix) with ESMTPSA id 37B882FB27 for ; Fri, 17 Apr 2015 14:50:16 +0000 (UTC) Message-ID: <55311DA7.8080209@metricspace.net> Date: Fri, 17 Apr 2015 10:50:15 -0400 From: Eric McCorkle User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.4.0 MIME-Version: 1.0 To: freebsd-hackers@freebsd.org Subject: Re: ZFS support for EFI References: <55189CBA.9040107@metricspace.net> In-Reply-To: <55189CBA.9040107@metricspace.net> Content-Type: multipart/mixed; boundary="------------030702070506070109040607" X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 17 Apr 2015 14:50:18 -0000 This is a multi-part message in MIME format. --------------030702070506070109040607 Content-Type: text/plain; charset=windows-1252 Content-Transfer-Encoding: 7bit I did some work on this last weekend. I've got the zfs-enabled boot1 loading the ZFS uberblock, but it stops somewhere in the vdev_probe code, believing the block to be a log. I've attached a patch if anyone wants to play around with it. Also, if someone with a UFS system could test that the modularization didn't break UFS functionality, that'd be helpful. On 03/29/2015 08:45 PM, Eric McCorkle wrote: > Hi folks, > > I've been messing around off and on for a while with adding ZFS support > to the EFI boot. It's been mostly exploratory and self-contained up to > this point, but I've gotten to a point that warrants some discussion. > > > First, I've converted boot1.c (the EFI boot block) to use an FS module > framework. This facilitates the addition of ZFS, and should also come > in handy if someone wants to add other functionality later (ie. crypto, > netboot, etc.) > > > More importantly, the EFI loader doesn't seem to make use of its > command-line arguments at all. But a ZFS-enabled loader would really > need the ability to take arguments from boot1 (or grub, or whatever > else). On the boot1 side, with ZFS you need to load and parse > /boot/loader.conf (which may cause you to switch pools), then hand off > the information to loader. In the BIOS loader, that's done through a > binary data object that gets passed in. Command-line strings seem like > the most sensible way to do it with EFI. > > Would this be the right way to go, and if so, what ought these > command-line strings look like? > > > Thanks, > Eric > _______________________________________________ > freebsd-hackers@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/freebsd-hackers > To unsubscribe, send any mail to "freebsd-hackers-unsubscribe@freebsd.org" > --------------030702070506070109040607 Content-Type: text/x-patch; name="zfsefi.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="zfsefi.diff" Index: sys/boot/efi/boot1/Makefile =================================================================== --- sys/boot/efi/boot1/Makefile (revision 281381) +++ sys/boot/efi/boot1/Makefile (working copy) @@ -13,7 +13,7 @@ INTERNALPROG= # architecture-specific loader code -SRCS= boot1.c reloc.c start.S +SRCS= boot1.c reloc.c start.S ufs_module.c zfs_module.c CFLAGS+= -I. CFLAGS+= -I${.CURDIR}/../include @@ -20,6 +20,8 @@ CFLAGS+= -I${.CURDIR}/../include/${MACHINE_CPUARCH} CFLAGS+= -I${.CURDIR}/../../../contrib/dev/acpica/include CFLAGS+= -I${.CURDIR}/../../.. +CFLAGS+= -I${.CURDIR}/../../zfs/ +CFLAGS+= -I${.CURDIR}/../../../cddl/boot/zfs/ # Always add MI sources and REGULAR efi loader bits .PATH: ${.CURDIR}/../loader/arch/${MACHINE_CPUARCH} Index: sys/boot/efi/boot1/boot1.c =================================================================== --- sys/boot/efi/boot1/boot1.c (revision 281381) +++ sys/boot/efi/boot1/boot1.c (working copy) @@ -5,6 +5,8 @@ * All rights reserved. * Copyright (c) 2014 Nathan Whitehorn * All rights reserved. + * Copyright (c) 2014 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,7 +23,6 @@ __FBSDID("$FreeBSD$"); #include -#include #include #include @@ -28,6 +29,8 @@ #include #include +#include "boot_module.h" + #define _PATH_LOADER "/boot/loader.efi" #define _PATH_KERNEL "/boot/kernel/kernel" @@ -41,14 +44,20 @@ u_int sp_size; }; +static const boot_module_t* const boot_modules[] = +{ +#ifdef ZFS_EFI_BOOT + &zfs_module, +#endif +#ifdef UFS_EFI_BOOT + &ufs_module +#endif +}; + +#define NUM_BOOT_MODULES (sizeof(boot_modules) / sizeof(boot_module_t*)) + static const char digits[] = "0123456789abcdef"; -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); - static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap); static int __putc(char c, void *arg); static int __puts(const char *s, putc_func_t *putc, void *arg); @@ -62,9 +71,67 @@ static EFI_SYSTEM_TABLE *systab; static EFI_HANDLE *image; -static void -bcopy(const void *src, void *dst, size_t len) + +void* Malloc(size_t len, const char* file, int line) { + void* out; + printf("Allocating %lu bytes at %s:%d\n", len, file, line); + if (systab->BootServices->AllocatePool(EfiLoaderData, + len, &out) != + EFI_SUCCESS) { + printf("Can't allocate memory pool\n"); + return NULL; + } + printf("Allocated pool at %p\n", out); + return out; +} + +int strncmp(const char *a, const char *b, size_t len) +{ + for (int 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; +} + +char* strdup(const char* s) { + int len; + + for(len = 1; s[len]; len++); + + char* out = malloc(len); + + for(int i = 0; i < len; i++) + out[i] = s[i]; + + return out; +} + +int bcmp(const void *a, const void *b, size_t len) +{ + const char *sa; + const char *sb; + + for (int 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; char *d = dst; @@ -72,23 +139,24 @@ *d++ = *s++; } -static void -memcpy(void *dst, const void *src, size_t len) +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 -strcmp(const char *s1, const char *s2) +int strcmp(const char *s1, const char *s2) { for (; *s1 == *s2 && *s1; s1++, s2++) ; @@ -95,30 +163,50 @@ 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) +void efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab) { - EFI_HANDLE handles[128]; + 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; + UINTN nparts = sizeof(handles); 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; + // Basic initialization systab = Xsystab; image = Ximage; + for(int i = 0; i < NUM_BOOT_MODULES; i++) + { + dev_offsets[i] = 0; + } + + // Set up the console, so printf works. BS = systab->BootServices; status = BS->LocateProtocol(&ConsoleControlGUID, NULL, (VOID **)&ConsoleControl); @@ -128,10 +216,14 @@ /* * Reset the console and find the best text mode. */ + UINTN max_dim; + UINTN best_mode; + UINTN cols; + UINTN rows; conout = systab->ConOut; conout->Reset(conout, TRUE); max_dim = best_mode = 0; - for (i = 0; ; i++) { + for (int i = 0; ; i++) { status = conout->QueryMode(conout, i, &cols, &rows); if (EFI_ERROR(status)) @@ -141,6 +233,7 @@ best_mode = i; } } + if (max_dim > 0) conout->SetMode(conout, best_mode); conout->EnableCursor(conout, TRUE); @@ -147,206 +240,93 @@ conout->ClearScreen(conout); printf("\n" - ">> FreeBSD EFI boot block\n"); - printf(" Loader path: %s\n", path); + ">> FreeBSD ZFS-enabled EFI boot block\n"); + printf(" Loader path: %s\n\n", _PATH_LOADER); + printf(" Initializing modules:"); + for(int i = 0; i < NUM_BOOT_MODULES; i++) + { + if (NULL != boot_modules[i]) + { + 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]); + //printf(" Scanning %lu device handles\n", nparts); - for (i = 0; i < nparts; i++) { + // Scan all partitions, probing with all modules. + for (int 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)) + if (EFI_ERROR(status)) { + //printf(" Not a device path protocol\n"); continue; + } - while (!IsDevicePathEnd(NextDevicePathNode(devpath))) + while (!IsDevicePathEnd(NextDevicePathNode(devpath))) { + //printf(" Advancing to next device\n"); devpath = NextDevicePathNode(devpath); + } status = systab->BootServices->HandleProtocol(handles[i], &BlockIoProtocolGUID, (void **)&blkio); - if (EFI_ERROR(status)) + if (EFI_ERROR(status)) { + //printf(" Not a block device\n"); continue; + } - if (!blkio->Media->LogicalPartition) + if (!blkio->Media->LogicalPartition) { + //printf(" Logical partition\n"); continue; + } - if (domount(devpath, blkio, 1) >= 0) - break; - } + // Setup devinfo + devinfo.dev = blkio; + devinfo.devpath = devpath; + devinfo.devhandle = handles[i]; - 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; - } - 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; + // Run through each module, see if it can load this partition + for (int j = 0; j < NUM_BOOT_MODULES; j++ ) + { + if (NULL != boot_modules[j] && + boot_modules[j]->probe(devinfo)) + { + // If it can, save it to the device list for + // that module + module_devs[j][dev_offsets[j]++] = devinfo; + } + } } - size = DIP(di_size); - n = size - fs_off; - return (n); -} -static struct dmadat __dmadat; + // Select a partition to boot. We do this by trying each + // module in order. + for (int i = 0; i < NUM_BOOT_MODULES; i++) + { + if (NULL != boot_modules[i]) + { + printf(" Trying to load from %lu %s partitions\n", + dev_offsets[i], boot_modules[i]->name); + boot_modules[i]->load(module_devs[i], dev_offsets[i], + _PATH_LOADER); + printf(" Failed\n"); + } + } -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); + // If we get here, we're out of luck... + panic("No bootable partitions found!"); } -static void -load(const char *fname) +void panic(const char *fmt, ...) { - 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; - } - - 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); -} - -static void -panic(const char *fmt, ...) -{ char buf[128]; va_list ap; @@ -358,50 +338,25 @@ while (1) {} } -static int -printf(const char *fmt, ...) +int printf(const char *fmt, ...) { va_list ap; int ret; - /* Don't annoy the user as we probe for partitions */ - if (strcmp(fmt,"Not ufs\n") == 0) - 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) +void vprintf(const char *fmt, va_list ap) { - 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); + __printf(fmt, putchr, 0, ap); } -static int -vprintf(const char *fmt, va_list ap) +int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap) { - int ret; - - ret = __printf(fmt, putchar, 0, ap); - return (ret); -} - -static int -vsnprintf(char *str, size_t sz, const char *fmt, va_list ap) -{ struct sp_data sp; int ret; Index: sys/boot/efi/boot1/boot_module.h =================================================================== --- sys/boot/efi/boot1/boot_module.h (revision 0) +++ sys/boot/efi/boot1/boot_module.h (working copy) @@ -0,0 +1,57 @@ +#ifndef _BOOT_MODULE_H_ +#define _BOOT_MODULE_H_ + +#include + +#include +#include +#include + +#define UFS_EFI_BOOT 1 +#define ZFS_EFI_BOOT 1 + +// EFI device info +typedef struct dev_info_t +{ + EFI_BLOCK_IO *dev; + EFI_DEVICE_PATH *devpath; + EFI_HANDLE *devhandle; +} 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* const name; + + // Initialize the module. + void (* const init)(EFI_HANDLE image, + EFI_SYSTEM_TABLE* systab, + EFI_BOOT_SERVICES *bootsrv); + + // Check to see if curr_dev is a device that this module can handle. + bool (* const probe)(dev_info_t dev); + + // Select the best out of a set of devices that probe indicated were + // loadable, and load it. + void (* const load)(const dev_info_t devs[], + size_t ndevs, + const char* loader_path); +} boot_module_t; + +// Standard boot modules +#ifdef UFS_EFI_BOOT +extern const boot_module_t ufs_module; +#endif +#ifdef ZFS_EFI_BOOT +extern const boot_module_t zfs_module; +#endif + +// Functions available to modules +extern int strcmp(const char *s1, const char *s2); +extern void bcopy(const void *src, void *dst, size_t len); +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); + +#endif Property changes on: sys/boot/efi/boot1/boot_module.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: sys/boot/efi/boot1/ufs_module.c =================================================================== --- sys/boot/efi/boot1/ufs_module.c (revision 0) +++ sys/boot/efi/boot1/ufs_module.c (working copy) @@ -0,0 +1,211 @@ +/*- + * 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 are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + */ +#include +#include + +#include +#include + +#include + +#include "boot_module.h" + +static EFI_HANDLE image; +static EFI_SYSTEM_TABLE* systab; +static EFI_BOOT_SERVICES *bootsrv; +static dev_info_t devinfo; +static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; + +static int +dskread(void *buf, u_int64_t lba, int nblk) +{ + EFI_STATUS status; + int size; + + 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 (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; + } + 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 bool +probe(const dev_info_t dev) +{ + devinfo = dev; + dmadat = &__dmadat; + if (fsread(0, NULL, 0)) { + return 0; + } + return 1; +} + +static void +try_load(const dev_info_t dev, + const char* const loader_path) +{ + ufs_ino_t ino; + EFI_STATUS status; + EFI_HANDLE loaderhandle; + EFI_LOADED_IMAGE *loaded_image; + void *buffer; + size_t bufsize; + + devinfo = dev; + if ((ino = lookup(loader_path)) == 0) { + printf("File %s not found\n", loader_path); + return; + } + + bufsize = fsstat(ino); + status = systab->BootServices->AllocatePool(EfiLoaderData, + bufsize, &buffer); + fsread(ino, buffer, bufsize); + + status = systab->BootServices->LoadImage(TRUE, image, devinfo.devpath, + buffer, bufsize, &loaderhandle); + + status = systab->BootServices->HandleProtocol(loaderhandle, + &LoadedImageGUID, (VOID**)&loaded_image); + loaded_image->DeviceHandle = devinfo.devhandle; + + status = systab->BootServices->StartImage(loaderhandle, NULL, NULL); +} + +static void +load(const dev_info_t devs[], + const size_t ndevs, + const char* const loader_path) +{ + for(int i = 0; i < ndevs; i++) + { + try_load(devs[i], loader_path); + } +} + + +static void init(EFI_HANDLE xImage, + EFI_SYSTEM_TABLE* xSystab, + EFI_BOOT_SERVICES * xBootsrv) +{ + image = xImage; + systab = xSystab; + bootsrv = xBootsrv; +} + +const boot_module_t ufs_module = +{ + .name = "UFS", + .init = init, + .probe = probe, + .load = load +}; Property changes on: sys/boot/efi/boot1/ufs_module.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: sys/boot/efi/boot1/zfs_module.c =================================================================== --- sys/boot/efi/boot1/zfs_module.c (revision 0) +++ sys/boot/efi/boot1/zfs_module.c (working copy) @@ -0,0 +1,237 @@ +/* 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. + * + * 3. Neither the name of the author nor the names of any contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include + +#include +#include +#include + +#include + +#include "boot_module.h" + +#include "libzfs.h" +#include "zfsimpl.c" + +#define PATH_CONFIG "/boot/config" +#define PATH_DOTCONFIG "/boot/.config" + +static EFI_HANDLE image; +static EFI_SYSTEM_TABLE* systab; +static EFI_BOOT_SERVICES *bootsrv; +static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; + +static int +vdev_read(vdev_t * const vdev, + void * const priv, + const off_t off, + void * const buf, + const size_t bytes) +{ + const dev_info_t* const devinfo = (const dev_info_t*) priv; + const off_t lba = off / devinfo->dev->Media->BlockSize; + printf(" Request to read %lu bytes at offset %lu, lba %lu to %p\n", + bytes, off, lba, buf); + const EFI_STATUS status = + devinfo->dev->ReadBlocks(devinfo->dev, + devinfo->dev->Media->MediaId, + lba, bytes, buf); + printf(" Read completed, status %lu\n", status); + if (EFI_ERROR(status)) + return (-1); + + return (0); +} + +static bool probe(dev_info_t dev) +{ + printf(" Probing device for ZFS filesystem\n"); + int result = vdev_probe(vdev_read, &dev, NULL); + + if (result) { + printf(" ZFS probe failed\n"); + } + + return result == 0; +} + +static void try_load(const dev_info_t devinfo, + const char* const loader_path) +{ + spa_t *spa; + struct zfsmount zfsmount; + dnode_phys_t dn; + bool autoboot = true; + + printf(" Attempting ZFS mount..."); + // First, try mounting the ZFS volume + if (zfs_spa_init(spa) != 0 || zfs_mount(spa, 0, &zfsmount) != 0) { + printf("failed\n"); + // Mount failed. Don't report this loudly + return; + } + printf("success\n"); + + //vdev_t * const primary_vdev = spa_get_primary_vdev(spa); + + printf(" Attempting lookup of %s...", loader_path); + if (zfs_lookup(&zfsmount, loader_path, &dn) == 0) { + printf("failed\n"); + return; + } + printf("success\n"); + + printf(" Attempting to stat..."); + struct stat st; + if (zfs_dnode_stat(spa, &dn, &st)) { + printf("Unable to get file statistics\n"); + return; + } + printf("success\n"); + + const size_t bufsize = st.st_size; + void* buffer; + EFI_STATUS status; + EFI_HANDLE loaderhandle; + EFI_LOADED_IMAGE *loaded_image; + + printf(" Attempting to allocate pool of %zu bytes...", bufsize); + if (systab->BootServices->AllocatePool(EfiLoaderData, + bufsize, &buffer) != + EFI_SUCCESS) { + printf("Can't allocate loader pool\n"); + return; + } + printf("success\n"); + + printf(" Attempting to read %zu bytes...", bufsize); + if (dnode_read(spa, &dn, 0, buffer, bufsize) < 0) { + printf("Can't read image\n"); + return; + } + printf("success\n"); + + printf(" Attempting to load image..."); + if (systab->BootServices->LoadImage(TRUE, image, devinfo.devpath, + buffer, bufsize, &loaderhandle) != + EFI_SUCCESS) { + printf("Bad loader image\n"); + return; + } + printf("success\n"); + + printf(" Attempting to prepare image for execution..."); + if (systab->BootServices->HandleProtocol(loaderhandle, + &LoadedImageGUID, + (VOID**)&loaded_image) != + EFI_SUCCESS) { + printf("Failed to prepare loader\n"); + return; + } + printf("success\n"); + + loaded_image->DeviceHandle = devinfo.devhandle; + + printf(" Attempting to execute next stage..."); + // XXX Set up command args first + if (systab->BootServices->StartImage(loaderhandle, NULL, NULL) != + EFI_SUCCESS) { + printf("Failed to execute loader\n"); + return; + } + +} + +static int zfs_mount_ds(const char * const dsname, + struct zfsmount * const zfsmount, + spa_t ** const spa) +{ + uint64_t newroot; + spa_t *newspa; + char *q; + + q = strchr(dsname, '/'); + if (q) + *q++ = '\0'; + newspa = spa_find_by_name(dsname); + if (newspa == NULL) { + printf("\nCan't find ZFS pool %s\n", dsname); + return -1; + } + + if (zfs_spa_init(newspa)) + return -1; + + newroot = 0; + if (q) { + if (zfs_lookup_dataset(newspa, q, &newroot)) { + printf("\nCan't find dataset %s in ZFS pool %s\n", + q, newspa->spa_name); + return -1; + } + } + if (zfs_mount(newspa, newroot, zfsmount)) { + printf("\nCan't mount ZFS dataset\n"); + return -1; + } + *spa = newspa; + return (0); +} + +static void load(const dev_info_t devs[], + const size_t ndevs, + const char* const loader_path) +{ + for(int i = 0; i < ndevs; i++) { + try_load(devs[i], loader_path); + } +} + +static void init(EFI_HANDLE xImage, + EFI_SYSTEM_TABLE* xSystab, + EFI_BOOT_SERVICES * xBootsrv) +{ + image = xImage; + systab = xSystab; + bootsrv = xBootsrv; + zfs_init(); +} + +const boot_module_t zfs_module = +{ + .name = "ZFS", + .init = init, + .probe = probe, + .load = load +}; Property changes on: sys/boot/efi/boot1/zfs_module.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property --------------030702070506070109040607--