svn commit: r192665 - in stable/7/sys/boot: . common i386 i386/libi386 i386/loader i386/zfsboot zfs

Kip Macy kmacy at FreeBSD.org
Sat May 23 19:54:22 UTC 2009


Author: kmacy
Date: Sat May 23 19:54:18 2009
New Revision: 192665
URL: http://svn.freebsd.org/changeset/base/192665

Log:
  Import ZFS loader support missed in the initial MFC
  set LOADER_ZFS_SUPPORT=Y in make.conf to enable

Added:
  stable/7/sys/boot/i386/zfsboot/Makefile   (contents, props changed)
  stable/7/sys/boot/i386/zfsboot/zfsldr.S   (contents, props changed)
  stable/7/sys/boot/zfs/Makefile   (contents, props changed)
  stable/7/sys/boot/zfs/zfs.c   (contents, props changed)
Modified:
  stable/7/sys/boot/Makefile
  stable/7/sys/boot/common/bootstrap.h
  stable/7/sys/boot/i386/Makefile
  stable/7/sys/boot/i386/libi386/bootinfo32.c
  stable/7/sys/boot/i386/libi386/devicename.c
  stable/7/sys/boot/i386/loader/Makefile
  stable/7/sys/boot/i386/loader/conf.c
  stable/7/sys/boot/i386/loader/main.c

Modified: stable/7/sys/boot/Makefile
==============================================================================
--- stable/7/sys/boot/Makefile	Sat May 23 19:42:23 2009	(r192664)
+++ stable/7/sys/boot/Makefile	Sat May 23 19:54:18 2009	(r192665)
@@ -17,6 +17,10 @@ SUBDIR+=		efi
 SUBDIR+=		ofw
 .endif
 
+.if defined(LOADER_ZFS_SUPPORT)
+SUBDIR+=		zfs
+.endif
+
 # Pick the machine-dependent subdir based on the target architecture.
 SUBDIR+=		${MACHINE:S/amd64/i386/:S/sun4v/sparc64/}
 

Modified: stable/7/sys/boot/common/bootstrap.h
==============================================================================
--- stable/7/sys/boot/common/bootstrap.h	Sat May 23 19:42:23 2009	(r192664)
+++ stable/7/sys/boot/common/bootstrap.h	Sat May 23 19:54:18 2009	(r192665)
@@ -43,6 +43,7 @@ struct devdesc 
 #define DEVT_DISK	1
 #define DEVT_NET	2
 #define	DEVT_CD		3
+#define DEVT_ZFS	4
     int			d_unit;
 };
 

Modified: stable/7/sys/boot/i386/Makefile
==============================================================================
--- stable/7/sys/boot/i386/Makefile	Sat May 23 19:42:23 2009	(r192664)
+++ stable/7/sys/boot/i386/Makefile	Sat May 23 19:54:18 2009	(r192665)
@@ -1,7 +1,7 @@
 # $FreeBSD$
 
-SUBDIR=		mbr pmbr boot0 boot0sio btx boot2 cdboot gptboot kgzldr \
-		libi386 libfirewire loader
+SUBDIR=		mbr pmbr boot0 boot0sio btx boot2 cdboot gptboot zfsboot \
+		kgzldr libi386 libfirewire loader
 
 # special boot programs, 'self-extracting boot2+loader'
 SUBDIR+=	pxeldr

