Master boot record for GPT partition tables
authorH. Peter Anvin <hpa@zytor.com>
Mon, 25 Feb 2008 22:22:54 +0000 (14:22 -0800)
committerH. Peter Anvin <hpa@zytor.com>
Mon, 25 Feb 2008 22:22:54 +0000 (14:22 -0800)
Beginnings of a master boot record for GPT partition tables.

mbr/Makefile
mbr/gptmbr.S [new file with mode: 0644]

index a64869b..ed33aed 100644 (file)
@@ -29,7 +29,7 @@ PERL     = perl
 
 .SUFFIXES: .S .s .o .elf
 
-all:   mbr.bin
+all:   mbr.bin gptmbr.bin
 
 .PRECIOUS: %.o
 %.o: %.S
@@ -42,6 +42,13 @@ mbr.bin: mbr.elf checksize.pl
        $(OBJCOPY) -O binary $< $@
        $(PERL) checksize.pl mbr.bin 440
 
+gptmbr.elf: gptmbr.o mbr.ld
+       $(LD) -T mbr.ld -e _start -o $@ $<
+
+gptmbr.bin: gptmbr.elf checksize.pl
+       $(OBJCOPY) -O binary $< $@
+       $(PERL) checksize.pl gptmbr.bin 424
+
 tidy:
        rm -f *.o *.elf *.lst
 
