Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 23 May 2015 17:45:34 -0400
From:      Eric McCorkle <eric@metricspace.net>
To:        freebsd-hackers@freebsd.org
Subject:   EFI ZFS loader successful load and boot
Message-ID:  <5560F4FE.4030502@metricspace.net>

next in thread | raw e-mail | index | archive | help
This is an OpenPGP/MIME signed message (RFC 4880 and 3156)
--5wXiKkjMGm8L5K77UST2Lh3U5c7DtNFJI
Content-Type: multipart/mixed;
 boundary="------------010602090203020408050102"

This is a multi-part message in MIME format.
--------------010602090203020408050102
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

My work on ZFS support for EFI has now progressed to the point where I
have successfully loaded and booted a kernel.  The patch I have attached
includes modifications to both boot1 and loader.  The modified
loader.efi can be loaded and run by boot1 or an appropriately-configured
GRUB (I've tested with both).

The code is not ready for integration; however, it is at this point
ready for testing.  The following need to be done, IMO, before it can be
considered for integration:

* boot1 completely ignores partition type GUIDs and probes everything.
A notable effect of this are the "Not ufs" messages that show up.

* There is some commented-out code for looking at command-line arguments
in loader.  It turns out I didn't need to do that.

* I (ab)use the EFI pool allocator in a malloc-like fashion, allocating
single objects in boot1.  This might be OK, but someone with more EFI
knowledge should probably comment as to whether or not it is.

* A future refactoring project that might be useful would be to add a
payload field to the end of struct devdesc, similar to what is done with
struct sockaddr.  That way, extended devdesc structures (like
zfs_devdesc) could be handled in the same way that struct sockaddr_in,
etc are.  If you look at my code, there are a couple of places where I
explicitly check for ZFS, and have separate branches that create
zfs_devdesc's


Please apply and test my patch with both UFS and ZFS filesystems.



There is also one other issue, which I think is the fault of my hardware.=
=2E.

When I boot a kernel in EFI mode, it prints info about the EFI console,
then the screen freezes.  However, I can tell that the kernel and OS
finish booting, because functions like suspend-on-lid-close and the
power button work as normal after a while.  However, when waking from
suspend, the screen is just blank.

This resembles an issue I've had with this particular laptop, which I've
reported before on the ACPI list.  Given this as well as basic common
sense, I think it's extremely unlikely that this issue arises as a
result of my modifications to loader.

If anyone out there has a ZFS-based system and can confirm or deny this,
that would be extremely useful information.


Thanks,
Eric

--------------010602090203020408050102
Content-Type: text/x-patch;
 name="zfsefi.diff"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
 filename="zfsefi.diff"

Index: sys/boot/efi/boot1/Makefile
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- sys/boot/efi/boot1/Makefile	(revision 281381)
+++ sys/boot/efi/boot1/Makefile	(working copy)
@@ -13,7 +13,7 @@
 INTERNALPROG=3D
=20
 # architecture-specific loader code
-SRCS=3D	boot1.c reloc.c start.S
+SRCS=3D	boot1.c reloc.c start.S ufs_module.c zfs_module.c
=20
 CFLAGS+=3D	-I.
 CFLAGS+=3D	-I${.CURDIR}/../include
@@ -20,6 +20,8 @@
 CFLAGS+=3D	-I${.CURDIR}/../include/${MACHINE_CPUARCH}
 CFLAGS+=3D	-I${.CURDIR}/../../../contrib/dev/acpica/include
 CFLAGS+=3D	-I${.CURDIR}/../../..
+CFLAGS+=3D	-I${.CURDIR}/../../zfs/
+CFLAGS+=3D	-I${.CURDIR}/../../../cddl/boot/zfs/
=20
 # Always add MI sources and REGULAR efi loader bits
 .PATH:		${.CURDIR}/../loader/arch/${MACHINE_CPUARCH}
Index: sys/boot/efi/boot1/boot1.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- 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$");
=20
 #include <sys/param.h>
-#include <sys/dirent.h>
 #include <machine/elf.h>
 #include <machine/stdarg.h>
=20
@@ -28,6 +29,8 @@
 #include <efi.h>
 #include <eficonsctl.h>
=20
+#include "boot_module.h"
+
 #define _PATH_LOADER	"/boot/loader.efi"
 #define _PATH_KERNEL	"/boot/kernel/kernel"
=20
@@ -41,14 +44,20 @@
 	u_int	sp_size;
 };
=20
+static const boot_module_t* const boot_modules[] =3D
+{
+#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[] =3D "0123456789abcdef";
=20
-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_li=
st ap);
 static int __putc(char c, void *arg);
 static int __puts(const char *s, putc_func_t *putc, void *arg);
@@ -62,9 +71,80 @@
 static EFI_SYSTEM_TABLE *systab;
 static EFI_HANDLE *image;
