git: 7313f59b8680 - stable/12 - loader: create single zfs nextboot implementation

From: Kyle Evans <kevans_at_FreeBSD.org>
Date: Fri, 08 Oct 2021 06:10:52 UTC
The branch stable/12 has been updated by kevans:

URL: https://cgit.FreeBSD.org/src/commit/?id=7313f59b868025caa34453591e5d24cd75cd9076

commit 7313f59b868025caa34453591e5d24cd75cd9076
Author:     Toomas Soome <tsoome@FreeBSD.org>
AuthorDate: 2020-06-20 06:23:31 +0000
Commit:     Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2021-10-08 05:24:20 +0000

    loader: create single zfs nextboot implementation
    
    We should have nextboot feature implemented in libsa zfs code.
    To get there, I have created zfs_nextboot() implementation based on
    two sources, our current simple textual string based approach with added
    structured boot label PAD structure from OpenZFS.
    
    Secondly, all nvlist details are moved to separate source file and
    restructured a bit. This is done to provide base support to add nvlist
    add/update feature in followup updates.
    
    And finally, the zfsboot/gptzfsboot disk access functions are swapped to
    use libi386 and libsa.
    
    (cherry picked from commit 3830659e99640001c09d26dfc0e1bbd77d919a62)
    (cherry picked from commit a137f7997efc8a34da75a7643c8fade4be67e82c)
    (cherry picked from commit 4583682ec14cc63f063b6769b7706af1891b0934)
---
 stand/efi/libefi/Makefile        |    2 +
 stand/efi/loader/main.c          |   15 +-
 stand/i386/gptzfsboot/Makefile   |   19 +-
 stand/i386/libi386/Makefile      |    2 +
 stand/i386/zfsboot/Makefile      |   22 +-
 stand/i386/zfsboot/zfsboot.c     | 1158 +++++++++++---------------------------
 stand/libofw/Makefile            |    3 +-
 stand/libsa/zfs/Makefile.inc     |    2 +-
 stand/libsa/zfs/libzfs.h         |   79 ++-
 stand/libsa/zfs/nvlist.c         |  601 ++++++++++++++++++++
 stand/libsa/zfs/zfs.c            |  264 ++++++++-
 stand/libsa/zfs/zfsimpl.c        |  415 ++++----------
 stand/loader.mk                  |    1 +
 stand/sparc64/loader/Makefile    |    3 +
 stand/sparc64/loader/main.c      |    9 +-
 stand/userboot/userboot/Makefile |    1 +
 sys/cddl/boot/zfs/zfsimpl.h      |   35 +-
 sys/vm/vm.h                      |    2 +
 18 files changed, 1446 insertions(+), 1187 deletions(-)

diff --git a/stand/efi/libefi/Makefile b/stand/efi/libefi/Makefile
index 7ca1a1f92fd7..788583215f0b 100644
--- a/stand/efi/libefi/Makefile
+++ b/stand/efi/libefi/Makefile
@@ -47,6 +47,8 @@ CFLAGS+= -I${EFIINC}
 CFLAGS+= -I${EFIINCMD}
 .if ${MK_LOADER_ZFS} != "no"
 CFLAGS+=	-I${ZFSSRC}
+CFLAGS+=	-I${SYSDIR}/cddl/boot/zfs
+CFLAGS+=	-I${SYSDIR}/cddl/contrib/opensolaris/uts/common
 CFLAGS+=	-DEFI_ZFS_BOOT
 .endif
 
diff --git a/stand/efi/loader/main.c b/stand/efi/loader/main.c
index b391f091b1e4..58e5763f14ff 100644
--- a/stand/efi/loader/main.c
+++ b/stand/efi/loader/main.c
@@ -264,6 +264,8 @@ probe_zfs_currdev(uint64_t guid)
 {
 	char *devname;
 	struct zfs_devdesc currdev;
+	char *buf = NULL;
+	bool rv;
 
 	currdev.dd.d_dev = &zfs_dev;
 	currdev.dd.d_unit = 0;
@@ -273,7 +275,18 @@ probe_zfs_currdev(uint64_t guid)
 	devname = efi_fmtdev(&currdev);
 	init_zfs_bootenv(devname);
 
-	return (sanity_check_currdev());
+	rv = sanity_check_currdev();
+	if (rv) {
+		buf = malloc(VDEV_PAD_SIZE);
+		if (buf != NULL) {
+			if (zfs_nextboot(&currdev, buf, VDEV_PAD_SIZE) == 0) {
+				printf("zfs nextboot: %s\n", buf);
+				set_currdev(buf);
+			}
+			free(buf);
+		}
+	}
+	return (rv);
 }
 #endif
 
diff --git a/stand/i386/gptzfsboot/Makefile b/stand/i386/gptzfsboot/Makefile
index fb5c801d8bcd..6aa7464e1503 100644
--- a/stand/i386/gptzfsboot/Makefile
+++ b/stand/i386/gptzfsboot/Makefile
@@ -4,7 +4,7 @@
 
 .PATH:		${BOOTSRC}/i386/boot2 ${BOOTSRC}/i386/gptboot \
 		${BOOTSRC}/i386/zfsboot ${BOOTSRC}/i386/common \
