[FREELDR] Switch partition interface to using the more generic PARTITION_INFORMATION

instead of the MBR-specific PARTITION_TABLE_ENTRY structure.

Simplify also some aspects of the code:

- for MBR code, avoid copying around partition entries, but use
  pointers instead;

- more generally, use the actual disk sector size instead of guessing,
  and pass it to the partition interface routines.
This commit is contained in:
Hermès Bélusca-Maïto
2026-04-12 22:28:17 +02:00
parent c479bf81ff
commit e2c92c0ffb
9 changed files with 318 additions and 239 deletions

View File

@@ -87,9 +87,9 @@ DiskOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
CONFIGURATION_TYPE DriveType;
UCHAR DriveNumber;
ULONG DrivePartition, SectorSize;
ULONGLONG SectorOffset = 0;
ULONGLONG SectorCount = 0;
PARTITION_TABLE_ENTRY PartitionTableEntry;
GEOMETRY Geometry;
ULONGLONG SectorOffset;
ULONGLONG SectorCount;
if (DiskReadBufferSize == 0)
{
@@ -102,38 +102,37 @@ DiskOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
return EINVAL;
DriveType = DiskGetConfigType(DriveNumber);
if (DriveType == CdromController)
if (!MachDiskGetDriveGeometry(DriveNumber, &Geometry))
return EIO;
if (Geometry.BytesPerSector == 0)
{
/* This is a CD-ROM device */
SectorSize = 2048;
}
else
{
/* This is either a floppy disk or a hard disk device, but it doesn't
* matter which one because they both have 512 bytes per sector */
SectorSize = 512;
WARN("MachDiskGetDriveGeometry(0x%x) failed, fall back to hardcoded values\n", DriveNumber);
if (DriveType == CdromController)
{
/* This is a CD-ROM device */
Geometry.BytesPerSector = 2048;
}
else
{
/* This is either a floppy disk or a hard disk device, but it doesn't
* matter which one because they both have 512 bytes per sector */
Geometry.BytesPerSector = 512;
}
}
SectorSize = Geometry.BytesPerSector;
if (DrivePartition != 0xff && DrivePartition != 0)
{
if (!DiskGetPartitionEntry(DriveNumber, DrivePartition, &PartitionTableEntry))
return EINVAL;
PARTITION_INFORMATION PartitionEntry;
if (!DiskGetPartitionEntry(DriveNumber, SectorSize, DrivePartition, &PartitionEntry))
return EIO;
SectorOffset = PartitionTableEntry.SectorCountBeforePartition;
SectorCount = PartitionTableEntry.PartitionSectorCount;
SectorOffset = PartitionEntry.StartingOffset.QuadPart / SectorSize;
SectorCount = PartitionEntry.PartitionLength.QuadPart / SectorSize;
}
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 = Geometry.Sectors;
}
@@ -202,7 +201,7 @@ DiskRead(ULONG FileId, VOID* Buffer, ULONG N, ULONG* Count)
*Count = (ULONG)((ULONG_PTR)Ptr - (ULONG_PTR)Buffer);
Context->SectorNumber = SectorOffset - Context->SectorOffset;
return (!ret) ? EIO : ESUCCESS;
return (ret ? ESUCCESS : EIO);
}
static ARC_STATUS
@@ -406,11 +405,9 @@ DiskGetBootPath(
}
else
{
ULONG BootPartition;
PARTITION_TABLE_ENTRY PartitionEntry;
/* This is a hard disk, find the boot partition */
if (!DiskGetBootPartitionEntry(FrldrBootDrive, &PartitionEntry, &BootPartition))
ULONG BootPartition;
if (!DiskGetBootPartitionEntry(FrldrBootDrive, NULL, &BootPartition))
{
ERR("Failed to get boot partition entry\n");
return FALSE;

View File

@@ -57,6 +57,8 @@ IoSetPartitionInformation(
}
#ifndef _M_AMD64
#include "disk/part_mbr.h" // For PARTITION_TABLE_ENTRY and MASTER_BOOT_RECORD
NTSTATUS
NTAPI
IopReadBootRecord(
@@ -203,7 +205,7 @@ IoReadPartitionTable(
*PartitionBuffer = Partitions;
return STATUS_SUCCESS;
}
#endif // _M_AMD64
#endif // !_M_AMD64
NTSTATUS
FASTCALL

View File

@@ -2,7 +2,7 @@
* PROJECT: FreeLoader UEFI Support
* LICENSE: MIT (https://spdx.org/licenses/MIT)
* PURPOSE: Disk Access Functions
* COPYRIGHT: Copyright 2022 Justin Miller <justinmiller100@gmail.com>
* COPYRIGHT: Copyright 2022-2026 Justin Miller <justin.miller@reactos.org>
*/
/* INCLUDES ******************************************************************/
@@ -169,16 +169,17 @@ DiskReadGptHeader(
static
BOOLEAN
UefiGetBootPartitionEntry(
IN UCHAR DriveNumber,
OUT PPARTITION_TABLE_ENTRY PartitionTableEntry,
OUT PULONG BootPartition)
_In_ UCHAR DriveNumber,
_Out_opt_ PPARTITION_INFORMATION PartitionEntry,
_Out_ PULONG BootPartition)
{
ULONG PartitionNum;
ULONG ArcDriveIndex;
EFI_BLOCK_IO* BootBlockIo;
EFI_STATUS Status;
ULONG BlockSize;
ULONGLONG BootPartitionSize;
PARTITION_TABLE_ENTRY TempPartitionEntry;
PARTITION_INFORMATION TempPartitionEntry;
TRACE("UefiGetBootPartitionEntry: DriveNumber: %d\n", DriveNumber - FIRST_BIOS_DISK);
@@ -206,16 +207,25 @@ UefiGetBootPartitionEntry(
BootPartitionSize = BootBlockIo->Media->LastBlock + 1;
TRACE("Boot partition: Size=%llu blocks, BlockSize=%lu\n",
BootPartitionSize, BootBlockIo->Media->BlockSize);
BootPartitionSize, BootBlockIo->Media->BlockSize);
/* If boot handle is the root device itself (not a logical partition) */
if (!BootBlockIo->Media->LogicalPartition)
{
TRACE("Boot handle is root device, using partition 0\n");
*BootPartition = 0;
if (PartitionTableEntry != NULL)
if (PartitionEntry)
{
RtlZeroMemory(PartitionTableEntry, sizeof(*PartitionTableEntry));
// RtlZeroMemory(PartitionEntry, sizeof(*PartitionEntry));
/* Represent the whole disk */
PartitionEntry->StartingOffset.QuadPart = 0ULL;
PartitionEntry->PartitionLength.QuadPart = (BootPartitionSize * BootBlockIo->Media->BlockSize);
PartitionEntry->HiddenSectors = 0;
PartitionEntry->PartitionNumber = *BootPartition;
PartitionEntry->PartitionType = PARTITION_GPT; /* Mark as GPT partition */
PartitionEntry->BootIndicator = TRUE;
PartitionEntry->RecognizedPartition = TRUE;
PartitionEntry->RewritePartition = FALSE;
}
return TRUE;
}
@@ -228,14 +238,11 @@ UefiGetBootPartitionEntry(
{
/* For GPT, iterate through GPT partition entries */
GPT_PARTITION_ENTRY GptEntry;
ULONG ArcDriveIndex = DriveNumber - FIRST_BIOS_DISK;
EFI_BLOCK_IO* RootBlockIo;
ULONG BlockSize;
ULONGLONG EntryLba;
ULONG EntryOffset;
ULONG EntriesPerBlock;
EFI_STATUS Status;
EFI_GUID UnusedGuid = EFI_PART_TYPE_UNUSED_GUID;
EFI_GUID SystemGuid = EFI_PART_TYPE_EFI_SYSTEM_PART_GUID;
Status = GlobalSystemTable->BootServices->HandleProtocol(
InternalUefiDisk[ArcDriveIndex].Handle,
@@ -251,8 +258,8 @@ UefiGetBootPartitionEntry(
/* Iterate through GPT partition entries */
for (ULONG i = 0; i < GptHeader.NumberOfPartitionEntries; i++)
{
EntryLba = GptHeader.PartitionEntryLba + (i / EntriesPerBlock);
EntryOffset = (i % EntriesPerBlock) * GptHeader.SizeOfPartitionEntry;
ULONGLONG EntryLba = GptHeader.PartitionEntryLba + (i / EntriesPerBlock);
ULONG EntryOffset = (i % EntriesPerBlock) * GptHeader.SizeOfPartitionEntry;
/* Read the block containing the partition entry */
Status = RootBlockIo->ReadBlocks(
@@ -276,28 +283,30 @@ UefiGetBootPartitionEntry(
ULONGLONG PartitionSizeBlocks = GptEntry.EndingLba - GptEntry.StartingLba + 1;
TRACE("GPT Partition %lu: StartLba=%llu, EndLba=%llu, SizeBlocks=%llu\n",
i + 1, GptEntry.StartingLba, GptEntry.EndingLba, PartitionSizeBlocks);
i + 1, GptEntry.StartingLba, GptEntry.EndingLba, PartitionSizeBlocks);
/* Match partition by size (within 1 block tolerance for rounding) */
if (PartitionSizeBlocks == BootPartitionSize ||
(PartitionSizeBlocks > 0 &&
(PartitionSizeBlocks > 0 &&
(PartitionSizeBlocks - 1 <= BootPartitionSize &&
BootPartitionSize <= PartitionSizeBlocks + 1)))
{
TRACE("Found matching GPT partition %lu: Size matches (%llu blocks)\n",
i + 1, BootPartitionSize);
i + 1, BootPartitionSize);
*BootPartition = i + 1; /* GPT partitions are 1-indexed */
/* Convert GPT entry to MBR-style entry for compatibility */
if (PartitionTableEntry != NULL)
/* Convert GPT entry to standard-style entry */
if (PartitionEntry)
{
RtlZeroMemory(PartitionTableEntry, sizeof(*PartitionTableEntry));
ULONGLONG StartSector = (GptEntry.StartingLba * BlockSize) / 512;
ULONGLONG SectorCount = (PartitionSizeBlocks * BlockSize) / 512;
PartitionTableEntry->SectorCountBeforePartition = (ULONG)StartSector;
PartitionTableEntry->PartitionSectorCount = (ULONG)SectorCount;
PartitionTableEntry->SystemIndicator = PARTITION_GPT;
PartitionEntry->StartingOffset.QuadPart = (GptEntry.StartingLba * BlockSize);
PartitionEntry->PartitionLength.QuadPart = ((ULONGLONG)PartitionSizeBlocks * BlockSize);
PartitionEntry->HiddenSectors = 0;
PartitionEntry->PartitionNumber = *BootPartition;
PartitionEntry->PartitionType = PARTITION_GPT; /* Mark as GPT partition */
PartitionEntry->BootIndicator = RtlEqualMemory(&GptEntry.PartitionTypeGuid, &SystemGuid, sizeof(SystemGuid));
PartitionEntry->RecognizedPartition = TRUE;
PartitionEntry->RewritePartition = FALSE;
}
return TRUE;
}
@@ -306,36 +315,32 @@ UefiGetBootPartitionEntry(
else
{
/* MBR partition matching */
BlockSize = BootBlockIo->Media->BlockSize;
PartitionNum = FIRST_PARTITION;
while (DiskGetPartitionEntry(DriveNumber, PartitionNum, &TempPartitionEntry))
while (DiskGetPartitionEntry(DriveNumber, BlockSize, PartitionNum, &TempPartitionEntry))
{
ULONGLONG PartitionSizeSectors = TempPartitionEntry.PartitionSectorCount;
ULONGLONG PartitionSizeBlocks;
/* Convert partition size to UEFI blocks */
ULONGLONG PartitionSizeBlocks = TempPartitionEntry.PartitionLength.QuadPart / BlockSize;
ULONGLONG StartingLba = TempPartitionEntry.StartingOffset.QuadPart / BlockSize;
ULONGLONG EndingLba = StartingLba + PartitionSizeBlocks - 1;
/* Convert partition size from MBR sectors (always 512 bytes) to UEFI blocks.
* MBR partition table always uses 512-byte sectors per specification.
* UEFI Block I/O protocol reports sizes in device's BlockSize bytes. */
/* Compare in bytes to avoid rounding issues, then convert to boot partition's block size */
ULONGLONG PartitionSizeBytes = PartitionSizeSectors * 512ULL;
PartitionSizeBlocks = PartitionSizeBytes / BootBlockIo->Media->BlockSize;
TRACE("Partition %lu: SizeSectors=%llu, SizeBlocks=%llu\n",
PartitionNum, PartitionSizeSectors, PartitionSizeBlocks);
TRACE("Partition %lu: StartLba=%llu, EndLba=%llu, SizeBlocks=%llu\n",
PartitionNum, StartingLba, EndingLba, PartitionSizeBlocks);
/* Match partition by size (within 1 block tolerance for rounding) */
if (PartitionSizeBlocks == BootPartitionSize ||
(PartitionSizeBlocks > 0 &&
(PartitionSizeBlocks > 0 &&
(PartitionSizeBlocks - 1 <= BootPartitionSize &&
BootPartitionSize <= PartitionSizeBlocks + 1)))
{
TRACE("Found matching partition %lu: Size matches (%llu blocks)\n",
PartitionNum, BootPartitionSize);
PartitionNum, BootPartitionSize);
*BootPartition = PartitionNum;
if (PartitionTableEntry != NULL)
{
RtlCopyMemory(PartitionTableEntry, &TempPartitionEntry, sizeof(*PartitionTableEntry));
}
if (PartitionEntry)
RtlCopyMemory(PartitionEntry, &TempPartitionEntry, sizeof(*PartitionEntry));
return TRUE;
}
@@ -348,9 +353,18 @@ UefiGetBootPartitionEntry(
{
TRACE("Boot device is CD-ROM, using partition 0xFF\n");
*BootPartition = 0xFF;
if (PartitionTableEntry != NULL)
if (PartitionEntry)
{
RtlZeroMemory(PartitionTableEntry, sizeof(*PartitionTableEntry));
// RtlZeroMemory(PartitionEntry, sizeof(*PartitionEntry));
/* Represent the whole disk */
PartitionEntry->StartingOffset.QuadPart = 0ULL;
PartitionEntry->PartitionLength.QuadPart = (BootPartitionSize * BootBlockIo->Media->BlockSize);
PartitionEntry->HiddenSectors = 0;
PartitionEntry->PartitionNumber = *BootPartition;
PartitionEntry->PartitionType = PARTITION_GPT; /* Mark as GPT partition */
PartitionEntry->BootIndicator = TRUE;
PartitionEntry->RecognizedPartition = TRUE;
PartitionEntry->RewritePartition = FALSE;
}
return TRUE;
}
@@ -358,13 +372,12 @@ UefiGetBootPartitionEntry(
/* Fallback: if we can't determine, use partition 1 */
ERR("Could not determine boot partition, using partition 1 as fallback\n");
PartitionNum = FIRST_PARTITION;
if (DiskGetPartitionEntry(DriveNumber, PartitionNum, &TempPartitionEntry))
if (DiskGetPartitionEntry(DriveNumber, BootBlockIo->Media->BlockSize,
PartitionNum, &TempPartitionEntry))
{
*BootPartition = PartitionNum;
if (PartitionTableEntry != NULL)
{
RtlCopyMemory(PartitionTableEntry, &TempPartitionEntry, sizeof(*PartitionTableEntry));
}
if (PartitionEntry)
RtlCopyMemory(PartitionEntry, &TempPartitionEntry, sizeof(*PartitionEntry));
return TRUE;
}
@@ -409,10 +422,9 @@ UefiDiskOpen(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
DISKCONTEXT* Context;
UCHAR DriveNumber;
ULONG DrivePartition, SectorSize;
ULONGLONG SectorOffset = 0;
ULONGLONG SectorCount = 0;
ULONGLONG SectorOffset;
ULONGLONG SectorCount;
ULONG ArcDriveIndex;
PARTITION_TABLE_ENTRY PartitionTableEntry;
EFI_BLOCK_IO* BlockIo;
EFI_STATUS Status;
@@ -453,33 +465,29 @@ UefiDiskOpen(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
if (!BlockIo->Media->MediaPresent)
{
ERR("Media not present for drive %d\n", DriveNumber);
return EINVAL;
return ENXIO;
}
#if 0
GEOMETRY Geometry;
if (!MachDiskGetDriveGeometry(DriveNumber, &Geometry))
return EIO;
#endif
SectorSize = BlockIo->Media->BlockSize;
if (DrivePartition != 0xff && DrivePartition != 0)
{
if (!DiskGetPartitionEntry(DriveNumber, DrivePartition, &PartitionTableEntry))
return EINVAL;
PARTITION_INFORMATION PartitionEntry;
if (!DiskGetPartitionEntry(DriveNumber, SectorSize, DrivePartition, &PartitionEntry))
return EIO;
SectorOffset = PartitionTableEntry.SectorCountBeforePartition;
SectorCount = PartitionTableEntry.PartitionSectorCount;
SectorOffset = PartitionEntry.StartingOffset.QuadPart / SectorSize;
SectorCount = PartitionEntry.PartitionLength.QuadPart / SectorSize;
}
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 = Geometry.Sectors;
SectorCount = BlockIo->Media->LastBlock + 1; // Geometry.Sectors;
}
Context = FrLdrTempAlloc(sizeof(DISKCONTEXT), TAG_HW_DISK_CONTEXT);
@@ -492,6 +500,7 @@ UefiDiskOpen(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
Context->SectorCount = SectorCount;
Context->SectorNumber = 0;
FsSetDeviceSpecific(*FileId, Context);
return ESUCCESS;
}
@@ -998,7 +1007,6 @@ UefiSetBootpath(VOID)
else
{
ULONG BootPartition;
PARTITION_TABLE_ENTRY PartitionEntry;
/* This is a hard disk */
/* If boot handle is a logical partition, we need to determine which partition number */
@@ -1013,7 +1021,7 @@ UefiSetBootpath(VOID)
else
{
/* Boot handle is the root device itself */
if (!UefiGetBootPartitionEntry(FrldrBootDrive, &PartitionEntry, &BootPartition))
if (!UefiGetBootPartitionEntry(FrldrBootDrive, NULL, &BootPartition))
{
ERR("Failed to get boot partition entry\n");
return FALSE;

View File

@@ -13,7 +13,8 @@
#include <debug.h>
DBG_DEFAULT_CHANNEL(DISK);
#include "disk/part_gpt.h"
#include "part_mbr.h" // FIXME: For MASTER_BOOT_RECORD
#include "part_gpt.h"
// Defined in part_gpt.c
extern BOOLEAN
@@ -85,30 +86,34 @@ DiskInitialize(
{
PMASTER_BOOT_RECORD Mbr;
PULONG Buffer;
GEOMETRY Geometry;
ULONGLONG SectorStart;
ULONG SectorSize;
ULONG MbrSectorSize;
ULONG i;
ULONG Checksum, Signature;
BOOLEAN ValidPartitionTable;
BOOLEAN IsCdRom;
PGUID GptDiskGuid = NULL;
GPT_TABLE_HEADER GptHeader;
PARTITION_TABLE_ENTRY PartitionTableEntry;
PARTITION_INFORMATION PartitionEntry;
CHAR ArcName[MAX_PATH];
NTSTATUS NtStatus;
TRACE("DiskInitialize(0x%02X, '%s', Type: %lu)\n", DriveNumber, DeviceName, DeviceType);
if (!MachDiskGetDriveGeometry(DriveNumber, &Geometry))
return FALSE;
IsCdRom = (DeviceType == CdromController);
if (IsCdRom)
{
SectorStart = 16ULL;
SectorSize = 2048;
MbrSectorSize = 2048;
}
else // (DeviceType == FloppyDiskPeripheral || DiskPeripheral)
{
SectorStart = 0ULL;
SectorSize = 512;
MbrSectorSize = 512;
}
/* Read the MBR */
@@ -126,7 +131,7 @@ DiskInitialize(
/* Calculate the MBR checksum */
Checksum = 0;
for (i = 0; i < SectorSize / sizeof(ULONG); i++)
for (i = 0; i < MbrSectorSize / sizeof(ULONG); i++)
{
Checksum += Buffer[i];
}
@@ -185,9 +190,9 @@ DiskInitialize(
/* Add partitions */
i = FIRST_PARTITION;
while (DiskGetPartitionEntry(DriveNumber, i, &PartitionTableEntry))
while (DiskGetPartitionEntry(DriveNumber, Geometry.BytesPerSector, i, &PartitionEntry))
{
if (PartitionTableEntry.SystemIndicator != PARTITION_ENTRY_UNUSED)
if (PartitionEntry.PartitionType != PARTITION_ENTRY_UNUSED)
{
NtStatus = RtlStringCbPrintfA(ArcName, sizeof(ArcName),
"%spartition(%lu)", DeviceName, i);

View File

@@ -18,9 +18,9 @@
static struct
{
ULONG SectorCountBeforePartition;
ULONG PartitionSectorCount;
UCHAR SystemIndicator;
ULONG SectorStart;
ULONG SectorCount;
UCHAR PartitionType;
} XboxPartitions[] =
{
/* This is in the \Device\Harddisk0\Partition.. order used by the Xbox kernel */
@@ -31,33 +31,45 @@ static struct
{ 0x002EE400, 0x00177000, PARTITION_FAT_16 } /* Cache3, Z: */
};
static BOOLEAN
DiskIsBrfr(
_In_ UCHAR DriveNumber)
{
/* Read the Xbox-specific sector */
if (!MachDiskReadLogicalSectors(DriveNumber, XBOX_SIGNATURE_SECTOR, 1, DiskReadBuffer))
return FALSE; /* Partition does not exist */
/* Verify the magic Xbox signature */
return (*((PULONG)DiskReadBuffer) == XBOX_SIGNATURE);
}
BOOLEAN
DiskGetBrfrPartitionEntry(
IN UCHAR DriveNumber,
IN ULONG PartitionNumber,
OUT PPARTITION_TABLE_ENTRY PartitionTableEntry)
_In_ UCHAR DriveNumber,
_In_ ULONG SectorSize,
_In_ ULONG PartitionNumber,
_Out_ PPARTITION_INFORMATION PartitionEntry)
{
/*
* Get partition entry of an Xbox-standard BRFR partitioned disk.
*/
if (PartitionNumber >= 1 && PartitionNumber <= RTL_NUMBER_OF(XboxPartitions) &&
MachDiskReadLogicalSectors(DriveNumber, XBOX_SIGNATURE_SECTOR, 1, DiskReadBuffer))
{
if (*((PULONG)DiskReadBuffer) != XBOX_SIGNATURE)
{
/* No magic Xbox partitions */
return FALSE;
}
ASSERT(SectorSize >= 512);
RtlZeroMemory(PartitionTableEntry, sizeof(PARTITION_TABLE_ENTRY));
PartitionTableEntry->SystemIndicator = XboxPartitions[PartitionNumber - 1].SystemIndicator;
PartitionTableEntry->SectorCountBeforePartition = XboxPartitions[PartitionNumber - 1].SectorCountBeforePartition;
PartitionTableEntry->PartitionSectorCount = XboxPartitions[PartitionNumber - 1].PartitionSectorCount;
return TRUE;
}
if (!DiskIsBrfr(DriveNumber))
return FALSE; /* No magic Xbox partitions */
/* Partition does not exist */
return FALSE;
/* Get partition entry of an Xbox-standard BRFR partitioned disk */
if (!(1 <= PartitionNumber && PartitionNumber <= RTL_NUMBER_OF(XboxPartitions)))
return FALSE; /* Partition does not exist */
/* Convert to standard-style entry */
PartitionEntry->StartingOffset.QuadPart = (ULONGLONG)XboxPartitions[PartitionNumber - 1].SectorStart * SectorSize;
PartitionEntry->PartitionLength.QuadPart = (ULONGLONG)XboxPartitions[PartitionNumber - 1].SectorCount * SectorSize;
PartitionEntry->HiddenSectors = 0;
PartitionEntry->PartitionNumber = PartitionNumber;
PartitionEntry->PartitionType = XboxPartitions[PartitionNumber - 1].PartitionType;
PartitionEntry->BootIndicator = (PartitionNumber == FATX_DATA_PARTITION);
PartitionEntry->RecognizedPartition = TRUE;
PartitionEntry->RewritePartition = FALSE;
return TRUE;
}
#endif

View File

@@ -45,34 +45,33 @@ DiskReadGptHeader(
BOOLEAN
DiskGetGptPartitionEntry(
_In_ UCHAR DriveNumber,
_In_ ULONG SectorSize, // BlockSize
_In_ ULONG PartitionNumber,
_Out_ PPARTITION_TABLE_ENTRY PartitionTableEntry)
_Out_ PPARTITION_INFORMATION PartitionEntry)
{
GPT_TABLE_HEADER GptHeader;
GPT_PARTITION_ENTRY GptEntry;
GEOMETRY Geometry;
ULONG BlockSize;
ULONGLONG EntryLba;
ULONG EntryOffset;
ULONG EntriesPerBlock;
GUID UnusedGuid = EFI_PART_TYPE_UNUSED_GUID;
GUID SystemGuid = EFI_PART_TYPE_EFI_SYSTEM_PART_GUID;
if (!MachDiskGetDriveGeometry(DriveNumber, &Geometry))
return FALSE;
BlockSize = Geometry.BytesPerSector;
ASSERT(SectorSize >= 512);
/* Read GPT header */
if (!DiskReadGptHeader(DriveNumber, &GptHeader))
return FALSE;
/* Validate partition number */
if (PartitionNumber == 0 || PartitionNumber > GptHeader.NumberOfPartitionEntries)
//if (PartitionNumber == 0 || PartitionNumber > GptHeader.NumberOfPartitionEntries)
if (!(1 <= PartitionNumber && PartitionNumber <= GptHeader.NumberOfPartitionEntries))
return FALSE;
/* Convert to 0-based index */
ULONG EntryIndex = PartitionNumber - 1;
EntriesPerBlock = BlockSize / GptHeader.SizeOfPartitionEntry;
EntriesPerBlock = SectorSize / GptHeader.SizeOfPartitionEntry;
EntryLba = GptHeader.PartitionEntryLba + (EntryIndex / EntriesPerBlock);
EntryOffset = (EntryIndex % EntriesPerBlock) * GptHeader.SizeOfPartitionEntry;
@@ -87,20 +86,18 @@ DiskGetGptPartitionEntry(
if (RtlEqualMemory(&GptEntry.PartitionTypeGuid, &UnusedGuid, sizeof(UnusedGuid)))
return FALSE;
/* Convert GPT entry to MBR-style PARTITION_TABLE_ENTRY */
RtlZeroMemory(PartitionTableEntry, sizeof(*PartitionTableEntry));
/* Calculate partition size in blocks */
ULONGLONG PartitionSizeBlocks = GptEntry.EndingLba - GptEntry.StartingLba + 1;
/* Calculate sector offset and count.
* GPT uses LBA, convert to 512-byte sectors. */
ULONGLONG SectorCount = (GptEntry.EndingLba - GptEntry.StartingLba + 1);
/* For GPT, we need to convert from device block size to 512-byte sectors */
ULONGLONG StartSector = (GptEntry.StartingLba * BlockSize) / 512;
ULONGLONG SectorCount512 = (SectorCount * BlockSize) / 512;
PartitionTableEntry->SectorCountBeforePartition = (ULONG)StartSector;
PartitionTableEntry->PartitionSectorCount = (ULONG)SectorCount512;
PartitionTableEntry->SystemIndicator = PARTITION_GPT; /* Mark as GPT partition */
/* Convert GPT entry to standard-style entry */
PartitionEntry->StartingOffset.QuadPart = (GptEntry.StartingLba * SectorSize);
PartitionEntry->PartitionLength.QuadPart = (PartitionSizeBlocks * SectorSize);
PartitionEntry->HiddenSectors = 0;
PartitionEntry->PartitionNumber = PartitionNumber;
PartitionEntry->PartitionType = PARTITION_GPT; /* Mark as GPT partition */
PartitionEntry->BootIndicator = RtlEqualMemory(&GptEntry.PartitionTypeGuid, &SystemGuid, sizeof(SystemGuid));
PartitionEntry->RecognizedPartition = TRUE;
PartitionEntry->RewritePartition = FALSE;
return TRUE;
}

View File

@@ -15,8 +15,8 @@
static BOOLEAN
DiskGetFirstPartitionEntry(
IN PMASTER_BOOT_RECORD MasterBootRecord,
OUT PPARTITION_TABLE_ENTRY PartitionTableEntry)
_In_ PMASTER_BOOT_RECORD MasterBootRecord,
_Out_ PPARTITION_TABLE_ENTRY* pPartitionTableEntry)
{
ULONG Index;
@@ -27,7 +27,7 @@ DiskGetFirstPartitionEntry(
(MasterBootRecord->PartitionTable[Index].SystemIndicator != PARTITION_EXTENDED) &&
(MasterBootRecord->PartitionTable[Index].SystemIndicator != PARTITION_XINT13_EXTENDED))
{
RtlCopyMemory(PartitionTableEntry, &MasterBootRecord->PartitionTable[Index], sizeof(PARTITION_TABLE_ENTRY));
*pPartitionTableEntry = &MasterBootRecord->PartitionTable[Index];
return TRUE;
}
}
@@ -37,8 +37,8 @@ DiskGetFirstPartitionEntry(
static BOOLEAN
DiskGetFirstExtendedPartitionEntry(
IN PMASTER_BOOT_RECORD MasterBootRecord,
OUT PPARTITION_TABLE_ENTRY PartitionTableEntry)
_In_ PMASTER_BOOT_RECORD MasterBootRecord,
_Out_ PPARTITION_TABLE_ENTRY* pPartitionTableEntry)
{
ULONG Index;
@@ -48,7 +48,7 @@ DiskGetFirstExtendedPartitionEntry(
if ((MasterBootRecord->PartitionTable[Index].SystemIndicator == PARTITION_EXTENDED) ||
(MasterBootRecord->PartitionTable[Index].SystemIndicator == PARTITION_XINT13_EXTENDED))
{
RtlCopyMemory(PartitionTableEntry, &MasterBootRecord->PartitionTable[Index], sizeof(PARTITION_TABLE_ENTRY));
*pPartitionTableEntry = &MasterBootRecord->PartitionTable[Index];
return TRUE;
}
}
@@ -56,47 +56,66 @@ DiskGetFirstExtendedPartitionEntry(
return FALSE;
}
static VOID
DiskMbrPartitionTableEntryToInformation(
_Out_ PPARTITION_INFORMATION PartitionEntry,
_In_ PPARTITION_TABLE_ENTRY PartitionTableEntry,
_In_ ULONG PartitionNumber,
_In_ ULONG SectorSize)
{
PartitionEntry->StartingOffset.QuadPart = (ULONGLONG)PartitionTableEntry->SectorCountBeforePartition * SectorSize;
PartitionEntry->PartitionLength.QuadPart = (ULONGLONG)PartitionTableEntry->PartitionSectorCount * SectorSize;
PartitionEntry->HiddenSectors = 0;
PartitionEntry->PartitionNumber = PartitionNumber;
PartitionEntry->PartitionType = PartitionTableEntry->SystemIndicator;
PartitionEntry->BootIndicator = (PartitionTableEntry->BootIndicator == 0x80); // or "& 0x80"
PartitionEntry->RecognizedPartition = TRUE;
PartitionEntry->RewritePartition = FALSE;
}
BOOLEAN
DiskGetActivePartitionEntry(
IN UCHAR DriveNumber,
OUT PPARTITION_TABLE_ENTRY PartitionTableEntry,
OUT PULONG ActivePartition)
_In_ UCHAR DriveNumber,
_In_ ULONG SectorSize,
_Out_opt_ PPARTITION_INFORMATION PartitionEntry,
_Out_ PULONG ActivePartition)
{
MASTER_BOOT_RECORD MasterBootRecord;
ULONG BootablePartitionCount = 0;
ULONG CurrentPartitionNumber;
ULONG Index;
MASTER_BOOT_RECORD MasterBootRecord;
PPARTITION_TABLE_ENTRY ThisPartitionTableEntry;
ASSERT(SectorSize >= 512);
*ActivePartition = 0;
/* Read master boot record */
if (!DiskReadBootRecord(DriveNumber, 0, &MasterBootRecord))
{
return FALSE;
}
CurrentPartitionNumber = 0;
for (Index = 0; Index < 4; Index++)
{
ThisPartitionTableEntry = &MasterBootRecord.PartitionTable[Index];
PPARTITION_TABLE_ENTRY PartitionTableEntry = &MasterBootRecord.PartitionTable[Index];
if (ThisPartitionTableEntry->SystemIndicator != PARTITION_ENTRY_UNUSED &&
ThisPartitionTableEntry->SystemIndicator != PARTITION_EXTENDED &&
ThisPartitionTableEntry->SystemIndicator != PARTITION_XINT13_EXTENDED)
if (PartitionTableEntry->SystemIndicator != PARTITION_ENTRY_UNUSED &&
PartitionTableEntry->SystemIndicator != PARTITION_EXTENDED &&
PartitionTableEntry->SystemIndicator != PARTITION_XINT13_EXTENDED)
{
CurrentPartitionNumber++;
/* Test if this is the bootable partition */
if (ThisPartitionTableEntry->BootIndicator == 0x80)
if (PartitionTableEntry->BootIndicator == 0x80)
{
BootablePartitionCount++;
*ActivePartition = CurrentPartitionNumber;
/* Copy the partition table entry */
RtlCopyMemory(PartitionTableEntry,
ThisPartitionTableEntry,
sizeof(PARTITION_TABLE_ENTRY));
if (PartitionEntry)
{
DiskMbrPartitionTableEntryToInformation(PartitionEntry, PartitionTableEntry,
*ActivePartition, SectorSize);
}
}
}
}
@@ -118,39 +137,44 @@ DiskGetActivePartitionEntry(
BOOLEAN
DiskGetMbrPartitionEntry(
IN UCHAR DriveNumber,
IN ULONG PartitionNumber,
OUT PPARTITION_TABLE_ENTRY PartitionTableEntry)
_In_ UCHAR DriveNumber,
_In_ ULONG SectorSize,
_In_ ULONG PartitionNumber,
_Out_ PPARTITION_INFORMATION PartitionEntry)
{
MASTER_BOOT_RECORD MasterBootRecord;
PARTITION_TABLE_ENTRY ExtendedPartitionTableEntry;
PPARTITION_TABLE_ENTRY PartitionTableEntry;
ULONG ExtendedPartitionNumber;
ULONG ExtendedPartitionOffset;
ULONG Index;
ULONG CurrentPartitionNumber;
PPARTITION_TABLE_ENTRY ThisPartitionTableEntry;
ASSERT(SectorSize >= 512);
/* Validate partition number */
if (PartitionNumber < 1) //if (PartitionNumber == 0)
return FALSE;
/* Read master boot record */
if (!DiskReadBootRecord(DriveNumber, 0, &MasterBootRecord))
{
return FALSE;
}
CurrentPartitionNumber = 0;
for (Index = 0; Index < 4; Index++)
{
ThisPartitionTableEntry = &MasterBootRecord.PartitionTable[Index];
PartitionTableEntry = &MasterBootRecord.PartitionTable[Index];
if (ThisPartitionTableEntry->SystemIndicator != PARTITION_ENTRY_UNUSED &&
ThisPartitionTableEntry->SystemIndicator != PARTITION_EXTENDED &&
ThisPartitionTableEntry->SystemIndicator != PARTITION_XINT13_EXTENDED)
if (PartitionTableEntry->SystemIndicator != PARTITION_ENTRY_UNUSED &&
PartitionTableEntry->SystemIndicator != PARTITION_EXTENDED &&
PartitionTableEntry->SystemIndicator != PARTITION_XINT13_EXTENDED)
{
CurrentPartitionNumber++;
}
if (PartitionNumber == CurrentPartitionNumber)
{
RtlCopyMemory(PartitionTableEntry, ThisPartitionTableEntry, sizeof(PARTITION_TABLE_ENTRY));
DiskMbrPartitionTableEntryToInformation(PartitionEntry, PartitionTableEntry,
PartitionNumber, SectorSize);
return TRUE;
}
}
@@ -171,39 +195,38 @@ DiskGetMbrPartitionEntry(
for (Index = 0; Index <= ExtendedPartitionNumber; Index++)
{
PPARTITION_TABLE_ENTRY ExtendedPartitionTableEntry;
ULONG SectorCountBeforePartition;
/* Get the extended partition table entry */
if (!DiskGetFirstExtendedPartitionEntry(&MasterBootRecord, &ExtendedPartitionTableEntry))
{
return FALSE;
}
/* Adjust the relative starting sector of the partition */
ExtendedPartitionTableEntry.SectorCountBeforePartition += ExtendedPartitionOffset;
ExtendedPartitionTableEntry->SectorCountBeforePartition += ExtendedPartitionOffset;
if (ExtendedPartitionOffset == 0)
{
/* Set the start of the parrent extended partition */
ExtendedPartitionOffset = ExtendedPartitionTableEntry.SectorCountBeforePartition;
/* Set the start of the parent extended partition */
ExtendedPartitionOffset = ExtendedPartitionTableEntry->SectorCountBeforePartition;
}
SectorCountBeforePartition = ExtendedPartitionTableEntry->SectorCountBeforePartition;
/* Read the partition boot record */
if (!DiskReadBootRecord(DriveNumber, ExtendedPartitionTableEntry.SectorCountBeforePartition, &MasterBootRecord))
{
if (!DiskReadBootRecord(DriveNumber, SectorCountBeforePartition, &MasterBootRecord))
return FALSE;
}
/* Get the first real partition table entry */
if (!DiskGetFirstPartitionEntry(&MasterBootRecord, PartitionTableEntry))
{
if (!DiskGetFirstPartitionEntry(&MasterBootRecord, &PartitionTableEntry))
return FALSE;
}
/* Now correct the start sector of the partition */
PartitionTableEntry->SectorCountBeforePartition += ExtendedPartitionTableEntry.SectorCountBeforePartition;
PartitionTableEntry->SectorCountBeforePartition += SectorCountBeforePartition;
}
/*
* When we get here we should have the correct entry already
* stored in PartitionTableEntry, so just return TRUE.
*/
/* When we get here we should have the correct entry already
* stored in PartitionTableEntry, so just return TRUE. */
DiskMbrPartitionTableEntryToInformation(PartitionEntry, PartitionTableEntry,
PartitionNumber, SectorSize);
return TRUE;
}

View File

@@ -5,6 +5,7 @@
* PURPOSE: Block Device partition management
* COPYRIGHT: Copyright 2002-2003 Brian Palmer <brianp@sginet.com>
* Copyright 2019 Stanislav Motylkov <x86corez@gmail.com>
* Copyright 2025-2026 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
*/
#ifndef _M_ARM
@@ -16,6 +17,8 @@ DBG_DEFAULT_CHANNEL(DISK);
#define MaxDriveNumber 0xFF
static PARTITION_STYLE DiskPartitionType[MaxDriveNumber + 1];
#include "part_mbr.h" // FIXME: For MASTER_BOOT_RECORD
BOOLEAN
DiskReadBootRecord(
IN UCHAR DriveNumber,
@@ -56,15 +59,14 @@ DiskReadBootRecord(
}
#include "part_mbr.c"
#include "part_brfr.c"
#include "part_gpt.c"
#include "part_brfr.c"
VOID
DiskDetectPartitionType(
IN UCHAR DriveNumber)
_In_ UCHAR DriveNumber)
{
MASTER_BOOT_RECORD MasterBootRecord;
PARTITION_TABLE_ENTRY PartitionTableEntry;
/* Probe for Master Boot Record */
if (DiskReadBootRecord(DriveNumber, 0, &MasterBootRecord))
@@ -82,17 +84,13 @@ DiskDetectPartitionType(
/* Check for GUID Partition Table */
for (Index = 0; Index < 4; Index++)
{
PPARTITION_TABLE_ENTRY ThisPartitionTableEntry;
ThisPartitionTableEntry = &MasterBootRecord.PartitionTable[Index];
PPARTITION_TABLE_ENTRY PartitionTableEntry = &MasterBootRecord.PartitionTable[Index];
if (ThisPartitionTableEntry->SystemIndicator != PARTITION_ENTRY_UNUSED)
if (PartitionTableEntry->SystemIndicator != PARTITION_ENTRY_UNUSED)
{
PartitionCount++;
if (Index == 0 && ThisPartitionTableEntry->SystemIndicator == PARTITION_GPT)
{
if (Index == 0 && PartitionTableEntry->SystemIndicator == PARTITION_GPT)
GPTProtect = TRUE;
}
}
}
@@ -108,14 +106,14 @@ DiskDetectPartitionType(
}
/* Probe for Xbox-BRFR partitioning */
if (DiskGetBrfrPartitionEntry(DriveNumber, FATX_DATA_PARTITION, &PartitionTableEntry))
if (DiskIsBrfr(DriveNumber))
{
DiskPartitionType[DriveNumber] = PARTITION_STYLE_BRFR;
TRACE("Drive 0x%X partition type Xbox-BRFR\n", DriveNumber);
return;
}
/* Failed to detect partitions, assume partitionless disk */
/* Failed to detect partitions, assume non-partitioned disk */
DiskPartitionType[DriveNumber] = PARTITION_STYLE_RAW;
TRACE("Drive 0x%X partition type unknown\n", DriveNumber);
}
@@ -123,15 +121,24 @@ DiskDetectPartitionType(
// FIXME: This function is specific to BIOS-based PC platform.
BOOLEAN
DiskGetBootPartitionEntry(
IN UCHAR DriveNumber,
OUT PPARTITION_TABLE_ENTRY PartitionTableEntry,
OUT PULONG BootPartition)
_In_ UCHAR DriveNumber,
_Out_opt_ PPARTITION_INFORMATION PartitionEntry,
_Out_ PULONG BootPartition)
{
#if 0
GEOMETRY Geometry;
if (!MachDiskGetDriveGeometry(DriveNumber, &Geometry))
return FALSE;
#endif
switch (DiskPartitionType[DriveNumber])
{
case PARTITION_STYLE_MBR:
{
return DiskGetActivePartitionEntry(DriveNumber, PartitionTableEntry, BootPartition);
return DiskGetActivePartitionEntry(DriveNumber,
/* MBR partition table always uses 512-byte sectors per specification */
512, // Geometry.BytesPerSector
PartitionEntry, BootPartition);
}
case PARTITION_STYLE_GPT:
{
@@ -145,7 +152,13 @@ DiskGetBootPartitionEntry(
}
case PARTITION_STYLE_BRFR:
{
if (DiskGetBrfrPartitionEntry(DriveNumber, FATX_DATA_PARTITION, PartitionTableEntry))
PARTITION_INFORMATION TempPartitionEntry;
if (!PartitionEntry)
PartitionEntry = &TempPartitionEntry;
if (DiskGetBrfrPartitionEntry(DriveNumber,
512, // Geometry.BytesPerSector
FATX_DATA_PARTITION,
PartitionEntry))
{
*BootPartition = FATX_DATA_PARTITION;
return TRUE;
@@ -163,19 +176,40 @@ DiskGetBootPartitionEntry(
BOOLEAN
DiskGetPartitionEntry(
IN UCHAR DriveNumber,
IN ULONG PartitionNumber,
OUT PPARTITION_TABLE_ENTRY PartitionTableEntry)
_In_ UCHAR DriveNumber,
_In_opt_ ULONG SectorSize,
_In_ ULONG PartitionNumber,
_Out_ PPARTITION_INFORMATION PartitionEntry)
{
if (SectorSize == 0)
{
GEOMETRY Geometry;
if (!MachDiskGetDriveGeometry(DriveNumber, &Geometry))
return FALSE;
SectorSize = Geometry.BytesPerSector;
}
if (SectorSize < 512)
{
ERR("Drive 0x%X: Invalid sector size %lu\n", DriveNumber, SectorSize);
return FALSE;
}
switch (DiskPartitionType[DriveNumber])
{
case PARTITION_STYLE_MBR:
{
return DiskGetMbrPartitionEntry(DriveNumber, PartitionNumber, PartitionTableEntry);
return DiskGetMbrPartitionEntry(DriveNumber,
/* MBR partition table always uses 512-byte sectors per specification */
512, // SectorSize
PartitionNumber,
PartitionEntry);
}
case PARTITION_STYLE_GPT:
{
return DiskGetGptPartitionEntry(DriveNumber, PartitionNumber, PartitionTableEntry);
return DiskGetGptPartitionEntry(DriveNumber,
SectorSize,
PartitionNumber,
PartitionEntry);
}
case PARTITION_STYLE_RAW:
{
@@ -184,7 +218,10 @@ DiskGetPartitionEntry(
}
case PARTITION_STYLE_BRFR:
{
return DiskGetBrfrPartitionEntry(DriveNumber, PartitionNumber, PartitionTableEntry);
return DiskGetBrfrPartitionEntry(DriveNumber,
512, // SectorSize
PartitionNumber,
PartitionEntry);
}
default:
{

View File

@@ -29,9 +29,6 @@ typedef struct _GEOMETRY
ULONGLONG Sectors; ///< Total number of disk sectors/LBA blocks
} GEOMETRY, *PGEOMETRY;
// Some modules use the explicit MBR structures. TODO: Deprecate
#include "disk/part_mbr.h"
/*
* Partition type defines (of PSDK)
*/
@@ -111,19 +108,20 @@ DiskInitialize(
VOID
DiskDetectPartitionType(
IN UCHAR DriveNumber);
_In_ UCHAR DriveNumber);
BOOLEAN
DiskGetBootPartitionEntry(
IN UCHAR DriveNumber,
OUT PPARTITION_TABLE_ENTRY PartitionTableEntry,
OUT PULONG BootPartition);
_In_ UCHAR DriveNumber,
_Out_opt_ PPARTITION_INFORMATION PartitionEntry,
_Out_ PULONG BootPartition);
BOOLEAN
DiskGetPartitionEntry(
IN UCHAR DriveNumber,
IN ULONG PartitionNumber,
OUT PPARTITION_TABLE_ENTRY PartitionTableEntry);
_In_ UCHAR DriveNumber,
_In_opt_ ULONG SectorSize,
_In_ ULONG PartitionNumber,
_Out_ PPARTITION_INFORMATION PartitionEntry);
/*