=20
-static void
-bcopy(const void *src, void *dst, size_t len)
+
+void* Malloc(size_t len, const char* file, int line)
 {
+        void* out;
+        if (systab->BootServices->AllocatePool(EfiLoaderData,
+                                               len, &out) !=3D
+            EFI_SUCCESS) {
+                printf("Can't allocate memory pool\n");
+                return NULL;
+        }
+        return out;
+}
+
+char* strcpy(char* dst, const char* src) {
+        for(int i =3D 0; src[i]; i++)
+                dst[i] =3D src[i];
+
+        return dst;
+}
+
+char* strchr(const char* s, int c) {
+        for(int i =3D 0; s[i]; i++)
+                if (s[i] =3D=3D c)
+                        return (char*)(s + i);
+
+        return NULL;
+}
+
+int strncmp(const char *a, const char *b, size_t len)
+{
+        for (int i =3D 0; i < len; i++)
+                if(a[i] =3D=3D '\0' && b[i] =3D=3D '\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 =3D 1; s[len]; len++);
+
+        char* out =3D malloc(len);
+
+        for(int i =3D 0; i < len; i++)
+                out[i] =3D s[i];
+
+        return out;
+}
+
+int bcmp(const void *a, const void *b, size_t len)
+{
+        const char *sa =3D a;
+        const char *sb =3D b;
+
+        for (int i =3D 0; i < len; i++)
+                if(sa[i] !=3D 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 =3D src;
 	char *d =3D dst;
=20
@@ -72,23 +152,24 @@
 		*d++ =3D *s++;
 }
=20
-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;
 }
=20
-static void
-bzero(void *b, size_t len)
+
+void* memset(void *b, int val, size_t len)
 {
 	char *p =3D b;
=20
 	while (len-- !=3D 0)
-		*p++ =3D 0;
+		*p++ =3D val;
+
+        return b;
 }
=20
-static int
-strcmp(const char *s1, const char *s2)
+int strcmp(const char *s1, const char *s2)
 {
 	for (; *s1 =3D=3D *s2 && *s1; s1++, s2++)
 		;
@@ -95,30 +176,99 @@
 	return ((u_char)*s1 - (u_char)*s2);
 }
=20
+int putchr(char c, void *arg)
+{
+	CHAR16 buf[2];
+
+	if (c =3D=3D '\n') {
+		buf[0] =3D '\r';
+		buf[1] =3D 0;
+		systab->ConOut->OutputString(systab->ConOut, buf);
+	}
+	buf[0] =3D c;
+	buf[1] =3D 0;
+        systab->ConOut->OutputString(systab->ConOut, buf);
+	return (1);
+}
+
 static EFI_GUID BlockIoProtocolGUID =3D BLOCK_IO_PROTOCOL;
 static EFI_GUID DevicePathGUID =3D DEVICE_PATH_PROTOCOL;
+static EFI_GUID ConsoleControlGUID =3D EFI_CONSOLE_CONTROL_PROTOCOL_GUID=
;
 static EFI_GUID LoadedImageGUID =3D LOADED_IMAGE_PROTOCOL;
-static EFI_GUID ConsoleControlGUID =3D EFI_CONSOLE_CONTROL_PROTOCOL_GUID=
;
=20
-static EFI_BLOCK_IO *bootdev;
-static EFI_DEVICE_PATH *bootdevpath;
-static EFI_HANDLE *bootdevhandle;
+#define MAX_DEVS 128
=20
-EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab)
+void try_load(const boot_module_t* const mod,
+              const dev_info_t devs[],
+              size_t ndevs)
 {
-	EFI_HANDLE handles[128];
+        int idx;
+        size_t bufsize;
+        void* const buffer =3D mod->load(devs, ndevs, _PATH_LOADER, &idx=
, &bufsize);
+        EFI_HANDLE loaderhandle;
+        EFI_LOADED_IMAGE *loaded_image;
+
+        if (NULL =3D=3D buffer) {
+                printf("Could not load file\n");
+                return;
+        }
+        //printf("Loaded file %s, image at %p\n"
+        //       "Attempting to load as bootable image...",
+        //       _PATH_LOADER, image);
+        if (systab->BootServices->LoadImage(TRUE, image, devs[idx].devpa=
th,
+                                            buffer, bufsize, &loaderhand=
le) !=3D
+            EFI_SUCCESS) {
+                //printf("failed\n");
+                return;
+        }
+        //printf("success\n"
+        //       "Preparing to execute image...");
+
+        if (systab->BootServices->HandleProtocol(loaderhandle,
+                                                 &LoadedImageGUID,
+                                                 (VOID**)&loaded_image) =
!=3D
+            EFI_SUCCESS) {
+                //printf("failed\n");
+                return;
+        }
+
+        //printf("success\n");
+
+        loaded_image->DeviceHandle =3D  devs[idx].devhandle;
+
+	//printf("Image prepared, attempting to execute\n");
+        // XXX Set up command args first
+        if (systab->BootServices->StartImage(loaderhandle, NULL, NULL) !=
=3D
+            EFI_SUCCESS) {
+                //printf("Failed to execute loader\n");
+                return;
+        }
+        //printf("Shouldn't be here!\n");
+}
+
+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 =3D sizeof(handles), cols, rows, max_dim, best_mode;
+	UINTN nparts =3D sizeof(handles);
 	EFI_STATUS status;
 	EFI_DEVICE_PATH *devpath;
 	EFI_BOOT_SERVICES *BS;
 	EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl =3D NULL;
 	SIMPLE_TEXT_OUTPUT_INTERFACE *conout =3D NULL;
-	char *path =3D _PATH_LOADER;
=20
+        // Basic initialization
 	systab =3D Xsystab;
 	image =3D Ximage;
=20
+        for(int i =3D 0; i < NUM_BOOT_MODULES; i++)
+        {
+                dev_offsets[i] =3D 0;
+        }
+
+        // Set up the console, so printf works.
 	BS =3D systab->BootServices;
 	status =3D BS->LocateProtocol(&ConsoleControlGUID, NULL,
 	    (VOID **)&ConsoleControl);
@@ -128,10 +278,14 @@
 	/*
 	 * Reset the console and find the best text mode.
 	 */
+        UINTN max_dim;
+        UINTN best_mode;
+        UINTN cols;
+        UINTN rows;
 	conout =3D systab->ConOut;
 	conout->Reset(conout, TRUE);
 	max_dim =3D best_mode =3D 0;
-	for (i =3D 0; ; i++) {
+	for (int i =3D 0; ; i++) {
 		status =3D conout->QueryMode(conout, i,
 		    &cols, &rows);
 		if (EFI_ERROR(status))
@@ -141,6 +295,7 @@
 			best_mode =3D i;
 		}
 	}
+
 	if (max_dim > 0)
 		conout->SetMode(conout, best_mode);
 	conout->EnableCursor(conout, TRUE);
@@ -147,206 +302,94 @@
 	conout->ClearScreen(conout);
=20
 	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);
