#include <freeldr.h>
-#define NDEBUG
#include <debug.h>
-
DBG_DEFAULT_CHANNEL(HWDETECT);
+/*
+ * This is the common code for harddisk for both the PC and the XBOX.
+ */
+
typedef struct tagDISKCONTEXT
{
UCHAR DriveNumber;
ULONGLONG SectorNumber;
} DISKCONTEXT;
-extern ULONG reactos_disk_count;
-extern ARC_DISK_SIGNATURE reactos_arc_disk_info[];
-extern CHAR reactos_arc_strings[32][256];
+static const CHAR Hex[] = "0123456789abcdef";
-static CHAR Hex[] = "0123456789abcdef";
+/* Data cache for BIOS disks pre-enumeration */
UCHAR PcBiosDiskCount = 0;
-CHAR PcDiskIdentifier[32][20];
+static CHAR PcDiskIdentifier[32][20];
+
+PVOID DiskReadBuffer;
+SIZE_T DiskReadBufferSize;
+
+/* FUNCTIONS *****************************************************************/
-static LONG DiskClose(ULONG FileId)
+static ARC_STATUS
+DiskClose(ULONG FileId)
{
DISKCONTEXT* Context = FsGetDeviceSpecific(FileId);
-
FrLdrTempFree(Context, TAG_HW_DISK_CONTEXT);
return ESUCCESS;
}
-static LONG DiskGetFileInformation(ULONG FileId, FILEINFORMATION* Information)
+static ARC_STATUS
+DiskGetFileInformation(ULONG FileId, FILEINFORMATION* Information)
{
DISKCONTEXT* Context = FsGetDeviceSpecific(FileId);
- RtlZeroMemory(Information, sizeof(FILEINFORMATION));
- Information->EndingAddress.QuadPart = (Context->SectorOffset + Context->SectorCount) * Context->SectorSize;
- Information->CurrentAddress.QuadPart = (Context->SectorOffset + Context->SectorNumber) * Context->SectorSize;
+ RtlZeroMemory(Information, sizeof(*Information));
+
+ /*
+ * The ARC specification mentions that for partitions, StartingAddress and
+ * EndingAddress are the start and end positions of the partition in terms
+ * of byte offsets from the start of the disk.
+ * CurrentAddress is the current offset into (i.e. relative to) the partition.
+ */
+ Information->StartingAddress.QuadPart = Context->SectorOffset * Context->SectorSize;
+ Information->EndingAddress.QuadPart = (Context->SectorOffset + Context->SectorCount) * Context->SectorSize;
+ Information->CurrentAddress.QuadPart = Context->SectorNumber * Context->SectorSize;
return ESUCCESS;
}
-static LONG DiskOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
+static ARC_STATUS
+DiskOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
{
DISKCONTEXT* Context;
UCHAR DriveNumber;
ULONGLONG SectorOffset = 0;
ULONGLONG SectorCount = 0;
PARTITION_TABLE_ENTRY PartitionTableEntry;
- CHAR FileName[1];
- if (!DissectArcPath(Path, FileName, &DriveNumber, &DrivePartition))
+ if (DiskReadBufferSize == 0)
+ {
+ ERR("DiskOpen(): DiskReadBufferSize is 0, something is wrong.\n");
+ ASSERT(FALSE);
+ return ENOMEM;
+ }
+
+ if (!DissectArcPath(Path, NULL, &DriveNumber, &DrivePartition))
return EINVAL;
if (DrivePartition == 0xff)
}
else
{
- /* This is either a floppy disk device (DrivePartition == 0) or
- * a hard disk device (DrivePartition != 0 && DrivePartition != 0xFF) but
- * it doesn't matter which one because they both have 512 bytes per sector */
+ /*
+ * This is either a floppy disk device (DrivePartition == 0) or
+ * a hard disk device (DrivePartition != 0 && DrivePartition != 0xFF)
+ * but it doesn't matter which one because they both have 512 bytes
+ * per sector.
+ */
SectorSize = 512;
}
{
if (!DiskGetPartitionEntry(DriveNumber, DrivePartition, &PartitionTableEntry))
return EINVAL;
+
SectorOffset = PartitionTableEntry.SectorCountBeforePartition;
SectorCount = PartitionTableEntry.PartitionSectorCount;
}
+ else
+ {
+ GEOMETRY Geometry;
+ if (!MachDiskGetDriveGeometry(DriveNumber, &Geometry))
+ return EINVAL;
+
+ if (SectorSize != Geometry.BytesPerSector)
+ {
+ ERR("SectorSize (%lu) != Geometry.BytesPerSector (%lu), expect problems!\n",
+ SectorSize, Geometry.BytesPerSector);
+ }
+
+ SectorOffset = 0;
+ SectorCount = (ULONGLONG)Geometry.Cylinders * Geometry.Heads * Geometry.Sectors;
+ }
Context = FrLdrTempAlloc(sizeof(DISKCONTEXT), TAG_HW_DISK_CONTEXT);
if (!Context)
return ENOMEM;
+
Context->DriveNumber = DriveNumber;
Context->SectorSize = SectorSize;
Context->SectorOffset = SectorOffset;
return ESUCCESS;
}
-static LONG DiskRead(ULONG FileId, VOID* Buffer, ULONG N, ULONG* Count)
+static ARC_STATUS
+DiskRead(ULONG FileId, VOID* Buffer, ULONG N, ULONG* Count)
{
DISKCONTEXT* Context = FsGetDeviceSpecific(FileId);
UCHAR* Ptr = (UCHAR*)Buffer;
BOOLEAN ret;
ULONGLONG SectorOffset;
+ ASSERT(DiskReadBufferSize > 0);
+
TotalSectors = (N + Context->SectorSize - 1) / Context->SectorSize;
- MaxSectors = DISKREADBUFFER_SIZE / Context->SectorSize;
- SectorOffset = Context->SectorNumber + Context->SectorOffset;
+ MaxSectors = DiskReadBufferSize / Context->SectorSize;
+ SectorOffset = Context->SectorOffset + Context->SectorNumber;
+
+ // If MaxSectors is 0, this will lead to infinite loop.
+ // In release builds assertions are disabled, however we also have sanity checks in DiskOpen()
+ ASSERT(MaxSectors > 0);
- ret = 1;
+ ret = TRUE;
while (TotalSectors)
{
if (ReadSectors > MaxSectors)
ReadSectors = MaxSectors;
- ret = MachDiskReadLogicalSectors(
- Context->DriveNumber,
- SectorOffset,
- ReadSectors,
- (PVOID)DISKREADBUFFER);
+ ret = MachDiskReadLogicalSectors(Context->DriveNumber,
+ SectorOffset,
+ ReadSectors,
+ DiskReadBuffer);
if (!ret)
break;
if (Length > N)
Length = N;
- RtlCopyMemory(Ptr, (PVOID)DISKREADBUFFER, Length);
+ RtlCopyMemory(Ptr, DiskReadBuffer, Length);
Ptr += Length;
N -= Length;
return (!ret) ? EIO : ESUCCESS;
}
-static LONG DiskSeek(ULONG FileId, LARGE_INTEGER* Position, SEEKMODE SeekMode)
+static ARC_STATUS
+DiskSeek(ULONG FileId, LARGE_INTEGER* Position, SEEKMODE SeekMode)
{
DISKCONTEXT* Context = FsGetDeviceSpecific(FileId);
+ LARGE_INTEGER NewPosition = *Position;
- if (SeekMode != SeekAbsolute)
+ switch (SeekMode)
+ {
+ case SeekAbsolute:
+ break;
+ case SeekRelative:
+ NewPosition.QuadPart += (Context->SectorNumber * Context->SectorSize);
+ break;
+ default:
+ ASSERT(FALSE);
+ return EINVAL;
+ }
+
+ if (NewPosition.QuadPart & (Context->SectorSize - 1))
return EINVAL;
- if (Position->LowPart & (Context->SectorSize - 1))
+
+ /* Convert in number of sectors */
+ NewPosition.QuadPart /= Context->SectorSize;
+
+ /* HACK: CDROMs may have a SectorCount of 0 */
+ if (Context->SectorCount != 0 && NewPosition.QuadPart >= Context->SectorCount)
return EINVAL;
- Context->SectorNumber = (ULONG)(Position->QuadPart / Context->SectorSize);
+ Context->SectorNumber = NewPosition.QuadPart;
return ESUCCESS;
}
-static const DEVVTBL DiskVtbl = {
+static const DEVVTBL DiskVtbl =
+{
DiskClose,
DiskGetFileInformation,
DiskOpen,
DiskSeek,
};
+
PCHAR
-GetHarddiskIdentifier(
- UCHAR DriveNumber)
+GetHarddiskIdentifier(UCHAR DriveNumber)
{
return PcDiskIdentifier[DriveNumber - 0x80];
}
-VOID
-GetHarddiskInformation(
- UCHAR DriveNumber)
+static VOID
+GetHarddiskInformation(UCHAR DriveNumber)
{
PMASTER_BOOT_RECORD Mbr;
- ULONG *Buffer;
+ PULONG Buffer;
ULONG i;
ULONG Checksum;
ULONG Signature;
- CHAR ArcName[256];
+ BOOLEAN ValidPartitionTable;
+ CHAR ArcName[MAX_PATH];
PARTITION_TABLE_ENTRY PartitionTableEntry;
PCHAR Identifier = PcDiskIdentifier[DriveNumber - 0x80];
+ /* Detect disk partition type */
+ DiskDetectPartitionType(DriveNumber);
+
/* Read the MBR */
- if (!MachDiskReadLogicalSectors(DriveNumber, 0ULL, 1, (PVOID)DISKREADBUFFER))
+ if (!MachDiskReadLogicalSectors(DriveNumber, 0ULL, 1, DiskReadBuffer))
{
ERR("Reading MBR failed\n");
+ /* We failed, use a default identifier */
+ sprintf(Identifier, "BIOSDISK%d", DriveNumber - 0x80 + 1);
return;
}
- Buffer = (ULONG*)DISKREADBUFFER;
- Mbr = (PMASTER_BOOT_RECORD)DISKREADBUFFER;
+ Buffer = (ULONG*)DiskReadBuffer;
+ Mbr = (PMASTER_BOOT_RECORD)DiskReadBuffer;
- Signature = Mbr->Signature;
+ Signature = Mbr->Signature;
TRACE("Signature: %x\n", Signature);
/* Calculate the MBR checksum */
Checksum = 0;
- for (i = 0; i < 128; i++)
+ for (i = 0; i < 512 / sizeof(ULONG); i++)
{
Checksum += Buffer[i];
}
Checksum = ~Checksum + 1;
TRACE("Checksum: %x\n", Checksum);
+ ValidPartitionTable = (Mbr->MasterBootRecordMagic == 0xAA55);
+
/* Fill out the ARC disk block */
- reactos_arc_disk_info[reactos_disk_count].Signature = Signature;
- reactos_arc_disk_info[reactos_disk_count].CheckSum = Checksum;
- sprintf(ArcName, "multi(0)disk(0)rdisk(%lu)", reactos_disk_count);
- strcpy(reactos_arc_strings[reactos_disk_count], ArcName);
- reactos_arc_disk_info[reactos_disk_count].ArcName =
- reactos_arc_strings[reactos_disk_count];
- reactos_disk_count++;
+ sprintf(ArcName, "multi(0)disk(0)rdisk(%u)", DriveNumber - 0x80);
+ AddReactOSArcDiskInfo(ArcName, Signature, Checksum, ValidPartitionTable);
sprintf(ArcName, "multi(0)disk(0)rdisk(%u)partition(0)", DriveNumber - 0x80);
FsRegisterDevice(ArcName, &DiskVtbl);
Identifier[15] = Hex[(Signature >> 4) & 0x0F];
Identifier[16] = Hex[Signature & 0x0F];
Identifier[17] = '-';
- Identifier[18] = 'A';
+ Identifier[18] = (ValidPartitionTable ? 'A' : 'X');
Identifier[19] = 0;
TRACE("Identifier: %s\n", Identifier);
}
-
-BOOLEAN
-HwInitializeBiosDisks(VOID)
+static UCHAR
+EnumerateHarddisks(OUT PBOOLEAN BootDriveReported)
{
UCHAR DiskCount, DriveNumber;
ULONG i;
BOOLEAN Changed;
- CHAR BootPath[512];
- BOOLEAN BootDriveReported = FALSE;
- /* Count the number of visible drives */
+ *BootDriveReported = FALSE;
+
+ /* Count the number of visible harddisk drives */
DiskReportError(FALSE);
DiskCount = 0;
DriveNumber = 0x80;
- /* There are some really broken BIOSes out there. There are even BIOSes
- * that happily report success when you ask them to read from non-existent
- * harddisks. So, we set the buffer to known contents first, then try to
- * read. If the BIOS reports success but the buffer contents haven't
- * changed then we fail anyway */
- memset((PVOID) DISKREADBUFFER, 0xcd, 512);
- while (MachDiskReadLogicalSectors(DriveNumber, 0ULL, 1, (PVOID)DISKREADBUFFER))
+ ASSERT(DiskReadBufferSize > 0);
+
+ /*
+ * There are some really broken BIOSes out there. There are even BIOSes
+ * that happily report success when you ask them to read from non-existent
+ * harddisks. So, we set the buffer to known contents first, then try to
+ * read. If the BIOS reports success but the buffer contents haven't
+ * changed then we fail anyway.
+ */
+ memset(DiskReadBuffer, 0xcd, DiskReadBufferSize);
+ while (MachDiskReadLogicalSectors(DriveNumber, 0ULL, 1, DiskReadBuffer))
{
Changed = FALSE;
- for (i = 0; ! Changed && i < 512; i++)
+ for (i = 0; !Changed && i < DiskReadBufferSize; i++)
{
- Changed = ((PUCHAR)DISKREADBUFFER)[i] != 0xcd;
+ Changed = ((PUCHAR)DiskReadBuffer)[i] != 0xcd;
}
- if (! Changed)
+ if (!Changed)
{
- TRACE("BIOS reports success for disk %d but data didn't change\n",
- (int)DiskCount);
+ TRACE("BIOS reports success for disk %d (0x%02X) but data didn't change\n",
+ (int)DiskCount, DriveNumber);
break;
}
+ /* Cache the BIOS hard disk information for later use */
GetHarddiskInformation(DriveNumber);
+ /* Check if we have seen the boot drive */
if (FrldrBootDrive == DriveNumber)
- BootDriveReported = TRUE;
+ *BootDriveReported = TRUE;
DiskCount++;
DriveNumber++;
- memset((PVOID) DISKREADBUFFER, 0xcd, 512);
+ memset(DiskReadBuffer, 0xcd, DiskReadBufferSize);
}
DiskReportError(TRUE);
- /* Get the drive we're booting from */
- MachDiskGetBootPath(BootPath, sizeof(BootPath));
+ PcBiosDiskCount = DiskCount;
+ TRACE("BIOS reports %d harddisk%s\n",
+ (int)DiskCount, (DiskCount == 1) ? "" : "s");
+
+ return DiskCount;
+}
+
+static BOOLEAN
+DiskIsDriveRemovable(UCHAR DriveNumber)
+{
+ /*
+ * Hard disks use drive numbers >= 0x80 . So if the drive number
+ * indicates a hard disk then return FALSE.
+ * 0x49 is our magic ramdisk drive, so return FALSE for that too.
+ */
+ if ((DriveNumber >= 0x80) || (DriveNumber == 0x49))
+ return FALSE;
+
+ /* The drive is a floppy diskette so return TRUE */
+ return TRUE;
+}
+
+static BOOLEAN
+DiskGetBootPath(BOOLEAN IsPxe)
+{
+ if (*FrLdrBootPath)
+ return TRUE;
+
+ // FIXME! FIXME! Do this in some drive recognition procedure!!!!
+ if (IsPxe)
+ {
+ RtlStringCbCopyA(FrLdrBootPath, sizeof(FrLdrBootPath), "net(0)");
+ }
+ else
+ /* 0x49 is our magic ramdisk drive, so try to detect it first */
+ if (FrldrBootDrive == 0x49)
+ {
+ /* This is the ramdisk. See ArmInitializeBootDevices() too... */
+ // RtlStringCbPrintfA(FrLdrBootPath, sizeof(FrLdrBootPath), "ramdisk(%u)", 0);
+ RtlStringCbCopyA(FrLdrBootPath, sizeof(FrLdrBootPath), "ramdisk(0)");
+ }
+ else if (FrldrBootDrive < 0x80)
+ {
+ /* This is a floppy */
+ RtlStringCbPrintfA(FrLdrBootPath, sizeof(FrLdrBootPath),
+ "multi(0)disk(0)fdisk(%u)", FrldrBootDrive);
+ }
+ else if (FrldrBootPartition == 0xFF)
+ {
+ /* Boot Partition 0xFF is the magic value that indicates booting from CD-ROM (see isoboot.S) */
+ RtlStringCbPrintfA(FrLdrBootPath, sizeof(FrLdrBootPath),
+ "multi(0)disk(0)cdrom(%u)", FrldrBootDrive - 0x80);
+ }
+ else
+ {
+ ULONG BootPartition;
+ PARTITION_TABLE_ENTRY PartitionEntry;
+
+ /* This is a hard disk */
+ if (!DiskGetBootPartitionEntry(FrldrBootDrive, &PartitionEntry, &BootPartition))
+ {
+ ERR("Failed to get boot partition entry\n");
+ return FALSE;
+ }
+
+ FrldrBootPartition = BootPartition;
+
+ RtlStringCbPrintfA(FrLdrBootPath, sizeof(FrLdrBootPath),
+ "multi(0)disk(0)rdisk(%u)partition(%lu)",
+ FrldrBootDrive - 0x80, FrldrBootPartition);
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+PcInitializeBootDevices(VOID)
+{
+ UCHAR DiskCount;
+ BOOLEAN BootDriveReported = FALSE;
+ ULONG i;
+
+ DiskCount = EnumerateHarddisks(&BootDriveReported);
+
+ /* Initialize FrLdrBootPath, the boot path we're booting from (the "SystemPartition") */
+ DiskGetBootPath(PxeInit());
/* Add it, if it's a floppy or cdrom */
if ((FrldrBootDrive >= 0x80 && !BootDriveReported) ||
DiskIsDriveRemovable(FrldrBootDrive))
{
- /* TODO: Check if it's really a cdrom drive */
- ULONG* Buffer;
+ /* TODO: Check if it's really a CDROM drive */
+
+ PMASTER_BOOT_RECORD Mbr;
+ PULONG Buffer;
ULONG Checksum = 0;
+ ULONG Signature;
/* Read the MBR */
- if (!MachDiskReadLogicalSectors(FrldrBootDrive, 16ULL, 1, (PVOID)DISKREADBUFFER))
+ if (!MachDiskReadLogicalSectors(FrldrBootDrive, 16ULL, 1, DiskReadBuffer))
{
- ERR("Reading MBR failed\n");
- return FALSE;
+ ERR("Reading MBR failed\n");
+ return FALSE;
}
- Buffer = (ULONG*)DISKREADBUFFER;
+ Buffer = (ULONG*)DiskReadBuffer;
+ Mbr = (PMASTER_BOOT_RECORD)DiskReadBuffer;
+
+ Signature = Mbr->Signature;
+ TRACE("Signature: %x\n", Signature);
/* Calculate the MBR checksum */
- for (i = 0; i < 2048 / sizeof(ULONG); i++) Checksum += Buffer[i];
+ for (i = 0; i < 2048 / sizeof(ULONG); i++)
+ {
+ Checksum += Buffer[i];
+ }
Checksum = ~Checksum + 1;
TRACE("Checksum: %x\n", Checksum);
/* Fill out the ARC disk block */
- reactos_arc_disk_info[reactos_disk_count].CheckSum = Checksum;
- strcpy(reactos_arc_strings[reactos_disk_count], BootPath);
- reactos_arc_disk_info[reactos_disk_count].ArcName =
- reactos_arc_strings[reactos_disk_count];
- reactos_disk_count++;
+ AddReactOSArcDiskInfo(FrLdrBootPath, Signature, Checksum, TRUE);
- FsRegisterDevice(BootPath, &DiskVtbl);
- DiskCount++;
+ FsRegisterDevice(FrLdrBootPath, &DiskVtbl);
+ DiskCount++; // This is not accounted for in the number of pre-enumerated BIOS drives!
+ TRACE("Additional boot drive detected: 0x%02X\n", (int)FrldrBootDrive);
}
- PcBiosDiskCount = DiskCount;
- TRACE("BIOS reports %d harddisk%s\n",
- (int)DiskCount, (DiskCount == 1) ? "": "s");
-
- return DiskCount != 0;
+ return (DiskCount != 0);
}