svn commit: r223477 - head/sys/boot/i386/zfsboot

John Baldwin jhb at FreeBSD.org
Thu Jun 23 15:53:18 UTC 2011


Author: jhb
Date: Thu Jun 23 15:53:17 2011
New Revision: 223477
URL: http://svn.freebsd.org/changeset/base/223477

Log:
  The recent change to increase the zfsboot size to 64k made a few BIOSes
  unhappy (probably they don't handle crossing the 64k boundary, etc.).
  Fix this by changing zfsldr to use a loop reading from the disk one
  sector at a time.  To avoid trashing the saved copy of the MBR which is
  used for disk I/O, read zfsboot2 at address 0x9000.  This has the
  advantage that BTX no longer needs to be relocated as it is read into
  the correct location.  However, the loop to relocate zfsboot2.bin can
  now cross a 64k boundary, so change it to use relative segments instead.
  (This will need further work if zfsboot2.bin ever exceeds 64k.)
  
  While here, stop storing a relocated copy of zfsldr at 0x700.  This was
  only used by the xread hack which has recently been removed (and even
  that use was dubious).  Also, include the BIOS error code as hex when
  reporting read errors to aid in debugging.
  
  Much thanks to Henri Hennebert for patiently testing various iterations
  of the patch as well as fixing the zfsboot2.bin relocation to use
  relative segments.
  
  MFC after:	1 week

Modified:
  head/sys/boot/i386/zfsboot/zfsldr.S

Modified: head/sys/boot/i386/zfsboot/zfsldr.S
==============================================================================
--- head/sys/boot/i386/zfsboot/zfsldr.S	Thu Jun 23 15:28:54 2011	(r223476)
+++ head/sys/boot/i386/zfsboot/zfsldr.S	Thu Jun 23 15:53:17 2011	(r223477)
@@ -16,7 +16,6 @@
  */
 
 /* Memory Locations */
-		.set MEM_REL,0x700		# Relocation address
 		.set MEM_ARG,0x900		# Arguments
 		.set MEM_ORG,0x7c00		# Origin
 		.set MEM_BUF,0x8000		# Load area
@@ -91,26 +90,18 @@ main:		cld				# String ops inc
 		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
+		mov $part4,%si			# Dummy partition
 		cmpb $0x80,%dl			# Hard drive?
 		jb main.4			# No
-		movb $0x1,%dh			# Block count
-		callw nread			# Read MBR
+		xor %eax,%eax			# Read MBR
+		movl $MEM_BUF,%ebx		#  from first
+		callw nread			#  sector
 		mov $0x1,%cx	 		# Two passes
 main.1: 	mov $MEM_BUF+PRT_OFF,%si	# Partition table
 		movb $0x1,%dh			# Partition
@@ -139,52 +130,51 @@ 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
+ * for, so go ahead and load up the 128 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
+ * all at 0x9000. 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 zfsboot2, we use an entry point of 0x2000.  That entry point is
- * relative to MEM_USR; thus boot2.bin starts at 0xc000.
+ * binary to 0xc000.  Normally, BTX clients start at MEM_USR, or 0xa000,
+ * but when we use btxld to create zfsboot2, 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.
+ * the client starts at 0xc000).
  */
 main.5: 	mov %dx,MEM_ARG			# Save args
-		movb $NSECT,%dh			# Sector count
+		mov $NSECT,%cx			# Sector count
 		movl $1024,%eax			# 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 $MEM_BTX,%ebx		# Destination buffer
+main.6:		pushal				# Save params
+		callw nread			# Read disk
+		popal				# Restore
+		incl %eax			# Advance to
+		add $SIZ_SEC,%ebx		#  next sector
+		loop main.6			# If not last, read another
+		mov MEM_BTX+0xa,%bx		# Get BTX length
 		mov $NSECT*SIZ_SEC-1,%di	# Size of load area (less one)
-		mov %di,%si			# End of load
-		add $MEM_BUF,%si		#  area
+		mov %di,%si			# End of load area, 0x9000 rel
 		sub %bx,%di			# End of client, 0xc000 rel
 		mov %di,%cx			# Size of
 		inc %cx				#  client
+		mov $(MEM_BTX)>>4,%dx		# Segment
+		mov %dx,%ds			#   addressing 0x9000
 		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
+		cld				# Back to increment
+		xor %dx,%dx			# Back
+		mov %ds,%dx			#  to zero
+		mov %dx,%es			#  segment
 
 /*
  * Enable A20 so we can access memory above 1 meg.
@@ -211,32 +201,35 @@ seta20.3:	sti				# Enable interrupts
 
 /*
  * Trampoline used to call read from within zfsldr.  Sets up an EDD
- * packet on the stack and passes it to read.
+ * packet on the stack and passes it to read.  We assume that the
+ * destination address is always segment-aligned.
  *
  * %eax		- int     - LBA to read in relative to partition start
+ * %ebx		- ptr	  - destination address
  * %dl		- byte    - drive to read from
- * %dh		- byte    - num sectors to read
  * %si		- ptr     - MBR partition entry
  */
-nread:		xor %eax,%eax			# Sector offset in partition
-nread.1:	xor %ecx,%ecx			# Get
+nread:		xor %ecx,%ecx			# Get
 		addl 0x8(%si),%eax		#  LBA
 		adc $0,%ecx
 		pushl %ecx			# Starting absolute block
 		pushl %eax			#  block number
-		push %es			# Address of
-		push $MEM_BUF			#  transfer buffer
-		xor %ax,%ax			# Number of
-		movb %dh,%al			#  blocks to
-		push %ax			#  transfer
+		shr $4,%ebx			# Convert to segment
+		push %bx			# Address of
+		push $0				#  transfer buffer
+		push $0x1			# Read 1 sector
 		push $0x10			# Size of packet
 		mov %sp,%bp			# Packet pointer
 		callw read			# Read from disk
+		jc nread.1			# If error, fail
 		lea 0x10(%bp),%sp		# Clear stack
-		jnc return			# If success, return
-		mov $msg_read,%si		# Otherwise, set the error
-						#  message and fall through to
-						#  the error routine
+		ret				# If success, return
+nread.1:	mov %ah,%al			# Format
+		mov $read_err,%di		#  error
+		call hex8			#  code
+		mov $msg_read,%si		# 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.
@@ -259,14 +252,6 @@ putstr: 	lodsb				# Get char
 		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
@@ -294,14 +279,30 @@ read:		cmpb $0x80,%dl			# Hard drive?
 		retw				# To caller
 read.1:		mov $msg_chs,%si
 		jmp error
-msg_chs:	.asciz "CHS not supported"
+
+/*
+ * AL to hex, saving the result to [EDI].
+ */
+hex8:		push %ax			# Save
+		shrb $0x4,%al			# Do upper
+		call hex8.1			#  4
+		pop %ax				# Restore
+hex8.1: 	andb $0xf,%al			# Get lower 4
+		cmpb $0xa,%al			# Convert
+		sbbb $0x69,%al			#  to hex
+		das				#  digit
+		orb $0x20,%al			# To lower case
+		stosb				# Save char
+		ret				# (Recursive)
 
 /* Messages */
 
-msg_read:	.asciz "Read"
-msg_part:	.asciz "Boot"
+msg_chs:	.asciz "CHS not supported"
+msg_read:	.ascii "Read error: "
+read_err:	.asciz "XX"
+msg_part:	.asciz "Boot error"
 
-prompt: 	.asciz " error\r\n"
+prompt: 	.asciz "\r\n"
 
 		.org PRT_OFF,0x90
 


More information about the svn-src-head mailing list