https://git.reactos.org/?p=reactos.git;a=commitdiff;h=7c93350e05f7105afd6fed...
commit 7c93350e05f7105afd6fedc8498d68c9a8841e31 Author: disean di.sean@protonmail.com AuthorDate: Tue Jan 14 09:08:53 2020 +0600 Commit: Hermès BÉLUSCA - MAÏTO hermes.belusca-maito@reactos.org CommitDate: Tue Jan 14 04:08:53 2020 +0100
[FREELDR] Cache INT13h drive data in pcdisk.c (#2097)
* [FREELDR] Cache the drive geometry in the PcDiskReadLogicalSectorsCHS()
Speed up the loading time a bit.
* [FREELDR] Generalize the cache to all the geometry data + INT 13h extensions-supported status.
The data structure used is "PC_DISK_DRIVE".
- Adapt the associated functions; - Make DiskGetExtendedDriveParameters() private to pcdisk.c
- Introduce PcDiskDriveNumberToDrive(), that is similar to the XBOX function XboxDiskDriveNumberToDeviceUnit(), that retrieves a valid pointer to the cached disk corresponding to the given BIOS DriveNumber. If needed the cached data gets initialized.
- Make XboxDiskDriveNumberToDeviceUnit() simpler by just returning the pointer to the corresponding drive, of NULL if there is none.
Co-authored-by: Hermès BÉLUSCA - MAÏTO hermes.belusca-maito@reactos.org --- boot/freeldr/freeldr/arch/i386/hwdisk.c | 2 + boot/freeldr/freeldr/arch/i386/machpc.c | 7 +- boot/freeldr/freeldr/arch/i386/pcdisk.c | 731 ++++++++++++++++---------- boot/freeldr/freeldr/arch/i386/xboxdisk.c | 52 +- boot/freeldr/freeldr/include/arch/pc/machpc.h | 2 +- 5 files changed, 498 insertions(+), 296 deletions(-)
diff --git a/boot/freeldr/freeldr/arch/i386/hwdisk.c b/boot/freeldr/freeldr/arch/i386/hwdisk.c index 7aec1c3db99..cf23c60ac21 100644 --- a/boot/freeldr/freeldr/arch/i386/hwdisk.c +++ b/boot/freeldr/freeldr/arch/i386/hwdisk.c @@ -396,6 +396,8 @@ EnumerateHarddisks(OUT PBOOLEAN BootDriveReported) return DiskCount; }
+// FIXME: Copied from pcdisk.c +// Actually this function is REALLY PC-specific!! static BOOLEAN DiskIsDriveRemovable(UCHAR DriveNumber) { diff --git a/boot/freeldr/freeldr/arch/i386/machpc.c b/boot/freeldr/freeldr/arch/i386/machpc.c index 712a0575b44..95253971c02 100644 --- a/boot/freeldr/freeldr/arch/i386/machpc.c +++ b/boot/freeldr/freeldr/arch/i386/machpc.c @@ -105,7 +105,7 @@ PcGetHarddiskConfigurationData(UCHAR DriveNumber, ULONG* pSize) { PCM_PARTIAL_RESOURCE_LIST PartialResourceList; PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry; - EXTENDED_GEOMETRY ExtGeometry; + // EXTENDED_GEOMETRY ExtGeometry; GEOMETRY Geometry; ULONG Size;
@@ -139,6 +139,7 @@ PcGetHarddiskConfigurationData(UCHAR DriveNumber, ULONG* pSize) DiskGeometry = (PVOID)(((ULONG_PTR)PartialResourceList) + sizeof(CM_PARTIAL_RESOURCE_LIST));
/* Get the disk geometry */ +#if 0 // This is somehow replaced by what PcDiskGetDriveGeometry() does internally. ExtGeometry.Size = sizeof(EXTENDED_GEOMETRY); if (DiskGetExtendedDriveParameters(DriveNumber, &ExtGeometry, ExtGeometry.Size)) { @@ -147,7 +148,9 @@ PcGetHarddiskConfigurationData(UCHAR DriveNumber, ULONG* pSize) DiskGeometry->SectorsPerTrack = ExtGeometry.SectorsPerTrack; DiskGeometry->NumberOfHeads = ExtGeometry.Heads; } - else if (PcDiskGetDriveGeometry(DriveNumber, &Geometry)) + else +#endif + if (PcDiskGetDriveGeometry(DriveNumber, &Geometry)) { DiskGeometry->BytesPerSector = Geometry.BytesPerSector; DiskGeometry->NumberOfCylinders = Geometry.Cylinders; diff --git a/boot/freeldr/freeldr/arch/i386/pcdisk.c b/boot/freeldr/freeldr/arch/i386/pcdisk.c index f9fc4f0c1ba..37058bced70 100644 --- a/boot/freeldr/freeldr/arch/i386/pcdisk.c +++ b/boot/freeldr/freeldr/arch/i386/pcdisk.c @@ -24,6 +24,9 @@ #include <debug.h> DBG_DEFAULT_CHANNEL(DISK);
+/* Enable this line if you want to support multi-drive caching (increases FreeLdr size!) */ +// #define CACHE_MULTI_DRIVES + #include <pshpack2.h>
typedef struct @@ -73,6 +76,43 @@ typedef struct
#include <poppack.h>
+typedef struct _PC_DISK_DRIVE +{ + /* Disk geometry (legacy BIOS and INT13 extended) */ + GEOMETRY Geometry; + EXTENDED_GEOMETRY ExtGeometry; + + /* TRUE when INT 13h extensions are supported */ + BOOLEAN Int13ExtensionsSupported; + + /* + * 'IsRemovable' flag: TRUE when the drive is removable (e.g. floppy, CD-ROM...). + * In that case some of the cached information might need to be refreshed regularly. + */ + BOOLEAN IsRemovable; + +#ifdef CACHE_MULTI_DRIVES + /* + * 'Initialized' flag: if TRUE then the drive has been initialized; + * if FALSE then it needs to be initialized; if its high bit is set + * then there has been an error; don't try to use it. + */ + BOOLEAN Initialized; +#endif +} PC_DISK_DRIVE, *PPC_DISK_DRIVE; + +#ifdef CACHE_MULTI_DRIVES +/* Cache of all possible PC disk drives */ +// Maximum number of disks is 0x100, indexed from 0x00 to 0xFF. +static PC_DISK_DRIVE PcDiskDrive[0x100]; +#else +/* Cached data for the last-accessed PC disk drive */ +// We use a USHORT so that we can initialize it with a drive number that cannot exist +// on the system (they are <= 0xFF), therefore forcing drive caching on first access. +static USHORT LastDriveNumber = 0xFFFF; +static PC_DISK_DRIVE PcDiskDrive; +#endif /* CACHE_MULTI_DRIVES */ + /* DISK IO ERROR SUPPORT *****************************************************/
static LONG lReportError = 0; // >= 0: display errors; < 0: hide errors. @@ -130,7 +170,7 @@ static VOID DiskError(PCSTR ErrorString, ULONG ErrorCode) sprintf(ErrorCodeString, "%s\n\nError Code: 0x%lx\nError: %s", ErrorString, ErrorCode, DiskGetErrorCodeString(ErrorCode));
- TRACE("%s\n", ErrorCodeString); + ERR("%s\n", ErrorCodeString);
UiMessageBox(ErrorCodeString); } @@ -161,15 +201,370 @@ BOOLEAN DiskResetController(UCHAR DriveNumber) return INT386_SUCCESS(RegsOut); }
-static BOOLEAN PcDiskReadLogicalSectorsLBA(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer) +static BOOLEAN +DiskIsDriveRemovable(UCHAR DriveNumber) +{ + /* + * Hard disks use drive numbers >= 0x80 . So if the drive number + * indicates a hard disk then return FALSE. + * 0x49 is our magic ramdisk drive, so return FALSE for that too. + */ + if ((DriveNumber >= 0x80) || (DriveNumber == 0x49)) + return FALSE; + + /* The drive is a floppy diskette so return TRUE */ + return TRUE; +} + +static BOOLEAN +DiskInt13ExtensionsSupported(IN UCHAR DriveNumber) +{ + REGS RegsIn, RegsOut; + + /* + * Some BIOSes report that extended disk access functions are not supported + * when booting from a CD (e.g. Phoenix BIOS v6.00PG and Insyde BIOS shipping + * with Intel Macs). Therefore we just return TRUE if we're booting from a CD + * - we can assume that all El Torito capable BIOSes support INT 13 extensions. + * We simply detect whether we're booting from CD by checking whether the drive + * number is >= 0x8A. It's 0x90 on the Insyde BIOS, and 0x9F on most other BIOSes. + */ + if (DriveNumber >= 0x8A) + return TRUE; + + /* + * IBM/MS INT 13 Extensions - INSTALLATION CHECK + * AH = 41h + * BX = 55AAh + * DL = drive (80h-FFh) + * Return: + * CF set on error (extensions not supported) + * AH = 01h (invalid function) + * CF clear if successful + * BX = AA55h if installed + * AH = major version of extensions + * 01h = 1.x + * 20h = 2.0 / EDD-1.0 + * 21h = 2.1 / EDD-1.1 + * 30h = EDD-3.0 + * AL = internal use + * CX = API subset support bitmap + * DH = extension version (v2.0+ ??? -- not present in 1.x) + * + * Bitfields for IBM/MS INT 13 Extensions API support bitmap + * Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported + * Bit 1, removable drive controller functions (AH=45h,46h,48h,49h,INT 15/AH=52h) supported + * Bit 2, enhanced disk drive (EDD) functions (AH=48h,AH=4Eh) supported + * extended drive parameter table is valid + * Bits 3-15 reserved + */ + RegsIn.b.ah = 0x41; + RegsIn.w.bx = 0x55AA; + RegsIn.b.dl = DriveNumber; + + /* Reset the disk controller */ + Int386(0x13, &RegsIn, &RegsOut); + if (!INT386_SUCCESS(RegsOut)) + { + /* CF set on error (extensions not supported) */ + return FALSE; + } + + if (RegsOut.w.bx != 0xAA55) + { + /* BX = AA55h if installed */ + return FALSE; + } + + if (!(RegsOut.w.cx & 0x0001)) + { + /* + * CX = API subset support bitmap. + * Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported. + */ + WARN("Suspicious API subset support bitmap 0x%x on device 0x%lx\n", + RegsOut.w.cx, DriveNumber); + return FALSE; + } + + return TRUE; +} + +static BOOLEAN +DiskGetExtendedDriveParameters( + IN UCHAR DriveNumber, + IN PPC_DISK_DRIVE DiskDrive, + OUT PVOID Buffer, + IN USHORT BufferSize) +{ + REGS RegsIn, RegsOut; + PUSHORT Ptr = (PUSHORT)(BIOSCALLBUFFER); + + TRACE("DiskGetExtendedDriveParameters(0x%x)\n", DriveNumber); + + if (!DiskDrive->Int13ExtensionsSupported) + return FALSE; + + /* Initialize transfer buffer */ + *Ptr = BufferSize; + + /* + * BIOS Int 13h, function 48h - Get drive parameters + * AH = 48h + * DL = drive (bit 7 set for hard disk) + * DS:SI = result buffer + * Return: + * CF set on error + * AH = status (07h) + * CF clear if successful + * AH = 00h + * DS:SI -> result buffer + */ + RegsIn.b.ah = 0x48; + RegsIn.b.dl = DriveNumber; + RegsIn.x.ds = BIOSCALLBUFSEGMENT; // DS:SI -> result buffer + RegsIn.w.si = BIOSCALLBUFOFFSET; + + /* Get drive parameters */ + Int386(0x13, &RegsIn, &RegsOut); + if (!INT386_SUCCESS(RegsOut)) + return FALSE; + + RtlCopyMemory(Buffer, Ptr, BufferSize); + +#if DBG + TRACE("size of buffer: %x\n", Ptr[0]); + TRACE("information flags: %x\n", Ptr[1]); + TRACE("number of physical cylinders on drive: %u\n", *(PULONG)&Ptr[2]); + TRACE("number of physical heads on drive: %u\n", *(PULONG)&Ptr[4]); + TRACE("number of physical sectors per track: %u\n", *(PULONG)&Ptr[6]); + TRACE("total number of sectors on drive: %I64u\n", *(unsigned long long*)&Ptr[8]); + TRACE("bytes per sector: %u\n", Ptr[12]); + if (Ptr[0] >= 0x1e) + { + TRACE("EED configuration parameters: %x:%x\n", Ptr[13], Ptr[14]); + if (Ptr[13] != 0xffff && Ptr[14] != 0xffff) + { + PUCHAR SpecPtr = (PUCHAR)(ULONG_PTR)((Ptr[13] << 4) + Ptr[14]); + TRACE("SpecPtr: %x\n", SpecPtr); + TRACE("physical I/O port base address: %x\n", *(PUSHORT)&SpecPtr[0]); + TRACE("disk-drive control port address: %x\n", *(PUSHORT)&SpecPtr[2]); + TRACE("drive flags: %x\n", SpecPtr[4]); + TRACE("proprietary information: %x\n", SpecPtr[5]); + TRACE("IRQ for drive: %u\n", SpecPtr[6]); + TRACE("sector count for multi-sector transfers: %u\n", SpecPtr[7]); + TRACE("DMA control: %x\n", SpecPtr[8]); + TRACE("programmed I/O control: %x\n", SpecPtr[9]); + TRACE("drive options: %x\n", *(PUSHORT)&SpecPtr[10]); + } + } + if (Ptr[0] >= 0x42) + { + TRACE("signature: %x\n", Ptr[15]); + } +#endif + + return TRUE; +} + +static BOOLEAN +InitDriveGeometry( + IN UCHAR DriveNumber, + IN PPC_DISK_DRIVE DiskDrive) +{ + BOOLEAN Success; + REGS RegsIn, RegsOut; + ULONG Cylinders; + + /* Get the extended geometry first */ + DiskDrive->ExtGeometry.Size = sizeof(DiskDrive->ExtGeometry); + Success = DiskGetExtendedDriveParameters(DriveNumber, DiskDrive, + &DiskDrive->ExtGeometry, + DiskDrive->ExtGeometry.Size); + if (!Success) + { + /* Failed, zero it out */ + RtlZeroMemory(&DiskDrive->ExtGeometry, sizeof(DiskDrive->ExtGeometry)); + } + else + { + TRACE("DiskGetExtendedDriveParameters(0x%x) returned:\n" + "Cylinders : 0x%x\n" + "Heads : 0x%x\n" + "Sects/Track: 0x%x\n" + "Bytes/Sect : 0x%x\n", + DriveNumber, + DiskDrive->ExtGeometry.Cylinders, + DiskDrive->ExtGeometry.Heads, + DiskDrive->ExtGeometry.SectorsPerTrack, + DiskDrive->ExtGeometry.BytesPerSector); + } + + /* Now try the legacy geometry */ + RtlZeroMemory(&DiskDrive->Geometry, sizeof(DiskDrive->Geometry)); + + /* + * BIOS Int 13h, function 08h - Get drive parameters + * AH = 08h + * DL = drive (bit 7 set for hard disk) + * ES:DI = 0000h:0000h to guard against BIOS bugs + * Return: + * CF set on error + * AH = status (07h) + * CF clear if successful + * AH = 00h + * AL = 00h on at least some BIOSes + * BL = drive type (AT/PS2 floppies only) + * CH = low eight bits of maximum cylinder number + * CL = maximum sector number (bits 5-0) + * high two bits of maximum cylinder number (bits 7-6) + * DH = maximum head number + * DL = number of drives + * ES:DI -> drive parameter table (floppies only) + */ + RegsIn.b.ah = 0x08; + RegsIn.b.dl = DriveNumber; + RegsIn.w.es = 0x0000; + RegsIn.w.di = 0x0000; + + /* Get drive parameters */ + Int386(0x13, &RegsIn, &RegsOut); + if (!INT386_SUCCESS(RegsOut)) + { + /* We failed, return the result of the previous call (extended geometry) */ + return Success; + } + /* OR it with the old result, so that we return TRUE whenever either call succeeded */ + Success |= TRUE; + + Cylinders = (RegsOut.b.cl & 0xC0) << 2; + Cylinders += RegsOut.b.ch; + Cylinders++; + DiskDrive->Geometry.Cylinders = Cylinders; + DiskDrive->Geometry.Heads = RegsOut.b.dh + 1; + DiskDrive->Geometry.Sectors = RegsOut.b.cl & 0x3F; + DiskDrive->Geometry.BytesPerSector = 512; /* Just assume 512 bytes per sector */ + + TRACE("Regular Int13h(0x%x) returned:\n" + "Cylinders : 0x%x\n" + "Heads : 0x%x\n" + "Sects/Track: 0x%x (original 0x%x)\n" + "Bytes/Sect : 0x%x\n", + DriveNumber, + DiskDrive->Geometry.Cylinders, + DiskDrive->Geometry.Heads, + DiskDrive->Geometry.Sectors, RegsOut.b.cl, + DiskDrive->Geometry.BytesPerSector); + + return Success; +} + +static BOOLEAN +PcDiskDriveInit( + IN UCHAR DriveNumber, + IN OUT PPC_DISK_DRIVE DiskDrive) +{ + DiskDrive->IsRemovable = DiskIsDriveRemovable(DriveNumber); + + /* + * Check to see if it is a fixed disk drive. + * If so then check to see if INT 13h extensions work. + * If they do then use them, otherwise default back to BIOS calls. + */ + DiskDrive->Int13ExtensionsSupported = DiskInt13ExtensionsSupported(DriveNumber); + + if (!InitDriveGeometry(DriveNumber, DiskDrive)) + return FALSE; + + TRACE("\n" + "DriveNumber: 0x%x\n" + "IsRemovable = %s\n" + "Int13ExtensionsSupported = %s\n", + DriveNumber, + DiskDrive->IsRemovable ? "TRUE" : "FALSE", + DiskDrive->Int13ExtensionsSupported ? "TRUE" : "FALSE"); + + return TRUE; +} + +static inline +PPC_DISK_DRIVE +PcDiskDriveNumberToDrive(IN UCHAR DriveNumber) +{ +#ifdef CACHE_MULTI_DRIVES + PPC_DISK_DRIVE DiskDrive; + + ASSERT((0 <= DriveNumber) && (DriveNumber < RTL_NUMBER_OF(PcDiskDrive))); + + /* Retrieve a slot */ + DiskDrive = &PcDiskDrive[DriveNumber]; + + /* If the drive has not been initialized before... */ + if (!DiskDrive->Initialized) + { + /* ... try to initialize it now. */ + if (!PcDiskDriveInit(DriveNumber, DiskDrive)) + { + /* + * If we failed, there is no drive at this number + * and flag it as such (set its high bit). + */ + DiskDrive->Initialized |= 0x80; + return NULL; + } + DiskDrive->Initialized = TRUE; + } + else if (DiskDrive->Initialized & 0x80) + { + /* + * The disk failed to be initialized previously, reset its flag to give + * it chance to be initialized again later, but just fail for the moment. + */ + DiskDrive->Initialized = FALSE; + return NULL; + } + + return DiskDrive; +#else + static PC_DISK_DRIVE NewDiskDrive; + + ASSERT((0 <= DriveNumber) && (DriveNumber <= 0xFF)); + + /* Update cached information */ + + /* If the drive has not been accessed last before... */ + if ((USHORT)DriveNumber != LastDriveNumber) + { + /* ... try to (re-)initialize and cache it now. */ + RtlZeroMemory(&NewDiskDrive, sizeof(NewDiskDrive)); + if (!PcDiskDriveInit(DriveNumber, &NewDiskDrive)) + { + /* + * If we failed, there is no drive at this number. + * Keep the last-accessed valid drive cached. + */ + return NULL; + } + /* We succeeded, cache the drive data */ + PcDiskDrive = NewDiskDrive; + LastDriveNumber = (USHORT)DriveNumber; + } + + return &PcDiskDrive; +#endif /* CACHE_MULTI_DRIVES */ +} + +static BOOLEAN +PcDiskReadLogicalSectorsLBA( + IN UCHAR DriveNumber, + IN ULONGLONG SectorNumber, + IN ULONG SectorCount, + OUT PVOID Buffer) { REGS RegsIn, RegsOut; ULONG RetryCount; PI386_DISK_ADDRESS_PACKET Packet = (PI386_DISK_ADDRESS_PACKET)(BIOSCALLBUFFER);
- TRACE("PcDiskReadLogicalSectorsLBA() DriveNumber: 0x%x SectorNumber: %I64d SectorCount: %d Buffer: 0x%x\n", DriveNumber, SectorNumber, SectorCount, Buffer); - ASSERT(((ULONG_PTR)Buffer) <= 0xFFFFF); - /* Setup disk address packet */ RtlZeroMemory(Packet, sizeof(*Packet)); Packet->PacketSize = sizeof(*Packet); @@ -196,7 +591,7 @@ static BOOLEAN PcDiskReadLogicalSectorsLBA(UCHAR DriveNumber, ULONGLONG SectorNu RegsIn.w.si = BIOSCALLBUFOFFSET;
/* Retry 3 times */ - for (RetryCount=0; RetryCount<3; RetryCount++) + for (RetryCount = 0; RetryCount < 3; ++RetryCount) { Int386(0x13, &RegsIn, &RegsOut);
@@ -227,7 +622,13 @@ static BOOLEAN PcDiskReadLogicalSectorsLBA(UCHAR DriveNumber, ULONGLONG SectorNu return FALSE; }
-static BOOLEAN PcDiskReadLogicalSectorsCHS(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer) +static BOOLEAN +PcDiskReadLogicalSectorsCHS( + IN UCHAR DriveNumber, + IN PPC_DISK_DRIVE DiskDrive, + IN ULONGLONG SectorNumber, + IN ULONG SectorCount, + OUT PVOID Buffer) { UCHAR PhysicalSector; UCHAR PhysicalHead; @@ -237,19 +638,11 @@ static BOOLEAN PcDiskReadLogicalSectorsCHS(UCHAR DriveNumber, ULONGLONG SectorNu REGS RegsIn, RegsOut; ULONG RetryCount;
- TRACE("PcDiskReadLogicalSectorsCHS()\n"); - - /* Get the drive geometry */ - // - // TODO: Cache this information for the given drive. - // - if (!PcDiskGetDriveGeometry(DriveNumber, &DriveGeometry) || - DriveGeometry.Sectors == 0 || DriveGeometry.Heads == 0) - { + DriveGeometry = DiskDrive->Geometry; + if (DriveGeometry.Sectors == 0 || DriveGeometry.Heads == 0) return FALSE; - }
- while (SectorCount) + while (SectorCount > 0) { /* * Calculate the physical disk offsets. @@ -313,7 +706,7 @@ static BOOLEAN PcDiskReadLogicalSectorsCHS(UCHAR DriveNumber, ULONGLONG SectorNu RegsIn.w.bx = ((ULONG_PTR)Buffer) & 0x0F;
/* Perform the read. Retry 3 times. */ - for (RetryCount=0; RetryCount<3; RetryCount++) + for (RetryCount = 0; RetryCount < 3; ++RetryCount) { Int386(0x13, &RegsIn, &RegsOut);
@@ -327,7 +720,7 @@ static BOOLEAN PcDiskReadLogicalSectorsCHS(UCHAR DriveNumber, ULONGLONG SectorNu { break; } - /* If it failed the do the next retry */ + /* If it failed then do the next retry */ else { DiskResetController(DriveNumber); @@ -345,11 +738,13 @@ static BOOLEAN PcDiskReadLogicalSectorsCHS(UCHAR DriveNumber, ULONGLONG SectorNu return FALSE; }
- // I have learned that not all BIOSes return - // the sector read count in the AL register (at least mine doesn't) - // even if the sectors were read correctly. So instead - // of checking the sector read count we will rely solely - // on the carry flag being set on error + /* + * I have learned that not all BIOSes return + * the sector read count in the AL register (at least mine doesn't) + * even if the sectors were read correctly. So instead + * of checking the sector read count we will rely solely + * on the carry flag being set on error. + */
Buffer = (PVOID)((ULONG_PTR)Buffer + (NumberOfSectorsToRead * DriveGeometry.BytesPerSector)); SectorCount -= NumberOfSectorsToRead; @@ -359,128 +754,37 @@ static BOOLEAN PcDiskReadLogicalSectorsCHS(UCHAR DriveNumber, ULONGLONG SectorNu return TRUE; }
-static BOOLEAN DiskInt13ExtensionsSupported(UCHAR DriveNumber) -{ - static UCHAR LastDriveNumber = 0xff; - static BOOLEAN LastSupported; - REGS RegsIn, RegsOut; - - TRACE("DiskInt13ExtensionsSupported()\n"); - - if (DriveNumber == LastDriveNumber) - { - TRACE("Using cached value %s for drive 0x%x\n", - LastSupported ? "TRUE" : "FALSE", DriveNumber); - return LastSupported; - } - - /* - * Some BIOSes report that extended disk access functions are not supported - * when booting from a CD (e.g. Phoenix BIOS v6.00PG and Insyde BIOS shipping - * with Intel Macs). Therefore we just return TRUE if we're booting from a CD - - * we can assume that all El Torito capable BIOSes support INT 13 extensions. - * We simply detect whether we're booting from CD by checking whether the drive - * number is >= 0x8A. It's 0x90 on the Insyde BIOS, and 0x9F on most other BIOSes. - */ - if (DriveNumber >= 0x8A) - { - LastSupported = TRUE; - return TRUE; - } - - LastDriveNumber = DriveNumber; - - /* - * IBM/MS INT 13 Extensions - INSTALLATION CHECK - * AH = 41h - * BX = 55AAh - * DL = drive (80h-FFh) - * Return: - * CF set on error (extensions not supported) - * AH = 01h (invalid function) - * CF clear if successful - * BX = AA55h if installed - * AH = major version of extensions - * 01h = 1.x - * 20h = 2.0 / EDD-1.0 - * 21h = 2.1 / EDD-1.1 - * 30h = EDD-3.0 - * AL = internal use - * CX = API subset support bitmap - * DH = extension version (v2.0+ ??? -- not present in 1.x) - * - * Bitfields for IBM/MS INT 13 Extensions API support bitmap - * Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported - * Bit 1, removable drive controller functions (AH=45h,46h,48h,49h,INT 15/AH=52h) supported - * Bit 2, enhanced disk drive (EDD) functions (AH=48h,AH=4Eh) supported - * extended drive parameter table is valid - * Bits 3-15 reserved - */ - RegsIn.b.ah = 0x41; - RegsIn.w.bx = 0x55AA; - RegsIn.b.dl = DriveNumber; - - /* Reset the disk controller */ - Int386(0x13, &RegsIn, &RegsOut); - - if (!INT386_SUCCESS(RegsOut)) - { - /* CF set on error (extensions not supported) */ - LastSupported = FALSE; - return FALSE; - } - - if (RegsOut.w.bx != 0xAA55) - { - /* BX = AA55h if installed */ - LastSupported = FALSE; - return FALSE; - } - - if (!(RegsOut.w.cx & 0x0001)) - { - /* - * CX = API subset support bitmap. - * Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported. - */ - DbgPrint("Suspicious API subset support bitmap 0x%x on device 0x%lx\n", - RegsOut.w.cx, DriveNumber); - LastSupported = FALSE; - return FALSE; - } - - LastSupported = TRUE; - return TRUE; -} - -BOOLEAN PcDiskReadLogicalSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer) +BOOLEAN +PcDiskReadLogicalSectors( + IN UCHAR DriveNumber, + IN ULONGLONG SectorNumber, + IN ULONG SectorCount, + OUT PVOID Buffer) { - BOOLEAN ExtensionsSupported; + PPC_DISK_DRIVE DiskDrive;
TRACE("PcDiskReadLogicalSectors() DriveNumber: 0x%x SectorNumber: %I64d SectorCount: %d Buffer: 0x%x\n", DriveNumber, SectorNumber, SectorCount, Buffer);
- /* - * Check to see if it is a fixed disk drive. - * If so then check to see if Int13 extensions work. - * If they do then use them, otherwise default back to BIOS calls. - */ - ExtensionsSupported = DiskInt13ExtensionsSupported(DriveNumber); + /* 16-bit BIOS addressing limitation */ + ASSERT(((ULONG_PTR)Buffer) <= 0xFFFFF);
- if ((DriveNumber >= 0x80) && ExtensionsSupported) - { - TRACE("Using Int 13 Extensions for read. DiskInt13ExtensionsSupported(%d) = %s\n", DriveNumber, ExtensionsSupported ? "TRUE" : "FALSE"); + DiskDrive = PcDiskDriveNumberToDrive(DriveNumber); + if (!DiskDrive) + return FALSE;
+ if ((DriveNumber >= 0x80) && DiskDrive->Int13ExtensionsSupported) + { /* LBA is easy, nothing to calculate. Just do the read. */ + TRACE("--> Using LBA\n"); return PcDiskReadLogicalSectorsLBA(DriveNumber, SectorNumber, SectorCount, Buffer); } else { - /* LBA is not supported default to the CHS calls */ - return PcDiskReadLogicalSectorsCHS(DriveNumber, SectorNumber, SectorCount, Buffer); + /* LBA is not supported, default to CHS */ + TRACE("--> Using CHS\n"); + return PcDiskReadLogicalSectorsCHS(DriveNumber, DiskDrive, SectorNumber, SectorCount, Buffer); } - - return TRUE; }
#if defined(__i386__) || defined(_M_AMD64) @@ -490,159 +794,52 @@ VOID __cdecl DiskStopFloppyMotor(VOID) } #endif // defined __i386__ || defined(_M_AMD64)
-BOOLEAN DiskGetExtendedDriveParameters(UCHAR DriveNumber, PVOID Buffer, USHORT BufferSize) +BOOLEAN +PcDiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry) { - REGS RegsIn, RegsOut; - PUSHORT Ptr = (PUSHORT)(BIOSCALLBUFFER); + PPC_DISK_DRIVE DiskDrive;
- TRACE("DiskGetExtendedDriveParameters()\n"); + TRACE("PcDiskGetDriveGeometry(0x%x)\n", DriveNumber);
- if (!DiskInt13ExtensionsSupported(DriveNumber)) + DiskDrive = PcDiskDriveNumberToDrive(DriveNumber); + if (!DiskDrive) return FALSE;
- /* Initialize transfer buffer */ - *Ptr = BufferSize; - - /* - * BIOS Int 13h, function 48h - Get drive parameters - * AH = 48h - * DL = drive (bit 7 set for hard disk) - * DS:SI = result buffer - * Return: - * CF set on error - * AH = status (07h) - * CF clear if successful - * AH = 00h - * DS:SI -> result buffer - */ - RegsIn.b.ah = 0x48; - RegsIn.b.dl = DriveNumber; - RegsIn.x.ds = BIOSCALLBUFSEGMENT; // DS:SI -> result buffer - RegsIn.w.si = BIOSCALLBUFOFFSET; - - /* Get drive parameters */ - Int386(0x13, &RegsIn, &RegsOut); - if (!INT386_SUCCESS(RegsOut)) - return FALSE; - - memcpy(Buffer, Ptr, BufferSize); - -#if DBG - TRACE("size of buffer: %x\n", Ptr[0]); - TRACE("information flags: %x\n", Ptr[1]); - TRACE("number of physical cylinders on drive: %u\n", *(PULONG)&Ptr[2]); - TRACE("number of physical heads on drive: %u\n", *(PULONG)&Ptr[4]); - TRACE("number of physical sectors per track: %u\n", *(PULONG)&Ptr[6]); - TRACE("total number of sectors on drive: %I64u\n", *(unsigned long long*)&Ptr[8]); - TRACE("bytes per sector: %u\n", Ptr[12]); - if (Ptr[0] >= 0x1e) + /* Try to get the extended geometry first */ + if (DiskDrive->ExtGeometry.Size == sizeof(DiskDrive->ExtGeometry)) { - TRACE("EED configuration parameters: %x:%x\n", Ptr[13], Ptr[14]); - if (Ptr[13] != 0xffff && Ptr[14] != 0xffff) - { - PUCHAR SpecPtr = (PUCHAR)(ULONG_PTR)((Ptr[13] << 4) + Ptr[14]); - TRACE("SpecPtr: %x\n", SpecPtr); - TRACE("physical I/O port base address: %x\n", *(PUSHORT)&SpecPtr[0]); - TRACE("disk-drive control port address: %x\n", *(PUSHORT)&SpecPtr[2]); - TRACE("drive flags: %x\n", SpecPtr[4]); - TRACE("proprietary information: %x\n", SpecPtr[5]); - TRACE("IRQ for drive: %u\n", SpecPtr[6]); - TRACE("sector count for multi-sector transfers: %u\n", SpecPtr[7]); - TRACE("DMA control: %x\n", SpecPtr[8]); - TRACE("programmed I/O control: %x\n", SpecPtr[9]); - TRACE("drive options: %x\n", *(PUSHORT)&SpecPtr[10]); - } + /* Extended geometry has been initialized, return it */ + Geometry->Cylinders = DiskDrive->ExtGeometry.Cylinders; + Geometry->Heads = DiskDrive->ExtGeometry.Heads; + Geometry->Sectors = DiskDrive->ExtGeometry.SectorsPerTrack; + Geometry->BytesPerSector = DiskDrive->ExtGeometry.BytesPerSector; } - if (Ptr[0] >= 0x42) + else + /* Fall back to legacy BIOS geometry */ { - TRACE("signature: %x\n", Ptr[15]); + *Geometry = DiskDrive->Geometry; } -#endif
return TRUE; }
-BOOLEAN -PcDiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry) +ULONG +PcDiskGetCacheableBlockCount(UCHAR DriveNumber) { - EXTENDED_GEOMETRY ExtGeometry; - REGS RegsIn, RegsOut; - ULONG Cylinders; - - TRACE("DiskGetDriveGeometry()\n"); + PPC_DISK_DRIVE DiskDrive;
- /* Try to get the extended geometry first */ - ExtGeometry.Size = sizeof(ExtGeometry); - if (DiskGetExtendedDriveParameters(DriveNumber, &ExtGeometry, ExtGeometry.Size)) - { - Geometry->Cylinders = ExtGeometry.Cylinders; - Geometry->Heads = ExtGeometry.Heads; - Geometry->Sectors = ExtGeometry.SectorsPerTrack; - Geometry->BytesPerSector = ExtGeometry.BytesPerSector; - return TRUE; - } + DiskDrive = PcDiskDriveNumberToDrive(DriveNumber); + if (!DiskDrive) + return 1; // Unknown count.
/* - * BIOS Int 13h, function 08h - Get drive parameters - * AH = 08h - * DL = drive (bit 7 set for hard disk) - * ES:DI = 0000h:0000h to guard against BIOS bugs - * Return: - * CF set on error - * AH = status (07h) - * CF clear if successful - * AH = 00h - * AL = 00h on at least some BIOSes - * BL = drive type (AT/PS2 floppies only) - * CH = low eight bits of maximum cylinder number - * CL = maximum sector number (bits 5-0) - * high two bits of maximum cylinder number (bits 7-6) - * DH = maximum head number - * DL = number of drives - * ES:DI -> drive parameter table (floppies only) + * If LBA is supported then the block size will be 64 sectors (32k). + * If not then the block size is the size of one track. */ - RegsIn.b.ah = 0x08; - RegsIn.b.dl = DriveNumber; - RegsIn.w.es = 0x0000; - RegsIn.w.di = 0x0000; - - /* Get drive parameters */ - Int386(0x13, &RegsIn, &RegsOut); - if (!INT386_SUCCESS(RegsOut)) - return FALSE; - - Cylinders = (RegsOut.b.cl & 0xC0) << 2; - Cylinders += RegsOut.b.ch; - Cylinders++; - Geometry->Cylinders = Cylinders; - Geometry->Heads = RegsOut.b.dh + 1; - Geometry->Sectors = RegsOut.b.cl & 0x3F; - Geometry->BytesPerSector = 512; /* Just assume 512 bytes per sector */ - - return TRUE; -} - -ULONG -PcDiskGetCacheableBlockCount(UCHAR DriveNumber) -{ - GEOMETRY Geometry; - - /* If LBA is supported then the block size will be 64 sectors (32k) - * If not then the block size is the size of one track. */ - if (DiskInt13ExtensionsSupported(DriveNumber)) - { + if (DiskDrive->Int13ExtensionsSupported) return 64; - } - /* Get the disk geometry. If this fails then we will - * just return 1 sector to be safe. */ - else if (!PcDiskGetDriveGeometry(DriveNumber, &Geometry)) - { - return 1; - } else - { - return Geometry.Sectors; - } + return DiskDrive->Geometry.Sectors; }
/* EOF */ diff --git a/boot/freeldr/freeldr/arch/i386/xboxdisk.c b/boot/freeldr/freeldr/arch/i386/xboxdisk.c index 26a00e1136c..06e7e2d6691 100644 --- a/boot/freeldr/freeldr/arch/i386/xboxdisk.c +++ b/boot/freeldr/freeldr/arch/i386/xboxdisk.c @@ -58,44 +58,42 @@ XboxDiskInit(BOOLEAN Init) } }
-static -inline -BOOLEAN -XboxDiskDriveNumberToDeviceUnit(UCHAR DriveNumber, PDEVICE_UNIT *DeviceUnit) +static inline +PDEVICE_UNIT +XboxDiskDriveNumberToDeviceUnit(UCHAR DriveNumber) { /* Xbox has only 1 IDE controller and no floppy */ if (DriveNumber < 0x80 || (DriveNumber & 0x0F) >= 2) - return FALSE; + return NULL;
if (!AtaInitialized) XboxDiskInit(TRUE);
/* HDD */ if ((DriveNumber == 0x80) && HardDrive) - { - *DeviceUnit = HardDrive; - return TRUE; - } + return HardDrive;
/* CD */ - if ((DriveNumber & 0xF0) > 0x80 && CdDrive) - { - *DeviceUnit = CdDrive; - return TRUE; - } + if (((DriveNumber & 0xF0) > 0x80) && CdDrive) + return CdDrive;
- return FALSE; + return NULL; }
BOOLEAN -XboxDiskReadLogicalSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer) +XboxDiskReadLogicalSectors( + IN UCHAR DriveNumber, + IN ULONGLONG SectorNumber, + IN ULONG SectorCount, + OUT PVOID Buffer) { - PDEVICE_UNIT DeviceUnit = NULL; + PDEVICE_UNIT DeviceUnit;
TRACE("XboxDiskReadLogicalSectors() DriveNumber: 0x%x SectorNumber: %I64d SectorCount: %d Buffer: 0x%x\n", DriveNumber, SectorNumber, SectorCount, Buffer);
- if (!XboxDiskDriveNumberToDeviceUnit(DriveNumber, &DeviceUnit)) + DeviceUnit = XboxDiskDriveNumberToDeviceUnit(DriveNumber); + if (!DeviceUnit) return FALSE;
return AtaAtapiReadLogicalSectorsLBA(DeviceUnit, SectorNumber, SectorCount, Buffer); @@ -104,11 +102,12 @@ XboxDiskReadLogicalSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG Sect BOOLEAN XboxDiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry) { - PDEVICE_UNIT DeviceUnit = NULL; + PDEVICE_UNIT DeviceUnit;
TRACE("XboxDiskGetDriveGeometry(0x%x)\n", DriveNumber);
- if (!XboxDiskDriveNumberToDeviceUnit(DriveNumber, &DeviceUnit)) + DeviceUnit = XboxDiskDriveNumberToDeviceUnit(DriveNumber); + if (!DeviceUnit) return FALSE;
Geometry->Cylinders = DeviceUnit->Cylinders; @@ -122,15 +121,14 @@ XboxDiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry) ULONG XboxDiskGetCacheableBlockCount(UCHAR DriveNumber) { - PDEVICE_UNIT DeviceUnit = NULL; + PDEVICE_UNIT DeviceUnit;
- TRACE("XboxDiskGetCacheableBlockCount(0x%x)\n", DriveNumber); - - if (!XboxDiskDriveNumberToDeviceUnit(DriveNumber, &DeviceUnit)) - return 0; + DeviceUnit = XboxDiskDriveNumberToDeviceUnit(DriveNumber); + if (!DeviceUnit) + return 1; // Unknown count.
/* - * If LBA is supported then the block size will be 64 sectors (32k) + * If LBA is supported then the block size will be 64 sectors (32k). * If not then the block size is the size of one track. */ if (DeviceUnit->Flags & ATA_DEVICE_LBA) @@ -138,3 +136,5 @@ XboxDiskGetCacheableBlockCount(UCHAR DriveNumber) else return DeviceUnit->Sectors; } + +/* EOF */ diff --git a/boot/freeldr/freeldr/include/arch/pc/machpc.h b/boot/freeldr/freeldr/include/arch/pc/machpc.h index d5d8bebce1d..b76e55e776a 100644 --- a/boot/freeldr/freeldr/include/arch/pc/machpc.h +++ b/boot/freeldr/freeldr/include/arch/pc/machpc.h @@ -60,7 +60,7 @@ extern ULONG FrldrBootPartition;
LONG DiskReportError(BOOLEAN bShowError); BOOLEAN DiskResetController(UCHAR DriveNumber); -BOOLEAN DiskGetExtendedDriveParameters(UCHAR DriveNumber, PVOID Buffer, USHORT BufferSize); +// BOOLEAN DiskGetExtendedDriveParameters(UCHAR DriveNumber, PVOID Buffer, USHORT BufferSize);
BOOLEAN PcDiskReadLogicalSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer); BOOLEAN PcDiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY DriveGeometry);