sparc64/165025: [PATCH] zfsboot support for sparc64

Gavin Mu gavin.mu at gmail.com
Sun Feb 12 09:30:14 UTC 2012


>Number:         165025
>Category:       sparc64
>Synopsis:       [PATCH] zfsboot support for sparc64
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-sparc64
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sun Feb 12 09:30:13 UTC 2012
>Closed-Date:
>Last-Modified:
>Originator:     Gavin Mu
>Release:        9.0-RELEASE
>Organization:
China
>Environment:
FreeBSD mybsd.localhost 9.0-RELEASE FreeBSD 9.0-RELEASE #0: Wed Jan  4 05:26:33 UTC 2012     root at heller.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  sparc64

>Description:
This patch enables the ZFS boot from zpool on a single whole disk for sparc64.
Two new programs zfsboot and zfsloader are introduced.
zfsboot is written to address [0x200, 0x2000) just like boot1, and is responsible to read zfsloader (one ELF program like loader) from 3.5MB ZFS Boot Block located at [0x80000, 0x400000).

Known Limitations:
1. only zpool on a whole disk is supported, zfs boot from zpool in VTOC8 partitions may not work.
2. boot from mirror/raidz is not supported due to limited dev environment.

>How-To-Repeat:
NA.
>Fix:
generic steps:
1. build zfsboot and zfsloader
2. create zpool on your disk
# zpool create tank /dev/<your disk, ie. ada0>
3. export the zpool
# zpool export tank
4. install zfsboot
# dd if=boot1 of=/dev/<your disk, ie. ada0> bs=512 skip=1 oseek=1 conv=notrunc
5. install zfsloader to ZFS Book Block location
# dd if=zfsloader of=/dev/<your disk, ie. ada0> bs=512 oseek=1024 conv=notrunc
6. re-import your zpool to install FreeBSD files


Patch attached with submission follows:

diff --git a/sys/boot/common/bootstrap.h b/sys/boot/common/bootstrap.h
index d8b4551..fea7192 100644
--- a/sys/boot/common/bootstrap.h
+++ b/sys/boot/common/bootstrap.h
@@ -25,6 +25,8 @@
  *
  * $FreeBSD$
  */
+#ifndef _BOOTSTRAP_H_
+#define _BOOTSTRAP_H_
 
 #include <sys/types.h>
 #include <sys/queue.h>
@@ -323,3 +325,6 @@ void	delay(int delay);
 void	dev_cleanup(void);
 
 time_t	time(time_t *tloc);
+
+#endif /* !_BOOTSTRAP_H_ */
+
diff --git a/sys/boot/ofw/libofw/devicename.c b/sys/boot/ofw/libofw/devicename.c
index 3cae23c..655b87a 100644
--- a/sys/boot/ofw/libofw/devicename.c
+++ b/sys/boot/ofw/libofw/devicename.c
@@ -28,6 +28,7 @@
 __FBSDID("$FreeBSD$");
 
 #include <stand.h>
+#include "bootstrap.h"
 #include "libofw.h"
 
 static int ofw_parsedev(struct ofw_devdesc **, const char *, const char **);
@@ -75,6 +76,7 @@ ofw_parsedev(struct ofw_devdesc **dev, const char *devspec, const char **path)
     struct devsw	*dv;
     phandle_t		handle;
     const char		*p;
+    char		*ep;
     const char		*s;
     char		name[256];
     char		type[64];
@@ -87,10 +89,12 @@ ofw_parsedev(struct ofw_devdesc **dev, const char *devspec, const char **path)
 	len = s - devspec;
 	bcopy(devspec, name, len);
 	name[len] = '\0';