Modified: stable/7/sys/boot/i386/libi386/bootinfo32.c
==============================================================================
--- stable/7/sys/boot/i386/libi386/bootinfo32.c	Sat May 23 19:42:23 2009	(r192664)
+++ stable/7/sys/boot/i386/libi386/bootinfo32.c	Sat May 23 19:54:18 2009	(r192665)
@@ -183,6 +183,7 @@ bi_load32(char *args, int *howtop, int *
 	break;
 
     case DEVT_NET:
+    case DEVT_ZFS:
 	    break;
 	    
     default:

Modified: stable/7/sys/boot/i386/libi386/devicename.c
==============================================================================
--- stable/7/sys/boot/i386/libi386/devicename.c	Sat May 23 19:42:23 2009	(r192664)
+++ stable/7/sys/boot/i386/libi386/devicename.c	Sat May 23 19:54:18 2009	(r192665)
@@ -171,6 +171,7 @@ i386_parsedev(struct i386_devdesc **dev,
 
     case DEVT_CD:
     case DEVT_NET:
+    case DEVT_ZFS:
 	unit = 0;
 
 	if (*np && (*np != ':')) {
@@ -246,6 +247,7 @@ i386_fmtdev(void *vdev)
 	break;
 
     case DEVT_NET:
+    case DEVT_ZFS:
 	sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit);
 	break;
     }

Modified: stable/7/sys/boot/i386/loader/Makefile
==============================================================================
--- stable/7/sys/boot/i386/loader/Makefile	Sat May 23 19:42:23 2009	(r192664)
+++ stable/7/sys/boot/i386/loader/Makefile	Sat May 23 19:54:18 2009	(r192665)
@@ -15,6 +15,12 @@ CFLAGS+=	-DLOADER_FIREWIRE_SUPPORT
 LIBFIREWIRE=	${.OBJDIR}/../libfirewire/libfirewire.a
 .endif
 
+# Put LOADER_ZFS_SUPPORT=yes in /etc/make.conf for ZFS support
+.if defined(LOADER_ZFS_SUPPORT)
+CFLAGS+=	-DLOADER_ZFS_SUPPORT
+LIBZFS=		${.OBJDIR}/../../zfs/libzfsboot.a
+.endif
+
 # Enable PXE TFTP or NFS support, not both.
 .if defined(LOADER_TFTP_SUPPORT)
 CFLAGS+=	-DLOADER_TFTP_SUPPORT
@@ -99,8 +105,8 @@ FILES+=	loader.rc
 # XXX crt0.o needs to be first for pxeboot(8) to work
 OBJS=	${BTXCRT} 
 
-DPADD=	${LIBFICL} ${LIBFIREWIRE} ${LIBI386} ${LIBSTAND}
-LDADD=	${LIBFICL} ${LIBFIREWIRE} ${LIBI386} -lstand
+DPADD=	${LIBFICL} ${LIBFIREWIRE} ${LIBZFS} ${LIBI386} ${LIBSTAND}
+LDADD=	${LIBFICL} ${LIBFIREWIRE} ${LIBZFS} ${LIBI386} -lstand
 
 .include <bsd.prog.mk>
 

Modified: stable/7/sys/boot/i386/loader/conf.c
==============================================================================
--- stable/7/sys/boot/i386/loader/conf.c	Sat May 23 19:42:23 2009	(r192664)
+++ stable/7/sys/boot/i386/loader/conf.c	Sat May 23 19:54:18 2009	(r192665)
@@ -50,6 +50,10 @@ __FBSDID("$FreeBSD$");
 extern struct devsw fwohci;
 #endif
 
+#if defined(LOADER_ZFS_SUPPORT)
+extern struct devsw zfs_dev;
+#endif
+
 /* Exported for libstand */
 struct devsw *devsw[] = {
     &bioscd,
@@ -60,15 +64,25 @@ struct devsw *devsw[] = {
 #if defined(LOADER_FIREWIRE_SUPPORT)
     &fwohci,
 #endif
+#if defined(LOADER_ZFS_SUPPORT)
+    &zfs_dev,
+#endif
     NULL
 };
 
+#if defined(LOADER_ZFS_SUPPORT)
+extern struct fs_ops zfs_fsops;
+#endif
+
 struct fs_ops *file_system[] = {
     &ufs_fsops,
     &ext2fs_fsops,
     &dosfs_fsops,
     &cd9660_fsops,
     &splitfs_fsops,
+#if defined(LOADER_ZFS_SUPPORT)
+    &zfs_fsops,
+#endif
 #ifdef LOADER_GZIP_SUPPORT
     &gzipfs_fsops,
 #endif

Modified: stable/7/sys/boot/i386/loader/main.c
==============================================================================
--- stable/7/sys/boot/i386/loader/main.c	Sat May 23 19:42:23 2009	(r192664)
+++ stable/7/sys/boot/i386/loader/main.c	Sat May 23 19:54:18 2009	(r192665)
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
 
 #define	KARGS_FLAGS_CD		0x1
 #define	KARGS_FLAGS_PXE		0x2
+#define	KARGS_FLAGS_ZFS		0x4
 
 /* Arguments passed in from the boot1/boot2 loader */
 static struct 
@@ -51,8 +52,13 @@ static struct 
     u_int32_t	howto;
     u_int32_t	bootdev;
     u_int32_t	bootflags;
-    u_int32_t	pxeinfo;
-    u_int32_t	res2;
+    union {
+	struct {
+	    u_int32_t	pxeinfo;
+	    u_int32_t	res2;
+	};
+	uint64_t	zfspool;
+    };
     u_int32_t	bootinfo;
 } *kargs;
 
@@ -96,7 +102,7 @@ main(void)
      */
     bios_getmem();
 
-#if defined(LOADER_BZIP2_SUPPORT) || defined(LOADER_FIREWIRE_SUPPORT) || defined(LOADER_GPT_SUPPORT)
+#if defined(LOADER_BZIP2_SUPPORT) || defined(LOADER_FIREWIRE_SUPPORT) || defined(LOADER_GPT_SUPPORT) || defined(LOADER_ZFS_SUPPORT)
     heap_top = PTOV(memtop_copyin);
     memtop_copyin -= 0x300000;
     heap_bottom = PTOV(memtop_copyin);
@@ -145,6 +151,14 @@ main(void)
 	    bc_add(initial_bootdev);
     }
 
+    archsw.arch_autoload = i386_autoload;
+    archsw.arch_getdev = i386_getdev;
+    archsw.arch_copyin = i386_copyin;
+    archsw.arch_copyout = i386_copyout;
+    archsw.arch_readin = i386_readin;
+    archsw.arch_isainb = isa_inb;
+    archsw.arch_isaoutb = isa_outb;
+
     /*
      * March through the device switch probing for things.
      */
@@ -172,14 +186,6 @@ main(void)
     
     bios_getsmap();
 
-    archsw.arch_autoload = i386_autoload;
-    archsw.arch_getdev = i386_getdev;
-    archsw.arch_copyin = i386_copyin;
-    archsw.arch_copyout = i386_copyout;
-    archsw.arch_readin = i386_readin;
-    archsw.arch_isainb = isa_inb;
-    archsw.arch_isaoutb = isa_outb;
-
     interact();			/* doesn't return */
 
     /* if we ever get here, it is an error */
@@ -252,6 +258,29 @@ extract_currdev(void)
 	       i386_setcurrdev, env_nounset);
     env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), env_noset,
 	       env_nounset);
