Skip to content

Commit

Permalink
[FREELDR] Change GEOMETRY "Sectors" to "SectorsPerTrack" and introduc…
Browse files Browse the repository at this point in the history
…e a new "Sectors" field (reactos#7379)

"SectorsPerTrack" is for the legacy Cylinders/Heads/Sectors(PerTrack)
scheme.

- On BIOS-based PCs, INT 13h can return (for LBA-only drives) an invalid
  geometry, like: C/H/S = (-1)/(-1)/(-1). This is also what happens in
  our hwide.c driver (see IdentifyDevice() for ATAPI devices):
https://github.com/reactos/reactos/blob/db419efbf26c78e39fb57bcaf4f9e4d915d0c96e/boot/freeldr/freeldr/arch/drivers/hwide.c#L918-L928

  as well as on VirtualBox for CD-ROMs:
https://www.virtualbox.org/browser/vbox/trunk/src/VBox/Devices/PC/BIOS/disk.c#L155

- Therefore, we cannot reliably calculate a valid total number of sectors
  by multiplying the Cylinders*Heads*SectorsPerTrack values. In addition,
  such a multiplication could overflow a 32-bit ULONG.
  Thus, a separate ULONGLONG Sectors member is required to hold such a
  value, that is retrieved differently. For example for ATAPI devices,
  our hwide.c driver does return a valid TotalSectors value, even though
  CHS values are invalid. Other platforms, like UEFI, just work using
  logical block addressing (LBA) values (see EFI_BLOCK_IO_MEDIA).

- uefidisk.c : Per the spec, EFI_BLOCK_IO_MEDIA::LastBlock contains
  "The last LBA on the device. [...] For ATA devices, this is reported
  in IDENTIFY DEVICE data words 60-61 (i.e., Total number of user
  addressable logical sectors) _minus one_.
  For SCSI devices, this is reported in the READ CAPACITY parameter
  data 'Returned Logical Block Address field' _minus one_."
  In other words, LastBlock is a zero-based LBA index quantity. The
  corresponding total number of valid "sectors"/blocks of the device
  is therefore, (LastBlock + 1).

- Cleanup some old disabled code.
  • Loading branch information
HBelusca authored and binarymaster committed Sep 29, 2024
1 parent 0c8c843 commit fe9f837
Show file tree
Hide file tree
Showing 11 changed files with 92 additions and 103 deletions.
2 changes: 1 addition & 1 deletion boot/freeldr/freeldr/arch/i386/hwdisk.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ DiskOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
}

SectorOffset = 0;
SectorCount = (ULONGLONG)Geometry.Cylinders * Geometry.Heads * Geometry.Sectors;
SectorCount = Geometry.Sectors;
}

Context = FrLdrTempAlloc(sizeof(DISKCONTEXT), TAG_HW_DISK_CONTEXT);
Expand Down
22 changes: 3 additions & 19 deletions boot/freeldr/freeldr/arch/i386/pc/machpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,10 @@ PcGetHarddiskConfigurationData(UCHAR DriveNumber, ULONG* pSize)
{
PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry;
// EXTENDED_GEOMETRY ExtGeometry;
GEOMETRY Geometry;
ULONG Size;

//
// Initialize returned size
//
/* Initialize returned size */
*pSize = 0;

/* Set 'Configuration Data' value */
Expand Down Expand Up @@ -155,22 +152,11 @@ 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))
{
DiskGeometry->BytesPerSector = ExtGeometry.BytesPerSector;
DiskGeometry->NumberOfCylinders = ExtGeometry.Cylinders;
DiskGeometry->SectorsPerTrack = ExtGeometry.SectorsPerTrack;
DiskGeometry->NumberOfHeads = ExtGeometry.Heads;
}
else
#endif
if (PcDiskGetDriveGeometry(DriveNumber, &Geometry))
{
DiskGeometry->BytesPerSector = Geometry.BytesPerSector;
DiskGeometry->NumberOfCylinders = Geometry.Cylinders;
DiskGeometry->SectorsPerTrack = Geometry.Sectors;
DiskGeometry->SectorsPerTrack = Geometry.SectorsPerTrack;
DiskGeometry->NumberOfHeads = Geometry.Heads;
}
else
Expand All @@ -186,9 +172,7 @@ PcGetHarddiskConfigurationData(UCHAR DriveNumber, ULONG* pSize)
DiskGeometry->SectorsPerTrack,
DiskGeometry->BytesPerSector);

