ReactOS 0.4.16-dev-297-gc569aee
partition.c
Go to the documentation of this file.
1/*
2 * FreeLoader
3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 *
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.
9 *
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.
14 *
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.
18 */
19
20#ifndef _M_ARM
21#include <freeldr.h>
22
23#include <debug.h>
25
26#define MaxDriveNumber 0xFF
28
29/* BRFR signature at disk offset 0x600 */
30#define XBOX_SIGNATURE_SECTOR 3
31#define XBOX_SIGNATURE ('B' | ('R' << 8) | ('F' << 16) | ('R' << 24))
32
33/* Default hardcoded partition number to boot from Xbox disk */
34#define FATX_DATA_PARTITION 1
35
36static struct
37{
42{
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: */
49};
50
51static BOOLEAN
53 IN UCHAR DriveNumber,
54 IN ULONGLONG LogicalSectorNumber,
55 OUT PMASTER_BOOT_RECORD BootRecord)
56{
58
59 /* Read master boot record */
60 if (!MachDiskReadLogicalSectors(DriveNumber, LogicalSectorNumber, 1, DiskReadBuffer))
61 {
62 return FALSE;
63 }
65
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));
69
70 for (Index = 0; Index < 4; Index++)
71 {
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);
84 }
85
86 /* Check the partition table magic value */
87 return (BootRecord->MasterBootRecordMagic == 0xaa55);
88}
89
90static BOOLEAN
92 IN PMASTER_BOOT_RECORD MasterBootRecord,
93 OUT PPARTITION_TABLE_ENTRY PartitionTableEntry)
94{
96
97 for (Index = 0; Index < 4; Index++)
98 {
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))
103 {
104 RtlCopyMemory(PartitionTableEntry, &MasterBootRecord->PartitionTable[Index], sizeof(PARTITION_TABLE_ENTRY));
105 return TRUE;
106 }
107 }
108
109 return FALSE;
110}
111
112static BOOLEAN
114 IN PMASTER_BOOT_RECORD MasterBootRecord,
115 OUT PPARTITION_TABLE_ENTRY PartitionTableEntry)
116{
117 ULONG Index;
118
119 for (Index = 0; Index < 4; Index++)
120 {
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))
124 {
125 RtlCopyMemory(PartitionTableEntry, &MasterBootRecord->PartitionTable[Index], sizeof(PARTITION_TABLE_ENTRY));
126 return TRUE;
127 }
128 }
129
130 return FALSE;
131}
132
133static BOOLEAN
135 IN UCHAR DriveNumber,
136 OUT PPARTITION_TABLE_ENTRY PartitionTableEntry,
137 OUT PULONG ActivePartition)
138{
139 ULONG BootablePartitionCount = 0;
140 ULONG CurrentPartitionNumber;
141 ULONG Index;
142 MASTER_BOOT_RECORD MasterBootRecord;
143 PPARTITION_TABLE_ENTRY ThisPartitionTableEntry;
144
145 *ActivePartition = 0;
146
147 /* Read master boot record */
148 if (!DiskReadBootRecord(DriveNumber, 0, &MasterBootRecord))
149 {
150 return FALSE;
151 }
152
153 CurrentPartitionNumber = 0;
154 for (Index = 0; Index < 4; Index++)
155 {
156 ThisPartitionTableEntry = &MasterBootRecord.PartitionTable[Index];
157
158 if (ThisPartitionTableEntry->SystemIndicator != PARTITION_ENTRY_UNUSED &&
159 ThisPartitionTableEntry->SystemIndicator != PARTITION_EXTENDED &&
160 ThisPartitionTableEntry->SystemIndicator != PARTITION_XINT13_EXTENDED)
161 {
162 CurrentPartitionNumber++;
163
164 /* Test if this is the bootable partition */
165 if (ThisPartitionTableEntry->BootIndicator == 0x80)
166 {
167 BootablePartitionCount++;
168 *ActivePartition = CurrentPartitionNumber;
169
170 /* Copy the partition table entry */
171 RtlCopyMemory(PartitionTableEntry,
172 ThisPartitionTableEntry,
173 sizeof(PARTITION_TABLE_ENTRY));
174 }
175 }
176 }
177
178 /* Make sure there was only one bootable partition */
179 if (BootablePartitionCount == 0)
180 {
181 ERR("No bootable (active) partitions found.\n");
182 return FALSE;
183 }
184 else if (BootablePartitionCount != 1)
185 {
186 ERR("Too many bootable (active) partitions found.\n");
187 return FALSE;
188 }
189
190 return TRUE;
191}
192
193static BOOLEAN
195 IN UCHAR DriveNumber,
197 OUT PPARTITION_TABLE_ENTRY PartitionTableEntry)
198{
199 MASTER_BOOT_RECORD MasterBootRecord;
200 PARTITION_TABLE_ENTRY ExtendedPartitionTableEntry;
201 ULONG ExtendedPartitionNumber;
202 ULONG ExtendedPartitionOffset;
203 ULONG Index;
204 ULONG CurrentPartitionNumber;
205 PPARTITION_TABLE_ENTRY ThisPartitionTableEntry;
206
207 /* Read master boot record */
208 if (!DiskReadBootRecord(DriveNumber, 0, &MasterBootRecord))
209 {
210 return FALSE;
211 }
212
213 CurrentPartitionNumber = 0;
214 for (Index = 0; Index < 4; Index++)
215 {
216 ThisPartitionTableEntry = &MasterBootRecord.PartitionTable[Index];
217
218 if (ThisPartitionTableEntry->SystemIndicator != PARTITION_ENTRY_UNUSED &&
219 ThisPartitionTableEntry->SystemIndicator != PARTITION_EXTENDED &&
220 ThisPartitionTableEntry->SystemIndicator != PARTITION_XINT13_EXTENDED)
221 {
222 CurrentPartitionNumber++;
223 }
224
225 if (PartitionNumber == CurrentPartitionNumber)
226 {
227 RtlCopyMemory(PartitionTableEntry, ThisPartitionTableEntry, sizeof(PARTITION_TABLE_ENTRY));
228 return TRUE;
229 }
230 }
231
232 /*
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.
236 */
237 ExtendedPartitionNumber = PartitionNumber - CurrentPartitionNumber - 1;
238
239 /*
240 * Set the initial relative starting sector to 0.
241 * This is because extended partition starting
242 * sectors a numbered relative to their parent.
243 */
244 ExtendedPartitionOffset = 0;
245
246 for (Index = 0; Index <= ExtendedPartitionNumber; Index++)
247 {
248 /* Get the extended partition table entry */
249 if (!DiskGetFirstExtendedPartitionEntry(&MasterBootRecord, &ExtendedPartitionTableEntry))
250 {
251 return FALSE;
252 }
253
254 /* Adjust the relative starting sector of the partition */
255 ExtendedPartitionTableEntry.SectorCountBeforePartition += ExtendedPartitionOffset;
256 if (ExtendedPartitionOffset == 0)
257 {
258 /* Set the start of the parrent extended partition */
259 ExtendedPartitionOffset = ExtendedPartitionTableEntry.SectorCountBeforePartition;
260 }
261 /* Read the partition boot record */
262 if (!DiskReadBootRecord(DriveNumber, ExtendedPartitionTableEntry.SectorCountBeforePartition, &MasterBootRecord))
263 {
264 return FALSE;
265 }
266
267 /* Get the first real partition table entry */
268 if (!DiskGetFirstPartitionEntry(&MasterBootRecord, PartitionTableEntry))
269 {
270 return FALSE;
271 }
272
273 /* Now correct the start sector of the partition */
274 PartitionTableEntry->SectorCountBeforePartition += ExtendedPartitionTableEntry.SectorCountBeforePartition;
275 }
276
277 /*
278 * When we get here we should have the correct entry already
279 * stored in PartitionTableEntry, so just return TRUE.
280 */
281 return TRUE;
282}
283
284static BOOLEAN
286 IN UCHAR DriveNumber,
288 OUT PPARTITION_TABLE_ENTRY PartitionTableEntry)
289{
290 /*
291 * Get partition entry of an Xbox-standard BRFR partitioned disk.
292 */
293 if (PartitionNumber >= 1 && PartitionNumber <= sizeof(XboxPartitions) / sizeof(XboxPartitions[0]) &&
295 {
297 {
298 /* No magic Xbox partitions */
299 return FALSE;
300 }
301
302 RtlZeroMemory(PartitionTableEntry, 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;
306 return TRUE;
307 }
308
309 /* Partition does not exist */
310 return FALSE;
311}
312
313VOID
315 IN UCHAR DriveNumber)
316{
317 MASTER_BOOT_RECORD MasterBootRecord;
318 ULONG Index;
319 ULONG PartitionCount = 0;
320 PPARTITION_TABLE_ENTRY ThisPartitionTableEntry;
321 BOOLEAN GPTProtect = FALSE;
322 PARTITION_TABLE_ENTRY PartitionTableEntry;
323
324 /* Probe for Master Boot Record */
325 if (DiskReadBootRecord(DriveNumber, 0, &MasterBootRecord))
326 {
328
329 /* Check for GUID Partition Table */
330 for (Index = 0; Index < 4; Index++)
331 {
332 ThisPartitionTableEntry = &MasterBootRecord.PartitionTable[Index];
333
334 if (ThisPartitionTableEntry->SystemIndicator != PARTITION_ENTRY_UNUSED)
335 {
336 PartitionCount++;
337
338 if (Index == 0 && ThisPartitionTableEntry->SystemIndicator == PARTITION_GPT)
339 {
340 GPTProtect = TRUE;
341 }
342 }
343 }
344
345 if (PartitionCount == 1 && GPTProtect)
346 {
348 }
349 TRACE("Drive 0x%X partition type %s\n", DriveNumber, DiskPartitionType[DriveNumber] == PARTITION_STYLE_MBR ? "MBR" : "GPT");
350 return;
351 }
352
353 /* Probe for Xbox-BRFR partitioning */
354 if (DiskGetBrfrPartitionEntry(DriveNumber, FATX_DATA_PARTITION, &PartitionTableEntry))
355 {
356 DiskPartitionType[DriveNumber] = PARTITION_STYLE_BRFR;
357 TRACE("Drive 0x%X partition type Xbox-BRFR\n", DriveNumber);
358 return;
359 }
360
361 /* Failed to detect partitions, assume partitionless disk */
362 DiskPartitionType[DriveNumber] = PARTITION_STYLE_RAW;
363 TRACE("Drive 0x%X partition type unknown\n", DriveNumber);
364}
365
368 IN UCHAR DriveNumber,
369 OUT PPARTITION_TABLE_ENTRY PartitionTableEntry,
370 OUT PULONG BootPartition)
371{
372 switch (DiskPartitionType[DriveNumber])
373 {
375 {
376 return DiskGetActivePartitionEntry(DriveNumber, PartitionTableEntry, BootPartition);
377 }
379 {
380 FIXME("DiskGetBootPartitionEntry() unimplemented for GPT\n");
381 return FALSE;
382 }
383 case PARTITION_STYLE_RAW:
384 {
385 FIXME("DiskGetBootPartitionEntry() unimplemented for RAW\n");
386 return FALSE;
387 }
388 case PARTITION_STYLE_BRFR:
389 {
390 if (DiskGetBrfrPartitionEntry(DriveNumber, FATX_DATA_PARTITION, PartitionTableEntry))
391 {
392 *BootPartition = FATX_DATA_PARTITION;
393 return TRUE;
394 }
395 return FALSE;
396 }
397 default:
398 {
399 ERR("Drive 0x%X partition type = %d, should not happen!\n", DriveNumber, DiskPartitionType[DriveNumber]);
400 ASSERT(FALSE);
401 }
402 }
403 return FALSE;
404}
405
408 IN UCHAR DriveNumber,
410 OUT PPARTITION_TABLE_ENTRY PartitionTableEntry)
411{
412 switch (DiskPartitionType[DriveNumber])
413 {
415 {
416 return DiskGetMbrPartitionEntry(DriveNumber, PartitionNumber, PartitionTableEntry);
417 }
419 {
420 FIXME("DiskGetPartitionEntry() unimplemented for GPT\n");
421 return FALSE;
422 }
423 case PARTITION_STYLE_RAW:
424 {
425 FIXME("DiskGetPartitionEntry() unimplemented for RAW\n");
426 return FALSE;
427 }
428 case PARTITION_STYLE_BRFR:
429 {
430 return DiskGetBrfrPartitionEntry(DriveNumber, PartitionNumber, PartitionTableEntry);
431 }
432 default:
433 {
434 ERR("Drive 0x%X partition type = %d, should not happen!\n", DriveNumber, DiskPartitionType[DriveNumber]);
435 ASSERT(FALSE);
436 }
437 }
438 return FALSE;
439}
440
441#endif
unsigned char BOOLEAN
#define FIXME(fmt,...)
Definition: precomp.h:53
#define ERR(fmt,...)
Definition: precomp.h:57
#define XBOX_SIGNATURE_SECTOR
Definition: partition.c:30
#define MaxDriveNumber
Definition: partition.c:26
static BOOLEAN DiskReadBootRecord(IN UCHAR DriveNumber, IN ULONGLONG LogicalSectorNumber, OUT PMASTER_BOOT_RECORD BootRecord)
Definition: partition.c:52
#define FATX_DATA_PARTITION
Definition: partition.c:34
#define XBOX_SIGNATURE
Definition: partition.c:31
static BOOLEAN DiskGetBrfrPartitionEntry(IN UCHAR DriveNumber, IN ULONG PartitionNumber, OUT PPARTITION_TABLE_ENTRY PartitionTableEntry)
Definition: partition.c:285
BOOLEAN DiskGetPartitionEntry(IN UCHAR DriveNumber, IN ULONG PartitionNumber, OUT PPARTITION_TABLE_ENTRY PartitionTableEntry)
Definition: partition.c:407
static BOOLEAN DiskGetActivePartitionEntry(IN UCHAR DriveNumber, OUT PPARTITION_TABLE_ENTRY PartitionTableEntry, OUT PULONG ActivePartition)
Definition: partition.c:134
static struct @154 XboxPartitions[]
static PARTITION_STYLE DiskPartitionType[MaxDriveNumber+1]
Definition: partition.c:27
UCHAR SystemIndicator
Definition: partition.c:40
static BOOLEAN DiskGetFirstPartitionEntry(IN PMASTER_BOOT_RECORD MasterBootRecord, OUT PPARTITION_TABLE_ENTRY PartitionTableEntry)
Definition: partition.c:91
static BOOLEAN DiskGetMbrPartitionEntry(IN UCHAR DriveNumber, IN ULONG PartitionNumber, OUT PPARTITION_TABLE_ENTRY PartitionTableEntry)
Definition: partition.c:194
BOOLEAN DiskGetBootPartitionEntry(IN UCHAR DriveNumber, OUT PPARTITION_TABLE_ENTRY PartitionTableEntry, OUT PULONG BootPartition)
Definition: partition.c:367
static BOOLEAN DiskGetFirstExtendedPartitionEntry(IN PMASTER_BOOT_RECORD MasterBootRecord, OUT PPARTITION_TABLE_ENTRY PartitionTableEntry)
Definition: partition.c:113
ULONG PartitionSectorCount
Definition: partition.c:39
ULONG SectorCountBeforePartition
Definition: partition.c:38
VOID DiskDetectPartitionType(IN UCHAR DriveNumber)
Definition: partition.c:314
#define DiskReadBuffer
Definition: hardware.h:33
#define DBG_DEFAULT_CHANNEL(ch)
Definition: debug.h:106
#define PARTITION_ENTRY_UNUSED
Definition: disk.h:87
#define PARTITION_FAT32
Definition: disk.h:96
#define PARTITION_EXTENDED
Definition: disk.h:92
#define PARTITION_FAT_16
Definition: disk.h:91
#define PARTITION_GPT
Definition: disk.h:106
#define PARTITION_XINT13_EXTENDED
Definition: disk.h:99
#define MachDiskReadLogicalSectors(Drive, Start, Count, Buf)
Definition: machine.h:126
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define ASSERT(a)
Definition: mode.c:44
enum _PARTITION_STYLE PARTITION_STYLE
@ PARTITION_STYLE_GPT
Definition: imports.h:202
@ PARTITION_STYLE_MBR
Definition: imports.h:201
#define TRACE(s)
Definition: solgame.cpp:4
PARTITION_TABLE_ENTRY PartitionTable[4]
Definition: parttest.c:92
Definition: parttest.c:75
ULONG SectorCountBeforePartition
Definition: parttest.c:84
Definition: disk.h:56
UCHAR BootIndicator
Definition: disk.h:57
UCHAR SystemIndicator
Definition: disk.h:62
uint32_t * PULONG
Definition: typedefs.h:59
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
uint64_t ULONGLONG
Definition: typedefs.h:67
#define OUT
Definition: typedefs.h:40
_In_ WDFCOLLECTION _In_ ULONG Index
_In_ ULONG _In_ ULONG PartitionNumber
Definition: iofuncs.h:2061
unsigned char UCHAR
Definition: xmlstorage.h:181