+
+#ifdef LOADER_ZFS_SUPPORT
+    /*
+     * If we were started from a ZFS-aware boot2, we can work out
+     * which ZFS pool we are booting from.
+     */
+    if (kargs->bootflags & KARGS_FLAGS_ZFS) {
+	/*
+	 * Dig out the pool guid and convert it to a 'unit number'
+	 */
+	uint64_t guid;
+	int unit;
+	char devname[32];
+	extern int zfs_guid_to_unit(uint64_t);
+
+	guid = kargs->zfspool;
+	unit = zfs_guid_to_unit(guid);
+	if (unit >= 0) {
+	    sprintf(devname, "zfs%d", unit);
+	    setenv("currdev", devname, 1);
+	}
+    }
+#endif
 }
 
 COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);

Added: stable/7/sys/boot/i386/zfsboot/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/7/sys/boot/i386/zfsboot/Makefile	Sat May 23 19:54:18 2009	(r192665)
@@ -0,0 +1,108 @@
+# $FreeBSD$
+
+.PATH:		${.CURDIR}/../boot2
+
+FILES=		zfsboot
+
+NM?=		nm
+
+# A value of 0x80 enables LBA support.
+BOOT_BOOT1_FLAGS?=	0x80
+
+BOOT_COMCONSOLE_PORT?= 0x3f8
+BOOT_COMCONSOLE_SPEED?= 9600
+B2SIOFMT?=	0x3
+
+REL1=	0x700
+ORG1=	0x7c00
+ORG2=	0x2000
+
+CFLAGS=	-Os -g \
+	-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 \
+	-DBOOT2 \
+	-DFLAGS=${BOOT_BOOT1_FLAGS} \
+	-DSIOPRT=${BOOT_COMCONSOLE_PORT} \
+	-DSIOFMT=${B2SIOFMT} \
+	-DSIOSPD=${BOOT_COMCONSOLE_SPEED} \
+	-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=	zfsboot
+
+zfsboot: zfsboot1 zfsboot2
+	cat zfsboot1 zfsboot2 > zfsboot
+
+CLEANFILES+=	zfsboot1 zfsldr.out zfsldr.o
+
+zfsboot1: zfsldr.out
+	objcopy -S -O binary zfsldr.out ${.TARGET}
+
+zfsldr.out: zfsldr.o
+	${LD} ${LDFLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} zfsldr.o
+
+CLEANFILES+=	zfsboot2 zfsboot.ld zfsboot.ldr zfsboot.bin zfsboot.out \
+		zfsboot.o zfsboot.s zfsboot.s.tmp zfsboot.h sio.o
+
+# We currently allow 32768 bytes for zfsboot - in practice it could be
+# any size up to 3.5Mb but keeping it fixed size simplifies zfsldr.
+# 
+BOOT2SIZE=	32768
+
+zfsboot2: zfsboot.ld
+	@set -- `ls -l zfsboot.ld`; x=$$((${BOOT2SIZE}-$$5)); \
+	    echo "$$x bytes available"; test $$x -ge 0
+	dd if=zfsboot.ld of=${.TARGET} obs=${BOOT2SIZE} conv=osync
+
+zfsboot.ld: zfsboot.ldr zfsboot.bin ${BTXKERN}
+	btxld -v -E ${ORG2} -f bin -b ${BTXKERN} -l zfsboot.ldr \
+	    -o ${.TARGET} -P 1 zfsboot.bin
+
+zfsboot.ldr:
+	cp /dev/null ${.TARGET}
+
+zfsboot.bin: zfsboot.out
+	objcopy -S -O binary zfsboot.out ${.TARGET}
+
+zfsboot.out: ${BTXCRT} zfsboot.o sio.o
+	${LD} ${LDFLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND}
+
+zfsboot.o: zfsboot.s
+
+SRCS=	zfsboot.c zfsboot.h
+
+zfsboot.s: zfsboot.c zfsboot.h ${.CURDIR}/../../zfs/zfsimpl.c
+	${CC} ${CFLAGS} -S -o zfsboot.s.tmp ${.CURDIR}/zfsboot.c
+	sed -e '/align/d' -e '/nop/d' < zfsboot.s.tmp > zfsboot.s
+	rm -f zfsboot.s.tmp
+
+zfsboot.h: zfsldr.out
+	${NM} -t d ${.ALLSRC} | awk '/([0-9])+ T xread/ \
+	    { x = $$1 - ORG1; \
+	    printf("#define XREADORG %#x\n", REL1 + x) }' \
+	    ORG1=`printf "%d" ${ORG1}` \
+	    REL1=`printf "%d" ${REL1}` > ${.TARGET}
+
+.if ${MACHINE_ARCH} == "amd64"
+beforedepend zfsboot.s: machine
+CLEANFILES+=	machine
+machine:
+	ln -sf ${.CURDIR}/../../../i386/include machine
+.endif
+
+.include <bsd.prog.mk>