=20
+	printf("   Initializing modules:");
+        for(int i =3D 0; i < NUM_BOOT_MODULES; i++)
+        {
+                if (NULL !=3D 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 =3D systab->BootServices->LocateHandle(ByProtocol,
 	    &BlockIoProtocolGUID, NULL, &nparts, handles);
 	nparts /=3D sizeof(handles[0]);
+	//printf("   Scanning %lu device handles\n", nparts);
=20
-	for (i =3D 0; i < nparts; i++) {
+        // Scan all partitions, probing with all modules.
+	for (int i =3D 0; i < nparts; i++) {
+                dev_info_t devinfo;
+
+                // Figure out if we're dealing with an actual partition
 		status =3D systab->BootServices->HandleProtocol(handles[i],
 		    &DevicePathGUID, (void **)&devpath);
-		if (EFI_ERROR(status))
+		if (EFI_ERROR(status)) {
+                        //printf("        Not a device path protocol\n")=
;
 			continue;
+                }
=20
-		while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
+		while (!IsDevicePathEnd(NextDevicePathNode(devpath))) {
+                        //printf("        Advancing to next device\n");
 			devpath =3D NextDevicePathNode(devpath);
+                }
=20
 		status =3D systab->BootServices->HandleProtocol(handles[i],
 		    &BlockIoProtocolGUID, (void **)&blkio);
-		if (EFI_ERROR(status))
+		if (EFI_ERROR(status)) {
+                        //printf("        Not a block device\n");
 			continue;
+                }
=20
-		if (!blkio->Media->LogicalPartition)
+		if (!blkio->Media->LogicalPartition) {
+                        //printf("        Logical partition\n");
 			continue;
+                }
=20
-		if (domount(devpath, blkio, 1) >=3D 0)
-			break;
-	}
+                // Setup devinfo
+                devinfo.dev =3D blkio;
+                devinfo.devpath =3D devpath;
+                devinfo.devhandle =3D handles[i];
+                devinfo.devdata =3D NULL;
=20
-	if (i =3D=3D nparts)
-		panic("No bootable partition found");
-
-	bootdevhandle =3D 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 =3D lba / (bootdev->Media->BlockSize / DEV_BSIZE);
-	size =3D nblk * DEV_BSIZE;
-	status =3D 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 =3D dmadat->blkbuf;
-	indbuf =3D dmadat->indbuf;
-	if (!dsk_meta) {
-		inomap =3D 0;
-		for (n =3D 0; sblock_try[n] !=3D -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 =3D=3D FS_UFS1_MAGIC
-#elif defined(UFS2_ONLY)
-			    (fs.fs_magic =3D=3D FS_UFS2_MAGIC &&
-			    fs.fs_sblockloc =3D=3D sblock_try[n])
-#else
-			    fs.fs_magic =3D=3D FS_UFS1_MAGIC ||
-			    (fs.fs_magic =3D=3D FS_UFS2_MAGIC &&
-			    fs.fs_sblockloc =3D=3D sblock_try[n])
-#endif
-			    ) &&
-			    fs.fs_bsize <=3D MAXBSIZE &&
-			    fs.fs_bsize >=3D sizeof(struct fs))
-				break;
-		}
-		if (sblock_try[n] =3D=3D -1) {
-			printf("Not ufs\n");
-			return -1;
-		}
-		dsk_meta++;
-	} else
-		memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
-	if (!inode)
-		return 0;
-	if (inomap !=3D inode) {
-		n =3D IPERVBLK(&fs);
-		if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK))
-			return -1;
-		n =3D 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 =3D=3D 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 =3D inode;
-		fs_off =3D 0;
-		blkmap =3D indmap =3D 0;
+                // Run through each module, see if it can load this part=
ition
+                for (int j =3D 0; j < NUM_BOOT_MODULES; j++ )
+                {
+                        if (NULL !=3D 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]++] =3D dev=
info;
+                        }
+                }
 	}
-	size =3D DIP(di_size);
-	n =3D size - fs_off;
-	return (n);
-}
=20
-static struct dmadat __dmadat;
+        // Select a partition to boot.  We do this by trying each
+        // module in order.
+        for (int i =3D 0; i < NUM_BOOT_MODULES; i++)
+        {
+                if (NULL !=3D boot_modules[i])
+                {
+                        //printf("   Trying to load from %lu %s partitio=
ns\n",
+                        //       dev_offsets[i], boot_modules[i]->name);=

+                        try_load(boot_modules[i], module_devs[i],
+                                 dev_offsets[i]);
+                        //printf("   Failed\n");
+                }
+        }
=20
-static int
-domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet)
-{
-
-	dmadat =3D &__dmadat;
-	bootdev =3D blkio;
-	bootdevpath =3D 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!");
 }
=20
-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 =3D lookup(fname)) =3D=3D 0) {
-		printf("File %s not found\n", fname);
-		return;
-	}
-
-	bufsize =3D fsstat(ino);
-	status =3D systab->BootServices->AllocatePool(EfiLoaderData,
-	    bufsize, &buffer);
-	fsread(ino, buffer, bufsize);
-
-	/* XXX: For secure boot, we need our own loader here */
-	status =3D systab->BootServices->LoadImage(TRUE, image, bootdevpath,
-	    buffer, bufsize, &loaderhandle);
-	if (EFI_ERROR(status))
-		printf("LoadImage failed with error %lx\n", status);
-
-	status =3D systab->BootServices->HandleProtocol(loaderhandle,
-	    &LoadedImageGUID, (VOID**)&loaded_image);
-	if (EFI_ERROR(status))
-		printf("HandleProtocol failed with error %lx\n", status);
-
-	loaded_image->DeviceHandle =3D bootdevhandle;
-
-	status =3D 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;
=20
@@ -358,50 +401,25 @@
 	while (1) {}
 }
=20
-static int
-printf(const char *fmt, ...)
+int printf(const char *fmt, ...)
 {
 	va_list ap;
 	int ret;
=20
-	/* Don't annoy the user as we probe for partitions */
-	if (strcmp(fmt,"Not ufs\n") =3D=3D 0)
-		return 0;
=20
 	va_start(ap, fmt);
-	ret =3D vprintf(fmt, ap);
+	ret =3D __printf(fmt, putchr, 0, ap);
 	va_end(ap);
 	return (ret);
 }
