linux/arch/i386/boot/edd.S
<<
>>
Prefs
   1/*
   2 * BIOS Enhanced Disk Drive support
   3 * Copyright (C) 2002, 2003, 2004 Dell, Inc.
   4 * by Matt Domsch <Matt_Domsch@dell.com> October 2002
   5 * conformant to T13 Committee www.t13.org
   6 *   projects 1572D, 1484D, 1386D, 1226DT
   7 * disk signature read by Matt Domsch <Matt_Domsch@dell.com>
   8 *      and Andrew Wilks <Andrew_Wilks@dell.com> September 2003, June 2004
   9 * legacy CHS retrieval by Patrick J. LoPresti <patl@users.sourceforge.net>
  10 *      March 2004
  11 * Command line option parsing, Matt Domsch, November 2004
  12 */
  13
  14#include <linux/edd.h>
  15#include <asm/setup.h>
  16
  17#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
  18
  19# It is assumed that %ds == INITSEG here
  20
  21        movb    $0, (EDD_MBR_SIG_NR_BUF)
  22        movb    $0, (EDDNR)
  23
  24# Check the command line for options:
  25# edd=of  disables EDD completely  (edd=off)
  26# edd=sk  skips the MBR test    (edd=skipmbr)
  27# edd=on  re-enables EDD (edd=on)
  28
  29        pushl   %esi
  30        movw    $edd_mbr_sig_start, %di # Default to edd=on
  31
  32        movl    %cs:(cmd_line_ptr), %esi
  33        andl    %esi, %esi
  34        jz      old_cl                  # Old boot protocol?
  35
  36# Convert to a real-mode pointer in fs:si
  37        movl    %esi, %eax
  38        shrl    $4, %eax
  39        movw    %ax, %fs
  40        andw    $0xf, %si
  41        jmp     have_cl_pointer
  42
  43# Old-style boot protocol?
  44old_cl:
  45        push    %ds                     # aka INITSEG
  46        pop     %fs
  47
  48        cmpw    $0xa33f, (0x20)
  49        jne     done_cl                 # No command line at all?
  50        movw    (0x22), %si             # Pointer relative to INITSEG
  51
  52# fs:si has the pointer to the command line now
  53have_cl_pointer:
  54
  55# Loop through kernel command line one byte at a time.  Just in
  56# case the loader is buggy and failed to null-terminate the command line
  57# terminate if we get close enough to the end of the segment that we
  58# cannot fit "edd=XX"...
  59cl_atspace:
  60        cmpw    $-5, %si                # Watch for segment wraparound
  61        jae     done_cl
  62        movl    %fs:(%si), %eax
  63        andb    %al, %al                # End of line?
  64        jz      done_cl
  65        cmpl    $EDD_CL_EQUALS, %eax
  66        jz      found_edd_equals
  67        cmpb    $0x20, %al              # <= space consider whitespace
  68        ja      cl_skipword
  69        incw    %si
  70        jmp     cl_atspace
  71
  72cl_skipword:
  73        cmpw    $-5, %si                # Watch for segment wraparound
  74        jae     done_cl
  75        movb    %fs:(%si), %al          # End of string?
  76        andb    %al, %al
  77        jz      done_cl
  78        cmpb    $0x20, %al
  79        jbe     cl_atspace
  80        incw    %si
  81        jmp     cl_skipword
  82
  83found_edd_equals:
  84# only looking at first two characters after equals
  85# late overrides early on the command line, so keep going after finding something
  86        movw    %fs:4(%si), %ax
  87        cmpw    $EDD_CL_OFF, %ax        # edd=of
  88        je      do_edd_off
  89        cmpw    $EDD_CL_SKIP, %ax       # edd=sk
  90        je      do_edd_skipmbr
  91        cmpw    $EDD_CL_ON, %ax         # edd=on
  92        je      do_edd_on
  93        jmp     cl_skipword
  94do_edd_skipmbr:
  95        movw    $edd_start, %di
  96        jmp     cl_skipword
  97do_edd_off:
  98        movw    $edd_done, %di
  99        jmp     cl_skipword
 100do_edd_on:
 101        movw    $edd_mbr_sig_start, %di
 102        jmp     cl_skipword
 103
 104done_cl:
 105        popl    %esi
 106        jmpw    *%di
 107
 108# Read the first sector of each BIOS disk device and store the 4-byte signature
 109edd_mbr_sig_start:
 110        movb    $0x80, %dl                      # from device 80
 111        movw    $EDD_MBR_SIG_BUF, %bx           # store buffer ptr in bx
 112edd_mbr_sig_read:
 113        movl    $0xFFFFFFFF, %eax
 114        movl    %eax, (%bx)                     # assume failure
 115        pushw   %bx
 116        movb    $READ_SECTORS, %ah
 117        movb    $1, %al                         # read 1 sector
 118        movb    $0, %dh                         # at head 0
 119        movw    $1, %cx                         # cylinder 0, sector 0
 120        pushw   %es
 121        pushw   %ds
 122        popw    %es
 123        movw    $EDDBUF, %bx                    # disk's data goes into EDDBUF
 124        pushw   %dx             # work around buggy BIOSes
 125        stc                     # work around buggy BIOSes
 126        int     $0x13
 127        sti                     # work around buggy BIOSes
 128        popw    %dx
 129        popw    %es
 130        popw    %bx
 131        jc      edd_mbr_sig_done                # on failure, we're done.
 132        cmpb    $0, %ah         # some BIOSes do not set CF
 133        jne     edd_mbr_sig_done                # on failure, we're done.
 134        movl    (EDDBUF+EDD_MBR_SIG_OFFSET), %eax # read sig out of the MBR
 135        movl    %eax, (%bx)                     # store success
 136        incb    (EDD_MBR_SIG_NR_BUF)            # note that we stored something
 137        incb    %dl                             # increment to next device
 138        addw    $4, %bx                         # increment sig buffer ptr
 139        cmpb    $EDD_MBR_SIG_MAX, (EDD_MBR_SIG_NR_BUF)  # Out of space?
 140        jb      edd_mbr_sig_read                # keep looping
 141edd_mbr_sig_done:
 142
 143# Do the BIOS Enhanced Disk Drive calls
 144# This consists of two calls:
 145#    int 13h ah=41h "Check Extensions Present"
 146#    int 13h ah=48h "Get Device Parameters"
 147#    int 13h ah=08h "Legacy Get Device Parameters"
 148#
 149# A buffer of size EDDMAXNR*(EDDEXTSIZE+EDDPARMSIZE) is reserved for our use
 150# in the boot_params at EDDBUF.  The first four bytes of which are
 151# used to store the device number, interface support map and version
 152# results from fn41.  The next four bytes are used to store the legacy
 153# cylinders, heads, and sectors from fn08. The following 74 bytes are used to
 154# store the results from fn48.  Starting from device 80h, fn41, then fn48
 155# are called and their results stored in EDDBUF+n*(EDDEXTSIZE+EDDPARMIZE).
 156# Then the pointer is incremented to store the data for the next call.
 157# This repeats until either a device doesn't exist, or until EDDMAXNR
 158# devices have been stored.
 159# The one tricky part is that ds:si always points EDDEXTSIZE bytes into
 160# the structure, and the fn41 and fn08 results are stored at offsets
 161# from there.  This removes the need to increment the pointer for
 162# every store, and leaves it ready for the fn48 call.
 163# A second one-byte buffer, EDDNR, in the boot_params stores
 164# the number of BIOS devices which exist, up to EDDMAXNR.
 165# In setup.c, copy_edd() stores both boot_params buffers away
 166# for later use, as they would get overwritten otherwise.
 167# This code is sensitive to the size of the structs in edd.h
 168edd_start:
 169                                                # %ds points to the bootsector
 170                                                # result buffer for fn48
 171        movw    $EDDBUF+EDDEXTSIZE, %si         # in ds:si, fn41 results
 172                                                # kept just before that
 173        movb    $0x80, %dl                      # BIOS device 0x80
 174
 175edd_check_ext:
 176        movb    $CHECKEXTENSIONSPRESENT, %ah    # Function 41
 177        movw    $EDDMAGIC1, %bx                 # magic
 178        int     $0x13                           # make the call
 179        jc      edd_done                        # no more BIOS devices
 180
 181        cmpw    $EDDMAGIC2, %bx                 # is magic right?
 182        jne     edd_next                        # nope, next...
 183
 184        movb    %dl, %ds:-8(%si)                # store device number
 185        movb    %ah, %ds:-7(%si)                # store version
 186        movw    %cx, %ds:-6(%si)                # store extensions
 187        incb    (EDDNR)                         # note that we stored something
 188
 189edd_get_device_params:
 190        movw    $EDDPARMSIZE, %ds:(%si)         # put size
 191        movw    $0x0, %ds:2(%si)                # work around buggy BIOSes
 192        movb    $GETDEVICEPARAMETERS, %ah       # Function 48
 193        int     $0x13                           # make the call
 194                                                # Don't check for fail return
 195                                                # it doesn't matter.
 196edd_get_legacy_chs:
 197        xorw    %ax, %ax
 198        movw    %ax, %ds:-4(%si)
 199        movw    %ax, %ds:-2(%si)
 200        # Ralf Brown's Interrupt List says to set ES:DI to
 201        # 0000h:0000h "to guard against BIOS bugs"
 202        pushw   %es
 203        movw    %ax, %es
 204        movw    %ax, %di
 205        pushw   %dx                             # legacy call clobbers %dl
 206        movb    $LEGACYGETDEVICEPARAMETERS, %ah # Function 08
 207        int     $0x13                           # make the call
 208        jc      edd_legacy_done                 # failed
 209        movb    %cl, %al                        # Low 6 bits are max
 210        andb    $0x3F, %al                      #   sector number
 211        movb    %al, %ds:-1(%si)                # Record max sect
 212        movb    %dh, %ds:-2(%si)                # Record max head number
 213        movb    %ch, %al                        # Low 8 bits of max cyl
 214        shr     $6, %cl
 215        movb    %cl, %ah                        # High 2 bits of max cyl
 216        movw    %ax, %ds:-4(%si)
 217
 218edd_legacy_done:
 219        popw    %dx
 220        popw    %es
 221        movw    %si, %ax                        # increment si
 222        addw    $EDDPARMSIZE+EDDEXTSIZE, %ax
 223        movw    %ax, %si
 224
 225edd_next:
 226        incb    %dl                             # increment to next device
 227        cmpb    $EDDMAXNR, (EDDNR)              # Out of space?
 228        jb      edd_check_ext                   # keep looping
 229
 230edd_done:
 231#endif
 232
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.