NEWS: document changes in 4.07
[profile/ivi/syslinux.git] / mbr / mbr.S
index b512c11..b71cfb7 100644 (file)
--- a/mbr/mbr.S
+++ b/mbr/mbr.S
@@ -1,6 +1,7 @@
 /* -----------------------------------------------------------------------
  *
- *   Copyright 2007 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2007-2009 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
  *
  *   Permission is hereby granted, free of charge, to any person
  *   obtaining a copy of this software and associated documentation
@@ -25,6 +26,8 @@
  *
  * ----------------------------------------------------------------------- */
 
+#include "adjust.h"
+
        .code16
        .text
 
@@ -34,7 +37,8 @@ driveno               = (stack-6)
 sectors                = (stack-8)
 secpercyl      = (stack-12)
 
-BIOS_page = 0x462
+BIOS_kbdflags  = 0x417
+BIOS_page      = 0x462
 
        /* gas/ld has issues with doing this as absolute addresses... */
        .section ".bootsec", "a", @nobits
@@ -45,15 +49,14 @@ bootsec:
        .text
        .globl  _start
 _start:
+       .byte   0x33, 0xc0      /* xorw %ax, %ax */
        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
@@ -64,11 +67,14 @@ _start:
        rep; movsw
 
        ljmpw   $0, $next
-
 next:
+
+       ADJUST_DRIVE
+       pushw   %dx             /* dl -> drive number */
+
        /* Check to see if we have EBIOS */
        pushw   %dx             /* drive number */
-       movw    $0x4100, %ax
+       movb    $0x41, %ah      /* %al == 0 already */
        movw    $0x55aa, %bx
        xorw    %cx, %cx
        xorb    %dh, %dh
@@ -77,11 +83,13 @@ next:
        jc      1f
        cmpw    $0xaa55, %bx
        jne     1f
-       testb   $0x01, %cl
-       j     1f
+       shrw    %cx             /* Bit 0 = fixed disk subset */
+       jnc     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)
+       /* 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
@@ -91,67 +99,79 @@ next:
        int     $0x13
        andw    $0x3f, %cx      /* Sector count */
        pushw   %cx             /* Save sectors on the stack */
-       xorw    %ax, %ax
-       pushw   %ax             /* High word of sectors/cylinder */
-       movb    %dh, %al        /* dh = number of heads */
-       incw    %ax             /* From 0-based to count */
+       movzbw  %dh, %ax        /* dh = max head */
+       incw    %ax             /* From 0-based max to count */
        mulw    %cx             /* Heads*sectors -> sectors per cylinder */
-       pushw   %ax             /* Save sectors/cylinder on the stack */
+
+       /* Save sectors/cylinder on the stack */
+       pushw   %dx             /* High word */
+       pushw   %ax             /* Low word */
 
        xorl    %eax, %eax      /* Base */
-       xorl    %edx, %edx      /* Root: %edx <- 0 */
+       cdq                     /* Root (%edx <- 0) */
        call    scan_partition_table
 
        /* If we get here, we have no OS */
-       jmp     missing_os
+missing_os:
+       call    error
+       .ascii  "Missing operating system.\r\n"
 
 /*
  * read_sector: read a single sector pointed to by %eax to 0x7c00.
- * CF is set on error.  All registers clobbered.
+ * CF is set on error.  All registers saved.
  */
 read_sector:
-read_sector_cbios:
+       pushal
        xorl    %edx, %edx
+       movw    $bootsec, %bx
+       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 %eax before this chunk! */
+       /* This also relies on %bx and %edx as set up above. */
+read_sector_cbios:
        divl    (secpercyl)
-       rorb    %ah
-       rorb    %ah
+       shlb    $6, %ah
        movb    %ah, %cl
        movb    %al, %ch
-       movw    %dx, %ax
+       xchgw   %dx, %ax
        divb    (sectors)
        movb    %al, %dh
-       incb    %ah
        orb     %ah, %cl
-       movw    $bootsec, %bx
+       incw    %cx     /* Sectors are 1-based */
        movw    $0x0201, %ax
-       jmp     read_common
-read_sector_ebios:
-       movw    $dapa, %si
-       movl    %eax, 8(%si)
-       movb    $0x42, %ah
+
 read_common:
        movb    (driveno), %dl
        int     $0x13
