ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[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
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 device 80h and store the 4-byte signature
16         movl    $0xFFFFFFFF, %eax
17         movl    %eax, (DISK80_SIG_BUFFER)       # assume failure
18         movb    $READ_SECTORS, %ah
19         movb    $1, %al                         # read 1 sector
20         movb    $0x80, %dl                      # from device 80
21         movb    $0, %dh                         # at head 0
22         movw    $1, %cx                         # cylinder 0, sector 0
23         pushw   %es
24         pushw   %ds
25         popw    %es
26         movw    $EDDBUF, %bx
27         pushw   %dx             # work around buggy BIOSes
28         stc                     # work around buggy BIOSes
29         int     $0x13
30         sti                     # work around buggy BIOSes
31         popw    %dx
32         jc      disk_sig_done
33         movl    (EDDBUF+MBR_SIG_OFFSET), %eax
34         movl    %eax, (DISK80_SIG_BUFFER)       # store success
35 disk_sig_done:
36         popw    %es
37
38 # Do the BIOS Enhanced Disk Drive calls
39 # This consists of two calls:
40 #    int 13h ah=41h "Check Extensions Present"
41 #    int 13h ah=48h "Get Device Parameters"
42 #    int 13h ah=08h "Legacy Get Device Parameters"
43 #
44 # A buffer of size EDDMAXNR*(EDDEXTSIZE+EDDPARMSIZE) is reserved for our use
45 # in the boot_params at EDDBUF.  The first four bytes of which are
46 # used to store the device number, interface support map and version
47 # results from fn41.  The next four bytes are used to store the legacy
48 # cylinders, heads, and sectors from fn08. The following 74 bytes are used to
49 # store the results from fn48.  Starting from device 80h, fn41, then fn48
50 # are called and their results stored in EDDBUF+n*(EDDEXTSIZE+EDDPARMIZE).
51 # Then the pointer is incremented to store the data for the next call.
52 # This repeats until either a device doesn't exist, or until EDDMAXNR
53 # devices have been stored.
54 # The one tricky part is that ds:si always points EDDEXTSIZE bytes into
55 # the structure, and the fn41 and fn08 results are stored at offsets
56 # from there.  This removes the need to increment the pointer for
57 # every store, and leaves it ready for the fn48 call.
58 # A second one-byte buffer, EDDNR, in the boot_params stores
59 # the number of BIOS devices which exist, up to EDDMAXNR.
60 # In setup.c, copy_edd() stores both boot_params buffers away
61 # for later use, as they would get overwritten otherwise.
62 # This code is sensitive to the size of the structs in edd.h
63 edd_start:
64                                                 # %ds points to the bootsector
65                                                 # result buffer for fn48
66         movw    $EDDBUF+EDDEXTSIZE, %si         # in ds:si, fn41 results
67                                                 # kept just before that
68         movb    $0, (EDDNR)                     # zero value at EDDNR
69         movb    $0x80, %dl                      # BIOS device 0x80
70
71 edd_check_ext:
72         movb    $CHECKEXTENSIONSPRESENT, %ah    # Function 41
73         movw    $EDDMAGIC1, %bx                 # magic
74         int     $0x13                           # make the call
75         jc      edd_done                        # no more BIOS devices
76
77         cmpw    $EDDMAGIC2, %bx                 # is magic right?
78         jne     edd_next                        # nope, next...
79
80         movb    %dl, %ds:-8(%si)                # store device number
81         movb    %ah, %ds:-7(%si)                # store version
82         movw    %cx, %ds:-6(%si)                # store extensions
83         incb    (EDDNR)                         # note that we stored something
84
85 edd_get_device_params:
86         movw    $EDDPARMSIZE, %ds:(%si)         # put size
87         movw    $0x0, %ds:2(%si)                # work around buggy BIOSes
88         movb    $GETDEVICEPARAMETERS, %ah       # Function 48
89         int     $0x13                           # make the call
90                                                 # Don't check for fail return
91                                                 # it doesn't matter.
92 edd_get_legacy_chs:
93         xorw    %ax, %ax
94         movw    %ax, %ds:-4(%si)
95         movw    %ax, %ds:-2(%si)
96         # Ralf Brown's Interrupt List says to set ES:DI to
97         # 0000h:0000h "to guard against BIOS bugs"
98         pushw   %es
99         movw    %ax, %es
100         movw    %ax, %di
101         pushw   %dx                             # legacy call clobbers %dl
102         movb    $LEGACYGETDEVICEPARAMETERS, %ah # Function 08
103         int     $0x13                           # make the call
104         jc      edd_legacy_done                 # failed
105         movb    %cl, %al                        # Low 6 bits are max
106         andb    $0x3F, %al                      #   sector number
107         movb    %al, %ds:-1(%si)                # Record max sect
108         movb    %dh, %ds:-2(%si)                # Record max head number
109         movb    %ch, %al                        # Low 8 bits of max cyl
110         shr     $6, %cl
111         movb    %cl, %ah                        # High 2 bits of max cyl
112         movw    %ax, %ds:-4(%si)
113
114 edd_legacy_done:
115         popw    %dx
116         popw    %es
117         movw    %si, %ax                        # increment si
118         addw    $EDDPARMSIZE+EDDEXTSIZE, %ax
119         movw    %ax, %si
120
121 edd_next:
122         incb    %dl                             # increment to next device
123         cmpb    $EDDMAXNR, (EDDNR)              # Out of space?
124         jb      edd_check_ext                   # keep looping
125
126 edd_done:
127 #endif