-		${SASRC}
+		${BOOTSRC}/common
 
 FILES=		gptzfsboot
 MAN=		gptzfsboot.8
@@ -19,12 +19,16 @@ ORG2=	0x0
 
 CFLAGS+=-DBOOTPROG=\"gptzfsboot\" \
 	-O1 \
-	-DGPT -DZFS -DBOOT2 \
+	-DBOOT2 \
+	-DLOADER_GPT_SUPPORT \
+	-DLOADER_MBR_SUPPORT \
+	-DLOADER_ZFS_SUPPORT \
 	-DSIOPRT=${BOOT_COMCONSOLE_PORT} \
 	-DSIOFMT=${B2SIOFMT} \
 	-DSIOSPD=${BOOT_COMCONSOLE_SPEED} \
 	-I${LDRSRC} \
 	-I${BOOTSRC}/i386/common \
+	-I${BOOTSRC}/i386/libi386 \
 	-I${ZFSSRC} \
 	-I${SYSDIR}/crypto/skein \
 	-I${SYSDIR}/cddl/boot/zfs \
@@ -60,15 +64,18 @@ gptldr.bin: gptldr.out
 gptldr.out: gptldr.o
 	${LD} ${LD_FLAGS} -e start --defsym ORG=${ORG1} -T ${LDSCRIPT} -o ${.TARGET} gptldr.o
 
-CLEANFILES+=	gptzfsboot.bin gptzfsboot.out zfsboot.o sio.o cons.o \
-		drv.o gpt.o ${OPENCRYPTO_XTS}
+OBJS=	zfsboot.o sio.o cons.o bcache.o devopen.o disk.o part.o zfs_cmd.o
+CLEANFILES+=	gptzfsboot.bin gptzfsboot.out ${OBJS} ${OPENCRYPTO_XTS}
+
+# i386 standalone support library
+LIBI386=	${BOOTOBJ}/i386/libi386/libi386.a
 
 gptzfsboot.bin: gptzfsboot.out
 	${OBJCOPY} -S -O binary gptzfsboot.out ${.TARGET}
 
-gptzfsboot.out: ${BTXCRT} zfsboot.o sio.o gpt.o drv.o cons.o \
+gptzfsboot.out: ${BTXCRT} ${OBJS} \
 	${OPENCRYPTO_XTS}
-	${LD} ${LD_FLAGS} --defsym ORG=${ORG2} -T ${LDSCRIPT} -o ${.TARGET} ${.ALLSRC} ${LIBSA32}
+	${LD} ${LD_FLAGS} --defsym ORG=${ORG2} -T ${LDSCRIPT} -o ${.TARGET} ${.ALLSRC} ${LIBI386} ${LIBSA32}
 
 zfsboot.o: ${ZFSSRC}/zfsimpl.c
 
diff --git a/stand/i386/libi386/Makefile b/stand/i386/libi386/Makefile
index 75e6448ca717..f3bec563ff48 100644
--- a/stand/i386/libi386/Makefile
+++ b/stand/i386/libi386/Makefile
@@ -33,6 +33,8 @@ CFLAGS+= -Dalloca=__builtin_alloca
 
 CFLAGS+=	-I${BOOTSRC}/ficl -I${BOOTSRC}/ficl/i386 \
 		-I${LDRSRC} -I${BOOTSRC}/i386/common \
+		-I${SYSDIR}/cddl/boot/zfs \
+		-I${SYSDIR}/cddl/contrib/opensolaris/uts/common \
 		-I${SYSDIR}/contrib/dev/acpica/include
 
 # Handle FreeBSD specific %b and %D printf format specifiers
diff --git a/stand/i386/zfsboot/Makefile b/stand/i386/zfsboot/Makefile
index 80303cb8fde0..8c0527848478 100644
--- a/stand/i386/zfsboot/Makefile
+++ b/stand/i386/zfsboot/Makefile
@@ -2,7 +2,7 @@
 
 .include <bsd.init.mk>
 
-.PATH:		${BOOTSRC}/i386/boot2 ${BOOTSRC}/i386/common ${SASRC}
+.PATH:		${BOOTSRC}/i386/boot2 ${BOOTSRC}/i386/common ${BOOTSRC}/common
 
 FILES=		zfsboot
 MAN=		zfsboot.8
