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.
This commit is contained in:
Doug Rabson 2008-11-19 16:39:01 +00:00
parent 14dddafbb3
commit 51f0d2e192
4 changed files with 188 additions and 5 deletions

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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);
}