-	if ((handle = OF_finddevice(name)) == -1)
-	    break;
-	if (OF_getprop(handle, "device_type", type, sizeof(type)) == -1)
+	if ((handle = OF_finddevice(name)) == -1) {
+	    bcopy(name, type, len);
+	    type[len] = '\0';
+	} else if (OF_getprop(handle, "device_type", type, sizeof(type)) == -1) {
 	    continue;
+        }
 	for (i = 0; (dv = devsw[i]) != NULL; i++) {
 	    if (strncmp(dv->dv_name, type, strlen(dv->dv_name)) == 0)
 		goto found;
@@ -109,6 +113,18 @@ found:
     strcpy(idev->d_path, name);
     idev->d_dev = dv;
     idev->d_type = dv->dv_type;
+    if (idev->d_type == DEVT_ZFS) {
+	idev->d_unit = 0;
+	p = name + strlen(dv->dv_name);
+	if (*p && (*p != ':')) {
+	    idev->d_unit = strtol(p, &ep, 0);
+	    if (ep == p) {
+		free(idev);
+		return EUNIT;
+	    }
+	}
+    }
+
     if (dev == NULL) {
 	free(idev);
     } else {
diff --git a/sys/boot/sparc64/boot1/Makefile b/sys/boot/sparc64/boot1/Makefile
index dec3e09..8e9a7b5 100644
--- a/sys/boot/sparc64/boot1/Makefile
+++ b/sys/boot/sparc64/boot1/Makefile
@@ -8,9 +8,15 @@ SRCS=	_start.s boot1.c
 
 BOOTBLOCKBASE= 0x4000
 
+ZFSBOOT?=	no
 CFLAGS=	-mcmodel=medlow -Os -I${.CURDIR}/../../common
 LDFLAGS=-Ttext ${BOOTBLOCKBASE} -Wl,-N
 
+.if ${ZFSBOOT} == "yes"
+CFLAGS+=        -DZFSBOOT
+.endif
+
+
 # Construct boot1. sunlabel expects it to contain zeroed-out space for the
 # label, and to be of the correct size.
 boot1: boot1.aout
diff --git a/sys/boot/sparc64/boot1/boot1.c b/sys/boot/sparc64/boot1/boot1.c
index 6b9fa30..95e36e5 100644
--- a/sys/boot/sparc64/boot1/boot1.c
+++ b/sys/boot/sparc64/boot1/boot1.c
@@ -25,6 +25,7 @@ __FBSDID("$FreeBSD$");
 
 #define _PATH_LOADER	"/boot/loader"
 #define _PATH_KERNEL	"/boot/kernel/kernel"
+#define READ_BUF_SIZE 8192
 
 typedef int putc_func_t(char c, void *arg);
 typedef int32_t ofwh_t;
@@ -48,6 +49,9 @@ int main(int ac, char **av);
 
 static void exit(int) __dead2;
 static void load(const char *);
+#ifdef ZFSBOOT
+static void loadzfs(void);
+#endif
 static int dskread(void *, u_int64_t, int);
 
 static void usage(void);
@@ -335,6 +339,17 @@ main(int ac, char **av)
 		}
 	}
 
+#ifdef ZFSBOOT
+	printf(" \n>> FreeBSD/sparc64 ZFS boot block\n"
+	"   Boot path:   %s\n"
+	"   Boot loader on ZFS boot block\n", bootpath, path);
+
+	if ((bootdev = ofw_open(bootpath)) == -1) {
+		printf("can't open device\n");
+		return (-1);
+	}
+	loadzfs();
+#else
 	printf(" \n>> FreeBSD/sparc64 boot block\n"
 	"   Boot path:   %s\n"
 	"   Boot loader: %s\n", bootpath, path);
@@ -343,6 +358,7 @@ main(int ac, char **av)
 		panic("mount");
 
 	load(path);
+#endif
 	return (1);
 }
 
@@ -379,6 +395,80 @@ mount(const char *device)
 	return (0);
 }
 
