mirror of
https://github.com/reactos/reactos.git
synced 2026-05-30 23:33:24 +08:00
[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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user