[FREELDR:PC98] Refactor PC-98 disk access routines (#8546)

- Fix incorrect IDE controller ownership leading to strange and inconsistent behavior during boot.
- Fix a mismatch between the type and flags of the drive.
- Remove obsolete definitions.
- Use SAL2 annotations.

CORE-17977
This commit is contained in:
Dmitry Borisov
2026-03-09 19:04:35 +06:00
committed by GitHub
parent 5a147d292d
commit 1cec553ed1
3 changed files with 253 additions and 332 deletions

View File

@@ -40,7 +40,8 @@ Pc98PrepareForReactOS(VOID)
}
ULONG
Pc98GetBootSectorLoadAddress(IN UCHAR DriveNumber)
Pc98GetBootSectorLoadAddress(
_In_ UCHAR DriveNumber)
{
PPC98_DISK_DRIVE DiskDrive;
@@ -57,7 +58,7 @@ Pc98GetBootSectorLoadAddress(IN UCHAR DriveNumber)
/* 1.44 MB floppy */
return 0x1FE00;
}
else if (DiskDrive->Type & DRIVE_FDD)
else if (DiskDrive->Type == DRIVE_TYPE_FDD)
{
return 0x1FC00;
}

View File

@@ -19,14 +19,15 @@ DBG_DEFAULT_CHANNEL(DISK);
#define MAX_DRIVES 0x100
/* Cache of all possible PC disk drives */
PC98_DISK_DRIVE Pc98DiskDrive[MAX_DRIVES];
static PC98_DISK_DRIVE Pc98DiskDrive[MAX_DRIVES];
/* DISK IO ERROR SUPPORT ******************************************************/
static LONG lReportError = 0; /* >= 0: display errors; < 0: hide errors */
LONG
DiskReportError(BOOLEAN bShowError)
DiskReportError(
_In_ BOOLEAN bShowError)
{
/* Set the reference count */
if (bShowError)
@@ -36,8 +37,10 @@ DiskReportError(BOOLEAN bShowError)
return lReportError;
}
static PCSTR
DiskGetErrorCodeString(ULONG ErrorCode)
static
PCSTR
DiskGetErrorCodeString(
_In_ ULONG ErrorCode)
{
switch (ErrorCode & 0xF0)
{
@@ -70,16 +73,23 @@ DiskGetErrorCodeString(ULONG ErrorCode)
}
}
static VOID
DiskError(PCSTR ErrorString, ULONG ErrorCode)
static
VOID
DiskError(
_In_ PCSTR ErrorString,
_In_ ULONG ErrorCode)
{
CHAR ErrorCodeString[200];
if (lReportError < 0)
return;
RtlStringCbPrintfA(ErrorCodeString, sizeof(ErrorCodeString), "%s\n\nError Code: 0x%lx\nError: %s",
ErrorString, ErrorCode, DiskGetErrorCodeString(ErrorCode));
RtlStringCbPrintfA(ErrorCodeString,
sizeof(ErrorCodeString),
"%s\n\nError Code: 0x%lx\nError: %s",
ErrorString,
ErrorCode,
DiskGetErrorCodeString(ErrorCode));
ERR("%s\n", ErrorCodeString);
@@ -88,11 +98,14 @@ DiskError(PCSTR ErrorString, ULONG ErrorCode)
/* FUNCTIONS ******************************************************************/
BOOLEAN DiskResetController(IN PPC98_DISK_DRIVE DiskDrive)
static
BOOLEAN
DiskResetController(
_In_ PPC98_DISK_DRIVE DiskDrive)
{
REGS Regs;
if (DiskDrive->Type & DRIVE_FDD)
if (DiskDrive->Type == DRIVE_TYPE_FDD)
{
/* Int 1Bh AH=07h
* DISK BIOS - Recalibrate
@@ -106,7 +119,7 @@ BOOLEAN DiskResetController(IN PPC98_DISK_DRIVE DiskDrive)
*/
Regs.b.ah = 0x07;
}
else if (DiskDrive->Type != (DRIVE_IDE | DRIVE_CDROM))
else if (DiskDrive->Type == DRIVE_TYPE_HDD)
{
/* Int 1Bh AH=03h
* DISK BIOS - Initialize
@@ -125,7 +138,8 @@ BOOLEAN DiskResetController(IN PPC98_DISK_DRIVE DiskDrive)
return FALSE;
}
WARN("DiskResetController(0x%x) DISK OPERATION FAILED -- RESETTING CONTROLLER\n", DiskDrive->DaUa);
WARN("DiskResetController(0x%x) DISK OPERATION FAILED -- RESETTING CONTROLLER\n",
DiskDrive->DaUa);
Regs.b.al = DiskDrive->DaUa;
Int386(0x1B, &Regs, &Regs);
@@ -133,17 +147,18 @@ BOOLEAN DiskResetController(IN PPC98_DISK_DRIVE DiskDrive)
}
PPC98_DISK_DRIVE
Pc98DiskDriveNumberToDrive(IN UCHAR DriveNumber)
Pc98DiskDriveNumberToDrive(
_In_ UCHAR DriveNumber)
{
PPC98_DISK_DRIVE DiskDrive;
ASSERT((0 <= DriveNumber) && (DriveNumber < RTL_NUMBER_OF(Pc98DiskDrive)));
ASSERT(DriveNumber < RTL_NUMBER_OF(Pc98DiskDrive));
/* Retrieve a slot */
DiskDrive = &Pc98DiskDrive[DriveNumber];
/* The pre-initialization of the BIOS disks was already done in Pc98InitializeBootDevices() */
if (DiskDrive->Initialized)
if (DiskDrive->Flags & DRIVE_FLAGS_INITIALIZED)
return DiskDrive;
else
return NULL;
@@ -159,17 +174,18 @@ DiskGetConfigType(
if (!DiskDrive)
return -1; // MaximumType;
if (DiskDrive->Type & DRIVE_CDROM || DiskDrive->Type & DRIVE_MO)
if (DiskDrive->Type == DRIVE_TYPE_CDROM)
return CdromController;
else if (DiskDrive->Type & DRIVE_FDD)
else if (DiskDrive->Type == DRIVE_TYPE_FDD)
return FloppyDiskPeripheral;
else
return DiskPeripheral;
}
static inline
static
UCHAR
BytesPerSectorToSectorLengthCode(IN ULONG BytesPerSector)
BytesPerSectorToSectorLengthCode(
_In_ ULONG BytesPerSector)
{
switch (BytesPerSector)
{
@@ -188,58 +204,52 @@ BytesPerSectorToSectorLengthCode(IN ULONG BytesPerSector)
}
}
static BOOLEAN
static
BOOLEAN
Pc98DiskReadLogicalSectorsLBA(
IN PPC98_DISK_DRIVE DiskDrive,
IN ULONGLONG SectorNumber,
IN ULONG SectorCount,
OUT PVOID Buffer)
_In_ PPC98_DISK_DRIVE DiskDrive,
_In_ ULONG64 SectorNumber,
_In_ ULONG SectorCount,
_Out_writes_bytes_all_(SectorCount * DiskDrive->Geometry.BytesPerSector) PVOID Buffer)
{
REGS RegsIn, RegsOut;
ULONG RetryCount;
if (DiskDrive->Type & DRIVE_IDE && DiskDrive->Type & DRIVE_CDROM)
/* Int 1Bh AH=06h
* DISK BIOS - Read data
*
* Call with:
* AL - drive number
* BX - bytes to read
* CX - cylinder number
* DH - head number
* DL - sector number
* ES:BP -> buffer to read data into
*
* Return:
* CF - set on error, clear if successful
* AH - status
*/
RegsIn.b.al = DiskDrive->DaUa;
RegsIn.b.ah = 0x06;
RegsIn.w.bx = DiskDrive->Geometry.BytesPerSector * SectorCount;
RegsIn.w.cx = SectorNumber & 0xFFFF;
RegsIn.w.dx = (SectorNumber >> 16) & 0xFFFF;
RegsIn.w.es = (USHORT)(((ULONG_PTR)Buffer) >> 4);
RegsIn.w.bp = ((ULONG_PTR)Buffer) & 0x0F;
/* Retry 3 times */
for (RetryCount = 0; RetryCount < 3; ++RetryCount)
{
return AtaReadLogicalSectors(AtaGetDevice(DiskDrive->IdeUnitNumber), SectorNumber, SectorCount, Buffer);
}
else
{
/* Int 1Bh AH=06h
* DISK BIOS - Read data
*
* Call with:
* AL - drive number
* BX - bytes to read
* CX - cylinder number
* DH - head number
* DL - sector number
* ES:BP -> buffer to read data into
*
* Return:
* CF - set on error, clear if successful
* AH - status
*/
RegsIn.b.al = DiskDrive->DaUa;
RegsIn.b.ah = 0x06;
RegsIn.w.bx = DiskDrive->Geometry.BytesPerSector * SectorCount;
RegsIn.w.cx = SectorNumber & 0xFFFF;
RegsIn.w.dx = (SectorNumber >> 16) & 0xFFFF;
RegsIn.w.es = (USHORT)(((ULONG_PTR)Buffer) >> 4);
RegsIn.w.bp = ((ULONG_PTR)Buffer) & 0x0F;
Int386(0x1B, &RegsIn, &RegsOut);
/* Retry 3 times */
for (RetryCount = 0; RetryCount < 3; ++RetryCount)
{
Int386(0x1B, &RegsIn, &RegsOut);
/* If it worked, or if it was a corrected ECC error
* and the data is still good, return success */
if (INT386_SUCCESS(RegsOut) || (RegsOut.b.ah == 0x08))
return TRUE;
/* If it worked, or if it was a corrected ECC error
* and the data is still good, return success */
if (INT386_SUCCESS(RegsOut) || (RegsOut.b.ah == 0x08))
return TRUE;
/* It failed, do the next retry */
DiskResetController(DiskDrive);
}
/* It failed, do the next retry */
DiskResetController(DiskDrive);
}
/* If we get here then the read failed */
@@ -251,12 +261,13 @@ Pc98DiskReadLogicalSectorsLBA(
return FALSE;
}
static BOOLEAN
static
BOOLEAN
Pc98DiskReadLogicalSectorsCHS(
IN PPC98_DISK_DRIVE DiskDrive,
IN ULONGLONG SectorNumber,
IN ULONG SectorCount,
OUT PVOID Buffer)
_In_ PPC98_DISK_DRIVE DiskDrive,
_In_ ULONG64 SectorNumber,
_In_ ULONG SectorCount,
_Out_writes_bytes_all_(SectorCount * DiskDrive->Geometry.BytesPerSector) PVOID Buffer)
{
UCHAR PhysicalSector;
UCHAR PhysicalHead;
@@ -279,7 +290,7 @@ Pc98DiskReadLogicalSectorsCHS(
PhysicalTrack = (ULONG)((SectorNumber / DriveGeometry.SectorsPerTrack) / DriveGeometry.Heads);
/* Floppy sectors value always start at 1 */
if (DiskDrive->Type & DRIVE_FDD)
if (DiskDrive->Type == DRIVE_TYPE_FDD)
++PhysicalSector;
/* Calculate how many sectors we need to read this round */
@@ -303,7 +314,7 @@ Pc98DiskReadLogicalSectorsCHS(
return FALSE;
}
if (DiskDrive->Type & DRIVE_FDD)
if (DiskDrive->Type == DRIVE_TYPE_FDD)
{
/* Int 1Bh AH=x6h
* DISK BIOS - Read data
@@ -321,15 +332,10 @@ Pc98DiskReadLogicalSectorsCHS(
* CF - set on error, clear if successful
* AH - status
*/
RegsIn.b.al = DiskDrive->DaUa;
RegsIn.b.ah = 0x56; /* With SEEK, and use double-density format (MFM) */
RegsIn.w.bx = DriveGeometry.BytesPerSector * (UCHAR)NumberOfSectorsToRead;
RegsIn.b.cl = PhysicalTrack & 0xFFFF;
RegsIn.b.ch = BytesPerSectorToSectorLengthCode(DriveGeometry.BytesPerSector);
RegsIn.b.dl = PhysicalSector;
RegsIn.b.dh = PhysicalHead;
RegsIn.w.es = (USHORT)(((ULONG_PTR)Buffer) >> 4);
RegsIn.w.bp = ((ULONG_PTR)Buffer) & 0x0F;
}
else
{
@@ -348,15 +354,15 @@ Pc98DiskReadLogicalSectorsCHS(
* CF - set on error, clear if successful
* AH - status
*/
RegsIn.b.al = DiskDrive->DaUa;
RegsIn.b.ah = 0x06;
RegsIn.w.bx = DriveGeometry.BytesPerSector * (UCHAR)NumberOfSectorsToRead;
RegsIn.w.cx = PhysicalTrack & 0xFFFF;
RegsIn.b.dl = PhysicalSector;
RegsIn.b.dh = PhysicalHead;
RegsIn.w.es = (USHORT)(((ULONG_PTR)Buffer) >> 4);
RegsIn.w.bp = ((ULONG_PTR)Buffer) & 0x0F;
}
RegsIn.b.al = DiskDrive->DaUa;
RegsIn.b.dl = PhysicalSector;
RegsIn.b.dh = PhysicalHead;
RegsIn.w.es = (USHORT)(((ULONG_PTR)Buffer) >> 4);
RegsIn.w.bp = ((ULONG_PTR)Buffer) & 0x0F;
/* Perform the read. Retry 3 times. */
for (RetryCount = 0; RetryCount < 3; ++RetryCount)
@@ -390,16 +396,16 @@ Pc98DiskReadLogicalSectorsCHS(
return TRUE;
}
static BOOLEAN
static
BOOLEAN
InitScsiDrive(
IN UCHAR DaUa,
IN OUT PPC98_DISK_DRIVE DiskDrive)
_Out_ PPC98_DISK_DRIVE DiskDrive,
_In_ UCHAR DaUa)
{
REGS RegsIn, RegsOut;
UCHAR UnitAddress = DaUa & 0x0F;
USHORT DiskEquipment = *(PUCHAR)MEM_DISK_EQUIPS;
ULONG ScsiParameters = *(PULONG)(MEM_SCSI_TABLE + UnitAddress * sizeof(ULONG));
UCHAR DeviceType;
/* Hard drives */
if (DiskEquipment & (1 << UnitAddress))
@@ -422,22 +428,17 @@ InitScsiDrive(
RegsIn.b.ah = 0x84;
Int386(0x1B, &RegsIn, &RegsOut);
if (!INT386_SUCCESS(RegsOut) || RegsOut.w.cx == 0)
{
DiskDrive->Initialized = FALSE;
return FALSE;
}
DiskDrive->Geometry.Cylinders = RegsOut.w.cx;
DiskDrive->Geometry.Heads = RegsOut.b.dh;
DiskDrive->Geometry.SectorsPerTrack = RegsOut.b.dl;
DiskDrive->Geometry.BytesPerSector = RegsOut.w.bx;
DiskDrive->LBASupported = FALSE;
DiskDrive->IsRemovable = FALSE;
}
/* Other devices */
else if (ScsiParameters)
else if (ScsiParameters != 0)
{
DeviceType = ScsiParameters & 0x1F;
UCHAR DeviceType = ScsiParameters & 0x1F;
switch (DeviceType)
{
case 0x05:
@@ -446,9 +447,9 @@ InitScsiDrive(
DiskDrive->Geometry.Heads = 0xFFFF;
DiskDrive->Geometry.SectorsPerTrack = 0xFFFF;
DiskDrive->Geometry.BytesPerSector = 2048;
DiskDrive->Type = DRIVE_CDROM;
DiskDrive->LBASupported = TRUE;
DiskDrive->IsRemovable = TRUE;
DiskDrive->Type = DRIVE_TYPE_CDROM;
DiskDrive->Flags = DRIVE_FLAGS_LBA | DRIVE_FLAGS_REMOVABLE;
break;
case 0x07:
@@ -457,30 +458,27 @@ InitScsiDrive(
DiskDrive->Geometry.Heads = 8;
DiskDrive->Geometry.SectorsPerTrack = 32;
DiskDrive->Geometry.BytesPerSector = 512;
DiskDrive->Type = DRIVE_MO;
DiskDrive->LBASupported = TRUE;
DiskDrive->IsRemovable = TRUE;
DiskDrive->Type = DRIVE_TYPE_CDROM;
DiskDrive->Flags = DRIVE_FLAGS_LBA | DRIVE_FLAGS_REMOVABLE;
break;
default:
DiskDrive->Initialized = FALSE;
return FALSE;
}
}
else
{
DiskDrive->Initialized = FALSE;
return FALSE;
}
DiskDrive->Flags |= DRIVE_FLAGS_INITIALIZED;
DiskDrive->DaUa = DaUa;
DiskDrive->Geometry.Sectors = (ULONGLONG)DiskDrive->Geometry.Cylinders *
DiskDrive->Geometry.Heads *
DiskDrive->Geometry.SectorsPerTrack;
DiskDrive->DaUa = DaUa;
DiskDrive->Type |= DRIVE_SCSI;
DiskDrive->Initialized = TRUE;
TRACE("InitScsiDrive(0x%x) returned:\n"
"Cylinders : 0x%x\n"
"Heads : 0x%x\n"
@@ -497,130 +495,15 @@ InitScsiDrive(
return TRUE;
}
static BOOLEAN
InitIdeDrive(
IN UCHAR UnitNumber,
IN OUT PPC98_DISK_DRIVE DiskDrive)
{
PDEVICE_UNIT DeviceUnit = AtaGetDevice(UnitNumber);
/* We work directly only with ATAPI drives because BIOS has ATA support */
if (DeviceUnit && DeviceUnit->Flags & ATA_DEVICE_ATAPI)
{
DiskDrive->Geometry.Cylinders = DeviceUnit->Cylinders;
DiskDrive->Geometry.Heads = DeviceUnit->Heads;
DiskDrive->Geometry.SectorsPerTrack = DeviceUnit->SectorsPerTrack;
DiskDrive->Geometry.BytesPerSector = DeviceUnit->SectorSize;
DiskDrive->Geometry.Sectors = DeviceUnit->TotalSectors;
DiskDrive->DaUa = 0xFF;
DiskDrive->IdeUnitNumber = UnitNumber;
DiskDrive->Type = DRIVE_IDE | DRIVE_CDROM;
DiskDrive->LBASupported = TRUE;
DiskDrive->IsRemovable = TRUE;
DiskDrive->Initialized = TRUE;
TRACE("InitIdeDrive(0x%x) returned:\n"
"Cylinders : 0x%x\n"
"Heads : 0x%x\n"
"Sects/Track: 0x%x\n"
"Total Sects: 0x%llx\n"
"Bytes/Sect : 0x%x\n",
UnitNumber,
DiskDrive->Geometry.Cylinders,
DiskDrive->Geometry.Heads,
DiskDrive->Geometry.SectorsPerTrack,
DiskDrive->Geometry.Sectors,
DiskDrive->Geometry.BytesPerSector);
return TRUE;
}
DiskDrive->Initialized = FALSE;
return FALSE;
}
static BOOLEAN
InitHardDrive(
IN UCHAR DaUa,
IN OUT PPC98_DISK_DRIVE DiskDrive)
{
REGS RegsIn, RegsOut;
/* Int 1Bh AH=8Eh
* DISK BIOS - Set half-height operation mode
*
* Call with:
* AL - drive number
*/
RegsIn.b.al = DaUa;
RegsIn.b.ah = 0x8E;
Int386(0x1B, &RegsIn, &RegsOut);
/* Int 1Bh AH=84h
* DISK BIOS - Sense
*
* Call with:
* AL - drive number
*
* Return:
* BX - bytes per sector
* CX - cylinders number
* DH - heads number
* DL - sectors number
* CF - set on error, clear if successful
* AH - status
*/
RegsIn.b.al = DaUa;
RegsIn.b.ah = 0x84;
Int386(0x1B, &RegsIn, &RegsOut);
if (!INT386_SUCCESS(RegsOut) || RegsOut.w.cx == 0)
{
DiskDrive->Initialized = FALSE;
return FALSE;
}
DiskDrive->Geometry.Cylinders = RegsOut.w.cx;
DiskDrive->Geometry.Heads = RegsOut.b.dh;
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;
DiskDrive->IsRemovable = FALSE;
DiskDrive->Initialized = TRUE;
TRACE("InitHardDrive(0x%x) returned:\n"
"Cylinders : 0x%x\n"
"Heads : 0x%x\n"
"Sects/Track: 0x%x\n"
"Total Sects: 0x%llx\n"
"Bytes/Sect : 0x%x\n",
DaUa,
DiskDrive->Geometry.Cylinders,
DiskDrive->Geometry.Heads,
DiskDrive->Geometry.SectorsPerTrack,
DiskDrive->Geometry.Sectors,
DiskDrive->Geometry.BytesPerSector);
return TRUE;
}
static BOOLEAN
static
BOOLEAN
InitFloppyDrive(
IN UCHAR DaUa,
IN OUT PPC98_DISK_DRIVE DiskDrive)
_Out_ PPC98_DISK_DRIVE DiskDrive,
_In_ UCHAR DaUa)
{
REGS RegsIn, RegsOut;
USHORT BytesPerSector;
UCHAR DeviceAddress = DaUa & 0xF0;
/* There's no way to obtain floppy disk geometry in BIOS */
ULONG BytesPerSector;
UCHAR DeviceAddress;
/* Int 1Bh AH=4Ah
* DISK BIOS - Read ID
@@ -640,11 +523,10 @@ InitFloppyDrive(
RegsIn.b.al = DaUa;
Int386(0x1B, &RegsIn, &RegsOut);
if (!INT386_SUCCESS(RegsOut))
{
DiskDrive->Initialized = FALSE;
return FALSE;
}
/* There is no way to obtain floppy disk geometry in BIOS */
DeviceAddress = DaUa & 0xF0;
BytesPerSector = 128 << RegsOut.b.ch;
switch (BytesPerSector)
{
@@ -697,7 +579,6 @@ InitFloppyDrive(
break;
default:
DiskDrive->Initialized = FALSE;
return FALSE;
}
@@ -707,10 +588,8 @@ InitFloppyDrive(
DiskDrive->Geometry.SectorsPerTrack;
DiskDrive->DaUa = DaUa;
DiskDrive->Type = DRIVE_FDD;
DiskDrive->LBASupported = FALSE;
DiskDrive->IsRemovable = TRUE;
DiskDrive->Initialized = TRUE;
DiskDrive->Type = DRIVE_TYPE_FDD;
DiskDrive->Flags = DRIVE_FLAGS_REMOVABLE | DRIVE_FLAGS_INITIALIZED;
TRACE("InitFloppyDrive(0x%x) returned:\n"
"Cylinders : 0x%x\n"
@@ -728,119 +607,142 @@ InitFloppyDrive(
return TRUE;
}
/* We emulate PC BIOS drive numbers here */
static
BOOLEAN
InitIdeDrive(
_Out_ PPC98_DISK_DRIVE DiskDrive,
_In_ UCHAR AtaUnitNumber)
{
PDEVICE_UNIT DeviceUnit = AtaGetDevice(AtaUnitNumber);
if (!DeviceUnit)
return FALSE;
DiskDrive->Geometry.Cylinders = DeviceUnit->Cylinders;
DiskDrive->Geometry.Heads = DeviceUnit->Heads;
DiskDrive->Geometry.SectorsPerTrack = DeviceUnit->SectorsPerTrack;
DiskDrive->Geometry.BytesPerSector = DeviceUnit->SectorSize;
DiskDrive->Geometry.Sectors = DeviceUnit->TotalSectors;
DiskDrive->DaUa = 0xFF; // Invalid
DiskDrive->AtaUnitNumber = AtaUnitNumber;
DiskDrive->Flags = DRIVE_FLAGS_IDE | DRIVE_FLAGS_INITIALIZED;
if (DeviceUnit->Flags & ATA_DEVICE_LBA)
DiskDrive->Flags |= DRIVE_FLAGS_LBA;
if (DeviceUnit->Flags & ATA_DEVICE_ATAPI)
{
DiskDrive->Type = DRIVE_TYPE_CDROM;
DiskDrive->Flags |= DRIVE_FLAGS_REMOVABLE;
}
else
{
DiskDrive->Type = DRIVE_TYPE_HDD;
}
TRACE("InitIdeDrive(0x%x) returned:\n"
"Cylinders : 0x%x\n"
"Heads : 0x%x\n"
"Sects/Track: 0x%x\n"
"Total Sects: 0x%llx\n"
"Bytes/Sect : 0x%x\n",
AtaUnitNumber,
DiskDrive->Geometry.Cylinders,
DiskDrive->Geometry.Heads,
DiskDrive->Geometry.SectorsPerTrack,
DiskDrive->Geometry.Sectors,
DiskDrive->Geometry.BytesPerSector);
return TRUE;
}
BOOLEAN
Pc98InitializeBootDevices(VOID)
{
PPC98_DISK_DRIVE DiskDrive;
UCHAR FakeFloppyDriveNumber = 0x30;
UCHAR FakeHardDriveDriveNumber = 0x80;
UCHAR FakeCdRomDriveNumber = 0xE0;
USHORT DiskEquipment = *(PUSHORT)MEM_DISK_EQUIP & ~(*(PUCHAR)MEM_RDISK_EQUIP);
UCHAR IdeDetectedCount;
UCHAR i;
PPC98_DISK_DRIVE DiskDrive;
UCHAR BiosFloppyDriveNumber, BiosHardDriveDriveNumber, IdeDetectedCount;
ULONG i;
TRACE("Pc98InitializeBootDevices()\n");
RtlZeroMemory(&Pc98DiskDrive, sizeof(Pc98DiskDrive));
/*
* Map DA/UA to drive number, i.e.
* We emulate the standard PC BIOS drive numbers here. Map DA/UA to a drive number, i.e.
* 0x90 -> 0x30
* 0x80 -> 0x80
* 0xA0 -> 0x81, etc.
*/
BiosFloppyDriveNumber = 0x30;
BiosHardDriveDriveNumber = 0x80;
/* Map floppies */
for (i = 0; i < 4; i++)
{
DiskDrive = &Pc98DiskDrive[FakeFloppyDriveNumber];
DiskDrive = &Pc98DiskDrive[BiosFloppyDriveNumber];
if (FIRSTBYTE(DiskEquipment) & (1 << i))
{
if (InitFloppyDrive(0x30 + i, DiskDrive) || InitFloppyDrive(0xB0 + i, DiskDrive) ||
InitFloppyDrive(0x90 + i, DiskDrive) || InitFloppyDrive(0x10 + i, DiskDrive))
++FakeFloppyDriveNumber;
if (InitFloppyDrive(DiskDrive, 0x30 + i) || InitFloppyDrive(DiskDrive, 0xB0 + i) ||
InitFloppyDrive(DiskDrive, 0x90 + i) || InitFloppyDrive(DiskDrive, 0x10 + i))
++BiosFloppyDriveNumber;
}
}
for (i = 0; i < 4; i++)
{
DiskDrive = &Pc98DiskDrive[FakeFloppyDriveNumber];
DiskDrive = &Pc98DiskDrive[BiosFloppyDriveNumber];
if (FIRSTBYTE(DiskEquipment) & (16 << i))
{
if (InitFloppyDrive(0x50 + i, DiskDrive))
++FakeFloppyDriveNumber;
if (InitFloppyDrive(DiskDrive, 0x50 + i))
++BiosFloppyDriveNumber;
}
}
for (i = 0; i < 4; i++)
{
DiskDrive = &Pc98DiskDrive[FakeFloppyDriveNumber];
DiskDrive = &Pc98DiskDrive[BiosFloppyDriveNumber];
if (SECONDBYTE(DiskEquipment) & (16 << i))
{
if (InitFloppyDrive(0x70 + i, DiskDrive) || InitFloppyDrive(0xF0 + i, DiskDrive))
++FakeFloppyDriveNumber;
if (InitFloppyDrive(DiskDrive, 0x70 + i) || InitFloppyDrive(DiskDrive, 0xF0 + i))
++BiosFloppyDriveNumber;
}
}
/* Map IDE/SASI drives */
for (i = 0; i < 4; i++)
{
DiskDrive = &Pc98DiskDrive[FakeHardDriveDriveNumber];
if (InitHardDrive(0x80 + i, DiskDrive) || InitHardDrive(0x00 + i, DiskDrive))
++FakeHardDriveDriveNumber;
}
/*
* Map IDE drives. We provide our own IDE boot support because of IDE BIOS
* that cannot boot from a CD-ROM and has LBA limitations.
*/
AtaInit(&IdeDetectedCount);
for (i = 0; i <= IdeDetectedCount; i++)
{
DiskDrive = &Pc98DiskDrive[FakeCdRomDriveNumber];
if (InitIdeDrive(i, DiskDrive))
++FakeCdRomDriveNumber;
DiskDrive = &Pc98DiskDrive[BiosHardDriveDriveNumber];
if (InitIdeDrive(DiskDrive, i))
++BiosHardDriveDriveNumber;
}
/* Map SCSI drives */
for (i = 0; i < 7; i++)
{
DiskDrive = &Pc98DiskDrive[FakeHardDriveDriveNumber];
if (InitScsiDrive(0xA0 + i, DiskDrive) || InitScsiDrive(0x20 + i, DiskDrive))
{
if (DiskDrive->Type & DRIVE_CDROM || DiskDrive->Type & DRIVE_MO)
{
/* Move to CD-ROM area */
Pc98DiskDrive[FakeCdRomDriveNumber] = *DiskDrive;
RtlZeroMemory(DiskDrive, sizeof(PC98_DISK_DRIVE));
++FakeCdRomDriveNumber;
}
else
{
++FakeHardDriveDriveNumber;
}
}
DiskDrive = &Pc98DiskDrive[BiosHardDriveDriveNumber];
if (InitScsiDrive(DiskDrive, 0xA0 + i) || InitScsiDrive(DiskDrive, 0x20 + i))
++BiosHardDriveDriveNumber;
}
#if 1
// Ugly HACK: Force ISO boot
// FIXME: Fill ARC disk blocks completely
// to allow usage of CD-ROM root path (See floppy_pc98.ini).
FrldrBootDrive = 0xE0;
FrldrBootPartition = 0xFF;
#else
/* Reassign boot drive */
for (i = 0; i < MAX_DRIVES - 1; i++)
for (i = 0x80; i < RTL_NUMBER_OF(Pc98DiskDrive); i++)
{
DiskDrive = &Pc98DiskDrive[i];
if (DiskDrive->Initialized && DiskDrive->DaUa == FrldrBootDrive)
if ((DiskDrive->Flags & DRIVE_FLAGS_INITIALIZED) &&
(DiskDrive->Flags & DRIVE_FLAGS_IDE) &&
(DiskDrive->Type == DRIVE_TYPE_CDROM))
{
TRACE("Boot drive: old 0x%x, new 0x%x\n", FrldrBootDrive, i);
FrldrBootDrive = i;
FrldrBootPartition = 0xFF;
break;
}
}
#endif
/* Call PC version */
return PcInitializeBootDevices();
@@ -848,10 +750,10 @@ Pc98InitializeBootDevices(VOID)
BOOLEAN
Pc98DiskReadLogicalSectors(
IN UCHAR DriveNumber,
IN ULONGLONG SectorNumber,
IN ULONG SectorCount,
OUT PVOID Buffer)
_In_ UCHAR DriveNumber,
_In_ ULONGLONG SectorNumber,
_In_ ULONG SectorCount,
_Out_ PVOID Buffer)
{
PPC98_DISK_DRIVE DiskDrive;
@@ -865,7 +767,14 @@ Pc98DiskReadLogicalSectors(
if (!DiskDrive)
return FALSE;
if (DiskDrive->LBASupported)
if (DiskDrive->Flags & DRIVE_FLAGS_IDE)
{
return AtaReadLogicalSectors(AtaGetDevice(DiskDrive->AtaUnitNumber),
SectorNumber,
SectorCount,
Buffer);
}
else if (DiskDrive->Flags & DRIVE_FLAGS_LBA)
{
/* LBA is easy, nothing to calculate. Just do the read. */
TRACE("--> Using LBA\n");
@@ -880,7 +789,9 @@ Pc98DiskReadLogicalSectors(
}
BOOLEAN
Pc98DiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry)
Pc98DiskGetDriveGeometry(
_In_ UCHAR DriveNumber,
_Out_ PGEOMETRY Geometry)
{
PPC98_DISK_DRIVE DiskDrive;
@@ -896,7 +807,8 @@ Pc98DiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry)
}
ULONG
Pc98DiskGetCacheableBlockCount(UCHAR DriveNumber)
Pc98DiskGetCacheableBlockCount(
_In_ UCHAR DriveNumber)
{
PPC98_DISK_DRIVE DiskDrive;
@@ -908,7 +820,7 @@ Pc98DiskGetCacheableBlockCount(UCHAR DriveNumber)
* 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 (DiskDrive->LBASupported)
if (DiskDrive->Flags & DRIVE_FLAGS_LBA)
return 64;
else
return DiskDrive->Geometry.SectorsPerTrack;

View File

@@ -105,36 +105,24 @@ typedef struct _PC98_DISK_DRIVE
/* Disk geometry */
GEOMETRY Geometry;
/* BIOS drive number */
/* PC-98 BIOS drive number */
UCHAR DaUa;
/* IDE driver drive number */
UCHAR IdeUnitNumber;
UCHAR AtaUnitNumber;
/* Drive type flags */
/* Drive type */
UCHAR Type;
#define DRIVE_SASI 0x00
#define DRIVE_IDE 0x01
#define DRIVE_SCSI 0x02
#define DRIVE_CDROM 0x04
#define DRIVE_FDD 0x08
#define DRIVE_MO 0x10
#define DRIVE_RAM 0x20
#define DRIVE_TYPE_HDD 0
#define DRIVE_TYPE_CDROM 1
#define DRIVE_TYPE_FDD 2
/* TRUE when LBA access are supported */
BOOLEAN LBASupported;
/*
* '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;
/*
* 'Initialized' flag: if TRUE then the drive has been initialized;
* if FALSE then the disk isn't detected by BIOS/FreeLoader.
*/
BOOLEAN Initialized;
/* Drive flags */
UCHAR Flags;
#define DRIVE_FLAGS_IDE 0x01 // IDE drive, accessed by the IDE driver
#define DRIVE_FLAGS_LBA 0x02 // LBA access supported
#define DRIVE_FLAGS_REMOVABLE 0x04 // The drive is removable (e.g. floppy, CD-ROM...)
#define DRIVE_FLAGS_INITIALIZED 0x80 // The drive has been initialized
} PC98_DISK_DRIVE, *PPC98_DISK_DRIVE;
/* Platform-specific boot drive and partition numbers */
@@ -145,16 +133,36 @@ CONFIGURATION_TYPE
DiskGetConfigType(
_In_ UCHAR DriveNumber);
LONG DiskReportError(BOOLEAN bShowError);
BOOLEAN DiskResetController(IN PPC98_DISK_DRIVE DiskDrive);
LONG
DiskReportError(
_In_ BOOLEAN bShowError);
BOOLEAN Pc98DiskReadLogicalSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer);
BOOLEAN Pc98DiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY DriveGeometry);
ULONG Pc98DiskGetCacheableBlockCount(UCHAR DriveNumber);
UCHAR Pc98GetFloppyCount(VOID);
PPC98_DISK_DRIVE Pc98DiskDriveNumberToDrive(IN UCHAR DriveNumber);
BOOLEAN
Pc98DiskReadLogicalSectors(
_In_ UCHAR DriveNumber,
_In_ ULONGLONG SectorNumber,
_In_ ULONG SectorCount,
_Out_ PVOID Buffer);
ULONG Pc98GetBootSectorLoadAddress(IN UCHAR DriveNumber);
BOOLEAN
Pc98DiskGetDriveGeometry(
_In_ UCHAR DriveNumber,
_Out_ PGEOMETRY DriveGeometry);
ULONG
Pc98DiskGetCacheableBlockCount(
_In_ UCHAR DriveNumber);
UCHAR
Pc98GetFloppyCount(VOID);
PPC98_DISK_DRIVE
Pc98DiskDriveNumberToDrive(
_In_ UCHAR DriveNumber);
ULONG
Pc98GetBootSectorLoadAddress(
_In_ UCHAR DriveNumber);
/* hwdisk.c */
BOOLEAN PcInitializeBootDevices(VOID);