summaryrefslogtreecommitdiffstats
path: root/sys/boot
diff options
context:
space:
mode:
authordfr <dfr@FreeBSD.org>2008-11-19 16:39:01 +0000
committerdfr <dfr@FreeBSD.org>2008-11-19 16:39:01 +0000
commitd6f289d4433bdf255fa2c6abca2ab24c322bf884 (patch)
tree0a4e9c8e0a75ca6fc34e64f38b47d5e60c52f174 /sys/boot
parenta24417724cb96f3cb441f632dc3e87fb79a6e536 (diff)
downloadFreeBSD-src-d6f289d4433bdf255fa2c6abca2ab24c322bf884.zip
FreeBSD-src-d6f289d4433bdf255fa2c6abca2ab24c322bf884.tar.gz
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.
Diffstat (limited to 'sys/boot')
-rw-r--r--sys/boot/i386/Makefile2
-rw-r--r--sys/boot/i386/gptzfsboot/Makefile74
-rw-r--r--sys/boot/i386/zfsboot/zfsboot.c107
-rw-r--r--sys/boot/zfs/zfs.c10
4 files changed, 188 insertions, 5 deletions
diff --git a/sys/boot/i386/Makefile b/sys/boot/i386/Makefile
index 6af8642..912714f 100644
--- a/sys/boot/i386/Makefile
+++ b/sys/boot/i386/Makefile
@@ -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
diff --git a/sys/boot/i386/gptzfsboot/Makefile b/sys/boot/i386/gptzfsboot/Makefile
new file mode 100644
index 0000000..985c043
--- /dev/null
+++ b/sys/boot/i386/gptzfsboot/Makefile
@@ -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>
diff --git a/sys/boot/i386/zfsboot/zfsboot.c b/sys/boot/i386/zfsboot/zfsboot.c
index 9b0a465..43434ac 100644
--- a/sys/boot/i386/zfsboot/zfsboot.c
+++ b/sys/boot/i386/zfsboot/zfsboot.c
@@ -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 **spap)
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 **spap)
/*
* 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, unsigned lba, unsigned nblk)
return -1;
}
return 0;
+#endif
}
static int
diff --git a/sys/boot/zfs/zfs.c b/sys/boot/zfs/zfs.c
index cf0bb9c..e5cfad6 100644
--- a/sys/boot/zfs/zfs.c
+++ b/sys/boot/zfs/zfs.c
@@ -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);
}
OpenPOWER on IntegriCloud