[FREELDR] Implement proper partition type detection and handling (#1762)
authorStanislav Motylkov <x86corez@gmail.com>
Mon, 29 Jul 2019 12:25:54 +0000 (15:25 +0300)
committerHermès BÉLUSCA - MAÏTO <hermes.belusca-maito@reactos.org>
Mon, 29 Jul 2019 12:25:54 +0000 (14:25 +0200)
- 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

boot/freeldr/freeldr/arch/i386/hwdisk.c
boot/freeldr/freeldr/arch/i386/machpc.c
boot/freeldr/freeldr/arch/i386/machxbox.c
boot/freeldr/freeldr/arch/i386/xboxdisk.c
boot/freeldr/freeldr/disk/disk.c
boot/freeldr/freeldr/disk/partition.c
boot/freeldr/freeldr/include/arch/i386/machxbox.h
boot/freeldr/freeldr/include/disk.h
sdk/include/psdk/ntdddisk.h

index 826780a..50bb00e 100644 (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))
     {
index 497f89b..5ec2195 100644 (file)
@@ -1422,8 +1422,6 @@ PcMachInit(const char *CmdLine)
     MachVtbl.InitializeBootDevices = PcInitializeBootDevices;
     MachVtbl.HwDetect = PcHwDetect;
     MachVtbl.HwIdle = PcHwIdle;
-
-    // DiskGetPartitionEntry = DiskGetMbrPartitionEntry; // Default
 }
 
 VOID
index 350a0c3..139f571 100644 (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");
 }
index 9e31ce9..e1e4d35 100644 (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)
 {
index 5570120..11cc0a7 100644 (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;
         }
 
index 1feaf51..3aa69d9 100644 (file)
  *  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>
 
 
 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
index 3a394c3..d1c42a4 100644 (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);
 
index a701ad2..6629c76 100644 (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);
index 24387a0..13b8e0e 100644 (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 {