//
// Return configuration data
//
/* Return configuration data */
*pSize = Size;
return PartialResourceList;
}
Expand Down
40 changes: 20 additions & 20 deletions boot/freeldr/freeldr/arch/i386/pc/pcdisk.c
Original file line number Diff line number Diff line change
Expand Up @@ -443,8 +443,12 @@ InitDriveGeometry(
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 */
DiskDrive->Geometry.SectorsPerTrack = RegsOut.b.cl & 0x3F;
DiskDrive->Geometry.BytesPerSector = 512; /* Just assume 512 bytes per sector */

DiskDrive->Geometry.Sectors = (ULONGLONG)DiskDrive->Geometry.Cylinders *
DiskDrive->Geometry.Heads *
DiskDrive->Geometry.SectorsPerTrack;

TRACE("Regular Int13h(0x%x) returned:\n"
"Cylinders : 0x%x\n"
Expand All @@ -454,7 +458,7 @@ InitDriveGeometry(
DriveNumber,
DiskDrive->Geometry.Cylinders,
DiskDrive->Geometry.Heads,
DiskDrive->Geometry.Sectors, RegsOut.b.cl,
DiskDrive->Geometry.SectorsPerTrack, RegsOut.b.cl,
DiskDrive->Geometry.BytesPerSector);

return Success;
Expand Down Expand Up @@ -645,40 +649,35 @@ PcDiskReadLogicalSectorsCHS(
ULONG RetryCount;

DriveGeometry = DiskDrive->Geometry;
if (DriveGeometry.Sectors == 0 || DriveGeometry.Heads == 0)
if (DriveGeometry.SectorsPerTrack == 0 || DriveGeometry.Heads == 0)
return FALSE;

while (SectorCount > 0)
{
/*
* Calculate the physical disk offsets.
* Note: DriveGeometry.Sectors < 64
* Note: DriveGeometry.SectorsPerTrack < 64
*/
PhysicalSector = 1 + (UCHAR)(SectorNumber % DriveGeometry.Sectors);
PhysicalHead = (UCHAR)((SectorNumber / DriveGeometry.Sectors) % DriveGeometry.Heads);
PhysicalTrack = (ULONG)((SectorNumber / DriveGeometry.Sectors) / DriveGeometry.Heads);
PhysicalSector = 1 + (UCHAR)(SectorNumber % DriveGeometry.SectorsPerTrack);
PhysicalHead = (UCHAR)((SectorNumber / DriveGeometry.SectorsPerTrack) % DriveGeometry.Heads);
PhysicalTrack = (ULONG)((SectorNumber / DriveGeometry.SectorsPerTrack) / 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;
NumberOfSectorsToRead = min(SectorCount,
(DriveGeometry.SectorsPerTrack - (PhysicalSector - 1)));
}
else
{
if (SectorCount >= DriveGeometry.Sectors)
NumberOfSectorsToRead = DriveGeometry.Sectors;
else
NumberOfSectorsToRead = SectorCount;
NumberOfSectorsToRead = min(SectorCount, DriveGeometry.SectorsPerTrack);
}

/* Make sure the read is within the geometry boundaries */
if ((PhysicalHead >= DriveGeometry.Heads) ||
(PhysicalTrack >= DriveGeometry.Cylinders) ||
((NumberOfSectorsToRead + PhysicalSector) > (DriveGeometry.Sectors + 1)) ||
(PhysicalSector > DriveGeometry.Sectors))
((NumberOfSectorsToRead + PhysicalSector) > (DriveGeometry.SectorsPerTrack + 1)) ||
(PhysicalSector > DriveGeometry.SectorsPerTrack))
{
DiskError("Disk read exceeds drive geometry limits.", 0);
return FALSE;
Expand Down Expand Up @@ -817,8 +816,9 @@ PcDiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry)
/* Extended geometry has been initialized, return it */
Geometry->Cylinders = DiskDrive->ExtGeometry.Cylinders;
Geometry->Heads = DiskDrive->ExtGeometry.Heads;
Geometry->Sectors = DiskDrive->ExtGeometry.SectorsPerTrack;
Geometry->SectorsPerTrack = DiskDrive->ExtGeometry.SectorsPerTrack;
Geometry->BytesPerSector = DiskDrive->ExtGeometry.BytesPerSector;
Geometry->Sectors = DiskDrive->ExtGeometry.Sectors;
}
else
/* Fall back to legacy BIOS geometry */
Expand All @@ -845,7 +845,7 @@ PcDiskGetCacheableBlockCount(UCHAR DriveNumber)
if (DiskDrive->Int13ExtensionsSupported)
return 64;
else
return DiskDrive->Geometry.Sectors;
return DiskDrive->Geometry.SectorsPerTrack;
}

/* EOF */
4 changes: 2 additions & 2 deletions boot/freeldr/freeldr/arch/i386/pc/pchw.c
Original file line number Diff line number Diff line change
Expand Up @@ -394,15 +394,15 @@ DetectBiosDisks(PCONFIGURATION_COMPONENT_DATA SystemKey,
{
Int13Drives[i].DriveSelect = DriveNumber;
Int13Drives[i].MaxCylinders = Geometry.Cylinders - 1;
Int13Drives[i].SectorsPerTrack = (USHORT)Geometry.Sectors;
Int13Drives[i].SectorsPerTrack = (USHORT)Geometry.SectorsPerTrack;
Int13Drives[i].MaxHeads = (USHORT)Geometry.Heads - 1;
Int13Drives[i].NumberDrives = DiskCount;

TRACE("Disk %x: %u Cylinders %u Heads %u Sectors %u Bytes\n",
DriveNumber,
Geometry.Cylinders - 1,
Geometry.Heads - 1,
Geometry.Sectors,
Geometry.SectorsPerTrack,
Geometry.BytesPerSector);
}
}
Expand Down
70 changes: 40 additions & 30 deletions boot/freeldr/freeldr/arch/i386/pc98/pc98disk.c
Original file line number Diff line number Diff line change
Expand Up @@ -268,11 +268,11 @@ Pc98DiskReadLogicalSectorsCHS(
{
/*
* Calculate the physical disk offsets.
* Note: DriveGeometry.Sectors < 64
* Note: DriveGeometry.SectorsPerTrack < 64
*/
PhysicalSector = (UCHAR)(SectorNumber % DriveGeometry.Sectors);
PhysicalHead = (UCHAR)((SectorNumber / DriveGeometry.Sectors) % DriveGeometry.Heads);
PhysicalTrack = (ULONG)((SectorNumber / DriveGeometry.Sectors) / DriveGeometry.Heads);
PhysicalSector = (UCHAR)(SectorNumber % DriveGeometry.SectorsPerTrack);
PhysicalHead = (UCHAR)((SectorNumber / DriveGeometry.SectorsPerTrack) % DriveGeometry.Heads);
PhysicalTrack = (ULONG)((SectorNumber / DriveGeometry.SectorsPerTrack) / DriveGeometry.Heads);

/* Floppy sectors value always start at 1 */
if (DiskDrive->Type & DRIVE_FDD)
Expand All @@ -281,24 +281,19 @@ Pc98DiskReadLogicalSectorsCHS(
/* 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;
NumberOfSectorsToRead = min(SectorCount,
(DriveGeometry.SectorsPerTrack - (PhysicalSector - 1)));
}
else
{
if (SectorCount >= DriveGeometry.Sectors)
NumberOfSectorsToRead = DriveGeometry.Sectors;
else
NumberOfSectorsToRead = SectorCount;
NumberOfSectorsToRead = min(SectorCount, DriveGeometry.SectorsPerTrack);
}

/* Make sure the read is within the geometry boundaries */
if ((PhysicalHead >= DriveGeometry.Heads) ||
(PhysicalTrack >= DriveGeometry.Cylinders) ||
((NumberOfSectorsToRead + PhysicalSector) > (DriveGeometry.Sectors + 1)) ||
(PhysicalSector > DriveGeometry.Sectors))
((NumberOfSectorsToRead + PhysicalSector) > (DriveGeometry.SectorsPerTrack + 1)) ||
(PhysicalSector > DriveGeometry.SectorsPerTrack))
{
DiskError("Disk read exceeds drive geometry limits.", 0);
return FALSE;
Expand Down Expand Up @@ -439,7 +434,7 @@ InitScsiDrive(

DiskDrive->Geometry.Cylinders = RegsOut.w.cx;
DiskDrive->Geometry.Heads = RegsOut.b.dh;
DiskDrive->Geometry.Sectors = RegsOut.b.dl;
DiskDrive->Geometry.SectorsPerTrack = RegsOut.b.dl;
DiskDrive->Geometry.BytesPerSector = RegsOut.w.bx;
DiskDrive->LBASupported = FALSE;
DiskDrive->IsRemovable = FALSE;
Expand All @@ -454,7 +449,7 @@ InitScsiDrive(
/* CD-ROM */
DiskDrive->Geometry.Cylinders = 0xFFFF;
DiskDrive->Geometry.Heads = 0xFFFF;
DiskDrive->Geometry.Sectors = 0xFFFF;
DiskDrive->Geometry.SectorsPerTrack = 0xFFFF;
DiskDrive->Geometry.BytesPerSector = 2048;
DiskDrive->Type = DRIVE_CDROM;
DiskDrive->LBASupported = TRUE;
Expand All @@ -465,7 +460,7 @@ InitScsiDrive(
/* Magneto-optical drive */
DiskDrive->Geometry.Cylinders = 0xFFFF;
DiskDrive->Geometry.Heads = 8;
DiskDrive->Geometry.Sectors = 32;
DiskDrive->Geometry.SectorsPerTrack = 32;
DiskDrive->Geometry.BytesPerSector = 512;
DiskDrive->Type = DRIVE_MO;
DiskDrive->LBASupported = TRUE;
Expand All @@ -483,6 +478,10 @@ InitScsiDrive(
return FALSE;
}

DiskDrive->Geometry.Sectors = (ULONGLONG)DiskDrive->Geometry.Cylinders *
DiskDrive->Geometry.Heads *
DiskDrive->Geometry.SectorsPerTrack;

DiskDrive->DaUa = DaUa;
DiskDrive->Type |= DRIVE_SCSI;
DiskDrive->Initialized = TRUE;
Expand All @@ -495,7 +494,7 @@ InitScsiDrive(
DaUa,
DiskDrive->Geometry.Cylinders,
DiskDrive->Geometry.Heads,
DiskDrive->Geometry.Sectors,
DiskDrive->Geometry.SectorsPerTrack,
DiskDrive->Geometry.BytesPerSector);

return TRUE;
Expand All @@ -513,8 +512,10 @@ InitIdeDrive(
{
DiskDrive->Geometry.Cylinders = DeviceUnit->Cylinders;
DiskDrive->Geometry.Heads = DeviceUnit->Heads;
DiskDrive->Geometry.Sectors = DeviceUnit->Sectors;
DiskDrive->Geometry.SectorsPerTrack = DeviceUnit->Sectors;
DiskDrive->Geometry.BytesPerSector = DeviceUnit->SectorSize;
DiskDrive->Geometry.Sectors = DeviceUnit->TotalSectors;

DiskDrive->DaUa = 0xFF;
DiskDrive->IdeUnitNumber = UnitNumber;
DiskDrive->Type = DRIVE_IDE | DRIVE_CDROM;
Expand All @@ -530,7 +531,7 @@ InitIdeDrive(
UnitNumber,
DiskDrive->Geometry.Cylinders,
DiskDrive->Geometry.Heads,
DiskDrive->Geometry.Sectors,
DiskDrive->Geometry.SectorsPerTrack,
DiskDrive->Geometry.BytesPerSector);

return TRUE;
Expand Down Expand Up @@ -582,8 +583,13 @@ InitHardDrive(

DiskDrive->Geometry.Cylinders = RegsOut.w.cx;
DiskDrive->Geometry.Heads = RegsOut.b.dh;
DiskDrive->Geometry.Sectors = RegsOut.b.dl;
DiskDrive->Geometry.SectorsPerTrack = RegsOut.b.dl;
DiskDrive->Geometry.BytesPerSector = RegsOut.w.bx;

DiskDrive->Geometry.Sectors = (ULONGLONG)DiskDrive->Geometry.Cylinders *
DiskDrive->Geometry.Heads *
DiskDrive->Geometry.SectorsPerTrack;

DiskDrive->DaUa = DaUa;
DiskDrive->Type = DRIVE_IDE;
DiskDrive->LBASupported = FALSE;
Expand All @@ -598,7 +604,7 @@ InitHardDrive(
DaUa,
DiskDrive->Geometry.Cylinders,
DiskDrive->Geometry.Heads,
DiskDrive->Geometry.Sectors,
DiskDrive->Geometry.SectorsPerTrack,
DiskDrive->Geometry.BytesPerSector);

return TRUE;
Expand Down Expand Up @@ -647,14 +653,14 @@ InitFloppyDrive(
/* 320 kB 2DD */
DiskDrive->Geometry.Cylinders = 80;
DiskDrive->Geometry.Heads = 2;
DiskDrive->Geometry.Sectors = 16;
DiskDrive->Geometry.SectorsPerTrack = 16;
}
else
{
/* 1 MB 2HD */
DiskDrive->Geometry.Cylinders = 77;
DiskDrive->Geometry.Heads = 2;
DiskDrive->Geometry.Sectors = 26;
DiskDrive->Geometry.SectorsPerTrack = 26;
}
break;

Expand All @@ -664,29 +670,29 @@ InitFloppyDrive(
/* 1.44 MB 2HD */
DiskDrive->Geometry.Cylinders = 80;
DiskDrive->Geometry.Heads = 2;
DiskDrive->Geometry.Sectors = 18;
DiskDrive->Geometry.SectorsPerTrack = 18;
}
else if (DeviceAddress == 0x70 || DeviceAddress == 0xF0)
{
/* 720/640 kB 2DD */
DiskDrive->Geometry.Cylinders = 80;
DiskDrive->Geometry.Heads = 2;
DiskDrive->Geometry.Sectors = 8;
DiskDrive->Geometry.SectorsPerTrack = 8;
}
else
{
/* 1.2 MB 2HC */
DiskDrive->Geometry.Cylinders = 80;
DiskDrive->Geometry.Heads = 2;
DiskDrive->Geometry.Sectors = 15;
DiskDrive->Geometry.SectorsPerTrack = 15;
}
break;

case 1024:
/* 1.25 MB 2HD */
DiskDrive->Geometry.Cylinders = 77;
DiskDrive->Geometry.Heads = 2;
DiskDrive->Geometry.Sectors = 8;
DiskDrive->Geometry.SectorsPerTrack = 8;
break;

default:
Expand All @@ -695,6 +701,10 @@ InitFloppyDrive(
}

DiskDrive->Geometry.BytesPerSector = BytesPerSector;
DiskDrive->Geometry.Sectors = (ULONGLONG)DiskDrive->Geometry.Cylinders *
DiskDrive->Geometry.Heads *
DiskDrive->Geometry.SectorsPerTrack;

DiskDrive->DaUa = DaUa;
DiskDrive->Type = DRIVE_FDD;
DiskDrive->LBASupported = FALSE;
Expand All @@ -709,7 +719,7 @@ InitFloppyDrive(
DaUa,
DiskDrive->Geometry.Cylinders,
DiskDrive->Geometry.Heads,
DiskDrive->Geometry.Sectors,
DiskDrive->Geometry.SectorsPerTrack,
DiskDrive->Geometry.BytesPerSector);

return TRUE;
Expand Down Expand Up @@ -898,5 +908,5 @@ Pc98DiskGetCacheableBlockCount(UCHAR DriveNumber)
if (DiskDrive->LBASupported)
return 64;
else
return DiskDrive->Geometry.Sectors;
return DiskDrive->Geometry.SectorsPerTrack;
}
Loading

0 comments on commit fe9f837

Please sign in to comment.