=20
-static int
-putchar(char c, void *arg)
+void vprintf(const char *fmt, va_list ap)
 {
-	CHAR16 buf[2];
-
-	if (c =3D=3D '\n') {
-		buf[0] =3D '\r';
-		buf[1] =3D 0;
-		systab->ConOut->OutputString(systab->ConOut, buf);
-	}
-	buf[0] =3D c;
-	buf[1] =3D 0;
-	systab->ConOut->OutputString(systab->ConOut, buf);
-	return (1);
+	__printf(fmt, putchr, 0, ap);
 }
=20
-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 =3D __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;
=20
Index: sys/boot/efi/boot1/boot_module.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- sys/boot/efi/boot1/boot_module.h	(revision 0)
+++ sys/boot/efi/boot1/boot_module.h	(working copy)
@@ -0,0 +1,60 @@
+#ifndef _BOOT_MODULE_H_
+#define _BOOT_MODULE_H_
+
+#include <stdbool.h>
+
+#include <efi.h>
+#include <efilib.h>
+#include <eficonsctl.h>
+
+#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;
+      void *devdata;
+} 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 han=
dle.
+        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,
+                             int* idxref,
+                             size_t* bufsizeref);
+} 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=3D%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
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- sys/boot/efi/boot1/ufs_module.c	(revision 0)
+++ sys/boot/efi/boot1/ufs_module.c	(working copy)
@@ -0,0 +1,210 @@
+/*-
+ * 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 <stdarg.h>
+#include <stdbool.h>
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+
+#include <efi.h>
+
+#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 =3D LOADED_IMAGE_PROTOCOL;
+
+static int
+dskread(void *buf, u_int64_t lba, int nblk)
+{
+	EFI_STATUS status;
+	int size;
+
+	lba =3D lba / (devinfo.dev->Media->BlockSize / DEV_BSIZE);
+	size =3D nblk * DEV_BSIZE;
+	status =3D devinfo.dev->ReadBlocks(devinfo.dev,
+                                         devinfo.dev->Media->MediaId, lb=
a,
+	    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 =3D dmadat->blkbuf;
+	indbuf =3D dmadat->indbuf;
+	if (!dsk_meta) {
+		inomap =3D 0;
+		for (n =3D 0; sblock_try[n] !=3D -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 =3D=3D FS_UFS1_MAGIC
+#elif defined(UFS2_ONLY)
+			    (fs.fs_magic =3D=3D FS_UFS2_MAGIC &&
+			    fs.fs_sblockloc =3D=3D sblock_try[n])
+#else
+			    fs.fs_magic =3D=3D FS_UFS1_MAGIC ||
+			    (fs.fs_magic =3D=3D FS_UFS2_MAGIC &&
+			    fs.fs_sblockloc =3D=3D sblock_try[n])
+#endif
+			    ) &&
+			    fs.fs_bsize <=3D MAXBSIZE &&
+			    fs.fs_bsize >=3D sizeof(struct fs))
+				break;
+		}
+		if (sblock_try[n] =3D=3D -1) {
+			return -1;
+		}
+		dsk_meta++;
+	} else
+		memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
+	if (!inode)
+		return 0;
+	if (inomap !=3D inode) {
+		n =3D IPERVBLK(&fs);
+		if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK))
+			return -1;
+		n =3D 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 =3D=3D 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 =3D inode;
+		fs_off =3D 0;
+		blkmap =3D indmap =3D 0;
+	}
+	size =3D DIP(di_size);
+	n =3D size - fs_off;
+	return (n);
+}
+
+static struct dmadat __dmadat;
+
+static bool
+probe(dev_info_t* const dev)
+{
+        devinfo =3D *dev;
+	dmadat =3D &__dmadat;
+	if (fsread(0, NULL, 0)) {
+		return 0;
+	}
+	return 1;
+}
+
+static void*
+try_load(const dev_info_t dev,
+         const char* const loader_path,
+         size_t* const bufsizeref)
+{
+	ufs_ino_t ino;
+	EFI_STATUS status;
+	void *buffer;
+	size_t bufsize;
+
+        devinfo =3D dev;
+	if ((ino =3D lookup(loader_path)) =3D=3D 0) {
+		printf("File %s not found\n", loader_path);
+		return NULL;
+	}
+
+	bufsize =3D fsstat(ino);
+        *bufsizeref =3D bufsize;
+	status =3D systab->BootServices->AllocatePool(EfiLoaderData,
+	    bufsize, &buffer);
+	fsread(ino, buffer, bufsize);
+        return buffer;
+}
+
+static void*
+load(const dev_info_t devs[],
+     const size_t ndevs,
+     const char* const loader_path,
+     int* const idxref,
+     size_t* const bufsizeref)
+{
+        for(int i =3D 0; i < ndevs; i++)
+        {
+               void* const out =3D try_load(devs[i], loader_path, bufsiz=
eref);
+               if (out !=3D NULL)
+               {
+                       *idxref =3D i;
+                       return out;
+               }
+        }
+        return NULL;
+}
+
+
+static void init(EFI_HANDLE xImage,
+                 EFI_SYSTEM_TABLE* xSystab,
+                 EFI_BOOT_SERVICES * xBootsrv)
+{
+        image =3D xImage;
+        systab =3D xSystab;
+        bootsrv =3D xBootsrv;
+}
+
+const boot_module_t ufs_module =3D
+{
+        .name =3D "UFS",
+        .init =3D init,
+        .probe =3D probe,
+        .load =3D 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=3D%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
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- sys/boot/efi/boot1/zfs_module.c	(revision 0)
+++ sys/boot/efi/boot1/zfs_module.c	(working copy)
@@ -0,0 +1,201 @@
+/* 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 <stddef.h>
+#include <stdarg.h>
+#include <stdbool.h>
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+
+#include <efi.h>
+
+#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 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 =3D (const dev_info_t*) priv;
+        const off_t lba =3D off / devinfo->dev->Media->BlockSize;
+	const EFI_STATUS status =3D
+          devinfo->dev->ReadBlocks(devinfo->dev,
+                                   devinfo->dev->Media->MediaId,
+                                   lba, bytes, buf);
+	if (EFI_ERROR(status))
+		return (-1);
+
+	return (0);
+}
+
+static bool probe(dev_info_t* const dev)
+{
+        spa_t* spa;
+        int result =3D vdev_probe(vdev_read, dev, &spa);
+        dev->devdata =3D spa;
+
+        return result =3D=3D 0;
+}
+
+static void* try_load(const dev_info_t devinfo,
+                      const char* const loader_path,
+                      size_t* const bufsizeref)
+{
+        spa_t *spa =3D devinfo.devdata;
+        struct zfsmount zfsmount;
+        dnode_phys_t dn;
+        bool autoboot =3D true;
+
+        if (zfs_spa_init(spa) !=3D 0) {
+                // Mount failed.  Don't report this loudly
+                return NULL;
+        }
+
+        // First, try mounting the ZFS volume
+        if (zfs_mount(spa, 0, &zfsmount) !=3D 0) {
+                // Mount failed.  Don't report this loudly
+                return NULL;
+        }
+
+        //vdev_t * const primary_vdev =3D spa_get_primary_vdev(spa);
+
+        if (zfs_lookup(&zfsmount, loader_path, &dn) !=3D 0) {
+                return NULL;
+        }
+
+        struct stat st;
+        if (zfs_dnode_stat(spa, &dn, &st)) {
+                return NULL;
+        }
+
+        const size_t bufsize =3D st.st_size;
+        void* buffer;
+        EFI_STATUS status;
+
+        *bufsizeref =3D bufsize;
+
+        if (systab->BootServices->AllocatePool(EfiLoaderData,
+                                               bufsize, &buffer) !=3D
+            EFI_SUCCESS) {
+                return NULL;
+        }
+
+        if (dnode_read(spa, &dn, 0, buffer, bufsize) < 0) {
+                return NULL;
+        }
+
+        return buffer;
+}
+
+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 =3D strchr(dsname, '/');
+        if (q)
+	        *q++ =3D '\0';
+        newspa =3D spa_find_by_name(dsname);
+        if (newspa =3D=3D NULL) {
+	        printf("\nCan't find ZFS pool %s\n", dsname);
+	        return -1;
+        }
+
+        if (zfs_spa_init(newspa))
+                return -1;
+
+        newroot =3D 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 =3D newspa;
+        return (0);
+}
+
+static void* load(const dev_info_t devs[],
+                  const size_t ndevs,
+                  const char* const loader_path,
+                  int* const idxref,
+                  size_t* const bufsizeref)
+{
+        for(int i =3D 0; i < ndevs; i++) {
+                void* const out =3D try_load(devs[i], loader_path, bufsi=
zeref);
+                if (out !=3D NULL)
+                {
+                        *idxref =3D i;
+                        return out;
+                }
+        }
+        return NULL;
+}
+
+static void init(EFI_HANDLE xImage,
+                 EFI_SYSTEM_TABLE* xSystab,
+                 EFI_BOOT_SERVICES * xBootsrv)
+{
+        image =3D xImage;
+        systab =3D xSystab;
+        bootsrv =3D xBootsrv;
+        zfs_init();
+}
+
+const boot_module_t zfs_module =3D
+{
+        .name =3D "ZFS",
+        .init =3D init,
+        .probe =3D probe,
+        .load =3D 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=3D%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/include/efilib.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- sys/boot/efi/include/efilib.h	(revision 281381)
+++ sys/boot/efi/include/efilib.h	(working copy)
@@ -43,7 +43,8 @@
=20
 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 *);
+void efi_handle_update_dev(EFI_HANDLE, struct devsw *, int, uint64_t);
+int efi_handle_lookup(EFI_HANDLE, struct devsw **, int *,  uint64_t *);
=20
 int efi_status_to_errno(EFI_STATUS);
 time_t efi_time(EFI_TIME *);
Index: sys/boot/efi/libefi/handles.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- sys/boot/efi/libefi/handles.c	(revision 281381)
+++ sys/boot/efi/libefi/handles.c	(working copy)
@@ -35,6 +35,7 @@
 	EFI_HANDLE alias;
 	struct devsw *dev;
 	int unit;
+        uint64_t extra;
 };
=20
 struct entry *entry;
@@ -78,8 +79,28 @@
 	return (NULL);
 }
=20
+void efi_handle_update_dev(const EFI_HANDLE handle,
+                           struct devsw * const dev,
+                           int unit,
+                           uint64_t guid)
+{
+	int idx;
+
+	for (idx =3D 0; idx < nentries; idx++) {
+		if (entry[idx].handle !=3D handle)
+			continue;
+		entry[idx].dev =3D dev;
+                entry[idx].unit =3D unit;
+                entry[idx].alias =3D NULL;
+                entry[idx].extra =3D guid;
+	}
+}
+
 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;
=20
@@ -90,6 +111,8 @@
 			*dev =3D entry[idx].dev;
 		if (unit !=3D NULL)
 			*unit =3D entry[idx].unit;
+                if (extra !=3D NULL)
+                        *extra =3D entry[idx].extra;
 		return (0);
 	}
 	return (ENOENT);
Index: sys/boot/efi/loader/Makefile
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- sys/boot/efi/loader/Makefile	(revision 281381)
+++ sys/boot/efi/loader/Makefile	(working copy)
@@ -12,6 +12,8 @@
 PROG=3D		loader.sym
 INTERNALPROG=3D
=20
+#LIBZFSBOOT=3D	${.OBJDIR}/../../zfs/libzfsboot.a
+
 .PATH: ${.CURDIR}/../../efi/loader
 # architecture-specific loader code
 SRCS=3D	autoload.c \
@@ -21,7 +23,8 @@
 	devicename.c \
 	main.c \
 	smbios.c \
-	vers.c
+	vers.c \
+        zfs.c
=20
 .PATH: ${.CURDIR}/arch/${MACHINE_CPUARCH}
 # For smbios.c
@@ -36,6 +39,8 @@
 CFLAGS+=3D	-I${.CURDIR}/../../../contrib/dev/acpica/include
 CFLAGS+=3D	-I${.CURDIR}/../../..
 CFLAGS+=3D	-I${.CURDIR}/../../i386/libi386
+CFLAGS+=3D	-I${.CURDIR}/../../zfs
+CFLAGS+=3D	-I${.CURDIR}/../../../cddl/boot/zfs
 CFLAGS+=3D	-DNO_PCI -DEFI
=20
 .if ${MK_FORTH} !=3D "no"
@@ -62,7 +67,7 @@
 CFLAGS+=3D	-DEFI_STAGING_SIZE=3D${EFI_STAGING_SIZE}
 .endif
=20
-# Always add MI sources=20
+# Always add MI sources
 .PATH:		${.CURDIR}/../../common
 .include	"${.CURDIR}/../../common/Makefile.inc"
 CFLAGS+=3D	-I${.CURDIR}/../../common
@@ -73,7 +78,7 @@
 LDSCRIPT=3D	${.CURDIR}/arch/${MACHINE_CPUARCH}/ldscript.${MACHINE_CPUARC=
H}
 LDFLAGS=3D	-Wl,-T${LDSCRIPT} -Wl,-Bsymbolic -shared -Wl,-znocombreloc
=20
-CLEANFILES=3D	vers.c loader.efi
+CLEANFILES=3D	vers.c loader.efi zfs.c
=20
 NEWVERSWHAT=3D	"EFI loader" ${MACHINE_CPUARCH}
=20
@@ -80,6 +85,9 @@
 vers.c:	${.CURDIR}/../../common/newvers.sh ${.CURDIR}/../../efi/loader/v=
ersion
 	sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT}=

=20
+zfs.c:
+	cp ${.CURDIR}/../../zfs/zfs.c ${.CURDIR}
+
 OBJCOPY?=3D	objcopy
 OBJDUMP?=3D	objdump
=20
@@ -103,9 +111,9 @@
=20
 LIBEFI=3D		${.OBJDIR}/../libefi/libefi.a
=20
-DPADD=3D		${LIBFICL} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBSTAND} \
+DPADD=3D		${LIBFICL} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ../../../../lib/l=
ibstand/libstand.a \
 		${LDSCRIPT}
-LDADD=3D		${LIBFICL} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBSTAND}
+LDADD=3D		${LIBFICL} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ../../../../lib/l=
ibstand/libstand.a
=20
 .endif # ${COMPILER_TYPE} !=3D "gcc"
=20
Index: sys/boot/efi/loader/conf.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- sys/boot/efi/loader/conf.c	(revision 281381)
+++ sys/boot/efi/loader/conf.c	(working copy)
@@ -31,14 +31,17 @@
 #include <bootstrap.h>
 #include <efi.h>
 #include <efilib.h>
+#include "../zfs/libzfs.h"
=20
 struct devsw *devsw[] =3D {
 	&efipart_dev,
 	&efinet_dev,
+        &zfs_dev,
 	NULL
 };
=20
 struct fs_ops *file_system[] =3D {
+        &zfs_fsops,
 	&dosfs_fsops,
 	&ufs_fsops,
 	&cd9660_fsops,
Index: sys/boot/efi/loader/devicename.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- sys/boot/efi/loader/devicename.c	(revision 281381)
+++ sys/boot/efi/loader/devicename.c	(working copy)
@@ -32,6 +32,7 @@
 #include <string.h>
 #include <sys/disklabel.h>
 #include "bootstrap.h"
+#include "libzfs.h"
=20
 #include <efi.h>
 #include <efilib.h>
@@ -38,7 +39,7 @@
=20
 static int efi_parsedev(struct devdesc **, const char *, const char **);=

=20
-/*=20
+/*
  * 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.
@@ -48,7 +49,6 @@
 {
 	struct devdesc **dev =3D (struct devdesc **)vdev;
 	int rv;
-
 	/*
 	 * If it looks like this is just a path and no device, then
 	 * use the current device instead.
@@ -61,7 +61,8 @@
 	}
=20
 	/* Parse the device name off the beginning of the devspec. */