Added: stable/7/sys/boot/i386/zfsboot/zfsldr.S
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/7/sys/boot/i386/zfsboot/zfsldr.S	Sat May 23 19:54:18 2009	(r192665)
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 1998 Robert Nordier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ *
+ * $FreeBSD$
+ */
+
+/* Memory Locations */
+		.set MEM_REL,0x700		# Relocation address
+		.set MEM_ARG,0x900		# Arguments
+		.set MEM_ORG,0x7c00		# Origin
+		.set MEM_BUF,0x8000		# Load area
+		.set MEM_BTX,0x9000		# BTX start
+		.set MEM_JMP,0x9010		# BTX entry point
+		.set MEM_USR,0xa000		# Client start
+		.set BDA_BOOT,0x472		# Boot howto flag
+	
+/* Partition Constants */
+		.set PRT_OFF,0x1be		# Partition offset
+		.set PRT_NUM,0x4		# Partitions
+		.set PRT_BSD,0xa5		# Partition type
+
+/* Flag Bits */
+		.set FL_PACKET,0x80		# Packet mode
+
+/* Misc. Constants */
+		.set SIZ_PAG,0x1000		# Page size
+		.set SIZ_SEC,0x200		# Sector size
+
+		.set NSECT,0x40
+		.globl start
+		.globl xread
+		.code16
+
+start:		jmp main			# Start recognizably
+
+/*
+ * This is the start of a standard BIOS Parameter Block (BPB). Most bootable
+ * FAT disks have this at the start of their MBR. While normal BIOS's will
+ * work fine without this section, IBM's El Torito emulation "fixes" up the
+ * BPB by writing into the memory copy of the MBR. Rather than have data
+ * written into our xread routine, we'll define a BPB to work around it.
+ * The data marked with (T) indicates a field required for a ThinkPad to
+ * recognize the disk and (W) indicates fields written from IBM BIOS code.
+ * The use of the BPB is based on what OpenBSD and NetBSD implemented in
+ * their boot code but the required fields were determined by trial and error.
+ *
+ * Note: If additional space is needed in boot1, one solution would be to
+ * move the "prompt" message data (below) to replace the OEM ID.
+ */
+		.org 0x03, 0x00
+oemid:		.space 0x08, 0x00	# OEM ID
+
+		.org 0x0b, 0x00
+bpb:		.word   512		# sector size (T)
+		.byte	0		# sectors/clustor
+		.word	0		# reserved sectors
+		.byte	0		# number of FATs
+		.word	0		# root entries
+		.word	0		# small sectors
+		.byte	0		# media type (W)
+		.word	0		# sectors/fat
+		.word	18		# sectors per track (T)
+		.word	2		# number of heads (T)
+		.long	0		# hidden sectors (W)
+		.long	0		# large sectors
+
+		.org 0x24, 0x00
+ebpb:		.byte	0		# BIOS physical drive number (W)
+
+		.org 0x25,0x90
+/*
+ * Trampoline used by boot2 to call read to read data from the disk via
+ * the BIOS.  Call with:
+ *
+ * %cx:%ax	- long    - LBA to read in
+ * %es:(%bx)	- caddr_t - buffer to read data into
+ * %dl		- byte    - drive to read from
+ * %dh		- byte    - num sectors to read
+ */
+
+xread:		push %ss			# Address
+		pop %ds				#  data
+/*
+ * Setup an EDD disk packet and pass it to read
+ */
+xread.1:					# Starting
+		pushl $0x0			#  absolute
+		push %cx			#  block
+		push %ax			#  number
+		push %es			# Address of
+		push %bx			#  transfer buffer
+		xor %ax,%ax			# Number of
+		movb %dh,%al			#  blocks to
+		push %ax			#  transfer
+		push $0x10			# Size of packet
+		mov %sp,%bp			# Packet pointer
+		callw read			# Read from disk
+		lea 0x10(%bp),%sp		# Clear stack
+		lret				# To far caller
+/*
+ * Load the rest of boot2 and BTX up, copy the parts to the right locations,
+ * and start it all up.
+ */
+
+/*
+ * Setup the segment registers to flat addressing (segment 0) and setup the
+ * stack to end just below the start of our code.
+ */
+main:		cld				# String ops inc
+		xor %cx,%cx			# Zero
+		mov %cx,%es			# Address
+		mov %cx,%ds			#  data
+		mov %cx,%ss			# Set up
+		mov $start,%sp			#  stack
+/*
+ * Relocate ourself to MEM_REL.  Since %cx == 0, the inc %ch sets
+ * %cx == 0x100.
+ */
+		mov %sp,%si			# Source
+		mov $MEM_REL,%di		# Destination
+		incb %ch			# Word count
+		rep				# Copy
+		movsw				#  code
+/*
+ * If we are on a hard drive, then load the MBR and look for the first
+ * FreeBSD slice.  We use the fake partition entry below that points to
+ * the MBR when we call nread.  The first pass looks for the first active
+ * FreeBSD slice.  The second pass looks for the first non-active FreeBSD
+ * slice if the first one fails.
+ */
+		mov $part4,%si			# Partition
+		cmpb $0x80,%dl			# Hard drive?
+		jb main.4			# No
+		movb $0x1,%dh			# Block count
+		callw nread			# Read MBR
+		mov $0x1,%cx	 		# Two passes
+main.1: 	mov $MEM_BUF+PRT_OFF,%si	# Partition table
+		movb $0x1,%dh			# Partition
+main.2: 	cmpb $PRT_BSD,0x4(%si)		# Our partition type?
+		jne main.3			# No
+		jcxz main.5			# If second pass
+		testb $0x80,(%si)		# Active?
+		jnz main.5			# Yes
+main.3: 	add $0x10,%si	 		# Next entry
+		incb %dh			# Partition
+		cmpb $0x1+PRT_NUM,%dh		# In table?
+		jb main.2			# Yes
+		dec %cx				# Do two
+		jcxz main.1			#  passes
+/*
+ * If we get here, we didn't find any FreeBSD slices at all, so print an
+ * error message and die.
+ */
+		mov $msg_part,%si		# Message
+		jmp error			# Error
+/*
+ * Floppies use partition 0 of drive 0.
+ */
+main.4: 	xor %dx,%dx			# Partition:drive
+
+/*
+ * Ok, we have a slice and drive in %dx now, so use that to locate and
+ * load boot2.  %si references the start of the slice we are looking
+ * for, so go ahead and load up the 64 sectors starting at sector 1024
+ * (i.e. after the two vdev labels).  We don't have do anything fancy
+ * here to allow for an extra copy of boot1 and a partition table
+ * (compare to this section of the UFS bootstrap) so we just load it
+ * all at 0x8000. The first part of boot2 is BTX, which wants to run
+ * at 0x9000. The boot2.bin binary starts right after the end of BTX,
+ * so we have to figure out where the start of it is and then move the
+ * binary to 0xc000. After we have moved the client, we relocate BTX
+ * itself to 0x9000 - doing it in this order means that none of the
+ * memcpy regions overlap which would corrupt the copy.  Normally, BTX
+ * clients start at MEM_USR, or 0xa000, but when we use btxld to
+ * create boot2, we use an entry point of 0x2000.  That entry point is
+ * relative to MEM_USR; thus boot2.bin starts at 0xc000.
+ *
+ * The load area and the target area for the client overlap so we have
+ * to use a decrementing string move. We also play segment register
+ * games with the destination address for the move so that the client
+ * can be larger than 16k (which would overflow the zero segment since
+ * the client starts at 0xc000). Relocating BTX is easy since the load
+ * area and target area do not overlap.
+ */
+main.5: 	mov %dx,MEM_ARG			# Save args
+		movb $NSECT,%dh			# Sector count
+		movw $1024,%ax			# Offset to boot2
+		callw nread.1			# Read disk
+main.6:		mov $MEM_BUF,%si		# BTX (before reloc)
+		mov 0xa(%si),%bx		# Get BTX length and set
+		mov $NSECT*SIZ_SEC-1,%di	# Size of load area (less one)
+		mov %di,%si			# End of load
+		add $MEM_BUF,%si		#  area
+		sub %bx,%di			# End of client, 0xc000 rel
+		mov %di,%cx			# Size of
+		inc %cx				#  client
+		mov $(MEM_USR+2*SIZ_PAG)>>4,%dx	# Segment
+		mov %dx,%es			#   addressing 0xc000
+		std				# Move with decrement
+		rep				# Relocate
+		movsb				#  client
+		mov %ds,%dx			# Back to
+		mov %dx,%es			#  zero segment
+		mov $MEM_BUF,%si		# BTX (before reloc)
+		mov $MEM_BTX,%di		# BTX
+		mov %bx,%cx			# Get BTX length
+		cld				# Increment this time
+		rep				# Relocate
+		movsb				#  BTX
+
+/*
+ * Enable A20 so we can access memory above 1 meg.
+ * Use the zero-valued %cx as a timeout for embedded hardware which do not
+ * have a keyboard controller.
+ */
+seta20: 	cli				# Disable interrupts
+seta20.1:	dec %cx				# Timeout?
+		jz seta20.3			# Yes
+		inb $0x64,%al			# Get status
+		testb $0x2,%al			# Busy?
+		jnz seta20.1			# Yes
+		movb $0xd1,%al			# Command: Write
+		outb %al,$0x64			#  output port
+seta20.2:	inb $0x64,%al			# Get status
+		testb $0x2,%al			# Busy?
+		jnz seta20.2			# Yes
+		movb $0xdf,%al			# Enable
+		outb %al,$0x60			#  A20
+seta20.3:	sti				# Enable interrupts
+
+		jmp start+MEM_JMP-MEM_ORG	# Start BTX
+
+
+/*
+ * Trampoline used to call read from within boot1.
+ */
+nread:		xor %ax,%ax			# Sector offset in partition
+nread.1:	mov $MEM_BUF,%bx		# Transfer buffer
+		add 0x8(%si),%ax		# Get
+		mov 0xa(%si),%cx		#  LBA
+		push %cs			# Read from
+		callw xread.1	 		#  disk
+		jnc return			# If success, return
+		mov $msg_read,%si		# Otherwise, set the error
+						#  message and fall through to
+						#  the error routine
+/*
+ * Print out the error message pointed to by %ds:(%si) followed
+ * by a prompt, wait for a keypress, and then reboot the machine.
+ */
+error:		callw putstr			# Display message
+		mov $prompt,%si			# Display
+		callw putstr			#  prompt
+		xorb %ah,%ah			# BIOS: Get
+		int $0x16			#  keypress
+		movw $0x1234, BDA_BOOT		# Do a warm boot
+		ljmp $0xffff,$0x0		# reboot the machine
+/*
+ * Display a null-terminated string using the BIOS output.
+ */
+putstr.0:	mov $0x7,%bx	 		# Page:attribute
+		movb $0xe,%ah			# BIOS: Display
+		int $0x10			#  character
+putstr: 	lodsb				# Get char
+		testb %al,%al			# End of string?
+		jne putstr.0			# No
+
+/*
+ * Overused return code.  ereturn is used to return an error from the
+ * read function.  Since we assume putstr succeeds, we (ab)use the
+ * same code when we return from putstr.
+ */
+ereturn:	movb $0x1,%ah			# Invalid
+		stc				#  argument
+return: 	retw				# To caller
+/*
+ * Reads sectors from the disk.  If EDD is enabled, then check if it is
+ * installed and use it if it is.  If it is not installed or not enabled, then
+ * fall back to using CHS.  Since we use a LBA, if we are using CHS, we have to
+ * fetch the drive parameters from the BIOS and divide it out ourselves.
+ * Call with:
+ *
+ * %dl	- byte     - drive number
+ * stack - 10 bytes - EDD Packet
+ */
+read:		testb $FL_PACKET,%cs:MEM_REL+flags-start # LBA support enabled?
+		jz read.1			# No, use CHS
+		cmpb $0x80,%dl			# Hard drive?
+		jb read.1			# No, use CHS
+		mov $0x55aa,%bx			# Magic
+		push %dx			# Save
+		movb $0x41,%ah			# BIOS: Check
+		int $0x13			#  extensions present
+		pop %dx				# Restore
+		jc read.1			# If error, use CHS
+		cmp $0xaa55,%bx			# Magic?
+		jne read.1			# No, so use CHS
+		testb $0x1,%cl			# Packet interface?
+		jz read.1			# No, so use CHS
+		mov %bp,%si			# Disk packet
+		movb $0x42,%ah			# BIOS: Extended
+		int $0x13			#  read
+		retw				# To caller
+#if 0	
+read.1:	 	push %dx			# Save
+		movb $0x8,%ah			# BIOS: Get drive
+		int $0x13			#  parameters
+		movb %dh,%ch			# Max head number
+		pop %dx				# Restore
+		jc return			# If error
+		andb $0x3f,%cl			# Sectors per track
+		jz ereturn			# If zero
+		cli				# Disable interrupts
+		mov 0x8(%bp),%eax		# Get LBA
+		push %dx			# Save
+		movzbl %cl,%ebx			# Divide by
+		xor %edx,%edx			#  sectors
+		div %ebx			#  per track
+		movb %ch,%bl			# Max head number
+		movb %dl,%ch			# Sector number
+		inc %bx				# Divide by
+		xorb %dl,%dl			#  number
+		div %ebx			#  of heads
+		movb %dl,%bh			# Head number
+		pop %dx				# Restore
+		cmpl $0x3ff,%eax		# Cylinder number supportable?
+		sti				# Enable interrupts
+		ja ereturn			# No, return an error
+		xchgb %al,%ah			# Set up cylinder
+		rorb $0x2,%al			#  number
+		orb %ch,%al			# Merge
+		inc %ax				#  sector
+		xchg %ax,%cx	 		#  number
+		movb %bh,%dh			# Head number
+		subb %ah,%al			# Sectors this track
+		mov 0x2(%bp),%ah		# Blocks to read
+		cmpb %ah,%al			# To read
+		jb read.2			#  this
+#ifdef	TRACK_AT_A_TIME
+		movb %ah,%al			#  track
+#else
+		movb $1,%al			#  one sector
+#endif
+read.2: 	mov $0x5,%di	 		# Try count
+read.3: 	les 0x4(%bp),%bx		# Transfer buffer
+		push %ax			# Save
+		movb $0x2,%ah			# BIOS: Read
+		int $0x13			#  from disk
+		pop %bx				# Restore
+		jnc read.4			# If success
+		dec %di				# Retry?
+		jz read.6			# No
+		xorb %ah,%ah			# BIOS: Reset
+		int $0x13			#  disk system
+		xchg %bx,%ax	 		# Block count
+		jmp read.3			# Continue
+read.4: 	movzbw %bl,%ax	 		# Sectors read
+		add %ax,0x8(%bp)		# Adjust
+		jnc read.5			#  LBA,
+		incw 0xa(%bp)	 		#  transfer
+read.5: 	shlb %bl			#  buffer
+		add %bl,0x5(%bp)		#  pointer,
+		sub %al,0x2(%bp)		#  block count
+		ja read.1			# If not done
+read.6: 	retw				# To caller
+#else
+read.1:		mov $msg_chs,%si
+		jmp error
+msg_chs:	.asciz "CHS not supported"
+#endif
+
+/* Messages */
+
+msg_read:	.asciz "Read"
+msg_part:	.asciz "Boot"
+
+prompt: 	.asciz " error\r\n"
+
+flags:		.byte FLAGS			# Flags
+
+		.org PRT_OFF,0x90
+
+/* Partition table */
+
+		.fill 0x30,0x1,0x0
+part4:		.byte 0x80, 0x00, 0x01, 0x00
+		.byte 0xa5, 0xfe, 0xff, 0xff
+		.byte 0x00, 0x00, 0x00, 0x00
+		.byte 0x50, 0xc3, 0x00, 0x00	# 50000 sectors long, bleh
+
+		.word 0xaa55			# Magic number

