Fix long-standing bug in boot1 code - can read junk from fake partition table
authorMatthew Dillon <dillon@apollo.backplane.com>
Wed, 11 Feb 2009 09:53:52 +0000 (01:53 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Wed, 11 Feb 2009 09:53:52 +0000 (01:53 -0800)
boot1 reads the MBR to locate the BSD partition type (0xA5).  However, to
reduce the size of the boot1 code the 32 bit LBA for the MBR was being
loaded via the fake partition table at label 'part4', which was assumed to
contain a LBA of 0.  Unfortunately this portion of the boot1 code is not
usually written by the disklabel program and may contain garbage.

For the last few years we have worked around the issue by zeroing out
the label area before installing a new label.  We still have to do this
to avoid disklabel32/disklabel64 confusion, but with this fix forgetting
to zero the area should not cause a properly installed disklabel to fail
to boot properly.

To fix the problem, add the necessary instructions to generate a 32 bit
LBA of 0 directly for reading the MBR.  They barely fit.

sys/boot/pc32/boot2/boot1.S

index f7194f7..39cfcdf 100644 (file)
@@ -143,6 +143,9 @@ xread.1:                                    // Starting
 // Setup the segment registers to flat addressing (segment 0) and setup the
 // stack to end just below the start of our code.
 // 
+// XXX note - our origin (start) points to the MEM_BIOS_LADDR.  We run
+// from there but boot2 later on calls xread at BOOT1_ORIGIN.
+//
 main:          cld                             // String ops inc
                xor %cx,%cx                     // Zero
                mov %cx,%es                     // Address
@@ -160,16 +163,18 @@ main:             cld                             // String ops inc
                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.
+// FreeBSD slice.
+//
+// Note, we can't use the fake partition entry (part4), as it may contain
+// garbage if this is a normal boot1 on a slice, verses a dangerously
+// dedicated disk.  Hardwire sector 0 to acquire the MBR
 // 
-               mov $part4,%si                  // Partition
+               xor %ax,%ax
+               xor %cx,%cx
                cmpb $0x80,%dl                  // Hard drive?
                jb main.4                       // No
                movb $0x1,%dh                   // Block count
-               callw nread                     // Read MBR
+               callw nread_alt                 // Read MBR
                mov $0x1,%cx                    // Two passes
 main.1:        mov $BOOT2_LOAD_BUF+PRT_OFF,%si // Partition table
                movb $0x1,%dh                   // Partition
@@ -273,9 +278,11 @@ seta20.2:  inb $0x64,%al                   // Get status
 // 
 // Trampoline used to call read from within boot1.
 // 
-nread:         mov $BOOT2_LOAD_BUF,%bx         // Transfer buffer
+nread:
                mov 0x8(%si),%ax                // Get
                mov 0xa(%si),%cx                //  LBA
+nread_alt:
+               mov $BOOT2_LOAD_BUF,%bx         // Transfer buffer
                push %cs                        // Read from
                callw xread.1                   //  disk
                jnc return                      // If success, return
@@ -430,6 +437,10 @@ flags:             .byte FLAGS                     // Flags
                .org PRT_OFF,0x90
 
 // Partition table
+//
+// THIS MAY NOT BE WRITTEN OUT TO THE BOOT1 AREA OF THE DISKLABEL.  This
+// section is only written out when the disklabel is placed on the raw
+// disk instead of in a slice, when creating a dangerously dedicated disk.
 
                .fill 0x30,0x1,0x0
 part4:         .byte 0x80, 0x00, 0x01, 0x00