-	return (efi_parsedev(dev, devspec, path));
+	const int out =3D efi_parsedev(dev, devspec, path);
+        return out;
 }
=20
 /*
@@ -87,8 +88,9 @@
 	int i, err;
=20
 	/* minimum length check */
-	if (strlen(devspec) < 2)
+	if (strlen(devspec) < 2) {
 		return (EINVAL);
+        }
=20
 	/* look for a device that matches */
 	for (i =3D 0; devsw[i] !=3D NULL; i++) {
@@ -96,27 +98,39 @@
 		if (!strncmp(devspec, dv->dv_name, strlen(dv->dv_name)))
 			break;
 	}
-	if (devsw[i] =3D=3D NULL)
+	if (devsw[i] =3D=3D NULL) {
 		return (ENOENT);
+        }
+	np =3D devspec + strlen(dv->dv_name);
=20
-	idev =3D malloc(sizeof(struct devdesc));
-	if (idev =3D=3D NULL)
-		return (ENOMEM);
+        if (DEVT_ZFS =3D=3D dv->dv_type) {
+                idev =3D malloc(sizeof(struct zfs_devdesc));
+                int out =3D zfs_parsedev((struct zfs_devdesc*)idev, np, =
path);
+                if (0 =3D=3D out) {
+                        *dev =3D idev;
+                        cp =3D strchr(np + 1, ':');
+                } else {
+                        free(idev);
+                        return out;
+                }
+        } else {
+                idev =3D malloc(sizeof(struct devdesc));
+                if (idev =3D=3D NULL)
+                        return (ENOMEM);
=20
-	idev->d_dev =3D dv;
-	idev->d_type =3D dv->dv_type;
-	idev->d_unit =3D -1;
-
+                idev->d_dev =3D dv;
+                idev->d_type =3D dv->dv_type;
+                idev->d_unit =3D -1;
+                if (*np !=3D '\0' && *np !=3D ':') {
+                        idev->d_unit =3D strtol(np, &cp, 0);
+                        if (cp =3D=3D np) {
+                                idev->d_unit =3D -1;
+                                free(idev);
+                                return (EUNIT);
+                        }
+                }
+        }
 	err =3D 0;
