VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / arch / i386 / boot / edd.S
1 /*
2  * BIOS Enhanced Disk Drive support
3  * by Matt Domsch <Matt_Domsch@dell.com> October 2002
4  * conformant to T13 Committee www.t13.org
5  *   projects 1572D, 1484D, 1386D, 1226DT
6  * disk signature read by Matt Domsch <Matt_Domsch@dell.com>
7  *      and Andrew Wilks <Andrew_Wilks@dell.com> September 2003, June 2004
8  * legacy CHS retreival by Patrick J. LoPresti <patl@users.sourceforge.net>
9  *      March 2004
10  */
11
12 #include <linux/edd.h>
13
14 #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
15 # Read the first sector of each BIOS disk device and store the 4-byte signature
16 edd_mbr_sig_start:
17         movb    $0, (EDD_MBR_SIG_NR_BUF)        # zero value at EDD_MBR_SIG_NR_BUF
18         movb    $0x80, %dl                      # from device 80
19         movw    $EDD_MBR_SIG_BUF, %bx           # store buffer ptr in bx
20 edd_mbr_sig_read:
21         movl    $0xFFFFFFFF, %eax
22         movl    %eax, (%bx)                     # assume failure
23         pushw   %bx
24         movb    $READ_SECTORS, %ah
25         movb    $1, %al                         # read 1 sector
26         movb    $0, %dh                         # at head 0
27         movw    $1, %cx                         # cylinder 0, sector 0
28         pushw   %es
29         pushw   %ds
30         popw    %es
31         movw    $EDDBUF, %bx                    # disk's data goes into EDDBUF
32         pushw   %dx             # work around buggy BIOSes
33         stc                     # work around buggy BIOSes
34         int     $0x13
35         sti                     # work around buggy BIOSes
36         popw    %dx
37         popw    %es
38         popw    %bx
39         jc      edd_mbr_sig_done                # on failure, we're done.
40         movl    (EDDBUF+EDD_MBR_SIG_OFFSET), %eax # read sig out of the MBR
41         movl    %eax, (%bx)                     # store success
42         incb    (EDD_MBR_SIG_NR_BUF)            # note that we stored something
43         incb    %dl                             # increment to next device
44         addw    $4, %bx                         # increment sig buffer ptr
45         cmpb    $EDD_MBR_SIG_MAX, (EDD_MBR_SIG_NR_BUF)  # Out of space?
46         jb      edd_mbr_sig_read                # keep looping
47 edd_mbr_sig_done:
48
49 # Do the BIOS Enhanced Disk Drive calls
50 # This consists of two calls:
51 #    int 13h ah=41h "Check Extensions Present"
52 #    int 13h ah=48h "Get Device Parameters"
53 #    int 13h ah=08h "Legacy Get Device Parameters"
54 #
55 # A buffer of size EDDMAXNR*(EDDEXTSIZE+EDDPARMSIZE) is reserved for our use
56 # in the boot_params at EDDBUF.  The first four bytes of which are
57 # used to store the device number, interface support map and version
58 # results from fn41.  The next four bytes are used to store the legacy
59 # cylinders, heads, and sectors from fn08. The following 74 bytes are used to
60 # store the results from fn48.  Starting from device 80h, fn41, then fn48
61 # are called and their results stored in EDDBUF+n*(EDDEXTSIZE+EDDPARMIZE).
62 # Then the pointer is incremented to store the data for the next call.
63 # This repeats until either a device doesn't exist, or until EDDMAXNR
64 # devices have been stored.
65 # The one tricky part is that ds:si always points EDDEXTSIZE bytes into
66 # the structure, and the fn41 and fn08 results are stored at offsets
67 # from there.  This removes the need to increment the pointer for
68 # every store, and leaves it ready for the fn48 call.
69 # A second one-byte buffer, EDDNR, in the boot_params stores
70 # the number of BIOS devices which exist, up to EDDMAXNR.
71 # In setup.c, copy_edd() stores both boot_params buffers away
72 # for later use, as they would get overwritten otherwise.
73 # This code is sensitive to the size of the structs in edd.h
74 edd_start:
75                                                 # %ds points to the bootsector
76                                                 # result buffer for fn48
77         movw    $EDDBUF+EDDEXTSIZE, %si         # in ds:si, fn41 results
78                                                 # kept just before that
79         movb    $0, (EDDNR)                     # zero value at EDDNR
80         movb    $0x80, %dl                      # BIOS device 0x80
81
82 edd_check_ext:
83         movb    $CHECKEXTENSIONSPRESENT, %ah    # Function 41
84         movw    $EDDMAGIC1, %bx                 # magic
85         int     $0x13                           # make the call
86         jc      edd_done                        # no more BIOS devices
87
88         cmpw    $EDDMAGIC2, %bx                 # is magic right?
89         jne     edd_next                        # nope, next...
90
91         movb    %dl, %ds:-8(%si)                # store device number
92         movb    %ah, %ds:-7(%si)                # store version
93         movw    %cx, %ds:-6(%si)                # store extensions
94         incb    (EDDNR)                         # note that we stored something
95
96 edd_get_device_params:
97         movw    $EDDPARMSIZE, %ds:(%si)         # put size
98         movw    $0x0, %ds:2(%si)                # work around buggy BIOSes
99         movb    $GETDEVICEPARAMETERS, %ah       # Function 48
100         int     $0x13                           # make the call
101                                                 # Don't check for fail return
102                                                 # it doesn't matter.
103 edd_get_legacy_chs:
104         xorw    %ax, %ax
105         movw    %ax, %ds:-4(%si)
106         movw    %ax, %ds:-2(%si)
107         # Ralf Brown's Interrupt List says to set ES:DI to
108         # 0000h:0000h "to guard against BIOS bugs"
109         pushw   %es
110         movw    %ax, %es
111         movw    %ax, %di
112         pushw   %dx                             # legacy call clobbers %dl
113         movb    $LEGACYGETDEVICEPARAMETERS, %ah # Function 08
114         int     $0x13                           # make the call
115         jc      edd_legacy_done                 # failed
116         movb    %cl, %al                        # Low 6 bits are max
117         andb    $0x3F, %al                      #   sector number
118         movb    %al, %ds:-1(%si)                # Record max sect
119         movb    %dh, %ds:-2(%si)                # Record max head number
120         movb    %ch, %al                        # Low 8 bits of max cyl
121         shr     $6, %cl
122         movb    %cl, %ah                        # High 2 bits of max cyl
123         movw    %ax, %ds:-4(%si)
124
125 edd_legacy_done:
126         popw    %dx
127         popw    %es
128         movw    %si, %ax                        # increment si
129         addw    $EDDPARMSIZE+EDDEXTSIZE, %ax
130         movw    %ax, %si
131
132 edd_next:
133         incb    %dl                             # increment to next device
134         cmpb    $EDDMAXNR, (EDDNR)              # Out of space?
135         jb      edd_check_ext                   # keep looping
136
137 edd_done:
138 #endif