+#ifdef ZFSBOOT
+#define VDEV_BOOT_OFFSET (2 * 256 * 1024)
+static char zbuf[READ_BUF_SIZE];
+
+static int
+zbread(char *buf, off_t off, size_t bytes)
+{
+	char *p;
+	unsigned int nb;
+	unsigned int lb;
+	size_t len;
+	off_t soff;
+	off_t poff;
+
+	p = buf;
+	soff = VDEV_BOOT_OFFSET + off;
+	lb = (soff + bytes + DEV_BSIZE - 1) / DEV_BSIZE;
+	poff = soff;
+	while (poff < soff + bytes) {
+		nb = lb - poff / DEV_BSIZE;
+		if (nb > READ_BUF_SIZE / DEV_BSIZE)
+			nb = READ_BUF_SIZE / DEV_BSIZE;
+		if (dskread(zbuf, poff / DEV_BSIZE, nb))
+			break;
+		if ((poff / DEV_BSIZE + nb) * DEV_BSIZE > soff + bytes)
+			len = soff + bytes - poff;
+		else
+			len = (poff / DEV_BSIZE + nb) * DEV_BSIZE - poff;
+		memcpy(p, zbuf + poff % DEV_BSIZE, len);
+		p += len;
+		poff += len;
+	}
+
+	return (poff - soff);
+}
+
+static void loadzfs(void)
+{
+	Elf64_Ehdr eh;
+	Elf64_Phdr ph;
+	caddr_t p;
+	ino_t ino;
+	int i;
+
+	if (zbread((char *)&eh, 0, sizeof(eh)) != sizeof(eh)) {
+		printf("Can't read elf header\n");
+		return;
+	}
+	if (!IS_ELF(eh)) {
+		printf("Not an ELF file\n");
+		return;
+	}
+	for (i = 0; i < eh.e_phnum; i++) {
+		fs_off = eh.e_phoff + i * eh.e_phentsize;
+		if (zbread((char *)&ph, fs_off, sizeof(ph)) != sizeof(ph)) {
+			printf("Can't read program header %d\n", i);
+			return;
+		}
+		if (ph.p_type != PT_LOAD)
+			continue;
+		fs_off = ph.p_offset;
+		p = (caddr_t)ph.p_vaddr;
+		if (zbread(p, fs_off, ph.p_filesz) != ph.p_filesz) {
+			printf("Can't read content of section %d\n", i);
+			return;
+		}
+		if (ph.p_filesz != ph.p_memsz)
+			bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
+	}
+	ofw_close(bootdev);
+	(*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw);
+}
+#endif /* ZFSBOOT */
+
 static void
 load(const char *fname)
 {
diff --git a/sys/boot/sparc64/loader/Makefile b/sys/boot/sparc64/loader/Makefile
index d32fbab..f4f1c12 100644
--- a/sys/boot/sparc64/loader/Makefile
+++ b/sys/boot/sparc64/loader/Makefile
@@ -3,8 +3,8 @@
 .include <bsd.own.mk>
 MK_SSP=		no
 
-PROG=		loader
-NEWVERSWHAT=	"bootstrap loader" sparc64
+PROG?=		loader
+NEWVERSWHAT?=	"bootstrap loader" sparc64
 INSTALLFLAGS=	-b
 
 # Architecture-specific loader code
@@ -13,12 +13,17 @@ SRCS=		locore.S main.c metadata.c vers.c
 LOADER_DISK_SUPPORT?=	yes
 LOADER_UFS_SUPPORT?=	yes
 LOADER_CD9660_SUPPORT?=	yes
+LOADER_ZFS_SUPPORT?=	no
 LOADER_NET_SUPPORT?=	yes
 LOADER_NFS_SUPPORT?=	yes
 LOADER_TFTP_SUPPORT?=	yes
 LOADER_GZIP_SUPPORT?=	yes
 LOADER_BZIP2_SUPPORT?=	no
+LOADER_DEBUG?=		no
 
+.if ${LOADER_DEBUG} == "yes"
+CFLAGS+=	-DLOADER_DEBUG
+.endif
 .if ${LOADER_DISK_SUPPORT} == "yes"
 CFLAGS+=	-DLOADER_DISK_SUPPORT
 .endif
@@ -28,6 +33,11 @@ CFLAGS+=	-DLOADER_UFS_SUPPORT
 .if ${LOADER_CD9660_SUPPORT} == "yes"
 CFLAGS+=	-DLOADER_CD9660_SUPPORT
 .endif
+.if ${LOADER_ZFS_SUPPORT} == "yes"
+CFLAGS+=	-DLOADER_ZFS_SUPPORT
+CFLAGS+=	-I${.CURDIR}/../../zfs
+CFLAGS+=	-I${.CURDIR}/../../../cddl/boot/zfs
+.endif
 .if ${LOADER_GZIP_SUPPORT} == "yes"
 CFLAGS+=	-DLOADER_GZIP_SUPPORT
 .endif
@@ -75,8 +85,8 @@ CFLAGS+=	-I${.CURDIR}/../../../../lib/libstand/
 DPADD=		${LIBFICL} ${LIBOFW} ${LIBSTAND}
 LDADD=		${LIBFICL} ${LIBOFW} -lstand
 
-vers.c:	${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version
-	sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT}
+vers.c:	${.CURDIR}/../../common/newvers.sh ${.CURDIR}/../loader/version
+	sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/../loader/version ${NEWVERSWHAT}
 
 loader.help: help.common help.sparc64
 	cat ${.ALLSRC} | \
diff --git a/sys/boot/sparc64/loader/main.c b/sys/boot/sparc64/loader/main.c
index be0819f..e8629f1 100644
--- a/sys/boot/sparc64/loader/main.c
+++ b/sys/boot/sparc64/loader/main.c
@@ -143,6 +143,10 @@ static vm_offset_t heapva;
 
 static phandle_t root;
 
+#if defined(LOADER_ZFS_SUPPORT)
+#include "zfs.c"
+static int sparc_zfs_dev_init(void);
+#endif
 /*
  * Machine dependent structures that the machine independent
  * loader part uses.
@@ -154,6 +158,9 @@ struct devsw *devsw[] = {
 #ifdef LOADER_NET_SUPPORT
 	&netdev,
 #endif
+#ifdef LOADER_ZFS_SUPPORT
+	&zfs_dev,
+#endif
 	0
 };
 struct arch_switch archsw;
@@ -166,6 +173,11 @@ struct file_format *file_formats[] = {
 	&sparc64_elf,
 	0
 };
+
+#if defined(LOADER_ZFS_SUPPORT)
+extern struct fs_ops zfs_fsops;
+#endif
+
 struct fs_ops *file_system[] = {
 #ifdef LOADER_UFS_SUPPORT
 	&ufs_fsops,
@@ -173,6 +185,9 @@ struct fs_ops *file_system[] = {
 #ifdef LOADER_CD9660_SUPPORT
 	&cd9660_fsops,
 #endif
+#ifdef LOADER_ZFS_SUPPORT
+	&zfs_fsops,
+#endif
 #ifdef LOADER_ZIP_SUPPORT
 	&zipfs_fsops,
 #endif
@@ -721,6 +736,32 @@ tlb_init_sun4u(void)
 		panic("%s: can't allocate TLB store", __func__);
 }
 
+#ifdef LOADER_ZFS_SUPPORT
+static int sparc_zfs_dev_init(void)
+{
+	int fd;
+
+	zfs_init();
+	fd = open(getenv("currdev"), O_RDONLY);
+	if (fd == -1)
+		return 0;
+
+	if (vdev_probe(vdev_read, (void*) (uintptr_t) fd, 0))
+		close(fd);
+
+	/*
+	 * ZFS virtual device becomes currdev instead of block device.
+	 * only one device zfs0 is supported now.
+	 */
+	env_setenv("currdev", EV_VOLATILE, "zfs0",
+	    ofw_setcurrdev, env_nounset);
+	env_setenv("loaddev", EV_VOLATILE, "zfs0",
+	    env_noset, env_nounset);
+
+	return 0;
+}
+#endif
+
 int
 main(int (*openfirm)(void *))
 {
@@ -756,14 +797,6 @@ main(int (*openfirm)(void *))
 	mmu_ops->tlb_init();
 
 	/*
-	 * Initialize devices.
-	 */
-	for (dp = devsw; *dp != 0; dp++) {
-		if ((*dp)->dv_init != 0)
-			(*dp)->dv_init();
-	}
-
-	/*
 	 * Set up the current device.
 	 */
 	OF_getprop(chosen, "bootpath", bootpath, sizeof(bootpath));
@@ -789,6 +822,19 @@ main(int (*openfirm)(void *))
 	    ofw_setcurrdev, env_nounset);
 	env_setenv("loaddev", EV_VOLATILE, bootpath,
 	    env_noset, env_nounset);