-	np =3D devspec + strlen(dv->dv_name);
-	if (*np !=3D '\0' && *np !=3D ':') {
-		idev->d_unit =3D strtol(np, &cp, 0);
-		if (cp =3D=3D np) {
-			idev->d_unit =3D -1;
-			free(idev);
-			return (EUNIT);
-		}
-	}
 	if (*cp !=3D '\0' && *cp !=3D ':') {
 		free(idev);
 		return (EINVAL);
@@ -138,10 +152,11 @@
 	static char buf[32];	/* XXX device length constant? */
=20
 	switch(dev->d_type) {
+        case DEVT_ZFS:
+                return zfs_fmtdev(dev);
 	case DEVT_NONE:
 		strcpy(buf, "(no device)");
 		break;
-
 	default:
 		sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit);
 		break;
Index: sys/boot/efi/loader/main.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- sys/boot/efi/loader/main.c	(revision 281381)
+++ sys/boot/efi/loader/main.c	(working copy)
@@ -39,6 +39,7 @@
 #include <smbios.h>
=20
 #include "loader_efi.h"
+#include "libzfs.h"
=20
 extern char bootprog_name[];
 extern char bootprog_rev[];
@@ -45,8 +46,9 @@
 extern char bootprog_date[];
 extern char bootprog_maker[];
=20
-struct devdesc currdev;		/* our current device */
-struct arch_switch archsw;	/* MI/MD interface boundary */
+/* our current device */
+/* MI/MD interface boundary */
+struct arch_switch archsw;
=20
 EFI_GUID acpi =3D ACPI_TABLE_GUID;
 EFI_GUID acpi20 =3D ACPI_20_TABLE_GUID;
@@ -60,6 +62,70 @@
 EFI_GUID memtype =3D MEMORY_TYPE_INFORMATION_TABLE_GUID;
 EFI_GUID debugimg =3D DEBUG_IMAGE_INFO_TABLE_GUID;
=20
+static void efi_zfs_probe(void);
+
+static void
+print_str16(const CHAR16* const str)
+{
+        for(int i; str[i]; i++)
+        {
+                printf("%c", str[i]);
+        }
+}
+
+/*
+static int
+str16cmp(const CHAR16 const *a,
+         const char* const b)
+{
+        for(int i =3D 0; a[i] || b[i]; i++)
+        {
+                const CHAR16 achr =3D a[i];
+                const CHAR16 bchr =3D b[i];
+                if (achr < bchr)
+                {
+                        return -1;
+                } else if (achr > bchr)
+                {
+                        return 1;
+                }
+        }
+        return 0;
+}
+
+// Split an arg of the form "argname=3Dargval", replacing the '=3D' with=
 a \0
+static CHAR16*
+split_arg(CHAR16 *const str)
+{
+        for (int i =3D 0; str[i]; i++)
+        {
+                if ('=3D' =3D=3D str[i])
+                {
+                        str[i] =3D 0;
+                        return str + i + 1;
+                }
+        }
+        return NULL;
+}
+
+static void
+handle_arg(CHAR16 *const arg)
+{
+        const CHAR16* const argval =3D split_arg(arg);
+        const CHAR16* const argname =3D arg;
+
+        if (NULL !=3D argval)
+        {
+                printf("Unrecognized argument \"");
+                print_arg(argname);
+                printf("\n");
+        } else {
+                printf("Unrecognized argument \"");
+                print_arg(argname);
+                printf("\n");
+        }
+}
+*/
 EFI_STATUS
 main(int argc, CHAR16 *argv[])
 {
@@ -68,7 +134,15 @@
 	EFI_GUID *guid;
 	int i;
=20
-	/*
+	archsw.arch_autoload =3D efi_autoload;
+	archsw.arch_getdev =3D efi_getdev;
+	archsw.arch_copyin =3D efi_copyin;
+	archsw.arch_copyout =3D efi_copyout;
+	archsw.arch_readin =3D efi_readin;
+        // Note this needs to be set before ZFS init
+        archsw.arch_zfs_probe =3D efi_zfs_probe;
+
+        /*
 	 * XXX Chicken-and-egg problem; we want to have console output
 	 * early, but some console attributes may depend on reading from
 	 * eg. the boot device, which we can't do yet.  We can use
@@ -84,13 +158,22 @@
 	/*
 	 * March through the device switch probing for things.
 	 */
-	for (i =3D 0; devsw[i] !=3D NULL; i++)
-		if (devsw[i]->dv_init !=3D NULL)
+	for (i =3D 0; devsw[i] !=3D NULL; i++) {
+                if (devsw[i]->dv_init !=3D NULL) {
+                        printf("Initializing %s\n", devsw[i]->dv_name);
 			(devsw[i]->dv_init)();
-
+                }
+        }
 	/* Get our loaded image protocol interface structure. */
 	BS->HandleProtocol(IH, &imgid, (VOID**)&img);
=20
+	printf("Command line arguments:");
+        for(i =3D 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);
@@ -104,8 +187,13 @@
 	printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
 	printf("(%s, %s)\n", bootprog_maker, bootprog_date);
=20
-	efi_handle_lookup(img->DeviceHandle, &currdev.d_dev, &currdev.d_unit);
-	currdev.d_type =3D currdev.d_dev->dv_type;
+        // Handle command-line arguments
+        /*
+        for(i =3D 1; i < argc; i++)
+        {
+                handle_arg(argv[i]);
+        }
+        */
=20
 	/*
 	 * Disable the watchdog timer. By default the boot manager sets
@@ -118,19 +206,39 @@
 	 */
 	BS->SetWatchdogTimer(0, 0, 0, NULL);
=20
-	env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev),
-	    efi_setcurrdev, env_nounset);
-	env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset,
-	    env_nounset);
+        struct devsw *dev;
+        int unit;
+        uint64_t pool_guid;
+        efi_handle_lookup(img->DeviceHandle, &dev, &unit, &pool_guid);
+        switch (dev->dv_type) {
+        case DEVT_ZFS: {
+                struct zfs_devdesc currdev;
+                currdev.d_dev =3D dev;
+                currdev.d_unit =3D unit;
+                currdev.d_type =3D currdev.d_dev->dv_type;
+                currdev.d_opendata =3D NULL;
+                currdev.pool_guid =3D pool_guid;
+                currdev.root_guid =3D 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;
+        default: {
+                struct devdesc currdev;
+                currdev.d_dev =3D dev;
+                currdev.d_unit =3D unit;
+                currdev.d_opendata =3D NULL;
+                currdev.d_type =3D 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;
+        }
=20
 	setenv("LINES", "24", 1);	/* optional */
=20
-	archsw.arch_autoload =3D efi_autoload;
-	archsw.arch_getdev =3D efi_getdev;
-	archsw.arch_copyin =3D efi_copyin;
-	archsw.arch_copyout =3D efi_copyout;
-	archsw.arch_readin =3D efi_readin;
-
 	for (i =3D 0; i < ST->NumberOfTableEntries; i++) {
 		guid =3D &ST->ConfigurationTable[i].VendorGuid;
 		if (!memcmp(guid, &smbios, sizeof(EFI_GUID))) {
@@ -347,7 +455,6 @@
 	return (CMD_OK);
 }
=20
-
 COMMAND_SET(nvram, "nvram", "get or set NVRAM variables", command_nvram)=
;
=20
 static int
@@ -399,6 +506,27 @@
 	return (CMD_OK);
 }
=20
+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 !=3D 2) {
+	command_errmsg =3D "wrong number of arguments";
+	return (CMD_ERROR);
+    }
+
+    err =3D zfs_list(argv[1]);
+    if (err !=3D 0) {
+	command_errmsg =3D strerror(err);
+	return (CMD_ERROR);
+    }
+    return (CMD_OK);
+}
+
 #ifdef LOADER_FDT_SUPPORT
 extern int command_fdt_internal(int argc, char *argv[]);
