xref: /reactos/hal/halx86/xbox/part_xbox.c (revision 40462c92)
1 /*
2  * PROJECT:         Xbox HAL
3  * LICENSE:         GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:         Xbox specific handling of partition tables
5  * COPYRIGHT:       Copyright 2004 Ge van Geldorp (gvg@reactos.com)
6  *                  Copyright 2020 Stanislav Motylkov (x86corez@gmail.com)
7  */
8 
9 /* INCLUDES *****************************************************************/
10 
11 #include "halxbox.h"
12 #include <internal/tag.h>
13 
14 #define NDEBUG
15 #include <debug.h>
16 
17 #define XBOX_SIGNATURE_SECTOR 3
18 #define XBOX_SIGNATURE        ('B' | ('R' << 8) | ('F' << 16) | ('R' << 24))
19 #define PARTITION_SIGNATURE   0xaa55
20 
21 /* VARIABLES ***************************************************************/
22 
23 static pHalExamineMBR NtoskrnlExamineMBR;
24 static pHalIoReadPartitionTable NtoskrnlIoReadPartitionTable;
25 static pHalIoSetPartitionInformation NtoskrnlIoSetPartitionInformation;
26 static pHalIoWritePartitionTable NtoskrnlIoWritePartitionTable;
27 
28 static struct
29 {
30     ULONG SectorStart;
31     ULONG SectorCount;
32     CHAR PartitionType;
33 } XboxPartitions[] =
34 {
35     /* This is in the \Device\Harddisk0\Partition.. order used by the Xbox kernel */
36     { 0x0055F400, 0x0098f800, PARTITION_FAT32  }, /* Store, E: */
37     { 0x00465400, 0x000FA000, PARTITION_FAT_16 }, /* System, C: */
38     { 0x00000400, 0x00177000, PARTITION_FAT_16 }, /* Cache1, X: */
39     { 0x00177400, 0x00177000, PARTITION_FAT_16 }, /* Cache2, Y: */
40     { 0x002EE400, 0x00177000, PARTITION_FAT_16 }  /* Cache3, Z: */
41 };
42 
43 #define XBOX_PARTITION_COUNT (sizeof(XboxPartitions) / sizeof(XboxPartitions[0]))
44 
45 /* FUNCTIONS ***************************************************************/
46 
47 
48 static NTSTATUS
49 HalpXboxReadSector(IN PDEVICE_OBJECT DeviceObject,
50                    IN ULONG SectorSize,
51                    IN PLARGE_INTEGER SectorOffset,
52                    OUT PVOID Sector)
53 {
54     IO_STATUS_BLOCK StatusBlock;
55     KEVENT Event;
56     PIRP Irp;
57     NTSTATUS Status;
58 
59     DPRINT("HalpXboxReadSector(%p %lu 0x%08x%08x %p)\n",
60            DeviceObject, SectorSize, SectorOffset->u.HighPart, SectorOffset->u.LowPart, Sector);
61 
62     ASSERT(DeviceObject);
63     ASSERT(Sector);
64 
65     KeInitializeEvent(&Event,
66                       NotificationEvent,
67                       FALSE);
68 
69     /* Read the sector */
70     Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
71                                        DeviceObject,
72                                        Sector,
73                                        SectorSize,
74                                        SectorOffset,
75                                        &Event,
76                                        &StatusBlock);
77     if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
78 
79     Status = IoCallDriver(DeviceObject,
80                           Irp);
81     if (Status == STATUS_PENDING)
82     {
83         KeWaitForSingleObject(&Event,
84                               Executive,
85                               KernelMode,
86                               FALSE,
87                               NULL);
88         Status = StatusBlock.Status;
89     }
90 
91     if (!NT_SUCCESS(Status))
92     {
93         DPRINT("Reading sector failed (Status 0x%08lx)\n", Status);
94         return Status;
95     }
96 
97     return Status;
98 }
99 
100 static NTSTATUS FASTCALL
101 HalpXboxDeviceHasXboxPartitioning(IN PDEVICE_OBJECT DeviceObject,
102                                   IN ULONG SectorSize,
103                                   OUT BOOLEAN *HasXboxPartitioning)
104 {
105     PVOID SectorData;
106     LARGE_INTEGER Offset;
107     NTSTATUS Status;
108     BOOLEAN HasMBRPartitioning;
109 
110     DPRINT("HalpXboxDeviceHasXboxPartitioning(%p %lu %p)\n",
111            DeviceObject,
112            SectorSize,
113            HasXboxPartitioning);
114 
115     SectorData = ExAllocatePoolWithTag(PagedPool, SectorSize, TAG_HAL_XBOX);
116     if (!SectorData)
117     {
118         return STATUS_NO_MEMORY;
119     }
120 
121     Offset.QuadPart = 0;
122     Status = HalpXboxReadSector(DeviceObject, SectorSize, &Offset, SectorData);
123     if (!NT_SUCCESS(Status))
124     {
125         goto Cleanup;
126     }
127 
128     HasMBRPartitioning = (*((USHORT *)SectorData + (SectorSize / sizeof(USHORT)) - 1) == PARTITION_SIGNATURE);
129     if (HasMBRPartitioning)
130     {
131         *HasXboxPartitioning = FALSE;
132         goto Cleanup;
133     }
134 
135     Offset.QuadPart = XBOX_SIGNATURE_SECTOR * SectorSize;
136     Status = HalpXboxReadSector(DeviceObject, SectorSize, &Offset, SectorData);
137     if (!NT_SUCCESS(Status))
138     {
139         goto Cleanup;
140     }
141 
142     DPRINT("Signature 0x%02x 0x%02x 0x%02x 0x%02x\n",
143            *((UCHAR *) SectorData), *((UCHAR *) SectorData + 1), *((UCHAR *) SectorData + 2), *((UCHAR *) SectorData + 3));
144     *HasXboxPartitioning = (XBOX_SIGNATURE == *((ULONG *) SectorData));
145 Cleanup:
146     ExFreePoolWithTag(SectorData, TAG_HAL_XBOX);
147     if (NT_SUCCESS(Status))
148     {
149         DPRINT("%s partitioning found\n", *HasXboxPartitioning ? "Xbox" : "MBR");
150     }
151 
152     return Status;
153 }
154 
155 static VOID FASTCALL
156 HalpXboxExamineMBR(IN PDEVICE_OBJECT DeviceObject,
157                    IN ULONG SectorSize,
158                    IN ULONG MBRTypeIdentifier,
159                    OUT PVOID *Buffer)
160 {
161     BOOLEAN HasXboxPartitioning;
162     NTSTATUS Status;
163 
164     DPRINT("HalpXboxExamineMBR(%p %lu %lx %p)\n",
165            DeviceObject,
166            SectorSize,
167            MBRTypeIdentifier,
168            Buffer);
169 
170     *Buffer = NULL;
171 
172     Status = HalpXboxDeviceHasXboxPartitioning(DeviceObject, SectorSize, &HasXboxPartitioning);
173     if (!NT_SUCCESS(Status))
174     {
175         return;
176     }
177 
178     if (!HasXboxPartitioning)
179     {
180         DPRINT("Delegating to standard MBR code\n");
181         NtoskrnlExamineMBR(DeviceObject, SectorSize, MBRTypeIdentifier, Buffer);
182         return;
183     }
184 
185     /* Buffer already set to NULL */
186     return;
187 }
188 
189 static NTSTATUS FASTCALL
190 HalpXboxIoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject,
191                              IN ULONG SectorSize,
192                              IN BOOLEAN ReturnRecognizedPartitions,
193                              OUT PDRIVE_LAYOUT_INFORMATION *PartitionBuffer)
194 {
195     BOOLEAN HasXboxPartitioning;
196     NTSTATUS Status;
197     ULONG Part;
198     PPARTITION_INFORMATION PartInfo;
199 
200     DPRINT("HalpXboxIoReadPartitionTable(%p %lu %x %p)\n",
201            DeviceObject,
202            SectorSize,
203            ReturnRecognizedPartitions,
204            PartitionBuffer);
205 
206     Status = HalpXboxDeviceHasXboxPartitioning(DeviceObject, SectorSize, &HasXboxPartitioning);
207     if (!NT_SUCCESS(Status))
208     {
209         return Status;
210     }
211 
212     if (!HasXboxPartitioning)
213     {
214         DPRINT("Delegating to standard MBR code\n");
215         return NtoskrnlIoReadPartitionTable(DeviceObject, SectorSize,
216                                             ReturnRecognizedPartitions, PartitionBuffer);
217     }
218 
219     *PartitionBuffer = (PDRIVE_LAYOUT_INFORMATION)ExAllocatePoolWithTag(
220                         PagedPool,
221                         sizeof(DRIVE_LAYOUT_INFORMATION) +
222                         XBOX_PARTITION_COUNT * sizeof(PARTITION_INFORMATION),
223                         TAG_FILE_SYSTEM);
224     if (*PartitionBuffer == NULL)
225     {
226         return STATUS_NO_MEMORY;
227     }
228     (*PartitionBuffer)->PartitionCount = XBOX_PARTITION_COUNT;
229     (*PartitionBuffer)->Signature = PARTITION_SIGNATURE;
230     for (Part = 0; Part < XBOX_PARTITION_COUNT; Part++)
231     {
232         PartInfo = (*PartitionBuffer)->PartitionEntry + Part;
233         PartInfo->StartingOffset.QuadPart = (ULONGLONG) XboxPartitions[Part].SectorStart *
234                                             (ULONGLONG) SectorSize;
235         PartInfo->PartitionLength.QuadPart = (ULONGLONG) XboxPartitions[Part].SectorCount *
236                                              (ULONGLONG) SectorSize;
237         PartInfo->HiddenSectors = 0;
238         PartInfo->PartitionNumber = Part + 1;
239         PartInfo->PartitionType = XboxPartitions[Part].PartitionType;
240         PartInfo->BootIndicator = FALSE;
241         PartInfo->RecognizedPartition = TRUE;
242         PartInfo->RewritePartition = FALSE;
243         DPRINT(" %ld: nr: %d boot: %1x type: %x start: 0x%I64x count: 0x%I64x rec: %d\n",
244                Part,
245                PartInfo->PartitionNumber,
246                PartInfo->BootIndicator,
247                PartInfo->PartitionType,
248                PartInfo->StartingOffset.QuadPart,
249                PartInfo->PartitionLength.QuadPart,
250                PartInfo->RecognizedPartition);
251     }
252 
253     return STATUS_SUCCESS;
254 }
255 
256 static NTSTATUS FASTCALL
257 HalpXboxIoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject,
258                                   IN ULONG SectorSize,
259                                   IN ULONG PartitionNumber,
260                                   IN ULONG PartitionType)
261 {
262     BOOLEAN HasXboxPartitioning;
263     NTSTATUS Status;
264 
265     DPRINT("HalpXboxIoSetPartitionInformation(%p %lu %lu %lu)\n",
266            DeviceObject,
267            SectorSize,
268            PartitionNumber,
269            PartitionType);
270 
271     Status = HalpXboxDeviceHasXboxPartitioning(DeviceObject, SectorSize, &HasXboxPartitioning);
272     if (!NT_SUCCESS(Status))
273     {
274         return Status;
275     }
276 
277     if (!HasXboxPartitioning)
278     {
279         DPRINT("Delegating to standard MBR code\n");
280         return NtoskrnlIoSetPartitionInformation(DeviceObject, SectorSize,
281                                                  PartitionNumber, PartitionType);
282     }
283 
284     /* Can't change the partitioning */
285     DPRINT1("Xbox partitions are fixed, can't change them\n");
286     return STATUS_ACCESS_DENIED;
287 }
288 
289 static NTSTATUS FASTCALL
290 HalpXboxIoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject,
291                               IN ULONG SectorSize,
292                               IN ULONG SectorsPerTrack,
293                               IN ULONG NumberOfHeads,
294                               IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer)
295 {
296     BOOLEAN HasXboxPartitioning;
297     NTSTATUS Status;
298 
299     DPRINT("HalpXboxIoWritePartitionTable(%p %lu %lu %lu %p)\n",
300            DeviceObject,
301            SectorSize,
302            SectorsPerTrack,
303            NumberOfHeads,
304            PartitionBuffer);
305 
306     Status = HalpXboxDeviceHasXboxPartitioning(DeviceObject, SectorSize, &HasXboxPartitioning);
307     if (!NT_SUCCESS(Status))
308     {
309         return Status;
310     }
311 
312     if (!HasXboxPartitioning)
313     {
314         DPRINT("Delegating to standard MBR code\n");
315         return NtoskrnlIoWritePartitionTable(DeviceObject, SectorSize,
316                                              SectorsPerTrack, NumberOfHeads,
317                                              PartitionBuffer);
318     }
319 
320     /* Can't change the partitioning */
321     DPRINT1("Xbox partitions are fixed, can't change them\n");
322     return STATUS_ACCESS_DENIED;
323 }
324 
325 #define HalExamineMBR                   HALDISPATCH->HalExamineMBR
326 #define HalIoReadPartitionTable         HALDISPATCH->HalIoReadPartitionTable
327 #define HalIoSetPartitionInformation    HALDISPATCH->HalIoSetPartitionInformation
328 #define HalIoWritePartitionTable        HALDISPATCH->HalIoWritePartitionTable
329 
330 void
331 HalpXboxInitPartIo(void)
332 {
333     NtoskrnlExamineMBR = HalExamineMBR;
334     HalExamineMBR = HalpXboxExamineMBR;
335     NtoskrnlIoReadPartitionTable = HalIoReadPartitionTable;
336     HalIoReadPartitionTable = HalpXboxIoReadPartitionTable;
337     NtoskrnlIoSetPartitionInformation = HalIoSetPartitionInformation;
338     HalIoSetPartitionInformation = HalpXboxIoSetPartitionInformation;
339     NtoskrnlIoWritePartitionTable = HalIoWritePartitionTable;
340     HalIoWritePartitionTable = HalpXboxIoWritePartitionTable;
341 }
342 
343 /* EOF */
344