Added: stable/7/sys/boot/zfs/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/7/sys/boot/zfs/Makefile	Sat May 23 19:54:18 2009	(r192665)
@@ -0,0 +1,39 @@
+# $FreeBSD$
+
+LIB=		zfsboot
+INTERNALLIB=
+
+SRCS+=		zfs.c
+
+CFLAGS+=	-I${.CURDIR}/../common -I${.CURDIR}/../.. -I.
+CFLAGS+=	-I${.CURDIR}/../../../lib/libstand
+CFLAGS+=	-I${.CURDIR}/../../cddl/boot/zfs
+
+CFLAGS+=	-ffreestanding
+.if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "amd64"
+CFLAGS+=	-mpreferred-stack-boundary=2
+CFLAGS+=	-mno-mmx -mno-3dnow -mno-sse -mno-sse2
+.endif
+.if ${MACHINE_ARCH} == "i386"
+CFLAGS+=	-mno-sse3
+.endif
+.if ${MACHINE_ARCH} == "powerpc" || ${MACHINE_ARCH} == "arm"
+CFLAGS+=	-msoft-float
+.endif
+.if ${MACHINE_ARCH} == "amd64"
+CFLAGS+=	-m32 -march=i386
+.endif
+
+CFLAGS+=	-Wformat -Wall
+
+.if ${MACHINE_ARCH} == "amd64"
+CLEANFILES+=    machine
+machine:
+	ln -sf ${.CURDIR}/../../i386/include machine
+.endif
+
+.include <bsd.lib.mk>
+
+.if ${MACHINE_ARCH} == "amd64"
+beforedepend ${OBJS}: machine
+.endif