+       leaw    16(%si), %sp    /* Drop DAPA */
+       popal
        ret
 
 /*
  * read_partition_table:
  *     Read a partition table (pointed to by %eax), and copy
  *     the partition table into the ptab buffer.
- *     Preserve registers.
+ *
+ *     Clobbers %si, %di, and %cx, other registers preserved.
+ *     %cx = 0 on exit.
+ *
+ *     On error, CF is set and ptab is overwritten with junk.
  */
 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
 
 /*
@@ -173,39 +193,40 @@ scan_partition_table:
        movw    %sp, %bp
 
        /* Search for active partitions */
-       movw    $ptab, %di
+       movw    $ptab, %bx
        movw    $4, %cx
        xorw    %ax, %ax
+       push    %bx
+       push    %cx
 5:
-       testb   $0x80, (%di)
+       testb   $0x80, (%bx)
        jz      6f
        incw    %ax
-       movw    %di, %si
+       movw    %bx, %si
 6:
-       addw    $16, %di
+       addw    $16, %bx
        loopw   5b
 
-       cmpw    $1, %ax         /* Number of active partitions found */
-       je      boot
-       j     too_many_active
+       decw    %ax             /* Number of active partitions found */
+       jz      boot
+       jns     too_many_active
 
        /* No active partitions found, look for extended partitions */
-       movw    $ptab, %di
-       movb    $4, %cl         /* cx == 0 here */
+       popw    %cx             /* %cx <- 4    */
+       popw    %bx             /* %bx <- ptab */
 7:
-       movb    4(%di), %al
-       cmpb    $0x05, %al      /* MS-DOS extended */
-       je      8f
-       cmpb    $0x0f, %al      /* Win9x extended */
+       movb    4(%bx), %al
+       cmpb    $0x0f, %al      /* 0x0f = Win9x extended */
        je      8f
-       cmpb    $0x85, %al      /* Linux extended */
+       andb    $~0x80, %al     /* 0x85 = Linux extended */
+       cmpb    $0x05, %al      /* 0x05 = MS-DOS 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    8(%bx), %eax            /* Partition table offset */
        movl    20(%bp), %edx           /* "Root" */
        addl    %edx, %eax              /* Compute location of new ptab */
        andl    %edx, %edx              /* Is this the MBR? */
@@ -217,82 +238,62 @@ scan_partition_table:
        call    scan_partition_table
 11:
        /* This returned, so we need to reload the current partition table */
-       movl    28(%bp), %eax
+       movl    28(%bp), %eax           /* "Base" */
        call    read_partition_table
 
        /* fall through */
 9:
        /* Not an extended partition */
-       addw    $16, %di
+       addw    $16, %bx
        loopw   7b
 
        /* Nothing found, return */
        popal
        ret
 
+too_many_active:
+       call    error
+       .ascii  "Multiple active partitions.\r\n"
+
 /*
  * boot: invoke the actual bootstrap. (%si) points to the partition
- *      table entry, and 22(%bp) has the partition table base.
+ *      table entry, and 28(%bp) has the partition table base.
  */
 boot:
        movl    8(%si), %eax
-       addl    22(%bp), %eax
-       movl    %eax, 8(%si)
-       pushw   %si
+       addl    28(%bp), %eax
+       movl    %eax, 8(%si)    /* Adjust in-memory partition table entry */
        call    read_sector
-       popw    %si
        jc      disk_error
        cmpw    $0xaa55, (bootsec+510)
        jne     missing_os              /* Not a valid boot sector */
-       movw    $driveno, %sp
+       movw    $driveno, %sp   /* driveno == bootsec-6 */
        popw    %dx             /* dl -> drive number */
        popw    %di             /* es:di -> $PnP vector */
        popw    %es
        cli
-       jmp     bootsec
+       jmpw    *%sp            /* %sp == 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 */
+       call    error
+       .ascii  "Operating system load error.\r\n"
 
+/*
+ * Print error messages.  This is invoked with "call", with the
+ * error message at the return address.
+ */
 error:
+       popw    %si
 2:
        lodsb
-       andb    %al, %al
-       jz      3f
        movb    $0x0e, %ah
        movb    (BIOS_page), %bh
        movb    $0x07, %bl
-       int     $0x10
-       jmp     2b
-3:
+       int     $0x10           /* May destroy %bp */
+       cmpb    $10, %al        /* Newline? */
+       jne     2b
+
        int     $0x18           /* Boot failure */
-       jmp     .               /* Die */
-
-missing_os_msg:
-       .ascii  "Missing operating system."
-       .byte   0
-disk_error_msg:
-       .ascii  "Operating system load error."
-       .byte   0
-too_many_active_msg:
-       .ascii  "Multiple active partitions."
-       .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 */
+die:
+       hlt
+       jmp     die