3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
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.
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.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 /////////////////////////////////////////////////////////////////////////////////////////////
27 /////////////////////////////////////////////////////////////////////////////////////////////
31 BOOLEAN
DiskResetController(ULONG DriveNumber
)
36 DbgPrint((DPRINT_DISK
, "DiskResetController(0x%x) DISK OPERATION FAILED -- RESETTING CONTROLLER\n", DriveNumber
));
38 // BIOS Int 13h, function 0 - Reset disk system
40 // DL = drive (if bit 7 is set both hard disks and floppy disks reset)
43 // CF clear if successful
46 RegsIn
.b
.dl
= DriveNumber
;
48 // Reset the disk controller
49 Int386(0x13, &RegsIn
, &RegsOut
);
51 return INT386_SUCCESS(RegsOut
);
54 BOOLEAN
DiskInt13ExtensionsSupported(ULONG DriveNumber
)
59 DbgPrint((DPRINT_DISK
, "DiskInt13ExtensionsSupported()\n"));
61 // IBM/MS INT 13 Extensions - INSTALLATION CHECK
64 // DL = drive (80h-FFh)
66 // CF set on error (extensions not supported)
67 // AH = 01h (invalid function)
68 // CF clear if successful
69 // BX = AA55h if installed
70 // AH = major version of extensions
72 // 20h = 2.0 / EDD-1.0
73 // 21h = 2.1 / EDD-1.1
76 // CX = API subset support bitmap
77 // DH = extension version (v2.0+ ??? -- not present in 1.x)
79 // Bitfields for IBM/MS INT 13 Extensions API support bitmap
80 // Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported
81 // Bit 1, removable drive controller functions (AH=45h,46h,48h,49h,INT 15/AH=52h) supported
82 // Bit 2, enhanced disk drive (EDD) functions (AH=48h,AH=4Eh) supported
83 // extended drive parameter table is valid
87 RegsIn
.b
.dl
= DriveNumber
;
89 // Reset the disk controller
90 Int386(0x13, &RegsIn
, &RegsOut
);
92 if (!INT386_SUCCESS(RegsOut
))
94 // CF set on error (extensions not supported)
98 if (RegsOut
.w
.bx
!= 0xAA55)
100 // BX = AA55h if installed
105 // The original check is too strict because some BIOSes report that
106 // extended disk access functions are not suported when booting
107 // from a CD (e.g. Phoenix BIOS v6.00PG). Argh!
109 if (!(RegsOut
.w
.cx
& 0x0001))
111 // CX = API subset support bitmap
112 // Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported
117 // Use this relaxed check instead
118 if (RegsOut
.w
.cx
== 0x0000)
120 // CX = API subset support bitmap
127 VOID
DiskStopFloppyMotor(VOID
)
129 WRITE_PORT_UCHAR((PUCHAR
)0x3F2, 0);
132 BOOLEAN
DiskGetExtendedDriveParameters(ULONG DriveNumber
, PVOID Buffer
, USHORT BufferSize
)
136 PUSHORT Ptr
= (PUSHORT
)(BIOSCALLBUFFER
);
138 DbgPrint((DPRINT_DISK
, "DiskGetExtendedDriveParameters()\n"));
140 // Initialize transfer buffer
143 // BIOS Int 13h, function 48h - Get drive parameters
145 // DL = drive (bit 7 set for hard disk)
146 // DS:SI = result buffer
150 // CF clear if successful
152 // DS:SI -> result buffer
154 RegsIn
.b
.dl
= DriveNumber
;
155 RegsIn
.x
.ds
= BIOSCALLBUFSEGMENT
; // DS:SI -> result buffer
156 RegsIn
.w
.si
= BIOSCALLBUFOFFSET
;
158 // Get drive parameters
159 Int386(0x13, &RegsIn
, &RegsOut
);
161 if (!INT386_SUCCESS(RegsOut
))
166 memcpy(Buffer
, Ptr
, BufferSize
);
168 DbgPrint((DPRINT_DISK
, "size of buffer: %x\n", Ptr
[0]));
169 DbgPrint((DPRINT_DISK
, "information flags: %x\n", Ptr
[1]));
170 DbgPrint((DPRINT_DISK
, "number of physical cylinders on drive: %u\n", *(PULONG
)&Ptr
[2]));
171 DbgPrint((DPRINT_DISK
, "number of physical heads on drive: %u\n", *(PULONG
)&Ptr
[4]));
172 DbgPrint((DPRINT_DISK
, "number of physical sectors per track: %u\n", *(PULONG
)&Ptr
[6]));
173 DbgPrint((DPRINT_DISK
, "total number of sectors on drive: %I64u\n", *(unsigned long long*)&Ptr
[8]));
174 DbgPrint((DPRINT_DISK
, "bytes per sector: %u\n", Ptr
[12]));
177 DbgPrint((DPRINT_DISK
, "EED configuration parameters: %x:%x\n", Ptr
[13], Ptr
[14]));
178 if (Ptr
[13] != 0xffff && Ptr
[14] != 0xffff)
180 PUCHAR SpecPtr
= (PUCHAR
)((Ptr
[13] << 4) + Ptr
[14]);
181 DbgPrint((DPRINT_DISK
, "SpecPtr: %x\n", SpecPtr
));
182 DbgPrint((DPRINT_DISK
, "physical I/O port base address: %x\n", *(PUSHORT
)&SpecPtr
[0]));
183 DbgPrint((DPRINT_DISK
, "disk-drive control port address: %x\n", *(PUSHORT
)&SpecPtr
[2]));
184 DbgPrint((DPRINT_DISK
, "drive flags: %x\n", SpecPtr
[4]));
185 DbgPrint((DPRINT_DISK
, "proprietary information: %x\n", SpecPtr
[5]));
186 DbgPrint((DPRINT_DISK
, "IRQ for drive: %u\n", SpecPtr
[6]));
187 DbgPrint((DPRINT_DISK
, "sector count for multi-sector transfers: %u\n", SpecPtr
[7]));
188 DbgPrint((DPRINT_DISK
, "DMA control: %x\n", SpecPtr
[8]));
189 DbgPrint((DPRINT_DISK
, "programmed I/O control: %x\n", SpecPtr
[9]));
190 DbgPrint((DPRINT_DISK
, "drive options: %x\n", *(PUSHORT
)&SpecPtr
[10]));
195 DbgPrint((DPRINT_DISK
, "signature: %x\n", Ptr
[15]));
201 BOOLEAN
i386DiskGetBootVolume(PULONG DriveNumber
, PULONGLONG StartSector
, PULONGLONG SectorCount
, int *FsType
)
203 PARTITION_TABLE_ENTRY PartitionTableEntry
;
205 ULONG ActivePartition
;
207 DbgPrint((DPRINT_FILESYSTEM
, "FsOpenVolume() DriveNumber: 0x%x PartitionNumber: 0x%x\n", i386BootDrive
, i386BootPartition
));
209 // Check and see if it is a floppy drive
210 // If so then just assume FAT12 file system type
211 if (DiskIsDriveRemovable(i386BootDrive
))
213 DbgPrint((DPRINT_FILESYSTEM
, "Drive is a floppy diskette drive. Assuming FAT12 file system.\n"));
215 *DriveNumber
= i386BootDrive
;
217 *SectorCount
= 2 * 80 * 18; /* FIXME hardcoded for 1.44 Mb */
222 // Check for ISO9660 file system type
223 if (i386BootDrive
>= 0x80 && FsRecIsIso9660(i386BootDrive
))
225 DbgPrint((DPRINT_FILESYSTEM
, "Drive is a cdrom drive. Assuming ISO-9660 file system.\n"));
227 *DriveNumber
= i386BootDrive
;
230 *FsType
= FS_ISO9660
;
234 // Get the requested partition entry
235 if (i386BootPartition
== 0)
237 // Partition requested was zero which means the boot partition
238 if (! DiskGetActivePartitionEntry(i386BootDrive
, &PartitionTableEntry
, &ActivePartition
))
240 /* Try partition-less disk */
244 /* Check for valid partition */
245 else if (PartitionTableEntry
.SystemIndicator
== PARTITION_ENTRY_UNUSED
)
251 *StartSector
= PartitionTableEntry
.SectorCountBeforePartition
;
252 *SectorCount
= PartitionTableEntry
.PartitionSectorCount
;
255 else if (0xff == i386BootPartition
)
257 /* Partition-less disk */
263 // Get requested partition
264 if (! MachDiskGetPartitionEntry(i386BootDrive
, i386BootPartition
, &PartitionTableEntry
))
268 /* Check for valid partition */
269 else if (PartitionTableEntry
.SystemIndicator
== PARTITION_ENTRY_UNUSED
)
275 *StartSector
= PartitionTableEntry
.SectorCountBeforePartition
;
276 *SectorCount
= PartitionTableEntry
.PartitionSectorCount
;
280 // Try to recognize the file system
281 if (!FsRecognizeVolume(i386BootDrive
, *StartSector
, &VolumeType
))
286 *DriveNumber
= i386BootDrive
;
290 case PARTITION_FAT_12
:
291 case PARTITION_FAT_16
:
293 case PARTITION_XINT13
:
294 case PARTITION_FAT32
:
295 case PARTITION_FAT32_XINT13
:
313 i386DiskGetBootDevice(PULONG BootDevice
)
315 ((char *)BootDevice
)[0] = (char)i386BootDrive
;
316 ((char *)BootDevice
)[1] = (char)i386BootPartition
;
320 i386DiskBootingFromFloppy(VOID
)
322 return i386BootDrive
< 0x80;
325 #define IsRecognizedPartition(P) \
326 ((P) == PARTITION_FAT_12 || \
327 (P) == PARTITION_FAT_16 || \
328 (P) == PARTITION_HUGE || \
329 (P) == PARTITION_IFS || \
330 (P) == PARTITION_EXT2 || \
331 (P) == PARTITION_FAT32 || \
332 (P) == PARTITION_FAT32_XINT13 || \
333 (P) == PARTITION_XINT13)
335 #define IsContainerPartition(P) \
336 ((P) == PARTITION_EXTENDED || \
337 (P) == PARTITION_XINT13_EXTENDED)
339 BOOLEAN
i386DiskGetSystemVolume(char *SystemPath
,
343 PULONGLONG StartSector
,
344 PULONGLONG SectorCount
,
347 ULONG PartitionNumber
;
348 PARTITION_TABLE_ENTRY PartitionTableEntry
;
351 unsigned i
, RosPartition
;
356 if (!DissectArcPath(SystemPath
, BootPath
, DriveNumber
, &PartitionNumber
))
360 if (NULL
!= RemainingPath
)
362 strcpy(RemainingPath
, BootPath
);
365 /* 0xff -> no partition table present, use whole device */
366 if (0xff == PartitionNumber
)
368 PartitionTableEntry
.SectorCountBeforePartition
= 0;
373 /* recalculate the boot partition for freeldr */
378 if (!MachDiskGetPartitionEntry(*DriveNumber
, ++i
, &PartitionTableEntry
))
382 if (!IsContainerPartition(PartitionTableEntry
.SystemIndicator
) &&
383 PartitionTableEntry
.SystemIndicator
!= PARTITION_ENTRY_UNUSED
)
385 if (++RosPartition
== PartitionNumber
)
393 /* Check for ISO9660 file system type */
394 if (*DriveNumber
>= 0x80 && FsRecIsIso9660(*DriveNumber
))
396 DbgPrint((DPRINT_FILESYSTEM
, "Drive is a cdrom drive. Assuming ISO-9660 file system.\n"));
400 ((char *)Device
)[0] = (char)(*DriveNumber
);
401 ((char *)Device
)[1] = (char)i
;
405 *FsType
= FS_ISO9660
;
409 if (!FsRecognizeVolume(*DriveNumber
, PartitionTableEntry
.SectorCountBeforePartition
, &VolumeType
))
416 ((char *)Device
)[0] = (char)(*DriveNumber
);
417 ((char *)Device
)[1] = (char)i
;
419 *StartSector
= PartitionTableEntry
.SectorCountBeforePartition
;
420 *SectorCount
= PartitionTableEntry
.PartitionSectorCount
;
424 case PARTITION_FAT_12
:
425 case PARTITION_FAT_16
:
427 case PARTITION_XINT13
:
428 case PARTITION_FAT32
:
429 case PARTITION_FAT32_XINT13
:
447 i386DiskGetBootPath(char *BootPath
, unsigned Size
)
449 static char Path
[] = "multi(0)disk(0)";
452 _itoa(i386BootDrive
, Device
, 10);
453 if (Size
<= sizeof(Path
) + 6 + strlen(Device
))
457 strcpy(BootPath
, Path
);
458 strcat(BootPath
, MachDiskBootingFromFloppy() ? "fdisk" : "cdrom");
459 strcat(strcat(strcat(BootPath
, "("), Device
), ")");
465 i386DiskNormalizeSystemPath(char *SystemPath
, unsigned Size
)
468 ULONG PartitionNumber
;
470 PARTITION_TABLE_ENTRY PartEntry
;
473 if (!DissectArcPath(SystemPath
, BootPath
, &DriveNumber
, &PartitionNumber
))
478 if (0 != PartitionNumber
)
483 if (! DiskGetActivePartitionEntry(DriveNumber
,
486 PartitionNumber
< 1 || 9 < PartitionNumber
)
492 while ('\0' != *p
&& 0 != _strnicmp(p
, "partition(", 10)) {
496 if (NULL
== p
|| '0' != *(p
- 1)) {
499 *(p
- 1) = '0' + PartitionNumber
;
504 #endif /* defined __i386__ */