svn commit: r185096 - in head/sys/boot: i386 i386/gptzfsboot i386/zfsboot zfs

Doug Rabson dfr at FreeBSD.org
Wed Nov 19 08:39:02 PST 2008


Author: dfr
Date: Wed Nov 19 16:39:01 2008
New Revision: 185096
URL: http://svn.freebsd.org/changeset/base/185096

Log:
  Add a GPT-aware variant of zfsboot which should be used in a similar manner
  to gptboot, i.e. installed in a freebsd-boot partition using /sbin/gpart or
  /sbin/gpt.
  
  Tweak the /boot/loader ZFS support so that it can find ZFS pools that are
  contained in GPT partitions.

Added:
  head/sys/boot/i386/gptzfsboot/
  head/sys/boot/i386/gptzfsboot/Makefile   (contents, props changed)
Modified:
  head/sys/boot/i386/Makefile
  head/sys/boot/i386/zfsboot/zfsboot.c
  head/sys/boot/zfs/zfs.c

Modified: head/sys/boot/i386/Makefile
==============================================================================
--- head/sys/boot/i386/Makefile	Wed Nov 19 16:04:07 2008	(r185095)
+++ head/sys/boot/i386/Makefile	Wed Nov 19 16:39:01 2008	(r185096)
@@ -1,7 +1,7 @@
 # $FreeBSD$
 
 SUBDIR=		mbr pmbr boot0 boot0sio btx boot2 cdboot gptboot zfsboot \
-		kgzldr libi386 libfirewire loader
+		gptzfsboot kgzldr libi386 libfirewire loader
 
 # special boot programs, 'self-extracting boot2+loader'
 SUBDIR+=	pxeldr

Added: head/sys/boot/i386/gptzfsboot/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/boot/i386/gptzfsboot/Makefile	Wed Nov 19 16:39:01 2008	(r185096)
@@ -0,0 +1,74 @@
+# $FreeBSD$
+
+.PATH:		${.CURDIR}/../boot2 ${.CURDIR}/../gptboot ${.CURDIR}/../zfsboot
+
+FILES=		gptzfsboot
+
+NM?=		nm
+
+BOOT_COMCONSOLE_PORT?= 0x3f8
+BOOT_COMCONSOLE_SPEED?= 9600
+B2SIOFMT?=	0x3
+
+REL1=	0x700
+ORG1=	0x7c00
+ORG2=	0x0
+
+CFLAGS=	-Os \
+	-fno-guess-branch-probability \
+	-fomit-frame-pointer \
+	-fno-unit-at-a-time \
+	-mno-align-long-strings \
+	-mrtd \
+	-mno-mmx -mno-3dnow -mno-sse -mno-sse2 -mno-sse3 \
+	-DGPT -DBOOT2 \
+	-DSIOPRT=${BOOT_COMCONSOLE_PORT} \
+	-DSIOFMT=${B2SIOFMT} \
+	-DSIOSPD=${BOOT_COMCONSOLE_SPEED} \
+	-I${.CURDIR}/../../common \
+	-I${.CURDIR}/../../zfs \
+	-I${.CURDIR}/../../../cddl/boot/zfs \
+	-I${.CURDIR}/../btx/lib -I. \
+	-I${.CURDIR}/../boot2 \
+	-Wall -Waggregate-return -Wbad-function-cast -Wcast-align \
+	-Wmissing-declarations -Wmissing-prototypes -Wnested-externs \
+	-Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \
+	-Winline --param max-inline-insns-single=100
+
+LDFLAGS=-static -N --gc-sections
+
+# Pick up ../Makefile.inc early.
+.include <bsd.init.mk>
+
+CLEANFILES=	gptzfsboot
+
+gptzfsboot: gptldr.bin gptzfsboot.bin ${BTXKERN}
+	btxld -v -E ${ORG2} -f bin -b ${BTXKERN} -l gptldr.bin \
+	    -o ${.TARGET} gptzfsboot.bin
+
+CLEANFILES+=	gptldr.bin gptldr.out gptldr.o
+
+gptldr.bin: gptldr.out
+	objcopy -S -O binary gptldr.out ${.TARGET}
+
+gptldr.out: gptldr.o
+	${LD} ${LDFLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} gptldr.o
+
+CLEANFILES+=	gptzfsboot.bin gptzfsboot.out zfsboot.o sio.o
+
+gptzfsboot.bin: gptzfsboot.out
+	objcopy -S -O binary gptzfsboot.out ${.TARGET}
+
+gptzfsboot.out: ${BTXCRT} zfsboot.o sio.o
+	${LD} ${LDFLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC}
+
+zfsboot.o: ${.CURDIR}/../../zfs/zfsimpl.c
+
+.if ${MACHINE_ARCH} == "amd64"
+beforedepend gptzfsboot.o: machine
+CLEANFILES+=	machine
+machine:
+	ln -sf ${.CURDIR}/../../../i386/include machine
+.endif
+
+.include <bsd.prog.mk>

Modified: head/sys/boot/i386/zfsboot/zfsboot.c
==============================================================================
--- head/sys/boot/i386/zfsboot/zfsboot.c	Wed Nov 19 16:04:07 2008	(r185095)
+++ head/sys/boot/i386/zfsboot/zfsboot.c	Wed Nov 19 16:39:01 2008	(r185096)
@@ -19,6 +19,9 @@ __FBSDID("$FreeBSD$");
 #include <sys/param.h>
 #include <sys/errno.h>
 #include <sys/diskmbr.h>
