Sync trunk.
[reactos.git] / boot / freeldr / freeldr / arch / i386 / i386disk.c
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <freeldr.h>
21
22 #define NDEBUG
23 #include <debug.h>
24
25 /////////////////////////////////////////////////////////////////////////////////////////////
26 // FUNCTIONS
27 /////////////////////////////////////////////////////////////////////////////////////////////
28
29 BOOLEAN DiskResetController(ULONG DriveNumber)
30 {
31 REGS RegsIn;
32 REGS RegsOut;
33
34 DPRINTM(DPRINT_DISK, "DiskResetController(0x%x) DISK OPERATION FAILED -- RESETTING CONTROLLER\n", DriveNumber);
35
36 // BIOS Int 13h, function 0 - Reset disk system
37 // AH = 00h
38 // DL = drive (if bit 7 is set both hard disks and floppy disks reset)
39 // Return:
40 // AH = status
41 // CF clear if successful
42 // CF set on error
43 RegsIn.b.ah = 0x00;
44 RegsIn.b.dl = DriveNumber;
45
46 // Reset the disk controller
47 Int386(0x13, &RegsIn, &RegsOut);
48
49 return INT386_SUCCESS(RegsOut);
50 }
51
52 BOOLEAN DiskInt13ExtensionsSupported(ULONG DriveNumber)
53 {
54 static ULONG LastDriveNumber = 0xffffffff;
55 static BOOLEAN LastSupported;
56 REGS RegsIn;
57 REGS RegsOut;
58
59 DPRINTM(DPRINT_DISK, "PcDiskInt13ExtensionsSupported()\n");
60
61 if (DriveNumber == LastDriveNumber)
62 {
63 DPRINTM(DPRINT_DISK, "Using cached value %s for drive 0x%x\n", LastSupported ? "TRUE" : "FALSE", DriveNumber);
64 return LastSupported;
65 }
66
67 // Some BIOSes report that extended disk access functions are not supported
68 // when booting from a CD (e.g. Phoenix BIOS v6.00PG and Insyde BIOS shipping
69 // with Intel Macs). Therefore we just return TRUE if we're booting from a CD -
70 // we can assume that all El Torito capable BIOSes support INT 13 extensions.
71 // We simply detect whether we're booting from CD by checking whether the drive
72 // number is >= 0x8A. It's 0x90 on the Insyde BIOS, and 0x9F on most other BIOSes.
73 if (DriveNumber >= 0x8A)
74 {
75 LastSupported = TRUE;
76 return TRUE;
77 }
78
79 LastDriveNumber = DriveNumber;
80
81 // IBM/MS INT 13 Extensions - INSTALLATION CHECK
82 // AH = 41h
83 // BX = 55AAh
84 // DL = drive (80h-FFh)
85 // Return:
86 // CF set on error (extensions not supported)
87 // AH = 01h (invalid function)
88 // CF clear if successful
89 // BX = AA55h if installed
90 // AH = major version of extensions
91 // 01h = 1.x
92 // 20h = 2.0 / EDD-1.0
93 // 21h = 2.1 / EDD-1.1
94 // 30h = EDD-3.0
95 // AL = internal use
96 // CX = API subset support bitmap
97 // DH = extension version (v2.0+ ??? -- not present in 1.x)
98 //
99 // Bitfields for IBM/MS INT 13 Extensions API support bitmap
100 // Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported
101 // Bit 1, removable drive controller functions (AH=45h,46h,48h,49h,INT 15/AH=52h) supported
102 // Bit 2, enhanced disk drive (EDD) functions (AH=48h,AH=4Eh) supported
103 // extended drive parameter table is valid
104 // Bits 3-15 reserved
105 RegsIn.b.ah = 0x41;
106 RegsIn.w.bx = 0x55AA;
107 RegsIn.b.dl = DriveNumber;
108
109 // Reset the disk controller
110 Int386(0x13, &RegsIn, &RegsOut);
111
112 if (!INT386_SUCCESS(RegsOut))
113 {
114 // CF set on error (extensions not supported)
115 LastSupported = FALSE;
116 return FALSE;
117 }
118
119 if (RegsOut.w.bx != 0xAA55)
120 {
121 // BX = AA55h if installed
122 LastSupported = FALSE;
123 return FALSE;
124 }
125
126 if (!(RegsOut.w.cx & 0x0001))
127 {
128 // CX = API subset support bitmap
129 // Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported
130 DbgPrint("Suspicious API subset support bitmap 0x%x on device 0x%lx\n", RegsOut.w.cx, DriveNumber);
131 LastSupported = FALSE;
132 return FALSE;
133 }
134
135 LastSupported = TRUE;
136 return TRUE;
137 }
138
139 VOID DiskStopFloppyMotor(VOID)
140 {
141 WRITE_PORT_UCHAR((PUCHAR)0x3F2, 0);
142 }
143
144 BOOLEAN DiskGetExtendedDriveParameters(ULONG DriveNumber, PVOID Buffer, USHORT BufferSize)
145 {
146 REGS RegsIn;
147 REGS RegsOut;
148 PUSHORT Ptr = (PUSHORT)(BIOSCALLBUFFER);
149
150 DPRINTM(DPRINT_DISK, "DiskGetExtendedDriveParameters()\n");
151
152 if (!DiskInt13ExtensionsSupported(DriveNumber))
153 return FALSE;
154
155 // Initialize transfer buffer
156 *Ptr = BufferSize;
157
158 // BIOS Int 13h, function 48h - Get drive parameters
159 // AH = 48h
160 // DL = drive (bit 7 set for hard disk)
161 // DS:SI = result buffer
162 // Return:
163 // CF set on error
164 // AH = status (07h)
165 // CF clear if successful
166 // AH = 00h
167 // DS:SI -> result buffer
168 RegsIn.b.ah = 0x48;
169 RegsIn.b.dl = DriveNumber;
170 RegsIn.x.ds = BIOSCALLBUFSEGMENT; // DS:SI -> result buffer
171 RegsIn.w.si = BIOSCALLBUFOFFSET;
172
173 // Get drive parameters
174 Int386(0x13, &RegsIn, &RegsOut);
175
176 if (!INT386_SUCCESS(RegsOut))
177 {
178 return FALSE;
179 }
180
181 memcpy(Buffer, Ptr, BufferSize);
182
183 #if DBG
184 DPRINTM(DPRINT_DISK, "size of buffer: %x\n", Ptr[0]);
185 DPRINTM(DPRINT_DISK, "information flags: %x\n", Ptr[1]);
186 DPRINTM(DPRINT_DISK, "number of physical cylinders on drive: %u\n", *(PULONG)&Ptr[2]);
187 DPRINTM(DPRINT_DISK, "number of physical heads on drive: %u\n", *(PULONG)&Ptr[4]);
188 DPRINTM(DPRINT_DISK, "number of physical sectors per track: %u\n", *(PULONG)&Ptr[6]);
189 DPRINTM(DPRINT_DISK, "total number of sectors on drive: %I64u\n", *(unsigned long long*)&Ptr[8]);
190 DPRINTM(DPRINT_DISK, "bytes per sector: %u\n", Ptr[12]);
191 if (Ptr[0] >= 0x1e)
192 {
193 DPRINTM(DPRINT_DISK, "EED configuration parameters: %x:%x\n", Ptr[13], Ptr[14]);
194 if (Ptr[13] != 0xffff && Ptr[14] != 0xffff)
195 {
196 PUCHAR SpecPtr = (PUCHAR)(ULONG_PTR)((Ptr[13] << 4) + Ptr[14]);
197 DPRINTM(DPRINT_DISK, "SpecPtr: %x\n", SpecPtr);
198 DPRINTM(DPRINT_DISK, "physical I/O port base address: %x\n", *(PUSHORT)&SpecPtr[0]);
199 DPRINTM(DPRINT_DISK, "disk-drive control port address: %x\n", *(PUSHORT)&SpecPtr[2]);
200 DPRINTM(DPRINT_DISK, "drive flags: %x\n", SpecPtr[4]);
201 DPRINTM(DPRINT_DISK, "proprietary information: %x\n", SpecPtr[5]);
202 DPRINTM(DPRINT_DISK, "IRQ for drive: %u\n", SpecPtr[6]);
203 DPRINTM(DPRINT_DISK, "sector count for multi-sector transfers: %u\n", SpecPtr[7]);
204 DPRINTM(DPRINT_DISK, "DMA control: %x\n", SpecPtr[8]);
205 DPRINTM(DPRINT_DISK, "programmed I/O control: %x\n", SpecPtr[9]);
206 DPRINTM(DPRINT_DISK, "drive options: %x\n", *(PUSHORT)&SpecPtr[10]);
207 }
208 }
209 if (Ptr[0] >= 0x42)
210 {
211 DPRINTM(DPRINT_DISK, "signature: %x\n", Ptr[15]);
212 }
213 #endif
214
215 return TRUE;
216 }
217
218 /* EOF */