Skip to content

Commit 840d39b

Browse files
committed
[FREELDR] i386/pc/pcdisk.c: Fix LBA reads retry loop (reactos#7367)
When the Int 13h AH=42h "Extended read" function fails, the disk address packet's LBA block count is reset to the number of blocks that have been successfully transferred. This is more or less fine, unless one wants to ensure the exact number of sectors gets read. If the function fails so that zero sectors were read, the retry loop is restarted, but with the packet's LBA block count member reset, as per the documentation. (In this example, it is reset to zero.) Then, at the next retry attempt, zero sectors are requested to be read, and this time of course, the call succeeds... Wrongly, of course, this is not what's expected. Therefore, for each retry, the LBA block count member should be set again to the correct number of sectors to read. There are maximum 3 retries, so the retry loop will stop anyway, but the LBA read will now correctly fail and return FALSE, as expected. This problem doesn't exist in the retry loop for the Int 13h, AH=02h "Read Disk Sectors" CHS function, because here, the call is made only using registers, and we use a pair of RegsIn/RegsOut. RegsOut receives the modified register values, but the input RegsIn stays unchanged.
1 parent 4190b48 commit 840d39b

File tree

1 file changed

+9
-4
lines changed
  • boot/freeldr/freeldr/arch/i386/pc

1 file changed

+9
-4
lines changed

boot/freeldr/freeldr/arch/i386/pc/pcdisk.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -570,14 +570,13 @@ PcDiskReadLogicalSectorsLBA(
570570
RtlZeroMemory(Packet, sizeof(*Packet));
571571
Packet->PacketSize = sizeof(*Packet);
572572
Packet->Reserved = 0;
573-
Packet->LBABlockCount = (USHORT)SectorCount;
574-
ASSERT(Packet->LBABlockCount == SectorCount);
573+
// Packet->LBABlockCount set in the loop.
575574
Packet->TransferBufferOffset = ((ULONG_PTR)Buffer) & 0x0F;
576575
Packet->TransferBufferSegment = (USHORT)(((ULONG_PTR)Buffer) >> 4);
577576
Packet->LBAStartBlock = SectorNumber;
578577

579578
/*
580-
* BIOS int 0x13, function 42h - IBM/MS INT 13 Extensions - EXTENDED READ
579+
* BIOS Int 13h, function 42h - IBM/MS INT 13 Extensions - EXTENDED READ
581580
* Return:
582581
* CF clear if successful
583582
* AH = 00h
@@ -586,14 +585,20 @@ PcDiskReadLogicalSectorsLBA(
586585
* Disk address packet's block count field set to the
587586
* number of blocks successfully transferred.
588587
*/
589-
RegsIn.b.ah = 0x42; // Subfunction 42h
588+
RegsIn.b.ah = 0x42;
590589
RegsIn.b.dl = DriveNumber; // Drive number in DL (0 - floppy, 0x80 - harddisk)
591590
RegsIn.x.ds = BIOSCALLBUFSEGMENT; // DS:SI -> disk address packet
592591
RegsIn.w.si = BIOSCALLBUFOFFSET;
593592

594593
/* Retry 3 times */
595594
for (RetryCount = 0; RetryCount < 3; ++RetryCount)
596595
{
596+
/* Restore the number of blocks to transfer, since it gets reset
597+
* on failure with the number of blocks that were successfully
598+
* transferred (and which could be zero). */
599+
Packet->LBABlockCount = (USHORT)SectorCount;
600+
ASSERT(Packet->LBABlockCount == SectorCount);
601+
597602
Int386(0x13, &RegsIn, &RegsOut);
598603

599604
/* If it worked return TRUE */

0 commit comments

Comments
 (0)