=20
@@ -417,3 +545,23 @@
=20
 COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt);
 #endif
+
+static void
+efi_zfs_probe(void)
+{
+	EFI_BLOCK_IO *blkio;
+	EFI_HANDLE h;
+	EFI_STATUS status;
+	u_int unit =3D 0;
+        char devname[32];
+        uint64_t pool_guid;
+
+	for (int i =3D 0, h =3D efi_find_handle(&efipart_dev, 0);
+	    h !=3D NULL; h =3D efi_find_handle(&efipart_dev, ++i)) {
+                snprintf(devname, sizeof devname, "%s%d:",
+                         efipart_dev.dv_name, i);
+                if(0 =3D=3D zfs_probe_dev(devname, &pool_guid)) {
+                        efi_handle_update_dev(h, &zfs_dev, unit++, pool_=
guid);
+                }
+        }
+}
Index: sys/boot/zfs/zfs.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- sys/boot/zfs/zfs.c	(revision 281381)
+++ sys/boot/zfs/zfs.c	(working copy)
@@ -140,7 +140,7 @@
 	n =3D size;
 	if (fp->f_seekp + n > sb.st_size)
 		n =3D sb.st_size - fp->f_seekp;
-=09
+
 	rc =3D 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);
 }
=20
 /*

--------------010602090203020408050102--

--5wXiKkjMGm8L5K77UST2Lh3U5c7DtNFJI
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: OpenPGP digital signature
Content-Disposition: attachment; filename="signature.asc"

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2

iQIcBAEBAgAGBQJVYPUFAAoJEEGB2s+NNG0FVHgQANAaljoGjvG6spswXKFMfwTI
hAgqpD+zzSNz16BDWCczUMRgX0YWqJjKR3i9oLRvV0oWa4/oKq4iDDlqOAY1Vtjm
f+4gePZl2h0Y8cOk4M7GTM3qMe3+0XfobNmENgSOnwOusBI0eX2Sbn20020tknMp
95TtQ8nAJaQ0ipY3bXD+u9Fq89LSJtc1OiH8i8CcV++QNZ61Vsr7wsGhtTu2jSDN
2lPaVOypAciHNRpJAVX5HPPIxJl53dUb/K3H/E4YFjrmOS7rEwk9Z2KAOwYIIUng
8zriGpn3G2Q1SnhW8OUw/h7+wzZGLbw7dw0GSFvgnx67UypL8K3qJEKYhWbsj0xl
8p6y+r97U+I8nXQ9DMqYSaIYT4WuSvr6S9a2cy897ENZWHAQIvpDMtlpRChGbqmf
dNBA5OPmOF2aJiWHGcJ8PpAHwSzRfq9LrserICWdidqoP43+9g21ySrN0T/kAbWO
go+dFX1W4s0TquraDtJLw5RIDSX3ZSJwzA1m1axecYkmGqP/bdvCZGDsNko014/t
56Z3Lah2tamUxRLKsYhPwQsp4WuXNtD7vImID0NmHIW63lt329+UmhNgCNsj1fvE
ZHdeY9wbrW35GbrmiYAB62/e4kGuLVRAQcnZ2zpEPX/gS3DJrRecLCdxpTFEZL+o
2TbgrNqCGHdRO92a6aAh
=Ubtv
-----END PGP SIGNATURE-----

--5wXiKkjMGm8L5K77UST2Lh3U5c7DtNFJI--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?5560F4FE.4030502>