New MBR which supports logical partitions.
authorH. Peter Anvin <hpa@zytor.com>
Sun, 4 Feb 2007 23:59:37 +0000 (15:59 -0800)
committerH. Peter Anvin <hpa@zytor.com>
Sun, 4 Feb 2007 23:59:37 +0000 (15:59 -0800)
New MBR which supports logical partitions.  Move the MBR to a subdirectory,
and convert it to gas with the expectation of including it in util-linux.

Makefile
mbr/Makefile [new file with mode: 0644]
mbr/checksize.pl [new file with mode: 0755]
mbr/mbr.S [new file with mode: 0644]

index 7673cf5..5814897 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -63,12 +63,16 @@ BINFILES = bootsect_bin.c ldlinux_bin.c mbr_bin.c \
 # mingw suite installed
 BTARGET  = kwdhash.gen version.gen version.h \
           ldlinux.bss ldlinux.sys ldlinux.bin \
-          pxelinux.0 mbr.bin isolinux.bin isolinux-debug.bin \
+          pxelinux.0 isolinux.bin isolinux-debug.bin \
           extlinux.bin extlinux.bss extlinux.sys
-BOBJECTS = $(BTARGET) dos/syslinux.com win32/syslinux.exe memdisk/memdisk
+BOBJECTS = $(BTARGET) mbr/mbr.bin dos/syslinux.com win32/syslinux.exe memdisk/memdisk
+# BESUBDIRS and IESUBDIRS are "early", i.e. before the root; BSUBDIRS
+# and ISUBDIRS are "late", after the root.
+BESUBDIRS = mbr
 BSUBDIRS = memdisk dos win32
 ITARGET  = copybs.com gethostip mkdiskimage
 IOBJECTS = $(ITARGET) mtools/syslinux unix/syslinux extlinux/extlinux
+IESUBDIRS =
 ISUBDIRS = mtools unix extlinux sample com32
 DOCS     = COPYING NEWS README TODO BUGS *.doc sample menu com32
 OTHER    = Makefile bin2c.pl now.pl genhash.pl keywords findpatch.pl \
@@ -102,9 +106,10 @@ MAKE    += DATE=$(DATE) HEXDATE=$(HEXDATE)
 # error every time you try to build.
 #
 
-all:   all-local
-       set -e ; for i in $(BSUBDIRS) $(ISUBDIRS) ; do $(MAKE) -C $$i $@ ; done
+all:
+       set -e ; for i in $(BESUBDIRS) $(IESUBDIRS) ; do $(MAKE) -C $$i $@ ; done
        $(MAKE) all-local
+       set -e ; for i in $(BSUBDIRS) $(ISUBDIRS) ; do $(MAKE) -C $$i $@ ; done
        -ls -l $(BOBJECTS) $(IOBJECTS)
 
 all-local: $(BTARGET) $(ITARGET) $(BINFILES)
@@ -167,10 +172,7 @@ extlinux.bss: extlinux.bin
 extlinux.sys: extlinux.bin
        dd if=$< of=$@ bs=512 skip=1
 
-mbr.bin: mbr.asm
-       $(NASM) -f bin -l mbr.lst -o mbr.bin mbr.asm
-
-mbr_bin.c: mbr.bin bin2c.pl
+mbr_bin.c: mbr/mbr.bin bin2c.pl
        $(PERL) bin2c.pl syslinux_mbr < $< > $@
 
 copybs.com: copybs.asm
