syslinux/mbr/mbr.S
<<
>>
Prefs
   1/* -----------------------------------------------------------------------
   2 *
   3 *   Copyright 2007-2009 H. Peter Anvin - All Rights Reserved
   4 *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
   5 *
   6 *   Permission is hereby granted, free of charge, to any person
   7 *   obtaining a copy of this software and associated documentation
   8 *   files (the "Software"), to deal in the Software without
   9 *   restriction, including without limitation the rights to use,
  10 *   copy, modify, merge, publish, distribute, sublicense, and/or
  11 *   sell copies of the Software, and to permit persons to whom
  12 *   the Software is furnished to do so, subject to the following
  13 *   conditions:
  14 *
  15 *   The above copyright notice and this permission notice shall
  16 *   be included in all copies or substantial portions of the Software.
  17 *
  18 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  19 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  20 *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  21 *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  22 *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  23 *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  24 *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  25 *   OTHER DEALINGS IN THE SOFTWARE.
  26 *
  27 * ----------------------------------------------------------------------- */
  28
  29#include "adjust.h"
  30
  31        .code16
  32        .text
  33
  34        .globl  bootsec
  35stack           = 0x7c00
  36driveno         = (stack-6)
  37sectors         = (stack-8)
  38secpercyl       = (stack-12)
  39
  40BIOS_kbdflags   = 0x417
  41BIOS_page       = 0x462
  42
  43        /* gas/ld has issues with doing this as absolute addresses... */
  44        .section ".bootsec", "a", @nobits
  45        .globl  bootsec
  46bootsec:
  47        .space  512
  48
  49        .text
  50        .globl  _start
  51_start:
  52        .byte   0x33, 0xc0      /* xorw %ax, %ax */
  53        cli
  54        movw    %ax, %ds
  55        movw    %ax, %ss
  56        movw    $stack, %sp
  57        movw    %sp, %si
  58        pushw   %es             /* es:di -> $PnP header */
  59        pushw   %di
  60        movw    %ax, %es
  61        sti
  62        cld
  63
  64        /* Copy down to 0:0x600 */
  65        movw    $_start, %di
  66        movw    $(512/2), %cx
  67        rep; movsw
  68
  69        ljmpw   $0, $next
  70next:
  71
  72        ADJUST_DRIVE
  73        pushw   %dx             /* dl -> drive number */
  74
  75        /* Check to see if we have EBIOS */
  76        pushw   %dx             /* drive number */
  77        movb    $0x41, %ah      /* %al == 0 already */
  78        movw    $0x55aa, %bx
  79        xorw    %cx, %cx
  80        xorb    %dh, %dh
  81        stc
  82        int     $0x13
  83        jc      1f
  84        cmpw    $0xaa55, %bx
  85        jne     1f
  86        shrw    %cx             /* Bit 0 = fixed disk subset */
  87        jnc     1f
  88
  89        /* We have EBIOS; patch in the following code at
  90           read_sector_cbios: movb $0x42, %ah ;  jmp read_common */
  91        movl    $0xeb42b4+((read_common-read_sector_cbios-4) << 24), \
  92                (read_sector_cbios)
  93
  941:
  95        popw    %dx
  96
  97        /* Get (C)HS geometry */
  98        movb    $0x08, %ah
  99        int     $0x13
 100        andw    $0x3f, %cx      /* Sector count */
 101        pushw   %cx             /* Save sectors on the stack */
 102        movzbw  %dh, %ax        /* dh = max head */
 103        incw    %ax             /* From 0-based max to count */
 104        mulw    %cx             /* Heads*sectors -> sectors per cylinder */
 105
 106        /* Save sectors/cylinder on the stack */
 107        pushw   %dx             /* High word */
 108        pushw   %ax             /* Low word */
 109
 110        xorl    %eax, %eax      /* Base */
 111        cdq                     /* Root (%edx <- 0) */
 112        call    scan_partition_table
 113
 114        /* If we get here, we have no OS */
 115missing_os:
 116        call    error
 117        .ascii  "Missing operating system.\r\n"
 118
 119/*
 120 * read_sector: read a single sector pointed to by %eax to 0x7c00.
 121 * CF is set on error.  All registers saved.
 122 */
 123read_sector:
 124        pushal
 125        xorl    %edx, %edx
 126        movw    $bootsec, %bx
 127        pushl   %edx    /* MSW of LBA */
 128        pushl   %eax    /* LSW of LBA */
 129        pushw   %es     /* Buffer segment */
 130        pushw   %bx     /* Buffer offset */
 131        pushw   $1      /* Sector count */
 132        pushw   $16     /* Size of packet */
 133        movw    %sp, %si
 134
 135        /* This chunk is skipped if we have ebios */
 136        /* Do not clobber %eax before this chunk! */
 137        /* This also relies on %bx and %edx as set up above. */
 138read_sector_cbios:
 139        divl    (secpercyl)
 140        shlb    $6, %ah
 141        movb    %ah, %cl
 142        movb    %al, %ch
 143        xchgw   %dx, %ax
 144        divb    (sectors)
 145        movb    %al, %dh
 146        orb     %ah, %cl
 147        incw    %cx     /* Sectors are 1-based */
 148        movw    $0x0201, %ax
 149
 150read_common:
 151        movb    (driveno), %dl
 152        int     $0x13
 153        leaw    16(%si), %sp    /* Drop DAPA */
 154        popal
 155        ret
 156
 157/*
 158 * read_partition_table:
 159 *      Read a partition table (pointed to by %eax), and copy
 160 *      the partition table into the ptab buffer.
 161 *
 162 *      Clobbers %si, %di, and %cx, other registers preserved.
 163 *      %cx = 0 on exit.
 164 *
 165 *      On error, CF is set and ptab is overwritten with junk.
 166 */
 167ptab    = _start+446
 168
 169read_partition_table:
 170        call    read_sector
 171        movw    $bootsec+446, %si
 172        movw    $ptab, %di
 173        movw    $(16*4/2), %cx
 174        rep ; movsw
 175        ret
 176
 177/*
 178 * scan_partition_table:
 179 *      Scan a partition table currently loaded in the partition table
 180 *      area.  Preserve all registers.
 181 *
 182 *      On entry:
 183 *        %eax - base (location of this partition table)
 184 *        %edx - root (offset from MBR, or 0 for MBR)
 185 *
 186 *      These get pushed into stack slots:
 187 *        28(%bp) - %eax - base
 188 *        20(%bp) - %edx - root
 189 */
 190
 191scan_partition_table:
 192        pushal
 193        movw    %sp, %bp
 194
 195        /* Search for active partitions */
 196        movw    $ptab, %bx
 197        movw    $4, %cx
 198        xorw    %ax, %ax
 199        push    %bx
 200        push    %cx
 2015:
 202        testb   $0x80, (%bx)
 203        jz      6f
 204        incw    %ax
 205        movw    %bx, %si
 2066:
 207        addw    $16, %bx
 208        loopw   5b
 209
 210        decw    %ax             /* Number of active partitions found */
 211        jz      boot
 212        jns     too_many_active
 213
 214        /* No active partitions found, look for extended partitions */
 215        popw    %cx             /* %cx <- 4    */
 216        popw    %bx             /* %bx <- ptab */
 2177:
 218        movb    4(%bx), %al
 219        cmpb    $0x0f, %al      /* 0x0f = Win9x extended */
 220        je      8f
 221        andb    $~0x80, %al     /* 0x85 = Linux extended */
 222        cmpb    $0x05, %al      /* 0x05 = MS-DOS extended */
 223        jne     9f
 224
 225        /* It is an extended partition.  Read the extended partition and
 226           try to scan it.  If the scan returns, re-load the current
 227           partition table and resume scan. */
 2288:
 229        movl    8(%bx), %eax            /* Partition table offset */
 230        movl    20(%bp), %edx           /* "Root" */
 231        addl    %edx, %eax              /* Compute location of new ptab */
 232        andl    %edx, %edx              /* Is this the MBR? */
 233        jnz     10f
 234        movl    %eax, %edx              /* Offset -> root if this was MBR */
 23510:
 236        call    read_partition_table
 237        jc      11f
 238        call    scan_partition_table
 23911:
 240        /* This returned, so we need to reload the current partition table */
 241        movl    28(%bp), %eax           /* "Base" */
 242        call    read_partition_table
 243
 244        /* fall through */
 2459:
 246        /* Not an extended partition */
 247        addw    $16, %bx
 248        loopw   7b
 249
 250        /* Nothing found, return */
 251        popal
 252        ret
 253
 254too_many_active:
 255        call    error
 256        .ascii  "Multiple active partitions.\r\n"
 257
 258/*
 259 * boot: invoke the actual bootstrap. (%si) points to the partition
 260 *       table entry, and 28(%bp) has the partition table base.
 261 */
 262boot:
 263        movl    8(%si), %eax
 264        addl    28(%bp), %eax
 265        movl    %eax, 8(%si)    /* Adjust in-memory partition table entry */
 266        call    read_sector
 267        jc      disk_error
 268        cmpw    $0xaa55, (bootsec+510)
 269        jne     missing_os              /* Not a valid boot sector */
 270        movw    $driveno, %sp   /* driveno == bootsec-6 */
 271        popw    %dx             /* dl -> drive number */
 272        popw    %di             /* es:di -> $PnP vector */
 273        popw    %es
 274        cli
 275        jmpw    *%sp            /* %sp == bootsec */
 276
 277disk_error:
 278        call    error
 279        .ascii  "Operating system load error.\r\n"
 280
 281/*
 282 * Print error messages.  This is invoked with "call", with the
 283 * error message at the return address.
 284 */
 285error:
 286        popw    %si
 2872:
 288        lodsb
 289        movb    $0x0e, %ah
 290        movb    (BIOS_page), %bh
 291        movb    $0x07, %bl
 292        int     $0x10           /* May destroy %bp */
 293        cmpb    $10, %al        /* Newline? */
 294        jne     2b
 295
 296        int     $0x18           /* Boot failure */
 297die:
 298        hlt
 299        jmp     die
 300
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.