@@ -17,13 +17,17 @@ ORG2=	0x2000
 
 CFLAGS+=-DBOOTPROG=\"zfsboot\" \
 	-O1 \
-	-DZFS -DBOOT2 \
+	-DBOOT2 \
+	-DLOADER_GPT_SUPPORT \
+	-DLOADER_MBR_SUPPORT \
+	-DLOADER_ZFS_SUPPORT \
+	-DLOADER_UFS_SUPPORT \
 	-DSIOPRT=${BOOT_COMCONSOLE_PORT} \
 	-DSIOFMT=${B2SIOFMT} \
 	-DSIOSPD=${BOOT_COMCONSOLE_SPEED} \
 	-I${LDRSRC} \
 	-I${BOOTSRC}/i386/common \
-	-I${BOOTSRC}/i386 \
+	-I${BOOTSRC}/i386/libi386 \
 	-I${ZFSSRC} \
 	-I${SYSDIR}/crypto/skein \
 	-I${SYSDIR}/cddl/boot/zfs \
@@ -34,6 +38,8 @@ CFLAGS+=-DBOOTPROG=\"zfsboot\" \
 	-Wmissing-declarations -Wmissing-prototypes -Wnested-externs \
 	-Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings
 
+CFLAGS.part.c+= -DHAVE_MEMCPY -I${SRCTOP}/sys/contrib/zlib
+
 CFLAGS.gcc+=	--param max-inline-insns-single=100
 
 LD_FLAGS+=${LD_FLAGS_BIN}
@@ -51,14 +57,18 @@ zfsboot1: zfsldr.out
 zfsldr.out: zfsldr.o
 	${LD} ${LD_FLAGS} -e start --defsym ORG=${ORG1} -T ${LDSCRIPT} -o ${.TARGET} zfsldr.o
 
+OBJS=	zfsboot.o sio.o cons.o bcache.o devopen.o disk.o part.o zfs_cmd.o
 CLEANFILES+=	zfsboot2 zfsboot.ld zfsboot.ldr zfsboot.bin zfsboot.out \
-		zfsboot.o zfsboot.s zfsboot.s.tmp sio.o cons.o drv.o
+		${OBJS}
 
 # We currently allow 256k bytes for zfsboot - in practice it could be
 # any size up to 3.5Mb but keeping it fixed size simplifies zfsldr.
 # 
 BOOT2SIZE=	262144
 
+# i386 standalone support library
+LIBI386=	${BOOTOBJ}/i386/libi386/libi386.a
+
 zfsboot2: zfsboot.ld
 	@set -- `ls -l ${.ALLSRC}`; x=$$((${BOOT2SIZE}-$$5)); \
 	    echo "$$x bytes available"; test $$x -ge 0
@@ -74,8 +84,8 @@ zfsboot.ldr:
 zfsboot.bin: zfsboot.out
 	${OBJCOPY} -S -O binary zfsboot.out ${.TARGET}
 
-zfsboot.out: ${BTXCRT} zfsboot.o sio.o drv.o cons.o
-	${LD} ${LD_FLAGS} --defsym ORG=${ORG2} -T ${LDSCRIPT} -o ${.TARGET} ${.ALLSRC} ${LIBSA32}
+zfsboot.out: ${BTXCRT} ${OBJS}
+	${LD} ${LD_FLAGS} --defsym ORG=${ORG2} -T ${LDSCRIPT} -o ${.TARGET} ${.ALLSRC} ${LIBI386} ${LIBSA32}
 
 SRCS=	zfsboot.c
 
diff --git a/stand/i386/zfsboot/zfsboot.c b/stand/i386/zfsboot/zfsboot.c
index a51c69267fbc..e387d4a47c9d 100644
--- a/stand/i386/zfsboot/zfsboot.c
+++ b/stand/i386/zfsboot/zfsboot.c
@@ -16,7 +16,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-#include "stand.h"
+#include <stand.h>
 
 #include <sys/param.h>
 #include <sys/errno.h>
@@ -35,15 +35,16 @@ __FBSDID("$FreeBSD$");
 #include <stddef.h>
 
 #include <a.out.h>
-
+#include "bootstrap.h"
+#include "libi386.h"
 #include <btxv86.h>
 
 #include "lib.h"
 #include "rbx.h"
-#include "drv.h"
-#include "edd.h"
 #include "cons.h"
 #include "bootargs.h"
+#include "disk.h"
+#include "part.h"
 #include "paths.h"
 
 #include "libzfs.h"
@@ -61,13 +62,8 @@ __FBSDID("$FreeBSD$");
 #define	TYPE_MAXHARD		TYPE_DA
 #define	TYPE_FD			2
 
-#define	DEV_GELIBOOT_BSIZE	4096
-
 extern uint32_t _end;
 