Added: stable/7/sys/boot/zfs/zfs.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/7/sys/boot/zfs/zfs.c	Sat May 23 19:54:18 2009	(r192665)
@@ -0,0 +1,518 @@
+/*-
+ * Copyright (c) 2007 Doug Rabson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	$FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ *	Stand-alone file reading package.
+ */
+
+#include <sys/param.h>
+#include <sys/disklabel.h>
+#include <sys/time.h>
+#include <sys/queue.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stand.h>
+#include <bootstrap.h>
+
+#include "zfsimpl.c"
+
+static int	zfs_open(const char *path, struct open_file *f);
+static int	zfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
+static int	zfs_close(struct open_file *f);
+static int	zfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
+static off_t	zfs_seek(struct open_file *f, off_t offset, int where);
+static int	zfs_stat(struct open_file *f, struct stat *sb);
+static int	zfs_readdir(struct open_file *f, struct dirent *d);
+
+struct devsw zfs_dev;
+
+struct fs_ops zfs_fsops = {
+	"zfs",
+	zfs_open,
+	zfs_close,
+	zfs_read,
+	zfs_write,
+	zfs_seek,
+	zfs_stat,
+	zfs_readdir
+};
+
+/*
+ * In-core open file.
+ */
+struct file {
+	off_t		f_seekp;	/* seek pointer */
+	dnode_phys_t	f_dnode;
+	uint64_t	f_zap_type;	/* zap type for readdir */
+	uint64_t	f_num_leafs;	/* number of fzap leaf blocks */
+	zap_leaf_phys_t	*f_zap_leaf;	/* zap leaf buffer */
+};
+
+/*
+ * Open a file.
+ */
+static int
+zfs_open(const char *upath, struct open_file *f)
+{
+	spa_t *spa = (spa_t *) f->f_devdata;
+	struct file *fp;
+	int rc;
+
+	if (f->f_dev != &zfs_dev)
+		return (EINVAL);
+
+	rc = zfs_mount_pool(spa);
+	if (rc)
+		return (rc);
+
+	/* allocate file system specific data structure */
+	fp = malloc(sizeof(struct file));
+	bzero(fp, sizeof(struct file));
+	f->f_fsdata = (void *)fp;
+
+	if (spa->spa_root_objset.os_type != DMU_OST_ZFS) {
+		printf("Unexpected object set type %lld\n",
+		    spa->spa_root_objset.os_type);
+		rc = EIO;
+		goto out;
+	}
+
+	rc = zfs_lookup(spa, upath, &fp->f_dnode);
+	if (rc)
+		goto out;
+
+	fp->f_seekp = 0;
+out:
+	if (rc) {
+		f->f_fsdata = NULL;
+		free(fp);
+	}
+	return (rc);
+}
+
+static int
+zfs_close(struct open_file *f)
+{
+	struct file *fp = (struct file *)f->f_fsdata;
+
+	dnode_cache_obj = 0;
+	f->f_fsdata = (void *)0;
+	if (fp == (struct file *)0)
+		return (0);
+
+	free(fp);
+	return (0);
+}
+
+/*
+ * Copy a portion of a file into kernel memory.
+ * Cross block boundaries when necessary.
+ */
+static int
+zfs_read(struct open_file *f, void *start, size_t size, size_t *resid	/* out */)
+{
+	spa_t *spa = (spa_t *) f->f_devdata;
+	struct file *fp = (struct file *)f->f_fsdata;
+	const znode_phys_t *zp = (const znode_phys_t *) fp->f_dnode.dn_bonus;
+	size_t n;
+	int rc;
+
+	n = size;
+	if (fp->f_seekp + n > zp->zp_size)
+		n = zp->zp_size - fp->f_seekp;
+	
+	rc = dnode_read(spa, &fp->f_dnode, fp->f_seekp, start, n);
+	if (rc)
+		return (rc);
+
+	if (0) {
+	    int i;
+	    for (i = 0; i < n; i++)
+		putchar(((char*) start)[i]);
+	}
+	fp->f_seekp += n;
+	if (resid)
+		*resid = size - n;
+
+	return (0);
+}
+
+/*
+ * Don't be silly - the bootstrap has no business writing anything.
+ */
+static int
+zfs_write(struct open_file *f, void *start, size_t size, size_t *resid	/* out */)
+{
+
+	return (EROFS);
+}
+
+static off_t
+zfs_seek(struct open_file *f, off_t offset, int where)
+{
+	struct file *fp = (struct file *)f->f_fsdata;
+	znode_phys_t *zp = (znode_phys_t *) fp->f_dnode.dn_bonus;
+
+	switch (where) {
+	case SEEK_SET:
+		fp->f_seekp = offset;
+		break;
+	case SEEK_CUR:
+		fp->f_seekp += offset;
+		break;
+	case SEEK_END:
+		fp->f_seekp = zp->zp_size - offset;
+		break;
+	default:
+		errno = EINVAL;
+		return (-1);
+	}
+	return (fp->f_seekp);
+}
+
+static int
+zfs_stat(struct open_file *f, struct stat *sb)
+{
+	struct file *fp = (struct file *)f->f_fsdata;
+	znode_phys_t *zp = (znode_phys_t *) fp->f_dnode.dn_bonus;
+
+	/* only important stuff */
+	sb->st_mode = zp->zp_mode;
+	sb->st_uid = zp->zp_uid;
+	sb->st_gid = zp->zp_gid;
+	sb->st_size = zp->zp_size;
+
+	return (0);
+}
+

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-stable-7 mailing list