#include <pshpack2.h>
typedef struct
{
- UCHAR PacketSize; // 00h - Size of packet (10h or 18h)
- UCHAR Reserved; // 01h - Reserved (0)
- USHORT LBABlockCount; // 02h - Number of blocks to transfer (max 007Fh for Phoenix EDD)
- USHORT TransferBufferOffset; // 04h - Transfer buffer offset (seg:off)
- USHORT TransferBufferSegment; // Transfer buffer segment (seg:off)
- ULONGLONG LBAStartBlock; // 08h - Starting absolute block number
- //ULONGLONG TransferBuffer64; // 10h - (EDD-3.0, optional) 64-bit flat address of transfer buffer
- // used if DWORD at 04h is FFFFh:FFFFh
- // Commented since some earlier BIOSes refuse to work with
- // such extended structure
+ UCHAR PacketSize; // 00h - Size of packet (10h or 18h)
+ UCHAR Reserved; // 01h - Reserved (0)
+ USHORT LBABlockCount; // 02h - Number of blocks to transfer (max 007Fh for Phoenix EDD)
+ USHORT TransferBufferOffset; // 04h - Transfer buffer offset (seg:off)
+ USHORT TransferBufferSegment; // Transfer buffer segment (seg:off)
+ ULONGLONG LBAStartBlock; // 08h - Starting absolute block number
+ //ULONGLONG TransferBuffer64; // 10h - (EDD-3.0, optional) 64-bit flat address of transfer buffer
+ // used if DWORD at 04h is FFFFh:FFFFh
+ // Commented since some earlier BIOSes refuse to work with
+ // such extended structure
} I386_DISK_ADDRESS_PACKET, *PI386_DISK_ADDRESS_PACKET;
#include <poppack.h>
static BOOLEAN PcDiskResetController(UCHAR DriveNumber)
{
- REGS RegsIn;
- REGS RegsOut;
+ REGS RegsIn;
+ REGS RegsOut;
- WARN("PcDiskResetController(0x%x) DISK OPERATION FAILED -- RESETTING CONTROLLER\n", DriveNumber);
+ WARN("PcDiskResetController(0x%x) DISK OPERATION FAILED -- RESETTING CONTROLLER\n", DriveNumber);
- // BIOS Int 13h, function 0 - Reset disk system
- // AH = 00h
- // DL = drive (if bit 7 is set both hard disks and floppy disks reset)
- // Return:
- // AH = status
- // CF clear if successful
- // CF set on error
- RegsIn.b.ah = 0x00;
- RegsIn.b.dl = DriveNumber;
+ // BIOS Int 13h, function 0 - Reset disk system
+ // AH = 00h
+ // DL = drive (if bit 7 is set both hard disks and floppy disks reset)
+ // Return:
+ // AH = status
+ // CF clear if successful
+ // CF set on error
+ RegsIn.b.ah = 0x00;
+ RegsIn.b.dl = DriveNumber;
- // Reset the disk controller
- Int386(0x13, &RegsIn, &RegsOut);
+ // Reset the disk controller
+ Int386(0x13, &RegsIn, &RegsOut);
- return INT386_SUCCESS(RegsOut);
+ return INT386_SUCCESS(RegsOut);
}
static BOOLEAN PcDiskReadLogicalSectorsLBA(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer)
{
- REGS RegsIn;
- REGS RegsOut;
- ULONG RetryCount;
- PI386_DISK_ADDRESS_PACKET Packet = (PI386_DISK_ADDRESS_PACKET)(BIOSCALLBUFFER);
+ REGS RegsIn;
+ REGS 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);
+ TRACE("PcDiskReadLogicalSectorsLBA() DriveNumber: 0x%x SectorNumber: %I64d SectorCount: %d Buffer: 0x%x\n", DriveNumber, SectorNumber, SectorCount, Buffer);
ASSERT(((ULONG_PTR)Buffer) <= 0xFFFFF);
- // BIOS int 0x13, function 42h - IBM/MS INT 13 Extensions - EXTENDED READ
- RegsIn.b.ah = 0x42; // Subfunction 42h
- RegsIn.b.dl = DriveNumber; // Drive number in DL (0 - floppy, 0x80 - harddisk)
- RegsIn.x.ds = BIOSCALLBUFSEGMENT; // DS:SI -> disk address packet
- RegsIn.w.si = BIOSCALLBUFOFFSET;
-
- // Setup disk address packet
- RtlZeroMemory(Packet, sizeof(I386_DISK_ADDRESS_PACKET));
- Packet->PacketSize = sizeof(I386_DISK_ADDRESS_PACKET);
- Packet->Reserved = 0;
- Packet->LBABlockCount = (USHORT)SectorCount;
- ASSERT(Packet->LBABlockCount == SectorCount);
- Packet->TransferBufferOffset = ((ULONG_PTR)Buffer) & 0x0F;
- Packet->TransferBufferSegment = (USHORT)(((ULONG_PTR)Buffer) >> 4);
- Packet->LBAStartBlock = SectorNumber;
-
- // BIOS int 0x13, function 42h - IBM/MS INT 13 Extensions - EXTENDED READ
- // Return:
- // CF clear if successful
- // AH = 00h
- // CF set on error
- // AH = error code
- // disk address packet's block count field set to the
- // number of blocks successfully transferred
-
- // Retry 3 times
- for (RetryCount=0; RetryCount<3; RetryCount++)
- {
- Int386(0x13, &RegsIn, &RegsOut);
-
- // If it worked return TRUE
- if (INT386_SUCCESS(RegsOut))
- {
- return TRUE;
- }
- // If it was a corrected ECC error then the data is still good
- else if (RegsOut.b.ah == 0x11)
- {
- return TRUE;
- }
- // If it failed the do the next retry
- else
- {
- PcDiskResetController(DriveNumber);
-
- continue;
- }
- }
-
- // If we get here then the read failed
- ERR("Disk Read Failed in LBA mode: %x (DriveNumber: 0x%x SectorNumber: %I64d SectorCount: %d)\n", RegsOut.b.ah, DriveNumber, SectorNumber, SectorCount);
-
- return FALSE;
+ // BIOS int 0x13, function 42h - IBM/MS INT 13 Extensions - EXTENDED READ
+ RegsIn.b.ah = 0x42; // Subfunction 42h
+ RegsIn.b.dl = DriveNumber; // Drive number in DL (0 - floppy, 0x80 - harddisk)
+ RegsIn.x.ds = BIOSCALLBUFSEGMENT; // DS:SI -> disk address packet
+ RegsIn.w.si = BIOSCALLBUFOFFSET;
+
+ // Setup disk address packet
+ RtlZeroMemory(Packet, sizeof(I386_DISK_ADDRESS_PACKET));
+ Packet->PacketSize = sizeof(I386_DISK_ADDRESS_PACKET);
+ Packet->Reserved = 0;
+ Packet->LBABlockCount = (USHORT)SectorCount;
+ ASSERT(Packet->LBABlockCount == SectorCount);
+ Packet->TransferBufferOffset = ((ULONG_PTR)Buffer) & 0x0F;
+ Packet->TransferBufferSegment = (USHORT)(((ULONG_PTR)Buffer) >> 4);
+ Packet->LBAStartBlock = SectorNumber;
+
+ // BIOS int 0x13, function 42h - IBM/MS INT 13 Extensions - EXTENDED READ
+ // Return:
+ // CF clear if successful
+ // AH = 00h
+ // CF set on error
+ // AH = error code
+ // disk address packet's block count field set to the
+ // number of blocks successfully transferred
+
+ // Retry 3 times
+ for (RetryCount=0; RetryCount<3; RetryCount++)
+ {
+ Int386(0x13, &RegsIn, &RegsOut);
+
+ // If it worked return TRUE
+ if (INT386_SUCCESS(RegsOut))
+ {
+ return TRUE;
+ }
+ // If it was a corrected ECC error then the data is still good
+ else if (RegsOut.b.ah == 0x11)
+ {
+ return TRUE;
+ }
+ // If it failed the do the next retry
+ else
+ {
+ PcDiskResetController(DriveNumber);
+
+ continue;
+ }
+ }
+
+ // If we get here then the read failed
+ ERR("Disk Read Failed in LBA mode: %x (DriveNumber: 0x%x SectorNumber: %I64d SectorCount: %d)\n", RegsOut.b.ah, DriveNumber, SectorNumber, SectorCount);
+
+ return FALSE;
}
static BOOLEAN PcDiskReadLogicalSectorsCHS(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer)
{
- UCHAR PhysicalSector;
- UCHAR PhysicalHead;
- ULONG PhysicalTrack;
- GEOMETRY DriveGeometry;
- ULONG NumberOfSectorsToRead;
- REGS RegsIn;
- REGS RegsOut;
- ULONG RetryCount;
-
- TRACE("PcDiskReadLogicalSectorsCHS()\n");
-
- //
- // Get the drive geometry
- //
- if (!MachDiskGetDriveGeometry(DriveNumber, &DriveGeometry) ||
- DriveGeometry.Sectors == 0 ||
- DriveGeometry.Heads == 0)
- {
- return FALSE;
- }
-
- while (SectorCount)
- {
-
- //
- // Calculate the physical disk offsets
- // Note: DriveGeometry.Sectors < 64
- //
- PhysicalSector = 1 + (UCHAR)(SectorNumber % DriveGeometry.Sectors);
- PhysicalHead = (UCHAR)((SectorNumber / DriveGeometry.Sectors) % DriveGeometry.Heads);
- PhysicalTrack = (ULONG)((SectorNumber / DriveGeometry.Sectors) / DriveGeometry.Heads);
-
- //
- // Calculate how many sectors we need to read this round
- //
- if (PhysicalSector > 1)
- {
- if (SectorCount >= (DriveGeometry.Sectors - (PhysicalSector - 1)))
- NumberOfSectorsToRead = (DriveGeometry.Sectors - (PhysicalSector - 1));
- else
- NumberOfSectorsToRead = SectorCount;
- }
- else
- {
- if (SectorCount >= DriveGeometry.Sectors)
- NumberOfSectorsToRead = DriveGeometry.Sectors;
- else
- NumberOfSectorsToRead = SectorCount;
- }
-
- //
- // Make sure the read is within the geometry boundaries
- //
- if ((PhysicalHead >= DriveGeometry.Heads) ||
- (PhysicalTrack >= DriveGeometry.Cylinders) ||
- ((NumberOfSectorsToRead + PhysicalSector) > (DriveGeometry.Sectors + 1)) ||
- (PhysicalSector > DriveGeometry.Sectors))
- {
- DiskError("Disk read exceeds drive geometry limits.", 0);
- return FALSE;
- }
-
- // BIOS Int 13h, function 2 - Read Disk Sectors
- // AH = 02h
- // AL = number of sectors to read (must be nonzero)
- // CH = low eight bits of cylinder number
- // CL = sector number 1-63 (bits 0-5)
- // high two bits of cylinder (bits 6-7, hard disk only)
- // DH = head number
- // DL = drive number (bit 7 set for hard disk)
- // ES:BX -> data buffer
- // Return:
- // CF set on error
- // if AH = 11h (corrected ECC error), AL = burst length
- // CF clear if successful
- // AH = status
- // AL = number of sectors transferred
- // (only valid if CF set for some BIOSes)
- RegsIn.b.ah = 0x02;
- RegsIn.b.al = (UCHAR)NumberOfSectorsToRead;
- RegsIn.b.ch = (PhysicalTrack & 0xFF);
- RegsIn.b.cl = (UCHAR)(PhysicalSector + ((PhysicalTrack & 0x300) >> 2));
- RegsIn.b.dh = PhysicalHead;
- RegsIn.b.dl = DriveNumber;
- RegsIn.w.es = (USHORT)(((ULONG_PTR)Buffer) >> 4);
- RegsIn.w.bx = ((ULONG_PTR)Buffer) & 0x0F;
-
- //
- // Perform the read
- // Retry 3 times
- //
- for (RetryCount=0; RetryCount<3; RetryCount++)
- {
- Int386(0x13, &RegsIn, &RegsOut);
-
- // If it worked break out
- if (INT386_SUCCESS(RegsOut))
- {
- break;
- }
- // If it was a corrected ECC error then the data is still good
- else if (RegsOut.b.ah == 0x11)
- {
- break;
- }
- // If it failed the do the next retry
- else
- {
- PcDiskResetController(DriveNumber);
-
- continue;
- }
- }
-
- // If we retried 3 times then fail
- if (RetryCount >= 3)
- {
- ERR("Disk Read Failed in CHS mode, after retrying 3 times: %x\n", RegsOut.b.ah);
- 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
-
- Buffer = (PVOID)((ULONG_PTR)Buffer + (NumberOfSectorsToRead * DriveGeometry.BytesPerSector));
- SectorCount -= NumberOfSectorsToRead;
- SectorNumber += NumberOfSectorsToRead;
- }
-
- return TRUE;
+ UCHAR PhysicalSector;
+ UCHAR PhysicalHead;
+ ULONG PhysicalTrack;
+ GEOMETRY DriveGeometry;
+ ULONG NumberOfSectorsToRead;
+ REGS RegsIn;
+ REGS RegsOut;
+ ULONG RetryCount;
+
+ TRACE("PcDiskReadLogicalSectorsCHS()\n");
+
+ //
+ // Get the drive geometry
+ //
+ if (!MachDiskGetDriveGeometry(DriveNumber, &DriveGeometry) ||
+ DriveGeometry.Sectors == 0 ||
+ DriveGeometry.Heads == 0)
+ {
+ return FALSE;
+ }
+
+ while (SectorCount)
+ {
+
+ //
+ // Calculate the physical disk offsets
+ // Note: DriveGeometry.Sectors < 64
+ //
+ PhysicalSector = 1 + (UCHAR)(SectorNumber % DriveGeometry.Sectors);
+ PhysicalHead = (UCHAR)((SectorNumber / DriveGeometry.Sectors) % DriveGeometry.Heads);
+ PhysicalTrack = (ULONG)((SectorNumber / DriveGeometry.Sectors) / DriveGeometry.Heads);
+
+ //
+ // Calculate how many sectors we need to read this round
+ //
+ if (PhysicalSector > 1)
+ {
+ if (SectorCount >= (DriveGeometry.Sectors - (PhysicalSector - 1)))
+ NumberOfSectorsToRead = (DriveGeometry.Sectors - (PhysicalSector - 1));
+ else
+ NumberOfSectorsToRead = SectorCount;
+ }
+ else
+ {
+ if (SectorCount >= DriveGeometry.Sectors)
+ NumberOfSectorsToRead = DriveGeometry.Sectors;
+ else
+ NumberOfSectorsToRead = SectorCount;
+ }
+
+ //
+ // Make sure the read is within the geometry boundaries
+ //
+ if ((PhysicalHead >= DriveGeometry.Heads) ||
+ (PhysicalTrack >= DriveGeometry.Cylinders) ||
+ ((NumberOfSectorsToRead + PhysicalSector) > (DriveGeometry.Sectors + 1)) ||
+ (PhysicalSector > DriveGeometry.Sectors))
+ {
+ DiskError("Disk read exceeds drive geometry limits.", 0);
+ return FALSE;
+ }
+
+ // BIOS Int 13h, function 2 - Read Disk Sectors
+ // AH = 02h
+ // AL = number of sectors to read (must be nonzero)
+ // CH = low eight bits of cylinder number
+ // CL = sector number 1-63 (bits 0-5)
+ // high two bits of cylinder (bits 6-7, hard disk only)
+ // DH = head number
+ // DL = drive number (bit 7 set for hard disk)
+ // ES:BX -> data buffer
+ // Return:
+ // CF set on error
+ // if AH = 11h (corrected ECC error), AL = burst length
+ // CF clear if successful
+ // AH = status
+ // AL = number of sectors transferred
+ // (only valid if CF set for some BIOSes)
+ RegsIn.b.ah = 0x02;
+ RegsIn.b.al = (UCHAR)NumberOfSectorsToRead;
+ RegsIn.b.ch = (PhysicalTrack & 0xFF);
+ RegsIn.b.cl = (UCHAR)(PhysicalSector + ((PhysicalTrack & 0x300) >> 2));
+ RegsIn.b.dh = PhysicalHead;
+ RegsIn.b.dl = DriveNumber;
+ RegsIn.w.es = (USHORT)(((ULONG_PTR)Buffer) >> 4);
+ RegsIn.w.bx = ((ULONG_PTR)Buffer) & 0x0F;
+
+ //
+ // Perform the read
+ // Retry 3 times
+ //
+ for (RetryCount=0; RetryCount<3; RetryCount++)
+ {
+ Int386(0x13, &RegsIn, &RegsOut);
+
+ // If it worked break out
+ if (INT386_SUCCESS(RegsOut))
+ {
+ break;
+ }
+ // If it was a corrected ECC error then the data is still good
+ else if (RegsOut.b.ah == 0x11)
+ {
+ break;
+ }
+ // If it failed the do the next retry
+ else
+ {
+ PcDiskResetController(DriveNumber);
+
+ continue;
+ }
+ }
+
+ // If we retried 3 times then fail
+ if (RetryCount >= 3)
+ {
+ ERR("Disk Read Failed in CHS mode, after retrying 3 times: %x\n", RegsOut.b.ah);
+ 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
+
+ Buffer = (PVOID)((ULONG_PTR)Buffer + (NumberOfSectorsToRead * DriveGeometry.BytesPerSector));
+ SectorCount -= NumberOfSectorsToRead;
+ SectorNumber += NumberOfSectorsToRead;
+ }
+
+ return TRUE;
}
BOOLEAN PcDiskReadLogicalSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer)
{
- BOOLEAN ExtensionsSupported;
-
- 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);
-
- if ((DriveNumber >= 0x80) && ExtensionsSupported)
- {
- TRACE("Using Int 13 Extensions for read. DiskInt13ExtensionsSupported(%d) = %s\n", DriveNumber, ExtensionsSupported ? "TRUE" : "FALSE");
-
- //
- // LBA is easy, nothing to calculate
- // Just do the read
- //
- return PcDiskReadLogicalSectorsLBA(DriveNumber, SectorNumber, SectorCount, Buffer);
- }
- else
- {
- // LBA is not supported default to the CHS calls
- return PcDiskReadLogicalSectorsCHS(DriveNumber, SectorNumber, SectorCount, Buffer);
- }
-
- return TRUE;
+ BOOLEAN ExtensionsSupported;
+
+ 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);
+
+ if ((DriveNumber >= 0x80) && ExtensionsSupported)
+ {
+ TRACE("Using Int 13 Extensions for read. DiskInt13ExtensionsSupported(%d) = %s\n", DriveNumber, ExtensionsSupported ? "TRUE" : "FALSE");
+
+ //
+ // LBA is easy, nothing to calculate
+ // Just do the read
+ //
+ return PcDiskReadLogicalSectorsLBA(DriveNumber, SectorNumber, SectorCount, Buffer);
+ }
+ else
+ {
+ // LBA is not supported default to the CHS calls
+ return PcDiskReadLogicalSectorsCHS(DriveNumber, SectorNumber, SectorCount, Buffer);
+ }
+
+ return TRUE;
}
BOOLEAN
ULONG
PcDiskGetCacheableBlockCount(UCHAR DriveNumber)
{
- GEOMETRY Geometry;
+ 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 */