-#ifdef GPT
-static const uuid_t freebsd_zfs_uuid = GPT_ENT_TYPE_FREEBSD_ZFS;
-#endif
 static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */
 static const unsigned char flags[NOPT] = {
     RBX_DUAL,
@@ -107,785 +103,153 @@ static const struct string {
 
 static const unsigned char dev_maj[NDEV] = {30, 4, 2};
 
+static struct i386_devdesc *bdev;
 static char cmd[512];
 static char cmddup[512];
 static char kname[1024];
-static char rootname[256];
 static int comspeed = SIOSPD;
 static struct bootinfo bootinfo;
 static uint32_t bootdev;
 static struct zfs_boot_args zfsargs;
+#ifdef LOADER_GELI_SUPPORT
+static struct geli_boot_args geliargs;
+#endif
 
-vm_offset_t	high_heap_base;
-uint32_t	bios_basemem, bios_extmem, high_heap_size;
-
-static struct bios_smap smap;
-
-/*
- * The minimum amount of memory to reserve in bios_extmem for the heap.
- */
-#define	HEAP_MIN		(64 * 1024 * 1024)
-
-static char *heap_next;
-static char *heap_end;
+extern vm_offset_t high_heap_base;
+extern uint32_t	bios_basemem, bios_extmem, high_heap_size;
 
-/* Buffers that must not span a 64k boundary. */
-#define	READ_BUF_SIZE		8192
-struct dmadat {
-	char rdbuf[READ_BUF_SIZE];	/* for reading large things */
-	char secbuf[READ_BUF_SIZE];	/* for MBR/disklabel */
-};
-static struct dmadat *dmadat;
+static char *heap_top;
+static char *heap_bottom;
 
 void exit(int);
-void reboot(void);
+static void i386_zfs_probe(void);
 static void load(void);
 static int parse_cmd(void);
-static void bios_getmem(void);
-int main(void);
 
 #ifdef LOADER_GELI_SUPPORT
 #include "geliboot.h"
 static char gelipw[GELI_PW_MAXLEN];
 #endif
 
-struct zfsdsk {
-	struct dsk	dsk;
-#ifdef LOADER_GELI_SUPPORT
-	struct geli_dev	*gdev;
+struct arch_switch archsw;	/* MI/MD interface boundary */
+static char boot_devname[2 * ZFS_MAXNAMELEN + 8]; /* disk or pool:dataset */
+
+struct devsw *devsw[] = {
+	&bioshd,
+#if defined(LOADER_ZFS_SUPPORT)
+	&zfs_dev,
 #endif
+	NULL
 };
 
-#include "zfsimpl.c"
-
-/*
- * Read from a dnode (which must be from a ZPL filesystem).
- */
-static int
-zfs_read(spa_t *spa, const dnode_phys_t *dnode, off_t *offp, void *start,
-    size_t size)
-{
-	const znode_phys_t *zp = (const znode_phys_t *) dnode->dn_bonus;
-	size_t n;
-	int rc;
-
-	n = size;
-	if (*offp + n > zp->zp_size)
-		n = zp->zp_size - *offp;
-
-	rc = dnode_read(spa, dnode, *offp, start, n);
-	if (rc)
-		return (-1);
-	*offp += n;
-
-	return (n);
-}
-
-/*
- * Current ZFS pool
- */
-static spa_t *spa;
-static spa_t *primary_spa;
-static vdev_t *primary_vdev;
-
-/*
- * A wrapper for dskread that doesn't have to worry about whether the
- * buffer pointer crosses a 64k boundary.
- */
-static int
-vdev_read(void *xvdev, void *priv, off_t off, void *buf, size_t bytes)
-{
-	char *p;
-	daddr_t lba, alignlba;
-	off_t diff;
-	unsigned int nb, alignnb;
-	struct zfsdsk *zdsk = priv;
-
-	if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1)))
-		return (-1);
-
-	p = buf;
-	lba = off / DEV_BSIZE;
-	lba += zdsk->dsk.start;
-	/*
-	 * Align reads to 4k else 4k sector GELIs will not decrypt.
-	 * Round LBA down to nearest multiple of DEV_GELIBOOT_BSIZE bytes.
-	 */
-	alignlba = rounddown2(off, DEV_GELIBOOT_BSIZE) / DEV_BSIZE;
-	/*
-	 * The read must be aligned to DEV_GELIBOOT_BSIZE bytes relative to the
-	 * start of the GELI partition, not the start of the actual disk.
-	 */
-	alignlba += zdsk->dsk.start;
-	diff = (lba - alignlba) * DEV_BSIZE;
-
-	while (bytes > 0) {
-		nb = bytes / DEV_BSIZE;
-		/*
-		 * Ensure that the read size plus the leading offset does not
-		 * exceed the size of the read buffer.
-		 */
-		if (nb > (READ_BUF_SIZE - diff) / DEV_BSIZE)
-			nb = (READ_BUF_SIZE - diff) / DEV_BSIZE;
-		/*
-		 * Round the number of blocks to read up to the nearest multiple
-		 * of DEV_GELIBOOT_BSIZE.
-		 */
-		alignnb = roundup2(nb * DEV_BSIZE + diff, DEV_GELIBOOT_BSIZE)
-		    / DEV_BSIZE;
-
-		if (zdsk->dsk.size > 0 && alignlba + alignnb >
-		    zdsk->dsk.size + zdsk->dsk.start) {
-			printf("Shortening read at %lld from %d to %lld\n",
-			    alignlba, alignnb,
-			    (zdsk->dsk.size + zdsk->dsk.start) - alignlba);
-			alignnb = (zdsk->dsk.size + zdsk->dsk.start) - alignlba;
-		}
-
-		if (drvread(&zdsk->dsk, dmadat->rdbuf, alignlba, alignnb))
-			return (-1);
-#ifdef LOADER_GELI_SUPPORT
-		/* decrypt */
-		if (zdsk->gdev != NULL) {
-			if (geli_read(zdsk->gdev,
-			    ((alignlba - zdsk->dsk.start) * DEV_BSIZE),
-			    dmadat->rdbuf, alignnb * DEV_BSIZE))
-				return (-1);
-		}
+struct fs_ops *file_system[] = {
+#if defined(LOADER_ZFS_SUPPORT)
+	&zfs_fsops,
 #endif
-		memcpy(p, dmadat->rdbuf + diff, nb * DEV_BSIZE);
-		p += nb * DEV_BSIZE;
-		lba += nb;
-		alignlba += alignnb;
-		bytes -= nb * DEV_BSIZE;
-		/* Don't need the leading offset after the first block. */
-		diff = 0;
-	}
-
-	return (0);
-}
-/* Match the signature exactly due to signature madness */
-static int
-vdev_read2(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes)
-{
-	return (vdev_read(vdev, priv, off, buf, bytes));
-}
-
-
-static int
-vdev_write(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes)
-{
-	char *p;
-	daddr_t lba;
-	unsigned int nb;
-	struct zfsdsk *zdsk = priv;
-
-	if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1)))
-		return (-1);
-
-	p = buf;
-	lba = off / DEV_BSIZE;
-	lba += zdsk->dsk.start;
-	while (bytes > 0) {
-		nb = bytes / DEV_BSIZE;
-		if (nb > READ_BUF_SIZE / DEV_BSIZE)
-			nb = READ_BUF_SIZE / DEV_BSIZE;
-		memcpy(dmadat->rdbuf, p, nb * DEV_BSIZE);
-		if (drvwrite(&zdsk->dsk, dmadat->rdbuf, lba, nb))
-			return (-1);
-		p += nb * DEV_BSIZE;
-		lba += nb;
-		bytes -= nb * DEV_BSIZE;
-	}
-
-	return (0);
-}
-
-static int
-xfsread(const dnode_phys_t *dnode, off_t *offp, void *buf, size_t nbyte)
-{
-	if ((size_t)zfs_read(spa, dnode, offp, buf, nbyte) != nbyte) {
-		printf("Invalid format\n");
-		return (-1);
-	}
-	return (0);
-}
-
-/*
- * Read Pad2 (formerly "Boot Block Header") area of the first
- * vdev label of the given vdev.
- */
-static int
-vdev_read_pad2(vdev_t *vdev, char *buf, size_t size)
-{
-	blkptr_t bp;
-	char *tmp;
-	off_t off = offsetof(vdev_label_t, vl_pad2);
-	int rc;
-
-	if (size > VDEV_PAD_SIZE)
-		size = VDEV_PAD_SIZE;
-
-	tmp = malloc(VDEV_PAD_SIZE);
-	if (tmp == NULL)
-		return (ENOMEM);
-
-	BP_ZERO(&bp);
-	BP_SET_LSIZE(&bp, VDEV_PAD_SIZE);
-	BP_SET_PSIZE(&bp, VDEV_PAD_SIZE);
-	BP_SET_CHECKSUM(&bp, ZIO_CHECKSUM_LABEL);
-	BP_SET_COMPRESS(&bp, ZIO_COMPRESS_OFF);
-	DVA_SET_OFFSET(BP_IDENTITY(&bp), off);
-	rc = vdev_read_phys(vdev, &bp, tmp, off, 0);
-	if (rc == 0)
-		memcpy(buf, tmp, size);
-	free(tmp);
-	return (rc);
-}
-
-static int
-vdev_clear_pad2(vdev_t *vdev)
-{
-	char *zeroes;
-	uint64_t *end;
-	off_t off = offsetof(vdev_label_t, vl_pad2);
-	int rc;
-
-	zeroes = malloc(VDEV_PAD_SIZE);
-	if (zeroes == NULL)
-		return (ENOMEM);
-
-	memset(zeroes, 0, VDEV_PAD_SIZE);
-	end = (uint64_t *)(zeroes + VDEV_PAD_SIZE);
-	/* ZIO_CHECKSUM_LABEL magic and pre-calcualted checksum for all zeros */
-	end[-5] = 0x0210da7ab10c7a11;
-	end[-4] = 0x97f48f807f6e2a3f;
-	end[-3] = 0xaf909f1658aacefc;
-	end[-2] = 0xcbd1ea57ff6db48b;
-	end[-1] = 0x6ec692db0d465fab;
-	rc = vdev_write(vdev, vdev->v_read_priv, off, zeroes, VDEV_PAD_SIZE);
-	free(zeroes);
-	return (rc);
-}
-
-static void
-bios_getmem(void)
-{
-	uint64_t size;
-
-	/* Parse system memory map */
-	v86.ebx = 0;
-	do {
-		v86.ctl = V86_FLAGS;
-		v86.addr = 0x15;		/* int 0x15 function 0xe820 */
-		v86.eax = 0xe820;
-		v86.ecx = sizeof(struct bios_smap);
-		v86.edx = SMAP_SIG;
-		v86.es = VTOPSEG(&smap);
-		v86.edi = VTOPOFF(&smap);
-		v86int();
-		if (V86_CY(v86.efl) || (v86.eax != SMAP_SIG))
-			break;
-		/* look for a low-memory segment that's large enough */
-		if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) &&
-		    (smap.length >= (512 * 1024)))
-			bios_basemem = smap.length;
-		/* look for the first segment in 'extended' memory */
-		if ((smap.type == SMAP_TYPE_MEMORY) &&
-		    (smap.base == 0x100000)) {
-			bios_extmem = smap.length;
-		}
-
-		/*
-		 * Look for the largest segment in 'extended' memory beyond
-		 * 1MB but below 4GB.
-		 */
-		if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base > 0x100000) &&
-		    (smap.base < 0x100000000ull)) {
-			size = smap.length;
-
-			/*
-			 * If this segment crosses the 4GB boundary,
-			 * truncate it.
-			 */
-			if (smap.base + size > 0x100000000ull)
-				size = 0x100000000ull - smap.base;
-
-			if (size > high_heap_size) {
-				high_heap_size = size;
-				high_heap_base = smap.base;
-			}
-		}
-	} while (v86.ebx != 0);
-
-	/* Fall back to the old compatibility function for base memory */
-	if (bios_basemem == 0) {
-		v86.ctl = 0;
-		v86.addr = 0x12;		/* int 0x12 */
-		v86int();
-
-		bios_basemem = (v86.eax & 0xffff) * 1024;
-	}
-
-	/*
-	 * Fall back through several compatibility functions for extended
-	 * memory.
-	 */
-	if (bios_extmem == 0) {
-		v86.ctl = V86_FLAGS;
-		v86.addr = 0x15;		/* int 0x15 function 0xe801 */
-		v86.eax = 0xe801;
-		v86int();
-		if (!V86_CY(v86.efl)) {
-			bios_extmem = ((v86.ecx & 0xffff) +
-			    ((v86.edx & 0xffff) * 64)) * 1024;
-		}
-	}
-	if (bios_extmem == 0) {
-		v86.ctl = 0;
-		v86.addr = 0x15;		/* int 0x15 function 0x88 */
-		v86.eax = 0x8800;
-		v86int();
-		bios_extmem = (v86.eax & 0xffff) * 1024;
-	}
-
-	/*
-	 * If we have extended memory and did not find a suitable heap
-	 * region in the SMAP, use the last 3MB of 'extended' memory as a
-	 * high heap candidate.
-	 */
-	if (bios_extmem >= HEAP_MIN && high_heap_size < HEAP_MIN) {
-		high_heap_size = HEAP_MIN;
-		high_heap_base = bios_extmem + 0x100000 - HEAP_MIN;
-	}
-}
-
-/*
- * Try to detect a device supported by the legacy int13 BIOS
- */
-static int
-int13probe(int drive)
-{
-	v86.ctl = V86_FLAGS;
-	v86.addr = 0x13;
-	v86.eax = 0x800;
-	v86.edx = drive;
-	v86int();
-
-	if (!V86_CY(v86.efl) &&				/* carry clear */
-	    ((v86.edx & 0xff) != (drive & DRV_MASK))) {	/* unit # OK */
-		if ((v86.ecx & 0x3f) == 0) {		/* absurd sector size */
-			return (0);			/* skip device */
-		}
-		return (1);
-	}
-	return (0);
-}
-
-/*
- * We call this when we find a ZFS vdev - ZFS consumes the dsk
- * structure so we must make a new one.
- */
-static struct zfsdsk *
-copy_dsk(struct zfsdsk *zdsk)
-{
-	struct zfsdsk *newdsk;
-
-	newdsk = malloc(sizeof(struct zfsdsk));
-	*newdsk = *zdsk;
-	return (newdsk);
-}
-
-/*
- * Get disk size from GPT.
- */
-static uint64_t
-drvsize_gpt(struct dsk *dskp)
-{
-#ifdef GPT
-	struct gpt_hdr hdr;
-	char *sec;
-
-	sec = dmadat->secbuf;
-	if (drvread(dskp, sec, 1, 1))
-		return (0);
-
-	memcpy(&hdr, sec, sizeof(hdr));
-	if (memcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) != 0 ||
-	    hdr.hdr_lba_self != 1 || hdr.hdr_revision < 0x00010000 ||
-	    hdr.hdr_entsz < sizeof(struct gpt_ent) ||
-	    DEV_BSIZE % hdr.hdr_entsz != 0) {
-		return (0);
-	}
-	return (hdr.hdr_lba_alt + 1);
-#else
-	return (0);
+#if defined(LOADER_UFS_SUPPORT)
+	&ufs_fsops,
 #endif
