ZFS boot inside on the second partition inside a slice
jhb at freebsd.org
Wed Jun 22 15:58:18 UTC 2011
On Wednesday, June 22, 2011 10:23:22 am Henri Hennebert wrote:
> On 06/22/2011 16:19, Henri Hennebert wrote:
> > This time:
> > LBA: 3c802308
> > Read error: 04
> > This morning I was reading the code (I'm in Belgium) and find that the
> > previous LBA output was DAP+4 and so was the addr of the buffer. 0x8200
> > = $MEM_BUF+512, and so we must be in the second read.
> OK I think I see, the first read mangle the partition table previously
> read at $MEM_BUF and so the next one is wrong.
Ahh, very true. I was planning to simplify the code to just load at MEM_BTX
directly and avoid copying BTX. I went ahead and did that below:
--- zfsldr.S (revision 223365)
+++ zfsldr.S (working copy)
@@ -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
+ movw $MEM_BUF,%bx # from first
+ callw nread # sector
mov $0x1,%cx # Two passes
main.1: mov $MEM_BUF+PRT_OFF,%si # Partition table
movb $0x1,%dh # Partition
@@ -143,32 +134,35 @@ main.4: xor %dx,%dx # Partition:drive
* (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 $MEM_BTX,%bx # Destination buffer
+main.6: pushal # Save params
+ callw nread # Read disk
+ popal # Restore
+ incl %eax # Update for
+ add $SIZ_SEC,%bx # next sector
+ loop main.6 # If not last, read another
+ mov $MEM_BTX,%si # BTX
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
+ add $MEM_BTX,%si # area
sub %bx,%di # End of client, 0xc000 rel
mov %di,%cx # Size of
inc %cx # client
@@ -179,12 +173,6 @@ main.5: mov %dx,MEM_ARG # Save args
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.
@@ -214,29 +202,35 @@ seta20.3: sti # Enable interrupts
* packet on the stack and passes it to read.
* %eax - int - LBA to read in relative to partition start
+ * %es:%bx - 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
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
+ push %bx # 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
+ movl 0x8(%bp),%eax # Format
+ mov $lba,%di # LBA
+ call hex32
+ mov $msg_lba,%si # Display
+ call putstr # LBA
+ 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 +253,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 +280,38 @@ read: cmpb $0x80,%dl # Hard drive?
retw # To caller
read.1: mov $msg_chs,%si
-msg_chs: .asciz "CHS not supported"
+ * Convert EAX, AX, or AL to hex, saving the result to [EDI].
+hex32: pushl %eax # Save
+ shrl $0x10,%eax # Do upper
+ call hex16 # 16
+ popl %eax # Restore
+hex16: call hex16.1 # Do upper 8
+hex16.1: xchgb %ah,%al # Save/restore
+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_lba: .ascii "LBA: "
+lba: .asciz "XXXXXXXX\r\n"
+msg_part: .asciz "Boot error"
-prompt: .asciz " error\r\n"
+prompt: .asciz "\r\n"
More information about the freebsd-stable