Merge branch 'master'
[linux-2.6] / arch / i386 / boot / edd.S
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         movb    $0, (EDD_MBR_SIG_NR_BUF)
19         movb    $0, (EDDNR)
20
21 # Check the command line for two options:
22 # edd=of  disables EDD completely  (edd=off)
23 # edd=sk  skips the MBR test    (edd=skipmbr)
24         pushl   %esi
25         cmpl    $0, %cs:cmd_line_ptr
26         jz      done_cl
27         movl    %cs:(cmd_line_ptr), %esi
28 # ds:esi has the pointer to the command line now
29         movl    $(COMMAND_LINE_SIZE-7), %ecx
30 # loop through kernel command line one byte at a time
31 cl_loop:
32         cmpl    $EDD_CL_EQUALS, (%si)
33         jz      found_edd_equals
34         incl    %esi
35         loop    cl_loop
36         jmp     done_cl
37 found_edd_equals:
38 # only looking at first two characters after equals
39         addl    $4, %esi
40         cmpw    $EDD_CL_OFF, (%si)      # edd=of
41         jz      do_edd_off
42         cmpw    $EDD_CL_SKIP, (%si)     # edd=sk
43         jz      do_edd_skipmbr
44         jmp     done_cl
45 do_edd_skipmbr:
46         popl    %esi
47         jmp     edd_start
48 do_edd_off:
49         popl    %esi
50         jmp     edd_done
51 done_cl:
52         popl    %esi
53
54
55 # Read the first sector of each BIOS disk device and store the 4-byte signature
56 edd_mbr_sig_start:
57         movb    $0x80, %dl                      # from device 80
58         movw    $EDD_MBR_SIG_BUF, %bx           # store buffer ptr in bx
59 edd_mbr_sig_read:
60         movl    $0xFFFFFFFF, %eax
61         movl    %eax, (%bx)                     # assume failure
62         pushw   %bx
63         movb    $READ_SECTORS, %ah
64         movb    $1, %al                         # read 1 sector
65         movb    $0, %dh                         # at head 0
66         movw    $1, %cx                         # cylinder 0, sector 0
67         pushw   %es
68         pushw   %ds
69         popw    %es
70         movw    $EDDBUF, %bx                    # disk's data goes into EDDBUF
71         pushw   %dx             # work around buggy BIOSes
72         stc                     # work around buggy BIOSes
73         int     $0x13
74         sti                     # work around buggy BIOSes
75         popw    %dx
76         popw    %es
77         popw    %bx
78         jc      edd_mbr_sig_done                # on failure, we're done.
79         movl    (EDDBUF+EDD_MBR_SIG_OFFSET), %eax # read sig out of the MBR
80         movl    %eax, (%bx)                     # store success
81         incb    (EDD_MBR_SIG_NR_BUF)            # note that we stored something
82         incb    %dl                             # increment to next device
83         addw    $4, %bx                         # increment sig buffer ptr
84         cmpb    $EDD_MBR_SIG_MAX, (EDD_MBR_SIG_NR_BUF)  # Out of space?
85         jb      edd_mbr_sig_read                # keep looping
86 edd_mbr_sig_done:
87
88 # Do the BIOS Enhanced Disk Drive calls
89 # This consists of two calls:
90 #    int 13h ah=41h "Check Extensions Present"
91 #    int 13h ah=48h "Get Device Parameters"
92 #    int 13h ah=08h "Legacy Get Device Parameters"
93 #
94 # A buffer of size EDDMAXNR*(EDDEXTSIZE+EDDPARMSIZE) is reserved for our use
95 # in the boot_params at EDDBUF.  The first four bytes of which are
96 # used to store the device number, interface support map and version
97 # results from fn41.  The next four bytes are used to store the legacy
98 # cylinders, heads, and sectors from fn08. The following 74 bytes are used to
99 # store the results from fn48.  Starting from device 80h, fn41, then fn48
100 # are called and their results stored in EDDBUF+n*(EDDEXTSIZE+EDDPARMIZE).
101 # Then the pointer is incremented to store the data for the next call.
102 # This repeats until either a device doesn't exist, or until EDDMAXNR
103 # devices have been stored.
104 # The one tricky part is that ds:si always points EDDEXTSIZE bytes into
105 # the structure, and the fn41 and fn08 results are stored at offsets
106 # from there.  This removes the need to increment the pointer for
107 # every store, and leaves it ready for the fn48 call.
108 # A second one-byte buffer, EDDNR, in the boot_params stores
109 # the number of BIOS devices which exist, up to EDDMAXNR.
110 # In setup.c, copy_edd() stores both boot_params buffers away
111 # for later use, as they would get overwritten otherwise.
112 # This code is sensitive to the size of the structs in edd.h
113 edd_start:
114                                                 # %ds points to the bootsector
115                                                 # result buffer for fn48
116         movw    $EDDBUF+EDDEXTSIZE, %si         # in ds:si, fn41 results
117                                                 # kept just before that
118         movb    $0x80, %dl                      # BIOS device 0x80
119
120 edd_check_ext:
121         movb    $CHECKEXTENSIONSPRESENT, %ah    # Function 41
122         movw    $EDDMAGIC1, %bx                 # magic
123         int     $0x13                           # make the call
124         jc      edd_done                        # no more BIOS devices
125
126         cmpw    $EDDMAGIC2, %bx                 # is magic right?
127         jne     edd_next                        # nope, next...
128
129         movb    %dl, %ds:-8(%si)                # store device number
130         movb    %ah, %ds:-7(%si)                # store version
131         movw    %cx, %ds:-6(%si)                # store extensions
132         incb    (EDDNR)                         # note that we stored something
133
134 edd_get_device_params:
135         movw    $EDDPARMSIZE, %ds:(%si)         # put size
136         movw    $0x0, %ds:2(%si)                # work around buggy BIOSes
137         movb    $GETDEVICEPARAMETERS, %ah       # Function 48
138         int     $0x13                           # make the call
139                                                 # Don't check for fail return
140                                                 # it doesn't matter.
141 edd_get_legacy_chs:
142         xorw    %ax, %ax
143         movw    %ax, %ds:-4(%si)
144         movw    %ax, %ds:-2(%si)
145         # Ralf Brown's Interrupt List says to set ES:DI to
146         # 0000h:0000h "to guard against BIOS bugs"
147         pushw   %es
148         movw    %ax, %es
149         movw    %ax, %di
150         pushw   %dx                             # legacy call clobbers %dl
151         movb    $LEGACYGETDEVICEPARAMETERS, %ah # Function 08
152         int     $0x13                           # make the call
153         jc      edd_legacy_done                 # failed
154         movb    %cl, %al                        # Low 6 bits are max
155         andb    $0x3F, %al                      #   sector number
156         movb    %al, %ds:-1(%si)                # Record max sect
157         movb    %dh, %ds:-2(%si)                # Record max head number
158         movb    %ch, %al                        # Low 8 bits of max cyl
159         shr     $6, %cl
160         movb    %cl, %ah                        # High 2 bits of max cyl
161         movw    %ax, %ds:-4(%si)
162
163 edd_legacy_done:
164         popw    %dx
165         popw    %es
166         movw    %si, %ax                        # increment si
167         addw    $EDDPARMSIZE+EDDEXTSIZE, %ax
168         movw    %ax, %si
169
170 edd_next:
171         incb    %dl                             # increment to next device
172         cmpb    $EDDMAXNR, (EDDNR)              # Out of space?
173         jb      edd_check_ext                   # keep looping
174
175 edd_done:
176 #endif