[FREELDR] Implement proper partition type detection and handling (#1762)

- This allows to detect and dynamically handle different partitioning schemes.
- Implemented detection of MBR, GPT, Xbox-BRFR, and partitionless disks.
- Currently only MBR and Xbox-BRFR partitions are handled and tested.

CORE-9841 CORE-15768 CORE-16216 CORE-16248
This commit is contained in:
Stanislav Motylkov 2019-07-29 15:25:54 +03:00 committed by Hermès BÉLUSCA - MAÏTO
parent 8831328081
commit 06b77b8572
9 changed files with 184 additions and 72 deletions

View file

@ -231,6 +231,9 @@ GetHarddiskInformation(UCHAR DriveNumber)
PARTITION_TABLE_ENTRY PartitionTableEntry;
PCHAR Identifier = PcDiskIdentifier[DriveNumber - 0x80];
/* Detect disk partition type */
DiskDetectPartitionType(DriveNumber);
/* Read the MBR */
if (!MachDiskReadLogicalSectors(DriveNumber, 0ULL, 1, DiskReadBuffer))
{

View file

@ -1422,8 +1422,6 @@ PcMachInit(const char *CmdLine)
MachVtbl.InitializeBootDevices = PcInitializeBootDevices;
MachVtbl.HwDetect = PcHwDetect;
MachVtbl.HwIdle = PcHwIdle;
// DiskGetPartitionEntry = DiskGetMbrPartitionEntry; // Default
}
VOID

View file

@ -231,8 +231,6 @@ XboxMachInit(const char *CmdLine)
MachVtbl.HwDetect = XboxHwDetect;
MachVtbl.HwIdle = XboxHwIdle;
DiskGetPartitionEntry = XboxDiskGetPartitionEntry;
/* Set LEDs to orange after init */
XboxSetLED("oooo");
}

View file

