From dd46d40fd26717a0526e58e612491d094f9c83b9 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Wed, 18 Sep 2019 01:06:15 +0200 Subject: [PATCH] [FREELDR] Addendum / actual fix for ef76709b According to the Advanced RISC Computing Specification v1.2, 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. Fix also the FAT filesystem in accordance. - FIXME fix: Retrieve the size of the disk in number of sectors in DiskOpen(). - Add extra validity checks in the DiskSeek() functions. - Explicitly call PcDisk* functions in machpc.c and pcdisk.c, and XboxDisk* functions in machxbox.c (the code in these files is not called cross-platform). CORE-16216 CORE-16248 --- boot/freeldr/freeldr/arch/i386/hwdisk.c | 36 ++++++++++++++++++----- boot/freeldr/freeldr/arch/i386/machpc.c | 2 +- boot/freeldr/freeldr/arch/i386/machxbox.c | 2 +- boot/freeldr/freeldr/arch/i386/pcdisk.c | 8 +++-- boot/freeldr/freeldr/disk/scsiport.c | 21 ++++++++++--- boot/freeldr/freeldr/lib/fs/fat.c | 2 +- 6 files changed, 54 insertions(+), 17 deletions(-) diff --git a/boot/freeldr/freeldr/arch/i386/hwdisk.c b/boot/freeldr/freeldr/arch/i386/hwdisk.c index 9f623a36fe6..ef13c24bbe4 100644 --- a/boot/freeldr/freeldr/arch/i386/hwdisk.c +++ b/boot/freeldr/freeldr/arch/i386/hwdisk.c @@ -63,8 +63,16 @@ DiskGetFileInformation(ULONG FileId, FILEINFORMATION* Information) DISKCONTEXT* Context = FsGetDeviceSpecific(FileId); RtlZeroMemory(Information, sizeof(*Information)); - Information->EndingAddress.QuadPart = Context->SectorCount * Context->SectorSize; - Information->CurrentAddress.QuadPart = Context->SectorNumber * Context->SectorSize; + + /* + * 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; } @@ -113,12 +121,21 @@ DiskOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId) SectorOffset = PartitionTableEntry.SectorCountBeforePartition; SectorCount = PartitionTableEntry.PartitionSectorCount; } -#if 0 // FIXME: Investigate else { - SectorCount = 0; /* FIXME */ + 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; } -#endif Context = FrLdrTempAlloc(sizeof(DISKCONTEXT), TAG_HW_DISK_CONTEXT); if (!Context) @@ -147,7 +164,7 @@ DiskRead(ULONG FileId, VOID* Buffer, ULONG N, ULONG* Count) TotalSectors = (N + Context->SectorSize - 1) / Context->SectorSize; MaxSectors = DiskReadBufferSize / Context->SectorSize; - SectorOffset = Context->SectorNumber + Context->SectorOffset; + 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() @@ -189,13 +206,18 @@ static ARC_STATUS DiskSeek(ULONG FileId, LARGE_INTEGER* Position, SEEKMODE SeekMode) { DISKCONTEXT* Context = FsGetDeviceSpecific(FileId); + ULONGLONG SectorNumber; if (SeekMode != SeekAbsolute) return EINVAL; if (Position->LowPart & (Context->SectorSize - 1)) return EINVAL; - Context->SectorNumber = Position->QuadPart / Context->SectorSize; + SectorNumber = Position->QuadPart / Context->SectorSize; + if (SectorNumber >= Context->SectorCount) + return EINVAL; + + Context->SectorNumber = SectorNumber; return ESUCCESS; } diff --git a/boot/freeldr/freeldr/arch/i386/machpc.c b/boot/freeldr/freeldr/arch/i386/machpc.c index d95f70f6a25..712a0575b44 100644 --- a/boot/freeldr/freeldr/arch/i386/machpc.c +++ b/boot/freeldr/freeldr/arch/i386/machpc.c @@ -147,7 +147,7 @@ PcGetHarddiskConfigurationData(UCHAR DriveNumber, ULONG* pSize) DiskGeometry->SectorsPerTrack = ExtGeometry.SectorsPerTrack; DiskGeometry->NumberOfHeads = ExtGeometry.Heads; } - else if (MachDiskGetDriveGeometry(DriveNumber, &Geometry)) + else if (PcDiskGetDriveGeometry(DriveNumber, &Geometry)) { DiskGeometry->BytesPerSector = Geometry.BytesPerSector; DiskGeometry->NumberOfCylinders = Geometry.Cylinders; diff --git a/boot/freeldr/freeldr/arch/i386/machxbox.c b/boot/freeldr/freeldr/arch/i386/machxbox.c index 2bdee5f0f45..7b12084c294 100644 --- a/boot/freeldr/freeldr/arch/i386/machxbox.c +++ b/boot/freeldr/freeldr/arch/i386/machxbox.c @@ -133,7 +133,7 @@ XboxGetHarddiskConfigurationData(UCHAR DriveNumber, ULONG* pSize) /* Get the disk geometry */ //ExtGeometry.Size = sizeof(EXTENDED_GEOMETRY); - if (MachDiskGetDriveGeometry(DriveNumber, &Geometry)) + if (XboxDiskGetDriveGeometry(DriveNumber, &Geometry)) { DiskGeometry->BytesPerSector = Geometry.BytesPerSector; DiskGeometry->NumberOfCylinders = Geometry.Cylinders; diff --git a/boot/freeldr/freeldr/arch/i386/pcdisk.c b/boot/freeldr/freeldr/arch/i386/pcdisk.c index 87c21fc3b64..f9fc4f0c1ba 100644 --- a/boot/freeldr/freeldr/arch/i386/pcdisk.c +++ b/boot/freeldr/freeldr/arch/i386/pcdisk.c @@ -240,9 +240,11 @@ static BOOLEAN PcDiskReadLogicalSectorsCHS(UCHAR DriveNumber, ULONGLONG SectorNu TRACE("PcDiskReadLogicalSectorsCHS()\n"); /* Get the drive geometry */ - if (!MachDiskGetDriveGeometry(DriveNumber, &DriveGeometry) || - DriveGeometry.Sectors == 0 || - DriveGeometry.Heads == 0) + // + // TODO: Cache this information for the given drive. + // + if (!PcDiskGetDriveGeometry(DriveNumber, &DriveGeometry) || + DriveGeometry.Sectors == 0 || DriveGeometry.Heads == 0) { return FALSE; } diff --git a/boot/freeldr/freeldr/disk/scsiport.c b/boot/freeldr/freeldr/disk/scsiport.c index 21b7390e021..92b032ea574 100644 --- a/boot/freeldr/freeldr/disk/scsiport.c +++ b/boot/freeldr/freeldr/disk/scsiport.c @@ -178,8 +178,16 @@ static ARC_STATUS DiskGetFileInformation(ULONG FileId, FILEINFORMATION* Informat DISKCONTEXT* Context = FsGetDeviceSpecific(FileId); RtlZeroMemory(Information, sizeof(*Information)); - Information->EndingAddress.QuadPart = Context->SectorCount * Context->SectorSize; - Information->CurrentAddress.QuadPart = Context->SectorNumber * Context->SectorSize; + + /* + * 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; } @@ -276,7 +284,7 @@ static ARC_STATUS DiskRead(ULONG FileId, VOID* Buffer, ULONG N, ULONG* Count) /* Read full sectors */ ASSERT(Context->SectorNumber < 0xFFFFFFFF); - Lba = (ULONG)Context->SectorNumber; + Lba = (ULONG)(Context->SectorOffset + Context->SectorNumber); if (FullSectors > 0) { Srb = ExAllocatePool(PagedPool, sizeof(SCSI_REQUEST_BLOCK)); @@ -365,13 +373,18 @@ static ARC_STATUS DiskRead(ULONG FileId, VOID* Buffer, ULONG N, ULONG* Count) static ARC_STATUS DiskSeek(ULONG FileId, LARGE_INTEGER* Position, SEEKMODE SeekMode) { DISKCONTEXT* Context = FsGetDeviceSpecific(FileId); + ULONGLONG SectorNumber; if (SeekMode != SeekAbsolute) return EINVAL; if (Position->QuadPart & (Context->SectorSize - 1)) return EINVAL; - Context->SectorNumber = Position->QuadPart / Context->SectorSize; + SectorNumber = Position->QuadPart / Context->SectorSize; + if (SectorNumber >= Context->SectorCount) + return EINVAL; + + Context->SectorNumber = SectorNumber; return ESUCCESS; } diff --git a/boot/freeldr/freeldr/lib/fs/fat.c b/boot/freeldr/freeldr/lib/fs/fat.c index 63a1283a439..7dad4f2f516 100644 --- a/boot/freeldr/freeldr/lib/fs/fat.c +++ b/boot/freeldr/freeldr/lib/fs/fat.c @@ -1570,7 +1570,7 @@ const DEVVTBL* FatMount(ULONG DeviceId) FrLdrTempFree(Volume, TAG_FAT_VOLUME); return NULL; } - SectorCount.QuadPart = FileInformation.EndingAddress.QuadPart; + SectorCount.QuadPart = (FileInformation.EndingAddress.QuadPart - FileInformation.StartingAddress.QuadPart); SectorCount.QuadPart /= SECTOR_SIZE; // -- 2.17.1