diff --git a/mbr/gptmbr.S b/mbr/gptmbr.S
new file mode 100644 (file)
index 0000000..a6b2607
--- /dev/null
@@ -0,0 +1,284 @@
+/* -----------------------------------------------------------------------
+ *
+ *   Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+       .code16
+       .text
+
+       .globl  bootsec
+stack          = 0x7c00
+driveno                = (stack-6)
+sectors                = (stack-8)
+secpercyl      = (stack-12)
+
+/* Partition table header here */
+phdr           = _start + 512
+/* Partition table sector here */
+/* To handle > 32K we need to play segment tricks... */
+psec           = 0x8000        /* Above the boot sector and stack */
+
+/* BootGUID */
+bootguid       = _start + 0x1a8
+/* Where we put DS:SI */
+dssi_out       = _start + 0x1be
+
+BIOS_page      = 0x462
+
+       /* gas/ld has issues with doing this as absolute addresses... */
+       .section ".bootsec", "a", @nobits
+       .globl  bootsec
+bootsec:
+       .space  512
+
+       .text
+       .globl  _start
+_start:
+       cli
+       xorw    %ax, %ax
+       movw    %ax, %ds
+       movw    %ax, %ss
+       movw    $stack, %sp
+       movw    %sp, %si
+       pushw   %es             /* es:di -> $PnP header */
+       pushw   %di
+       pushw   %dx             /* dl -> drive number */
+       movw    %ax, %es
+       sti
+       cld
+
+       /* Copy down to 0:0x600 */
+       movw    $_start, %di
+       movw    $(512/2), %cx
+       rep; movsw
+
+       ljmpw   $0, $next
+
+next:
+       /* Check to see if we have EBIOS */
+       pushw   %dx             /* drive number */
+       movb    $0x41, %ah      /* %al == 0 already */
+       movw    $0x55aa, %bx
+       xorw    %cx, %cx
+       xorb    %dh, %dh
+       stc
+       int     $0x13
+       jc      1f
+       cmpw    $0xaa55, %bx
+       jne     1f
+       shrw    %cx             /* Bit 0 = fixed disk subset */
+       jnc     1f
+
+       /* We have EBIOS; patch in the following code at
+          read_sector_cbios: movb $0x42, %ah ;  jmp read_common */
+       movl    $0xeb42b4+((read_common-read_sector_cbios-4) << 24), \
+               (read_sector_cbios)
+
+1:
+       popw    %dx
+
+       /* Get (C)HS geometry */
+       movb    $0x08, %ah
+       int     $0x13
+       andw    $0x3f, %cx      /* Sector count */
+       pushw   %cx             /* Save sectors on the stack */
+       movzbw  %dh, %ax        /* dh = max head */
+       incw    %ax             /* From 0-based max to count */
+       mulw    %cx             /* Heads*sectors -> sectors per cylinder */
+
+       /* Save sectors/cylinder on the stack */
+       pushw   %dx             /* High word */
+       pushw   %ax             /* Low word */
+
+       /* Load partition table header */
+       xorl    %eax,%eax
+       xorl    %edx,%edx
+       incl    %eax
+       movw    $phdr,%bx
+       call    read_sector
+
+       /* Number of partition sectors */
+       /* We assume the partition table is 32K or less, and that
+          the sector size is 512. */
+       movw    (phdr+0x80),%cx         /* NumberOfPartitionEntries */
+       movw    (phdr+0x84),%ax         /* SizeOfPartitionEntry */
+       pushw   %ax
+       pushw   %cx
+       mulw    %cx
+       shrw    $9,%ax
+       xchgw   %ax,%cx
+       incw    %cx
+
+       /* Starting LBA of partition array */
+       movl    (phdr+0x72),%eax
+       movl    (phdr+0x76),%edx
+
+       movw    $psec,%bx
+       pushw   %bx
+get_ptab:
+       call    read_sector
+       addw    $512,%bx
+       call    inc64
+       loopw   get_ptab
+
+       /* Find the boot partition */
+       popw    %si                     /* Partition table in memory */
+       popw    %cx                     /* NumberOfPartitionEntries */
+       popw    %ax                     /* SizeOfPartitionEntry */
+find_part:
+       pushw   %cx
+       pushw   %si
+       addw    $16,%si
+       movw    $bootguid,%di
+       movw    $8,%cx
+       rep; cmpsw
+       popw    %si
+       popw    %cx
+       je found_part
+       addw    %ax,%si
+       loopw   find_part
+
+       call    error
+       .ascii  "Boot partition not found\r\n"
+
+found_part:
+       movw    $dssi_out+16,%di
+       movw    %ax,%cx
+       rep; movsb
+       movw    $dssi_out,%si
+       movw    %si,%di
+       /* 80 00 00 00 ee 00 00 00
+          - bootable partition, type EFI (EE), no CHS information */
+       xorl    %eax,%eax
+       movb    $0x80,%al
+       stosl
+       movb    $0xee,%al
+       stosl
+       movl    (40+16)(%si),%eax
+       movl    (48+16)(%si),%edx
+       pushl   %eax
+       pushl   %edx
+       call    saturate_stosl          /* Partition start */
+
+       subl    (32+16)(%si),%eax
+       sbbl    (36+16)(%si),%edx
+       call    inc64
+       call    saturate_stosl          /* Partition length */
+
+/*
+ * boot: invoke the actual bootstrap. (%si) points to the
+ * partition information in memory, and the block offset is
+ * on the stack.
+ */
+boot:
+       popl    %edx
+       popl    %eax
+       call    read_sector
+       cmpw    $0xaa55, (bootsec+510)
+       jne     missing_os      /* Not a valid boot sector */
+       movw    $driveno, %sp   /* driveno == bootsec-6 */
+       popw    %dx             /* dl -> drive number */
+       popw    %di             /* es:di -> $PnP vector */
+       popw    %es
+       cli
+       jmpw    *%sp            /* %sp == bootsec */
+
+missing_os:
+       call    error
+       .ascii  "Operating system not bootable\r\n"
+
+saturate_stosl:
+       pushl   %eax
+       andl    %edx,%edx
+       jz 1f
+       orl     $-1,%eax
+1:     stosl
+       popl    %eax
+       ret
+
+inc64:
+       addl    $1,%eax
+       adcl    $0,%edx
+       ret
+
+/*
+ * read_sector: read a single sector pointed to by %edx:%eax to
+ * %es:%bx.  CF is set on error.  All registers saved.
+ */
+read_sector:
+       pushal
+       pushl   %edx    /* MSW of LBA */
+       pushl   %eax    /* LSW of LBA */
+       pushw   %es     /* Buffer segment */
+       pushw   %bx     /* Buffer offset */
+       pushw   $1      /* Sector count */
+       pushw   $16     /* Size of packet */
+       movw    %sp, %si
+
+       /* This chunk is skipped if we have ebios */
+       /* Do not clobber %es:%bx or %edx:%eax before this chunk! */
+read_sector_cbios:
+       divl    (secpercyl)
+       shlb    $6, %ah
+       movb    %ah, %cl
+       movb    %al, %ch
+       xchgw   %dx, %ax
+       divb    (sectors)
+       movb    %al, %dh
+       orb     %ah, %cl
+       incw    %cx     /* Sectors are 1-based */
+       movw    $0x0201, %ax
+
+read_common:
+       movb    (driveno), %dl
+       int     $0x13
+       addw    $16, %sp        /* Drop DAPA */
+       popal
+       jc      disk_error
+       ret
+
+disk_error:
+       call    error
+       .ascii  "Disk error on boot\r\n"
+
+/*
+ * Print error messages.  This is invoked with "call", with the
+ * error message at the return address.
+ */
+error:
+       popw    %si
+2:
+       lodsb
+       movb    $0x0e, %ah
+       movb    (BIOS_page), %bh
+       movb    $0x07, %bl
+       int     $0x10           /* May destroy %bp */
+       cmpb    $10, %al        /* Newline? */
+       jne     2b
+
+       int     $0x18           /* Boot failure */
+die:
+       hlt
+       jmp     die