diff --git a/mbr/Makefile b/mbr/Makefile
new file mode 100644 (file)
index 0000000..d96ee46
--- /dev/null
@@ -0,0 +1,47 @@
+## -----------------------------------------------------------------------
+##   
+##   Copyright 2007 H. Peter Anvin - All Rights Reserved
+##
+##   This program is free software; you can redistribute it and/or modify
+##   it under the terms of the GNU General Public License as published by
+##   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+##   Boston MA 02111-1307, USA; either version 2 of the License, or
+##   (at your option) any later version; incorporated herein by reference.
+##
+## -----------------------------------------------------------------------
+
+#
+# Makefile for MBR
+#
+
+gcc_ok   = $(shell if gcc $(1) -c -x c /dev/null -o /dev/null 2>/dev/null; \
+                  then echo $(1); else echo $(2); fi)
+
+M32       := $(call gcc_ok,-m32,) $(call gcc_ok,-ffreestanding,)
+
+CC         = gcc
+LD         = ld -m elf_i386
+SFLAGS    = $(M32) -march=i386
+OBJCOPY           = objcopy
+PERL      = perl
+
+.SUFFIXES: .S .s .o .elf
+
+all:   mbr.bin
+
+.PRECIOUS: %.o
+%.o: %.S
+       $(CC) $(SFLAGS) -c -o $@ $<
+
+mbr.elf: mbr.o
+       $(LD) -Ttext 0x600 -e _start -o $@ $^
+
+mbr.bin: mbr.elf checksize.pl
+       $(OBJCOPY) -O binary $< $@
+       $(PERL) checksize.pl mbr.bin 440
+
+tidy:
+       rm -f *.o *.elf
+
+clean:
+       rm -f *.o *.elf *.bin
diff --git a/mbr/checksize.pl b/mbr/checksize.pl
new file mode 100755 (executable)
index 0000000..b7d560a
--- /dev/null
@@ -0,0 +1,31 @@
+## -----------------------------------------------------------------------
+##   
+##   Copyright 2007 H. Peter Anvin - All Rights Reserved
+##
+##   This program is free software; you can redistribute it and/or modify
+##   it under the terms of the GNU General Public License as published by
+##   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+##   Boston MA 02111-1307, USA; either version 2 of the License, or
+##   (at your option) any later version; incorporated herein by reference.
+##
+## -----------------------------------------------------------------------
+
+##
+## checksize.pl
+##
+## Check the size of a binary file
+##
+
+($file, $maxsize) = @ARGV;
+
+@st = stat($file);
+if (!defined($size = $st[7])) {
+    die "$0: $file: $!\n";
+}
+if ($size > $maxsize) {
+    print STDERR "$file: too big ($size > $maxsize)\n";
+    exit 1;
+} else {
+    exit 0;
+}
+
diff --git a/mbr/mbr.S b/mbr/mbr.S
new file mode 100644 (file)
index 0000000..edfccfb
--- /dev/null
+++ b/mbr/mbr.S
@@ -0,0 +1,290 @@
+/* -----------------------------------------------------------------------
+ *   
+ *   Copyright 2007 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
+
+bootsec = 0x7c00
+stack  = bootsec
+driveno        = (stack-4)
+heads  = (stack-6)
+sectors        = (stack-8)
+
+BIOS_page = 0x462
+       
+       .globl  _start
+_start:
+       cli
+       xorw    %ax, %ax
+       movw    %ax, %ds
+       movw    %ax, %ss
+       movw    $stack, %sp
+       pushw   %es             /* es:di -> $PnP header */
+       pushw   %di
+       pushw   %dx             /* dl -> drive number */
+       movw    %ax, %es
+       sti
+       cld
+
+       /* Copy down to 0:0x600 */
+       movw    %sp, %si
+       movw    $_start, %di
+       movw    $(512/2), %cx
+       rep; movsw
+
+       ljmpw   $0, $next
+
+next:
+       /* Check to see if we have EBIOS */
+       pushw   %dx             /* drive number */
+       movw    $0x4100, %ax
+       movw    $0x55aa, %bx
+       xorw    %cx, %cx
+       xorb    %dh, %dh
+       stc
+       int     $0x13
+       jc      1f
+       cmpw    $0xaa55, %bx
+       jne     1f
+       testb   $0x01, %cl
+       jz      1f
+
+       /* We have EBIOS; patch in a jump to read_sector_ebios */
+       movw    $0xeb+((read_sector_ebios-read_sector_cbios+2)<< 8), (read_sector_cbios)
+
+1:
+       popw    %dx
+
+       /* Get (C)HS geometry */
+       movb    $0x08, %ah
+       int     $0x13
+       xorw    %ax, %ax
+       movb    %dh, %al        /* dh = number of heads */
+       incw    %ax             /* From 0-based to count */
+       pushw   %ax             /* Save heads on the stack */
+       andw    $0x3f, %cx      /* Sector count */
+       pushw   %cx             /* Save sectors on the stack */
+
+       xorl    %eax, %eax
+       pushl   %eax            /* Base */
+       pushl   %eax            /* Root */
+       call    scan_partition_table
+
+       
+       /* If we get here, we have no OS */
+       jmp     missing_os
+
+/*
+ * read_sector: read a single sector pointed to by %eax to 0x7c00.
+ * CF is set on error.  All registers clobbered.
+ */
+read_sector:
+read_sector_cbios:
+       movl    %eax, %edx
+       shrl    $16, %edx
+       divw    (sectors)
+       incw    %dx
+       movw    %dx, %cx
+       xorw    %dx, %dx
+       divw    (heads)
+       /* dx = head, ax = cylinder */
+       movb    %al, %ch
+       shrw    $2, %ax
+       shrw    %ax
+       andb    $0xc0, %al
+       orb     %al, %cl
+       movb    %dl, %dh
+       movw    $bootsec, %bx
+       movw    $0x0201, %ax
+       jmp     read_common
+read_sector_ebios:
+       movw    $dapa, %si
+       movl    %eax, 8(%si)
+       movb    $0x42, %ah
+read_common:
+       int     $0x13
+       ret
+
+/*
+ * read_partition_table:
+ *     Read a partition table (pointed to by %eax), and copy
+ *     the partition table into the ptab buffer.
+ *     Preserve registers.
+ */
+ptab   = _start+446
+
+read_partition_table:
+       pushal
+       call    read_sector
+       jc      20f
+       movw    $bootsec+446, %si
+       movw    $ptab, %di
+       movw    $(16*4/2), %cx
+       rep ; movsw
+20:
+       popal
+       ret
+                       
+/*
+ * scan_partition_table:
+ *     Scan a partition table currently loaded in the partition table
+ *     area.  Preserve 16-bit registers.
+ *
+ *     On stack:
+ *       18(%bp) - root (offset from MBR, or 0 for MBR)
+ *       22(%bp) - base (location of this partition table)
+ */
+       
+scan_partition_table:
+       pusha
+       movw    %sp, %bp
+
+       /* Search for active partitions */      
+       movw    $ptab, %di
+       movw    $4, %cx
+       xorw    %ax, %ax
+5:
+       testb   $0x80, (%di)
+       jz 6f
+       incw    %ax
+       movw    %di, %si
+6:
+       addw    $16, %di
+       loopw   5b
+
+       cmpw    $1, %ax         /* Number of active partitions found */
+       je      boot
+       ja      too_many_active
+
+       /* No active partitions found, look for extended partitions */
+       movw    $ptab, %di
+       movb    $4, %cl         /* cx == 0 here */
+7:
+       movb    4(%di), %al
+       cmpb    $0x05, %al      /* MS-DOS extended */
+       je      8f
+       cmpb    $0x0f, %al      /* Win9x extended */
+       je      8f
+       cmpb    $0x85, %al      /* Linux extended */
+       jne     9f
+       
+       /* It is an extended partition.  Read the extended partition and
+          try to scan it.  If the scan returns, re-load the current
+          partition table and resume scan. */
+8:
+       movl    8(%di), %eax            /* Partition table offset */
+       movl    18(%bp), %edx           /* "Root" */
+       addl    %edx, %eax              /* Compute location of new ptab */
+       andl    %edx, %edx              /* Is this the MBR? */
+       jnz     10f
+       movl    %eax, %edx              /* Offset -> root if this was MBR */
+10:
+       pushl   %eax                    /* Push new base */
+       pushl   %edx                    /* Push new root */
+       call    read_partition_table
+       jc 11f
+       call    scan_partition_table
+11:
+       addw    $8, %sp
+       /* This returned, so we need to reload the current partition table */
+       movl    22(%bp), %eax
+       call    read_partition_table
+
+       /* fall through */              
+9:
+       /* Not an extended partition */
+       addw    $16, %di
+       loopw   7b
+
+       /* Nothing found, return */
+       popa
+       ret
+
+/*
+ * boot: invoke the actual bootstrap. (%si) points to the partition
+ *      table entry, and 22(%bp) has the partition table base.
+ */
+boot:
+       movl    8(%si), %eax
+       addl    22(%bp), %eax
+       movl    %eax, 8(%si)
+       call    read_sector
+       jc      disk_error
+       cmpw    $0xaa55, (bootsec+0x510)
+       je      missing_os              /* Not a valid boot sector */
+       movw    $stack-6, %sp
+       popw    %dx             /* dl -> drive number */
+       popw    %di             /* es:di -> $PnP vector */
+       popw    %es
+       cli
+       jmp     bootsec
+
+/*
+ * error messages
+ */
+missing_os:
+       movw    $missing_os_msg, %si
+       jmp     error
+disk_error:
+       movw    $disk_error_msg, %si
+       jmp     error
+too_many_active:
+       movw    $too_many_active_msg, %si
+       /* jmp error */
+       
+error:
+2:
+       lodsb
+       andb    %al, %al
+       jz      3f
+       movb    $0x0e, %ah
+       movb    (BIOS_page), %bh
+       movb    $0x07, %bl
+       int     $0x10
+       jmp     2b
+3:
+       int     $0x18           /* Boot failure */
+       jmp     .               /* Die */
+
+missing_os_msg:
+       .ascii  "Missing operating system."
+       .byte   0
+disk_error_msg:
+       .ascii  "Failed to load operating system."
+       .byte   0
+too_many_active_msg:
+       .ascii  "Multiple active partititons."
+       .byte   0
+
+       .balign 4
+dapa:
+       .short  16              /* Size of packet */
+       .short  1               /* Sector count */
+       .short  0x7c00          /* Buffer offset */
+       .short  0               /* Buffer segment */
+       .long   0               /* LSW of LBA */
+       .long   0               /* MSW of LBA */