+#ifdef LOADER_ZFS_SUPPORT
+	/*
+	 * overwrite to use our specific sparc version
+	 */
+	zfs_dev.dv_init = sparc_zfs_dev_init;
+#endif
+	/*
+	 * Initialize devices.
+	 */
+	for (dp = devsw; *dp != 0; dp++) {
+		if ((*dp)->dv_init != 0)
+			(*dp)->dv_init();
+	}
 
 	printf("\n");
 	printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
diff --git a/sys/boot/sparc64/zfsboot/Makefile b/sys/boot/sparc64/zfsboot/Makefile
new file mode 100644
index 0000000..45c409d
--- /dev/null
+++ b/sys/boot/sparc64/zfsboot/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+.PATH:  ${.CURDIR}/../boot1
+
+NEWVERSWHAT=    "ZFS enabled bootstrap loader" sparc64
+ZFSBOOT=yes
+
+.include "${.CURDIR}/../boot1/Makefile"
+
diff --git a/sys/boot/sparc64/zfsloader/Makefile b/sys/boot/sparc64/zfsloader/Makefile
new file mode 100644
index 0000000..2c33f17
--- /dev/null
+++ b/sys/boot/sparc64/zfsloader/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+.PATH:	${.CURDIR}/../loader
+
+PROG=		zfsloader
+NEWVERSWHAT=	"ZFS enabled bootstrap loader" sparc64
+LOADER_ZFS_SUPPORT=yes
+
+.include "${.CURDIR}/../loader/Makefile"
+


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-sparc64 mailing list