3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 DBG_DEFAULT_CHANNEL(DISK
);
26 #define MaxDriveNumber 0xFF
27 static PARTITION_STYLE DiskPartitionType
[MaxDriveNumber
+ 1];
29 /* BRFR signature at disk offset 0x600 */
30 #define XBOX_SIGNATURE_SECTOR 3
31 #define XBOX_SIGNATURE ('B' | ('R' << 8) | ('F' << 16) | ('R' << 24))
33 /* Default hardcoded partition number to boot from Xbox disk */
34 #define FATX_DATA_PARTITION 1
38 ULONG SectorCountBeforePartition
;
39 ULONG PartitionSectorCount
;
40 UCHAR SystemIndicator
;
43 /* This is in the \Device\Harddisk0\Partition.. order used by the Xbox kernel */
44 { 0x0055F400, 0x0098F800, PARTITION_FAT32
}, /* Store , E: */
45 { 0x00465400, 0x000FA000, PARTITION_FAT_16
}, /* System, C: */
46 { 0x00000400, 0x00177000, PARTITION_FAT_16
}, /* Cache1, X: */
47 { 0x00177400, 0x00177000, PARTITION_FAT_16
}, /* Cache2, Y: */
48 { 0x002EE400, 0x00177000, PARTITION_FAT_16
} /* Cache3, Z: */
54 IN ULONGLONG LogicalSectorNumber
,
55 OUT PMASTER_BOOT_RECORD BootRecord
)
59 /* Read master boot record */
60 if (!MachDiskReadLogicalSectors(DriveNumber
, LogicalSectorNumber
, 1, DiskReadBuffer
))
64 RtlCopyMemory(BootRecord
, DiskReadBuffer
, sizeof(MASTER_BOOT_RECORD
));
66 TRACE("Dumping partition table for drive 0x%x:\n", DriveNumber
);
67 TRACE("Boot record logical start sector = %d\n", LogicalSectorNumber
);
68 TRACE("sizeof(MASTER_BOOT_RECORD) = 0x%x.\n", sizeof(MASTER_BOOT_RECORD
));
70 for (Index
= 0; Index
< 4; Index
++)
72 TRACE("-------------------------------------------\n");
73 TRACE("Partition %d\n", (Index
+ 1));
74 TRACE("BootIndicator: 0x%x\n", BootRecord
->PartitionTable
[Index
].BootIndicator
);
75 TRACE("StartHead: 0x%x\n", BootRecord
->PartitionTable
[Index
].StartHead
);
76 TRACE("StartSector (Plus 2 cylinder bits): 0x%x\n", BootRecord
->PartitionTable
[Index
].StartSector
);
77 TRACE("StartCylinder: 0x%x\n", BootRecord
->PartitionTable
[Index
].StartCylinder
);
78 TRACE("SystemIndicator: 0x%x\n", BootRecord
->PartitionTable
[Index
].SystemIndicator
);
79 TRACE("EndHead: 0x%x\n", BootRecord
->PartitionTable
[Index
].EndHead
);
80 TRACE("EndSector (Plus 2 cylinder bits): 0x%x\n", BootRecord
->PartitionTable
[Index
].EndSector
);
81 TRACE("EndCylinder: 0x%x\n", BootRecord
->PartitionTable
[Index
].EndCylinder
);
82 TRACE("SectorCountBeforePartition: 0x%x\n", BootRecord
->PartitionTable
[Index
].SectorCountBeforePartition
);
83 TRACE("PartitionSectorCount: 0x%x\n", BootRecord
->PartitionTable
[Index
].PartitionSectorCount
);
86 /* Check the partition table magic value */
87 return (BootRecord
->MasterBootRecordMagic
== 0xaa55);
91 DiskGetFirstPartitionEntry(
92 IN PMASTER_BOOT_RECORD MasterBootRecord
,
93 OUT PPARTITION_TABLE_ENTRY PartitionTableEntry
)
97 for (Index
= 0; Index
< 4; Index
++)
99 /* Check the system indicator. If it's not an extended or unused partition then we're done. */
100 if ((MasterBootRecord
->PartitionTable
[Index
].SystemIndicator
!= PARTITION_ENTRY_UNUSED
) &&
101 (MasterBootRecord
->PartitionTable
[Index
].SystemIndicator
!= PARTITION_EXTENDED
) &&
102 (MasterBootRecord
->PartitionTable
[Index
].SystemIndicator
!= PARTITION_XINT13_EXTENDED
))
104 RtlCopyMemory(PartitionTableEntry
, &MasterBootRecord
->PartitionTable
[Index
], sizeof(PARTITION_TABLE_ENTRY
));
113 DiskGetFirstExtendedPartitionEntry(
114 IN PMASTER_BOOT_RECORD MasterBootRecord
,
115 OUT PPARTITION_TABLE_ENTRY PartitionTableEntry
)
119 for (Index
= 0; Index
< 4; Index
++)
121 /* Check the system indicator. If it an extended partition then we're done. */
122 if ((MasterBootRecord
->PartitionTable
[Index
].SystemIndicator
== PARTITION_EXTENDED
) ||
123 (MasterBootRecord
->PartitionTable
[Index
].SystemIndicator
== PARTITION_XINT13_EXTENDED
))
125 RtlCopyMemory(PartitionTableEntry
, &MasterBootRecord
->PartitionTable
[Index
], sizeof(PARTITION_TABLE_ENTRY
));
134 DiskGetActivePartitionEntry(
135 IN UCHAR DriveNumber
,
136 OUT PPARTITION_TABLE_ENTRY PartitionTableEntry
,
137 OUT PULONG ActivePartition
)
139 ULONG BootablePartitionCount
= 0;
140 ULONG CurrentPartitionNumber
;
142 MASTER_BOOT_RECORD MasterBootRecord
;
143 PPARTITION_TABLE_ENTRY ThisPartitionTableEntry
;
145 *ActivePartition
= 0;
147 /* Read master boot record */
148 if (!DiskReadBootRecord(DriveNumber
, 0, &MasterBootRecord
))
153 CurrentPartitionNumber
= 0;
154 for (Index
= 0; Index
< 4; Index
++)
156 ThisPartitionTableEntry
= &MasterBootRecord
.PartitionTable
[Index
];
158 if (ThisPartitionTableEntry
->SystemIndicator
!= PARTITION_ENTRY_UNUSED
&&
159 ThisPartitionTableEntry
->SystemIndicator
!= PARTITION_EXTENDED
&&
160 ThisPartitionTableEntry
->SystemIndicator
!= PARTITION_XINT13_EXTENDED
)
162 CurrentPartitionNumber
++;
164 /* Test if this is the bootable partition */
165 if (ThisPartitionTableEntry
->BootIndicator
== 0x80)
167 BootablePartitionCount
++;
168 *ActivePartition
= CurrentPartitionNumber
;
170 /* Copy the partition table entry */
171 RtlCopyMemory(PartitionTableEntry
,
172 ThisPartitionTableEntry
,
173 sizeof(PARTITION_TABLE_ENTRY
));
178 /* Make sure there was only one bootable partition */
179 if (BootablePartitionCount
== 0)
181 ERR("No bootable (active) partitions found.\n");
184 else if (BootablePartitionCount
!= 1)
186 ERR("Too many bootable (active) partitions found.\n");
194 DiskGetMbrPartitionEntry(
195 IN UCHAR DriveNumber
,
196 IN ULONG PartitionNumber
,
197 OUT PPARTITION_TABLE_ENTRY PartitionTableEntry
)
199 MASTER_BOOT_RECORD MasterBootRecord
;
200 PARTITION_TABLE_ENTRY ExtendedPartitionTableEntry
;
201 ULONG ExtendedPartitionNumber
;
202 ULONG ExtendedPartitionOffset
;
204 ULONG CurrentPartitionNumber
;
205 PPARTITION_TABLE_ENTRY ThisPartitionTableEntry
;
207 /* Read master boot record */
208 if (!DiskReadBootRecord(DriveNumber
, 0, &MasterBootRecord
))
213 CurrentPartitionNumber
= 0;
214 for (Index
= 0; Index
< 4; Index
++)
216 ThisPartitionTableEntry
= &MasterBootRecord
.PartitionTable
[Index
];
218 if (ThisPartitionTableEntry
->SystemIndicator
!= PARTITION_ENTRY_UNUSED
&&
219 ThisPartitionTableEntry
->SystemIndicator
!= PARTITION_EXTENDED
&&
220 ThisPartitionTableEntry
->SystemIndicator
!= PARTITION_XINT13_EXTENDED
)
222 CurrentPartitionNumber
++;
225 if (PartitionNumber
== CurrentPartitionNumber
)
227 RtlCopyMemory(PartitionTableEntry
, ThisPartitionTableEntry
, sizeof(PARTITION_TABLE_ENTRY
));
233 * They want an extended partition entry so we will need
234 * to loop through all the extended partitions on the disk
235 * and return the one they want.
237 ExtendedPartitionNumber
= PartitionNumber
- CurrentPartitionNumber
- 1;
240 * Set the initial relative starting sector to 0.
241 * This is because extended partition starting
242 * sectors a numbered relative to their parent.
244 ExtendedPartitionOffset
= 0;
246 for (Index
= 0; Index
<= ExtendedPartitionNumber
; Index
++)
248 /* Get the extended partition table entry */
249 if (!DiskGetFirstExtendedPartitionEntry(&MasterBootRecord
, &ExtendedPartitionTableEntry
))
254 /* Adjust the relative starting sector of the partition */
255 ExtendedPartitionTableEntry
.SectorCountBeforePartition
+= ExtendedPartitionOffset
;
256 if (ExtendedPartitionOffset
== 0)
258 /* Set the start of the parrent extended partition */
259 ExtendedPartitionOffset
= ExtendedPartitionTableEntry
.SectorCountBeforePartition
;
261 /* Read the partition boot record */
262 if (!DiskReadBootRecord(DriveNumber
, ExtendedPartitionTableEntry
.SectorCountBeforePartition
, &MasterBootRecord
))
267 /* Get the first real partition table entry */
268 if (!DiskGetFirstPartitionEntry(&MasterBootRecord
, PartitionTableEntry
))
273 /* Now correct the start sector of the partition */
274 PartitionTableEntry
->SectorCountBeforePartition
+= ExtendedPartitionTableEntry
.SectorCountBeforePartition
;
278 * When we get here we should have the correct entry already
279 * stored in PartitionTableEntry, so just return TRUE.
285 DiskGetBrfrPartitionEntry(
286 IN UCHAR DriveNumber
,
287 IN ULONG PartitionNumber
,
288 OUT PPARTITION_TABLE_ENTRY PartitionTableEntry
)
291 * Get partition entry of an Xbox-standard BRFR partitioned disk.
293 if (PartitionNumber
>= 1 && PartitionNumber
<= sizeof(XboxPartitions
) / sizeof(XboxPartitions
[0]) &&
294 MachDiskReadLogicalSectors(DriveNumber
, XBOX_SIGNATURE_SECTOR
, 1, DiskReadBuffer
))
296 if (*((PULONG
)DiskReadBuffer
) != XBOX_SIGNATURE
)
298 /* No magic Xbox partitions */
302 memset(PartitionTableEntry
, 0, sizeof(PARTITION_TABLE_ENTRY
));
303 PartitionTableEntry
->SystemIndicator
= XboxPartitions
[PartitionNumber
- 1].SystemIndicator
;
304 PartitionTableEntry
->SectorCountBeforePartition
= XboxPartitions
[PartitionNumber
- 1].SectorCountBeforePartition
;
305 PartitionTableEntry
->PartitionSectorCount
= XboxPartitions
[PartitionNumber
- 1].PartitionSectorCount
;
309 /* Partition does not exist */
314 DiskDetectPartitionType(
315 IN UCHAR DriveNumber
)
317 MASTER_BOOT_RECORD MasterBootRecord
;
319 ULONG PartitionCount
= 0;
320 PPARTITION_TABLE_ENTRY ThisPartitionTableEntry
;
321 BOOLEAN GPTProtect
= FALSE
;
322 PARTITION_TABLE_ENTRY PartitionTableEntry
;
324 /* Probe for Master Boot Record */
325 if (DiskReadBootRecord(DriveNumber
, 0, &MasterBootRecord
))
327 DiskPartitionType
[DriveNumber
] = PARTITION_STYLE_MBR
;
329 /* Check for GUID Partition Table */
330 for (Index
= 0; Index
< 4; Index
++)
332 ThisPartitionTableEntry
= &MasterBootRecord
.PartitionTable
[Index
];
334 if (ThisPartitionTableEntry
->SystemIndicator
!= PARTITION_ENTRY_UNUSED
)
338 if (Index
== 0 && ThisPartitionTableEntry
->SystemIndicator
== PARTITION_GPT
)
345 if (PartitionCount
== 1 && GPTProtect
)
347 DiskPartitionType
[DriveNumber
] = PARTITION_STYLE_GPT
;
349 TRACE("Drive 0x%X partition type %s\n", DriveNumber
, DiskPartitionType
[DriveNumber
] == PARTITION_STYLE_MBR
? "MBR" : "GPT");
353 /* Probe for Xbox-BRFR partitioning */
354 if (DiskGetBrfrPartitionEntry(DriveNumber
, FATX_DATA_PARTITION
, &PartitionTableEntry
))
356 DiskPartitionType
[DriveNumber
] = PARTITION_STYLE_BRFR
;
357 TRACE("Drive 0x%X partition type Xbox-BRFR\n", DriveNumber
);
361 /* Failed to detect partitions, assume partitionless disk */
362 DiskPartitionType
[DriveNumber
] = PARTITION_STYLE_RAW
;
363 TRACE("Drive 0x%X partition type unknown\n", DriveNumber
);
367 DiskGetBootPartitionEntry(
368 IN UCHAR DriveNumber
,
369 OUT PPARTITION_TABLE_ENTRY PartitionTableEntry
,
370 OUT PULONG BootPartition
)
372 switch (DiskPartitionType
[DriveNumber
])
374 case PARTITION_STYLE_MBR
:
376 return DiskGetActivePartitionEntry(DriveNumber
, PartitionTableEntry
, BootPartition
);
378 case PARTITION_STYLE_GPT
:
380 FIXME("DiskGetBootPartitionEntry() unimplemented for GPT\n");
383 case PARTITION_STYLE_RAW
:
385 FIXME("DiskGetBootPartitionEntry() unimplemented for RAW\n");
388 case PARTITION_STYLE_BRFR
:
390 if (DiskGetBrfrPartitionEntry(DriveNumber
, FATX_DATA_PARTITION
, PartitionTableEntry
))
392 *BootPartition
= FATX_DATA_PARTITION
;
399 ERR("Drive 0x%X partition type = %d, should not happen!\n", DriveNumber
, DiskPartitionType
[DriveNumber
]);
407 DiskGetPartitionEntry(
408 IN UCHAR DriveNumber
,
409 IN ULONG PartitionNumber
,
410 OUT PPARTITION_TABLE_ENTRY PartitionTableEntry
)
412 switch (DiskPartitionType
[DriveNumber
])
414 case PARTITION_STYLE_MBR
:
416 return DiskGetMbrPartitionEntry(DriveNumber
, PartitionNumber
, PartitionTableEntry
);
418 case PARTITION_STYLE_GPT
:
420 FIXME("DiskGetPartitionEntry() unimplemented for GPT\n");
423 case PARTITION_STYLE_RAW
:
425 FIXME("DiskGetPartitionEntry() unimplemented for RAW\n");
428 case PARTITION_STYLE_BRFR
:
430 return DiskGetBrfrPartitionEntry(DriveNumber
, PartitionNumber
, PartitionTableEntry
);
434 ERR("Drive 0x%X partition type = %d, should not happen!\n", DriveNumber
, DiskPartitionType
[DriveNumber
]);
445 IN PDEVICE_OBJECT DeviceObject
,
446 IN ULONGLONG LogicalSectorNumber
,
448 OUT PMASTER_BOOT_RECORD BootRecord
)
450 ULONG_PTR FileId
= (ULONG_PTR
)DeviceObject
;
451 LARGE_INTEGER Position
;
455 Position
.QuadPart
= LogicalSectorNumber
* SectorSize
;
456 Status
= ArcSeek(FileId
, &Position
, SeekAbsolute
);
457 if (Status
!= ESUCCESS
)
458 return STATUS_IO_DEVICE_ERROR
;
460 Status
= ArcRead(FileId
, BootRecord
, SectorSize
, &BytesRead
);
461 if (Status
!= ESUCCESS
|| BytesRead
!= SectorSize
)
462 return STATUS_IO_DEVICE_ERROR
;
464 return STATUS_SUCCESS
;
469 IopCopyPartitionRecord(
470 IN BOOLEAN ReturnRecognizedPartitions
,
472 IN PPARTITION_TABLE_ENTRY PartitionTableEntry
,
473 OUT PARTITION_INFORMATION
*PartitionEntry
)
475 BOOLEAN IsRecognized
;
477 IsRecognized
= TRUE
; /* FIXME */
478 if (!IsRecognized
&& ReturnRecognizedPartitions
)
481 PartitionEntry
->StartingOffset
.QuadPart
= (ULONGLONG
)PartitionTableEntry
->SectorCountBeforePartition
* SectorSize
;
482 PartitionEntry
->PartitionLength
.QuadPart
= (ULONGLONG
)PartitionTableEntry
->PartitionSectorCount
* SectorSize
;
483 PartitionEntry
->HiddenSectors
= 0;
484 PartitionEntry
->PartitionNumber
= 0; /* Will be filled later */
485 PartitionEntry
->PartitionType
= PartitionTableEntry
->SystemIndicator
;
486 PartitionEntry
->BootIndicator
= (PartitionTableEntry
->BootIndicator
& 0x80) ? TRUE
: FALSE
;
487 PartitionEntry
->RecognizedPartition
= IsRecognized
;
488 PartitionEntry
->RewritePartition
= FALSE
;
495 IoReadPartitionTable(
496 IN PDEVICE_OBJECT DeviceObject
,
498 IN BOOLEAN ReturnRecognizedPartitions
,
499 OUT PDRIVE_LAYOUT_INFORMATION
*PartitionBuffer
)
502 PMASTER_BOOT_RECORD MasterBootRecord
;
503 PDRIVE_LAYOUT_INFORMATION Partitions
;
504 ULONG NbPartitions
, i
, Size
;
506 *PartitionBuffer
= NULL
;
508 if (SectorSize
< sizeof(MASTER_BOOT_RECORD
))
509 return STATUS_NOT_SUPPORTED
;
511 MasterBootRecord
= ExAllocatePool(NonPagedPool
, SectorSize
);
512 if (!MasterBootRecord
)
513 return STATUS_NO_MEMORY
;
516 Status
= IopReadBootRecord(DeviceObject
, 0, SectorSize
, MasterBootRecord
);
517 if (!NT_SUCCESS(Status
))
519 ExFreePool(MasterBootRecord
);
523 /* Check validity of boot record */
524 if (MasterBootRecord
->MasterBootRecordMagic
!= 0xaa55)
526 ExFreePool(MasterBootRecord
);
527 return STATUS_NOT_SUPPORTED
;
530 /* Count number of partitions */
532 for (i
= 0; i
< 4; i
++)
536 if (MasterBootRecord
->PartitionTable
[i
].SystemIndicator
== PARTITION_EXTENDED
||
537 MasterBootRecord
->PartitionTable
[i
].SystemIndicator
== PARTITION_XINT13_EXTENDED
)
539 /* FIXME: unhandled case; count number of partitions */
544 if (NbPartitions
== 0)
546 ExFreePool(MasterBootRecord
);
547 return STATUS_NOT_SUPPORTED
;
550 /* Allocation space to store partitions */
551 Size
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
, PartitionEntry
) +
552 NbPartitions
* sizeof(PARTITION_INFORMATION
);
553 Partitions
= ExAllocatePool(NonPagedPool
, Size
);
556 ExFreePool(MasterBootRecord
);
557 return STATUS_NO_MEMORY
;
560 /* Count number of partitions */
562 for (i
= 0; i
< 4; i
++)
564 if (IopCopyPartitionRecord(ReturnRecognizedPartitions
,
566 &MasterBootRecord
->PartitionTable
[i
],
567 &Partitions
->PartitionEntry
[NbPartitions
]))
569 Partitions
->PartitionEntry
[NbPartitions
].PartitionNumber
= NbPartitions
+ 1;
573 if (MasterBootRecord
->PartitionTable
[i
].SystemIndicator
== PARTITION_EXTENDED
||
574 MasterBootRecord
->PartitionTable
[i
].SystemIndicator
== PARTITION_XINT13_EXTENDED
)
576 /* FIXME: unhandled case; copy partitions */
581 Partitions
->PartitionCount
= NbPartitions
;
582 Partitions
->Signature
= MasterBootRecord
->Signature
;
583 ExFreePool(MasterBootRecord
);
585 *PartitionBuffer
= Partitions
;
586 return STATUS_SUCCESS
;