-}
-
-/*
- * Get disk size from eax=0x800 and 0x4800. We need to probe both
- * because 0x4800 may not be available and we would like to get more
- * or less correct disk size - if it is possible at all.
- * Note we do not really want to touch drv.c because that code is shared
- * with boot2 and we can not afford to grow that code.
- */
-static uint64_t
-drvsize_ext(struct zfsdsk *zdsk)
-{
-	struct dsk *dskp;
-	uint64_t size, tmp;
-	int cyl, hds, sec;
-
-	dskp = &zdsk->dsk;
-
-	/* Try to read disk size from GPT */
-	size = drvsize_gpt(dskp);
-	if (size != 0)
-		return (size);
-
-	v86.ctl = V86_FLAGS;
-	v86.addr = 0x13;
-	v86.eax = 0x800;
-	v86.edx = dskp->drive;
-	v86int();
-
-	/* Don't error out if we get bad sector number, try EDD as well */
-	if (V86_CY(v86.efl) ||	/* carry set */
-	    (v86.edx & 0xff) <= (unsigned)(dskp->drive & 0x7f)) /* unit # bad */
-		return (0);
-	cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1;
-	/* Convert max head # -> # of heads */
-	hds = ((v86.edx & 0xff00) >> 8) + 1;
-	sec = v86.ecx & 0x3f;
-
-	size = (uint64_t)cyl * hds * sec;
-
-	/* Determine if we can use EDD with this device. */
-	v86.ctl = V86_FLAGS;
-	v86.addr = 0x13;
-	v86.eax = 0x4100;
-	v86.edx = dskp->drive;
-	v86.ebx = 0x55aa;
-	v86int();
-	if (V86_CY(v86.efl) ||			/* carry set */
-	    (v86.ebx & 0xffff) != 0xaa55 ||	/* signature */
-	    (v86.ecx & EDD_INTERFACE_FIXED_DISK) == 0)
-		return (size);
-
-	tmp = drvsize(dskp);
-	if (tmp > size)
-		size = tmp;
-
-	return (size);
-}
-
-/*
- * The "layered" ioctl to read disk/partition size. Unfortunately
- * the zfsboot case is hardest, because we do not have full software
- * stack available, so we need to do some manual work here.
- */
-uint64_t
-ldi_get_size(void *priv)
-{
-	struct zfsdsk *zdsk = priv;
-	uint64_t size = zdsk->dsk.size;
-
-	if (zdsk->dsk.start == 0)
-		size = drvsize_ext(zdsk);
-
-	return (size * DEV_BSIZE);
-}
+	NULL
+};
 
