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