@ -30,25 +30,6 @@ DBG_DEFAULT_CHANNEL(DISK);
#define XBOX_IDE_COMMAND_PORT 0x1f0
#define XBOX_IDE_CONTROL_PORT 0x170
/* BRFR signature at disk offset 0x600 */
#define XBOX_SIGNATURE_SECTOR 3
#define XBOX_SIGNATURE ('B' | ('R' << 8) | ('F' << 16) | ('R' << 24))
static struct
{
ULONG SectorCountBeforePartition;
ULONG PartitionSectorCount;
UCHAR SystemIndicator;
} XboxPartitions[] =
{
/* This is in the \Device\Harddisk0\Partition.. order used by the Xbox kernel */
{ 0x0055F400, 0x0098f800, PARTITION_FAT32 }, /* Store , E: */
{ 0x00465400, 0x000FA000, PARTITION_FAT_16 }, /* System, C: */
{ 0x00000400, 0x00177000, PARTITION_FAT_16 }, /* Cache1, X: */
{ 0x00177400, 0x00177000, PARTITION_FAT_16 }, /* Cache2, Y: */
{ 0x002EE400, 0x00177000, PARTITION_FAT_16 } /* Cache3, Z: */
};
#define IDE_SECTOR_BUF_SZ 512
#define IDE_MAX_POLL_RETRIES 100000
#define IDE_MAX_BUSY_RETRIES 50000
@ -471,32 +452,6 @@ XboxDiskReadLogicalSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG Sect
return TRUE;
}
BOOLEAN
XboxDiskGetPartitionEntry(UCHAR DriveNumber, ULONG PartitionNumber, PPARTITION_TABLE_ENTRY PartitionTableEntry)
{
UCHAR SectorData[IDE_SECTOR_BUF_SZ];
/*
* This is the Xbox, chances are that there is a Xbox-standard
* partitionless disk in it so let's check that first.
*/
if (PartitionNumber >= 1 && PartitionNumber <= sizeof(XboxPartitions) / sizeof(XboxPartitions[0]) &&
MachDiskReadLogicalSectors(DriveNumber, XBOX_SIGNATURE_SECTOR, 1, SectorData))
{
if (*((PULONG) SectorData) == XBOX_SIGNATURE)
{
memset(PartitionTableEntry, 0, sizeof(PARTITION_TABLE_ENTRY));
PartitionTableEntry->SystemIndicator = XboxPartitions[PartitionNumber - 1].SystemIndicator;
PartitionTableEntry->SectorCountBeforePartition = XboxPartitions[PartitionNumber - 1].SectorCountBeforePartition;
PartitionTableEntry->PartitionSectorCount = XboxPartitions[PartitionNumber - 1].PartitionSectorCount;
return TRUE;
}
}
/* No magic Xbox partitions, maybe there's a MBR */
return DiskGetMbrPartitionEntry(DriveNumber, PartitionNumber, PartitionTableEntry);
}
BOOLEAN
XboxDiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry)
{

View file

@ -130,9 +130,9 @@ BOOLEAN DiskGetBootPath(OUT PCHAR BootPath, IN ULONG Size)
PARTITION_TABLE_ENTRY PartitionEntry;
/* This is a hard disk */
if (!DiskGetActivePartitionEntry(FrldrBootDrive, &PartitionEntry, &BootPartition))
if (!DiskGetBootPartitionEntry(FrldrBootDrive, &PartitionEntry, &BootPartition))
{
ERR("Invalid active partition information\n");
ERR("Failed to get boot partition entry\n");
return FALSE;
}

View file

@ -17,11 +17,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* TODO: This is here where we should add support for GPT partitions
* as well as partitionless disks!
*/
#ifndef _M_ARM
#include <freeldr.h>
@ -29,8 +24,30 @@
DBG_DEFAULT_CHANNEL(DISK);
/* This function serves to retrieve a partition entry for devices that handle partitions differently */
DISK_GET_PARTITION_ENTRY DiskGetPartitionEntry = DiskGetMbrPartitionEntry;
#define MaxDriveNumber 0xFF
PARTITION_STYLE DiskPartitionType[MaxDriveNumber + 1];
/* BRFR signature at disk offset 0x600 */
#define XBOX_SIGNATURE_SECTOR 3
#define XBOX_SIGNATURE ('B' | ('R' << 8) | ('F' << 16) | ('R' << 24))
/* Default hardcoded partition number to boot from Xbox disk */
#define FATX_DATA_PARTITION 1
static struct
{
ULONG SectorCountBeforePartition;
ULONG PartitionSectorCount;
UCHAR SystemIndicator;
} XboxPartitions[] =
{
/* This is in the \Device\Harddisk0\Partition.. order used by the Xbox kernel */
{ 0x0055F400, 0x0098F800, PARTITION_FAT32 }, /* Store , E: */
{ 0x00465400, 0x000FA000, PARTITION_FAT_16 }, /* System, C: */
{ 0x00000400, 0x00177000, PARTITION_FAT_16 }, /* Cache1, X: */
{ 0x00177400, 0x00177000, PARTITION_FAT_16 }, /* Cache2, Y: */
{ 0x002EE400, 0x00177000, PARTITION_FAT_16 } /* Cache3, Z: */
};
BOOLEAN DiskGetActivePartitionEntry(UCHAR DriveNumber,
PPARTITION_TABLE_ENTRY PartitionTableEntry,
@ -253,6 +270,152 @@ BOOLEAN DiskReadBootRecord(UCHAR DriveNumber, ULONGLONG LogicalSectorNumber, PMA
return TRUE;
}
BOOLEAN
DiskGetBrfrPartitionEntry(UCHAR DriveNumber, ULONG PartitionNumber, PPARTITION_TABLE_ENTRY PartitionTableEntry)
{
/*
* Get partition entry of an Xbox-standard BRFR partitioned disk.
*/
if (PartitionNumber >= 1 && PartitionNumber <= sizeof(XboxPartitions) / sizeof(XboxPartitions[0]) &&
MachDiskReadLogicalSectors(DriveNumber, XBOX_SIGNATURE_SECTOR, 1, DiskReadBuffer))
{
if (*((PULONG)DiskReadBuffer) != XBOX_SIGNATURE)
{
/* No magic Xbox partitions */
return FALSE;
}
memset(PartitionTableEntry, 0, sizeof(PARTITION_TABLE_ENTRY));
PartitionTableEntry->SystemIndicator = XboxPartitions[PartitionNumber - 1].SystemIndicator;
PartitionTableEntry->SectorCountBeforePartition = XboxPartitions[PartitionNumber - 1].SectorCountBeforePartition;
PartitionTableEntry->PartitionSectorCount = XboxPartitions[PartitionNumber - 1].PartitionSectorCount;
return TRUE;
}
/* Partition does not exist */
return FALSE;
}
VOID DiskDetectPartitionType(UCHAR DriveNumber)
{
MASTER_BOOT_RECORD MasterBootRecord;
ULONG Index;
ULONG PartitionCount = 0;
PPARTITION_TABLE_ENTRY ThisPartitionTableEntry;
BOOLEAN GPTProtect = FALSE;
PARTITION_TABLE_ENTRY PartitionTableEntry;
/* Probe for Master Boot Record */
if (DiskReadBootRecord(DriveNumber, 0, &MasterBootRecord))
{
DiskPartitionType[DriveNumber] = PARTITION_STYLE_MBR;
/* Check for GUID Partition Table */
for (Index = 0; Index < 4; Index++)
{
ThisPartitionTableEntry = &MasterBootRecord.PartitionTable[Index];
if (ThisPartitionTableEntry->SystemIndicator != PARTITION_ENTRY_UNUSED)
{
PartitionCount++;
if (Index == 0 && ThisPartitionTableEntry->SystemIndicator == PARTITION_GPT)
{
GPTProtect = TRUE;
}
}
}
if (PartitionCount == 1 && GPTProtect)
{
DiskPartitionType[DriveNumber] = PARTITION_STYLE_GPT;
}
TRACE("Drive 0x%X partition type %s\n", DriveNumber, DiskPartitionType[DriveNumber] == PARTITION_STYLE_MBR ? "MBR" : "GPT");
return;
}
/* Probe for Xbox-BRFR partitioning */
if (DiskGetBrfrPartitionEntry(DriveNumber, FATX_DATA_PARTITION, &PartitionTableEntry))
{
DiskPartitionType[DriveNumber] = PARTITION_STYLE_BRFR;
TRACE("Drive 0x%X partition type Xbox-BRFR\n", DriveNumber);
return;
}
/* Failed to detect partitions, assume partitionless disk */
DiskPartitionType[DriveNumber] = PARTITION_STYLE_RAW;
TRACE("Drive 0x%X partition type unknown\n", DriveNumber);
}
BOOLEAN DiskGetBootPartitionEntry(UCHAR DriveNumber,
PPARTITION_TABLE_ENTRY PartitionTableEntry,
ULONG *BootPartition)
{
switch (DiskPartitionType[DriveNumber])
{
case PARTITION_STYLE_MBR:
{
return DiskGetActivePartitionEntry(DriveNumber, PartitionTableEntry, BootPartition);
}
case PARTITION_STYLE_GPT:
{
FIXME("DiskGetBootPartitionEntry() unimplemented for GPT\n");
return FALSE;
}
case PARTITION_STYLE_RAW:
{
FIXME("DiskGetBootPartitionEntry() unimplemented for RAW\n");
return FALSE;
}
case PARTITION_STYLE_BRFR:
{
if (DiskGetBrfrPartitionEntry(DriveNumber, FATX_DATA_PARTITION, PartitionTableEntry))
{
*BootPartition = FATX_DATA_PARTITION;
return TRUE;
}
return FALSE;
}
default:
{
ERR("Drive 0x%X partition type = %d, should not happen!\n", DriveNumber, DiskPartitionType[DriveNumber]);
ASSERT(FALSE);
}
}
return FALSE;
}
BOOLEAN DiskGetPartitionEntry(UCHAR DriveNumber, ULONG PartitionNumber, PPARTITION_TABLE_ENTRY PartitionTableEntry)
{
switch (DiskPartitionType[DriveNumber])
{
case PARTITION_STYLE_MBR:
{
return DiskGetMbrPartitionEntry(DriveNumber, PartitionNumber, PartitionTableEntry);
}
case PARTITION_STYLE_GPT:
{
FIXME("DiskGetPartitionEntry() unimplemented for GPT\n");
return FALSE;
}
case PARTITION_STYLE_RAW:
{
FIXME("DiskGetPartitionEntry() unimplemented for RAW\n");
return FALSE;
}
case PARTITION_STYLE_BRFR:
{
return DiskGetBrfrPartitionEntry(DriveNumber, PartitionNumber, PartitionTableEntry);
}
default:
{
ERR("Drive 0x%X partition type = %d, should not happen!\n", DriveNumber, DiskPartitionType[DriveNumber]);
ASSERT(FALSE);
}
}
return FALSE;
}
#ifndef _M_AMD64
NTSTATUS
NTAPI

View file

@ -52,7 +52,6 @@ PVOID XboxMemReserveMemory(ULONG MbToReserve);
PFREELDR_MEMORY_DESCRIPTOR XboxMemGetMemoryMap(ULONG *MemoryMapSize);
BOOLEAN XboxDiskReadLogicalSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer);
BOOLEAN XboxDiskGetPartitionEntry(UCHAR DriveNumber, ULONG PartitionNumber, PPARTITION_TABLE_ENTRY PartitionTableEntry);
BOOLEAN XboxDiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY DriveGeometry);
ULONG XboxDiskGetCacheableBlockCount(UCHAR DriveNumber);

