From owner-freebsd-sparc64@FreeBSD.ORG Sun Feb 12 09:30:13 2012 Return-Path: Delivered-To: freebsd-sparc64@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id DD23B10656E4 for ; Sun, 12 Feb 2012 09:30:13 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id AD5D48FC0C for ; Sun, 12 Feb 2012 09:30:13 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.5/8.14.5) with ESMTP id q1C9UDEg007718 for ; Sun, 12 Feb 2012 09:30:13 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.5/8.14.5/Submit) id q1C9UD6S007716; Sun, 12 Feb 2012 09:30:13 GMT (envelope-from gnats) Resent-Date: Sun, 12 Feb 2012 09:30:13 GMT Resent-Message-Id: <201202120930.q1C9UD6S007716@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-sparc64@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Gavin Mu Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id A2AE8106566C for ; Sun, 12 Feb 2012 09:27:33 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from red.freebsd.org (red.freebsd.org [IPv6:2001:4f8:fff6::22]) by mx1.freebsd.org (Postfix) with ESMTP id 908928FC08 for ; Sun, 12 Feb 2012 09:27:33 +0000 (UTC) Received: from red.freebsd.org (localhost [127.0.0.1]) by red.freebsd.org (8.14.4/8.14.4) with ESMTP id q1C9RXnV012713 for ; Sun, 12 Feb 2012 09:27:33 GMT (envelope-from nobody@red.freebsd.org) Received: (from nobody@localhost) by red.freebsd.org (8.14.4/8.14.4/Submit) id q1C9RXd7012709; Sun, 12 Feb 2012 09:27:33 GMT (envelope-from nobody) Message-Id: <201202120927.q1C9RXd7012709@red.freebsd.org> Date: Sun, 12 Feb 2012 09:27:33 GMT From: Gavin Mu To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-3.1 Cc: Subject: sparc64/165025: [PATCH] zfsboot support for sparc64 X-BeenThere: freebsd-sparc64@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Porting FreeBSD to the Sparc List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 12 Feb 2012 09:30:14 -0000 >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@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/ 3. export the zpool # zpool export tank 4. install zfsboot # dd if=boot1 of=/dev/ bs=512 skip=1 oseek=1 conv=notrunc 5. install zfsloader to ZFS Book Block location # dd if=zfsloader of=/dev/ 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 #include @@ -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 +#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 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: