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>
12 #include <linux/edd.h>
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
27 pushw %dx # work around buggy BIOSes
28 stc # work around buggy BIOSes
30 sti # work around buggy BIOSes
33 movl (EDDBUF+MBR_SIG_OFFSET), %eax
34 movl %eax, (DISK80_SIG_BUFFER) # store success
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"
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
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
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
77 cmpw $EDDMAGIC2, %bx # is magic right?
78 jne edd_next # nope, next...
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
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
96 # Ralf Brown's Interrupt List says to set ES:DI to
97 # 0000h:0000h "to guard against BIOS bugs"
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
111 movb %cl, %ah # High 2 bits of max cyl
112 movw %ax, %ds:-4(%si)
117 movw %si, %ax # increment si
118 addw $EDDPARMSIZE+EDDEXTSIZE, %ax
122 incb %dl # increment to next device
123 cmpb $EDDMAXNR, (EDDNR) # Out of space?
124 jb edd_check_ext # keep looping