-static void
-probe_drive(struct zfsdsk *zdsk)
+caddr_t
+ptov(uintptr_t x)
 {
-#ifdef GPT
-	struct gpt_hdr hdr;
-	struct gpt_ent *ent;
-	unsigned part, entries_per_sec;
-	daddr_t slba;
-#endif
-#if defined(GPT) || defined(LOADER_GELI_SUPPORT)
-	daddr_t elba;
-#endif
-
-	struct dos_partition *dp;
-	char *sec;
-	unsigned i;
-
-#ifdef LOADER_GELI_SUPPORT
-	/*
-	 * Taste the disk, if it is GELI encrypted, decrypt it then dig out the
-	 * partition table and probe each slice/partition in turn for a vdev or
-	 * GELI encrypted vdev.
-	 */
-	elba = drvsize_ext(zdsk);
-	if (elba > 0) {
-		elba--;
-	}
-	zdsk->gdev = geli_taste(vdev_read, zdsk, elba, "disk%u:0:");
-	if ((zdsk->gdev != NULL) && (geli_havekey(zdsk->gdev) == 0))
-		geli_passphrase(zdsk->gdev, gelipw);
-#endif /* LOADER_GELI_SUPPORT */
-
-	sec = dmadat->secbuf;
-	zdsk->dsk.start = 0;
-
-#ifdef GPT
-	/*
-	 * First check for GPT.
-	 */
-	if (drvread(&zdsk->dsk, sec, 1, 1)) {
-		return;
-	}
-	memcpy(&hdr, sec, sizeof(hdr));
-	if (memcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) != 0 ||
-	    hdr.hdr_lba_self != 1 || hdr.hdr_revision < 0x00010000 ||
-	    hdr.hdr_entsz < sizeof(*ent) || DEV_BSIZE % hdr.hdr_entsz != 0) {
-		goto trymbr;
-	}
-
-	/*
-	 * Probe all GPT partitions for the presence of ZFS pools. We
-	 * return the spa_t for the first we find (if requested). This
-	 * will have the effect of booting from the first pool on the
-	 * disk.
-	 *
-	 * If no vdev is found, GELI decrypting the device and try again
-	 */
-	entries_per_sec = DEV_BSIZE / hdr.hdr_entsz;
-	slba = hdr.hdr_lba_table;
-	elba = slba + hdr.hdr_entries / entries_per_sec;
-	while (slba < elba) {
-		zdsk->dsk.start = 0;
-		if (drvread(&zdsk->dsk, sec, slba, 1))
-			return;
-		for (part = 0; part < entries_per_sec; part++) {
-			ent = (struct gpt_ent *)(sec + part * hdr.hdr_entsz);
-			if (memcmp(&ent->ent_type, &freebsd_zfs_uuid,
-			    sizeof(uuid_t)) == 0) {
-				zdsk->dsk.start = ent->ent_lba_start;
-				zdsk->dsk.size =
-				    ent->ent_lba_end - ent->ent_lba_start + 1;
-				zdsk->dsk.slice = part + 1;
-				zdsk->dsk.part = 255;
-				if (vdev_probe(vdev_read2, zdsk, NULL) == 0) {
-					/*
-					 * This slice had a vdev. We need a new
-					 * dsk structure now since the vdev now
-					 * owns this one.
-					 */
-					zdsk = copy_dsk(zdsk);
-				}
-#ifdef LOADER_GELI_SUPPORT
-				else if ((zdsk->gdev = geli_taste(vdev_read,
-				    zdsk, ent->ent_lba_end - ent->ent_lba_start,
-				    "disk%up%u:", zdsk->dsk.unit,
-				    zdsk->dsk.slice)) != NULL) {
-					if (geli_havekey(zdsk->gdev) == 0 ||
-					    geli_passphrase(zdsk->gdev, gelipw)
-					    == 0) {
-						/*
-						 * This slice has GELI,
-						 * check it for ZFS.
-						 */
-						if (vdev_probe(vdev_read2,
-						    zdsk, NULL) == 0) {
-							/*
-							 * This slice had a
-							 * vdev. We need a new
-							 * dsk structure now
-							 * since the vdev now
-							 * owns this one.
-							 */
-							zdsk = copy_dsk(zdsk);
-						}
-						break;
-					}
-				}
-#endif /* LOADER_GELI_SUPPORT */
-			}
-		}
-		slba++;
-	}
-	return;
-trymbr:
-#endif /* GPT */
-
-	if (drvread(&zdsk->dsk, sec, DOSBBSECTOR, 1))
-		return;
-	dp = (void *)(sec + DOSPARTOFF);
-
-	for (i = 0; i < NDOSPART; i++) {
-		if (!dp[i].dp_typ)
-			continue;
-		zdsk->dsk.start = dp[i].dp_start;
-		zdsk->dsk.size = dp[i].dp_size;
-		zdsk->dsk.slice = i + 1;
-		if (vdev_probe(vdev_read2, zdsk, NULL) == 0) {
-			zdsk = copy_dsk(zdsk);
-		}
-#ifdef LOADER_GELI_SUPPORT
-		else if ((zdsk->gdev = geli_taste(vdev_read, zdsk,
-		    dp[i].dp_size - dp[i].dp_start, "disk%us%u:")) != NULL) {
-			if (geli_havekey(zdsk->gdev) == 0 ||
-			    geli_passphrase(zdsk->gdev, gelipw) == 0) {
-				/*
-				 * This slice has GELI, check it for ZFS.
-				 */
-				if (vdev_probe(vdev_read2, zdsk, NULL) == 0) {
-					/*
-					 * This slice had a vdev. We need a new
-					 * dsk structure now since the vdev now
-					 * owns this one.
-					 */
-					zdsk = copy_dsk(zdsk);
-				}
-				break;
-			}
-		}
-#endif /* LOADER_GELI_SUPPORT */
-	}
+	return (PTOV(x));
 }
 
 int
 main(void)
 {
-	dnode_phys_t dn;
-	off_t off;
-	struct zfsdsk *zdsk;
-	int autoboot, i;
-	int nextboot;
-	int rc;
-
-	dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base);
+	unsigned i;
+	int auto_boot, fd, nextboot = 0;
+	struct disk_devdesc devdesc;
 
 	bios_getmem();
 
 	if (high_heap_size > 0) {
-		heap_end = PTOV(high_heap_base + high_heap_size);
-		heap_next = PTOV(high_heap_base);
+		heap_top = PTOV(high_heap_base + high_heap_size);
+		heap_bottom = PTOV(high_heap_base);
 	} else {
-		heap_next = (char *)dmadat + sizeof(*dmadat);
-		heap_end = (char *)PTOV(bios_basemem);
+		heap_bottom = (char *)
+		    (roundup2(__base + (int32_t)&_end, 0x10000) - __base);
+		heap_top = (char *)PTOV(bios_basemem);
 	}
-	setheap(heap_next, heap_end);
+	setheap(heap_bottom, heap_top);
 
-	zdsk = calloc(1, sizeof(struct zfsdsk));
*** 2556 LINES SKIPPED ***