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
HalpXboxReadSector(IN PDEVICE_OBJECT DeviceObject,IN ULONG SectorSize,IN PLARGE_INTEGER SectorOffset,OUT PVOID Sector)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
HalpXboxDeviceHasXboxPartitioning(IN PDEVICE_OBJECT DeviceObject,IN ULONG SectorSize,OUT BOOLEAN * HasXboxPartitioning)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
HalpXboxExamineMBR(IN PDEVICE_OBJECT DeviceObject,IN ULONG SectorSize,IN ULONG MBRTypeIdentifier,OUT PVOID * Buffer)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
HalpXboxIoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject,IN ULONG SectorSize,IN BOOLEAN ReturnRecognizedPartitions,OUT PDRIVE_LAYOUT_INFORMATION * PartitionBuffer)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
HalpXboxIoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject,IN ULONG SectorSize,IN ULONG PartitionNumber,IN ULONG PartitionType)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
HalpXboxIoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject,IN ULONG SectorSize,IN ULONG SectorsPerTrack,IN ULONG NumberOfHeads,IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer)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
HalpXboxInitPartIo(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