View file

@ -102,6 +102,7 @@ typedef struct _MASTER_BOOT_RECORD
#define PARTITION_UNIX 0x63 // Unix
#define VALID_NTFT 0xC0 // NTFT uses high order bits
#define PARTITION_NTFT 0x80 // NTFT partition
#define PARTITION_GPT 0xEE // GPT protective partition
#ifdef __REACTOS__
#define PARTITION_OLD_LINUX 0x43
#define PARTITION_LINUX 0x83
@ -144,18 +145,9 @@ extern SIZE_T DiskReadBufferSize;
//
///////////////////////////////////////////////////////////////////////////////////////
/* Signature of DiskGetPartitionEntry(...) */
typedef
BOOLEAN
(*DISK_GET_PARTITION_ENTRY)(UCHAR DriveNumber,
ULONG PartitionNumber,
PPARTITION_TABLE_ENTRY PartitionTableEntry);
/* This function serves to retrieve a partition entry for devices that handle partitions differently */
extern DISK_GET_PARTITION_ENTRY DiskGetPartitionEntry;
BOOLEAN DiskGetActivePartitionEntry(UCHAR DriveNumber, PPARTITION_TABLE_ENTRY PartitionTableEntry, ULONG *ActivePartition);
BOOLEAN DiskGetMbrPartitionEntry(UCHAR DriveNumber, ULONG PartitionNumber, PPARTITION_TABLE_ENTRY PartitionTableEntry);
VOID DiskDetectPartitionType(UCHAR DriveNumber);
BOOLEAN DiskGetBootPartitionEntry(UCHAR DriveNumber, PPARTITION_TABLE_ENTRY PartitionTableEntry, ULONG *BootPartition);
BOOLEAN DiskGetPartitionEntry(UCHAR DriveNumber, ULONG PartitionNumber, PPARTITION_TABLE_ENTRY PartitionTableEntry);
BOOLEAN DiskGetFirstPartitionEntry(PMASTER_BOOT_RECORD MasterBootRecord, PPARTITION_TABLE_ENTRY PartitionTableEntry);
BOOLEAN DiskGetFirstExtendedPartitionEntry(PMASTER_BOOT_RECORD MasterBootRecord, PPARTITION_TABLE_ENTRY PartitionTableEntry);
BOOLEAN DiskReadBootRecord(UCHAR DriveNumber, ULONGLONG LogicalSectorNumber, PMASTER_BOOT_RECORD BootRecord);

View file

@ -410,7 +410,11 @@ typedef struct _PARTITION_INFORMATION_GPT {
typedef enum _PARTITION_STYLE {
PARTITION_STYLE_MBR,
PARTITION_STYLE_GPT,
PARTITION_STYLE_RAW
PARTITION_STYLE_RAW,
#ifdef __REACTOS__
/* ReactOS custom partition handlers */
PARTITION_STYLE_BRFR = 128 /* Xbox-BRFR partitioning scheme */
#endif
} PARTITION_STYLE;
typedef struct _DISK_PARTITION_INFO {