+#ifdef GPT
+#include <sys/gpt.h>
+#endif
 #include <sys/reboot.h>
 #include <sys/queue.h>
 
@@ -32,7 +35,9 @@ __FBSDID("$FreeBSD$");
 
 #include <btxv86.h>
 
+#ifndef GPT
 #include "zfsboot.h"
+#endif
 #include "lib.h"
 
 #define IO_KEYBOARD	1
@@ -103,6 +108,9 @@ __FBSDID("$FreeBSD$");
 
 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,
@@ -408,6 +416,12 @@ int13probe(int drive)
 static void
 probe_drive(struct dsk *dsk, spa_t **spap)
 {
+#ifdef GPT
+    struct gpt_hdr hdr;
+    struct gpt_ent *ent;
+    daddr_t slba, elba;
+    unsigned part, entries_per_sec;
+#endif
     struct dos_partition *dp;
     char *sec;
     unsigned i;
@@ -424,6 +438,63 @@ probe_drive(struct dsk *dsk, spa_t **spa
 
     sec = dmadat->secbuf;
     dsk->start = 0;
+
+#ifdef GPT
+    /*
+     * First check for GPT.
+     */
+    if (drvread(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 presense 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.
+     */
+    entries_per_sec = DEV_BSIZE / hdr.hdr_entsz;
+    slba = hdr.hdr_lba_table;
+    elba = slba + hdr.hdr_entries / entries_per_sec;
+    while (slba < elba) {
+	if (drvread(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) {
+		dsk->start = ent->ent_lba_start;
+		if (vdev_probe(vdev_read, dsk, spap) == 0) {
+		    /*
+		     * We record the first pool we find (we will try
+		     * to boot from that one.
+		     */
+		    spap = 0;
+
+		    /*
+		     * This slice had a vdev. We need a new dsk
+		     * structure now since the vdev now owns this one.
+		     */
+		    struct dsk *newdsk;
+		    newdsk = malloc(sizeof(struct dsk));
+		    *newdsk = *dsk;
+		    dsk = newdsk;
+		}
+		break;
+	    }
+	}
+	slba++;
+    }
+    return;
+trymbr:
+#endif
+
     if (drvread(dsk, sec, DOSBBSECTOR, 1))
 	return;
     dp = (void *)(sec + DOSPARTOFF);
@@ -441,7 +512,7 @@ probe_drive(struct dsk *dsk, spa_t **spa
 
 	    /*
 	     * This slice had a vdev. We need a new dsk structure now
-	     * sice the vdev now owns this one.
+	     * since the vdev now owns this one.
 	     */
 	    struct dsk *newdsk;
 	    newdsk = malloc(sizeof(struct dsk));
@@ -859,9 +930,42 @@ putchar(int c)
     xputc(c);
 }
 
+#ifdef GPT
+static struct {
+	uint16_t len;
+	uint16_t count;
+	uint16_t seg;
+	uint16_t off;
+	uint64_t lba;
+} packet;
+#endif
+
 static int
 drvread(struct dsk *dsk, void *buf, unsigned lba, unsigned nblk)
 {
+#ifdef GPT
+   static unsigned c = 0x2d5c7c2f;
+
+    if (!OPT_CHECK(RBX_QUIET))
+	printf("%c\b", c = c << 8 | c >> 24);
+    packet.len = 0x10;
+    packet.count = nblk;
+    packet.seg = VTOPOFF(buf);
+    packet.off = VTOPSEG(buf);
+    packet.lba = lba + dsk->start;
+    v86.ctl = V86_FLAGS;
+    v86.addr = 0x13;
+    v86.eax = 0x4200;
+    v86.edx = dsk->drive;
+    v86.ds = VTOPSEG(&packet);
+    v86.esi = VTOPOFF(&packet);
+    v86int();
+    if (V86_CY(v86.efl)) {
+	printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba);
+	return -1;
+    }
+    return 0;
+#else
     static unsigned c = 0x2d5c7c2f;
 
     lba += dsk->start;
@@ -881,6 +985,7 @@ drvread(struct dsk *dsk, void *buf, unsi
 	return -1;
     }
     return 0;
+#endif
 }
 
 static int

Modified: head/sys/boot/zfs/zfs.c
==============================================================================
--- head/sys/boot/zfs/zfs.c	Wed Nov 19 16:04:07 2008	(r185095)
+++ head/sys/boot/zfs/zfs.c	Wed Nov 19 16:39:01 2008	(r185096)
@@ -414,10 +414,14 @@ zfs_dev_init(void) 
 			close(fd);
 
 		for (slice = 1; slice <= 4; slice++) {
-			sprintf(devname, "disk%ds%d:", unit, slice);
+			sprintf(devname, "disk%dp%d:", unit, slice);
 			fd = open(devname, O_RDONLY);
-			if (fd == -1)
-				continue;
+			if (fd == -1) {
+				sprintf(devname, "disk%ds%d:", unit, slice);
+				fd = open(devname, O_RDONLY);
+				if (fd == -1)
+					continue;
+			}
 			if (vdev_probe(vdev_read, (void*) (uintptr_t) fd, 0))
 				close(fd);
 		}


More information about the svn-src-all mailing list