Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenfstubex.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/fstub/fstubex.c 00005 * PURPOSE: Extended FSTUB Routines (not linked to HAL) 00006 * PROGRAMMERS: Pierre Schweitzer (pierre.schweitzer@reactos.org) 00007 */ 00008 00009 /* INCLUDES ******************************************************************/ 00010 00011 #include <ntoskrnl.h> 00012 #define NDEBUG 00013 #include <debug.h> 00014 00015 /* PRIVATE FUNCTIONS *********************************************************/ 00016 00017 typedef struct _DISK_INFORMATION 00018 { 00019 PDEVICE_OBJECT DeviceObject; 00020 ULONG SectorSize; 00021 DISK_GEOMETRY_EX DiskGeometry; 00022 PUSHORT Buffer; 00023 ULONGLONG SectorCount; 00024 } DISK_INFORMATION, *PDISK_INFORMATION; 00025 00026 #include <pshpack1.h> 00027 typedef struct _EFI_PARTITION_HEADER 00028 { 00029 ULONGLONG Signature; // 0 00030 ULONG Revision; // 8 00031 ULONG HeaderSize; // 12 00032 ULONG HeaderCRC32; // 16 00033 ULONG Reserved; // 20 00034 ULONGLONG MyLBA; // 24 00035 ULONGLONG AlternateLBA; // 32 00036 ULONGLONG FirstUsableLBA; // 40 00037 ULONGLONG LastUsableLBA; // 48 00038 GUID DiskGUID; // 56 00039 ULONGLONG PartitionEntryLBA; // 72 00040 ULONG NumberOfEntries; // 80 00041 ULONG SizeOfPartitionEntry; // 84 00042 ULONG PartitionEntryCRC32; // 88 00043 } EFI_PARTITION_HEADER, *PEFI_PARTITION_HEADER; 00044 #include <poppack.h> 00045 00046 typedef struct _EFI_PARTITION_ENTRY 00047 { 00048 GUID PartitionType; // 0 00049 GUID UniquePartition; // 16 00050 ULONGLONG StartingLBA; // 32 00051 ULONGLONG EndingLBA; // 40 00052 ULONGLONG Attributes; // 48 00053 WCHAR Name[0x24]; // 56 00054 } EFI_PARTITION_ENTRY, *PEFI_PARTITION_ENTRY; 00055 00056 typedef struct _PARTITION_TABLE_ENTRY 00057 { 00058 UCHAR BootIndicator; 00059 UCHAR StartHead; 00060 UCHAR StartSector; 00061 UCHAR StartCylinder; 00062 UCHAR SystemIndicator; 00063 UCHAR EndHead; 00064 UCHAR EndSector; 00065 UCHAR EndCylinder; 00066 ULONG SectorCountBeforePartition; 00067 ULONG PartitionSectorCount; 00068 } PARTITION_TABLE_ENTRY, *PPARTITION_TABLE_ENTRY; 00069 00070 typedef struct _MASTER_BOOT_RECORD 00071 { 00072 UCHAR MasterBootRecordCodeAndData[0x1B8]; // 0 00073 ULONG Signature; // 440 00074 USHORT Reserved; // 444 00075 PARTITION_TABLE_ENTRY PartitionTable[4]; // 446 00076 USHORT MasterBootRecordMagic; // 510 00077 } MASTER_BOOT_RECORD, *PMASTER_BOOT_RECORD; 00078 00079 /* Tag for Fstub allocations */ 00080 #define TAG_FSTUB 'BtsF' 00081 /* Partition entry size (bytes) - FIXME: It's hardcoded as Microsoft does, but according to specs, it shouldn't be */ 00082 #define PARTITION_ENTRY_SIZE 128 00083 /* Defines "EFI PART" */ 00084 #define EFI_HEADER_SIGNATURE 0x5452415020494645ULL 00085 /* Defines version 1.0 */ 00086 #define EFI_HEADER_REVISION_1 0x00010000 00087 /* Defines system type for MBR showing that a GPT is following */ 00088 #define EFI_PMBR_OSTYPE_EFI 0xEE 00089 00090 #define IS_VALID_DISK_INFO(Disk) \ 00091 (Disk) && \ 00092 (Disk->DeviceObject) && \ 00093 (Disk->SectorSize) && \ 00094 (Disk->Buffer) && \ 00095 (Disk->SectorCount) 00096 00097 VOID 00098 NTAPI 00099 FstubDbgPrintPartitionEx(IN PPARTITION_INFORMATION_EX PartitionEntry, 00100 IN ULONG PartitionNumber 00101 ); 00102 00103 NTSTATUS 00104 NTAPI 00105 FstubDetectPartitionStyle(IN PDISK_INFORMATION Disk, 00106 IN PARTITION_STYLE * PartitionStyle 00107 ); 00108 00109 VOID 00110 NTAPI 00111 FstubFreeDiskInformation(IN PDISK_INFORMATION DiskBuffer 00112 ); 00113 00114 NTSTATUS 00115 NTAPI 00116 FstubGetDiskGeometry(IN PDEVICE_OBJECT DeviceObject, 00117 OUT PDISK_GEOMETRY_EX Geometry 00118 ); 00119 00120 NTSTATUS 00121 NTAPI 00122 FstubReadSector(IN PDEVICE_OBJECT DeviceObject, 00123 IN ULONG SectorSize, 00124 IN ULONGLONG StartingSector OPTIONAL, 00125 OUT PUSHORT Buffer 00126 ); 00127 00128 NTSTATUS 00129 NTAPI 00130 FstubWriteBootSectorEFI(IN PDISK_INFORMATION Disk 00131 ); 00132 00133 NTSTATUS 00134 NTAPI 00135 FstubWritePartitionTableEFI(IN PDISK_INFORMATION Disk, 00136 IN GUID DiskGUID, 00137 IN ULONG MaxPartitionCount, 00138 IN ULONGLONG FirstUsableLBA, 00139 IN ULONGLONG LastUsableLBA, 00140 IN BOOLEAN WriteBackupTable, 00141 IN ULONG PartitionCount, 00142 IN PPARTITION_INFORMATION_EX PartitionEntries OPTIONAL 00143 ); 00144 00145 NTSTATUS 00146 NTAPI 00147 FstubWriteSector(IN PDEVICE_OBJECT DeviceObject, 00148 IN ULONG SectorSize, 00149 IN ULONGLONG StartingSector OPTIONAL, 00150 IN PUSHORT Buffer 00151 ); 00152 00153 VOID 00154 NTAPI 00155 FstubAdjustPartitionCount(IN ULONG SectorSize, 00156 IN OUT PULONG PartitionCount) 00157 { 00158 ULONG Count; 00159 PAGED_CODE(); 00160 00161 ASSERT(SectorSize); 00162 ASSERT(PartitionCount); 00163 00164 /* Get partition count */ 00165 Count = *PartitionCount; 00166 /* We need at least 128 entries */ 00167 if (Count < 128) 00168 { 00169 Count = 128; 00170 } 00171 00172 /* Then, ensure that we will have a round value, 00173 * ie, all sectors will be full of entries 00174 * There won't be lonely entries 00175 */ 00176 Count = (Count * PARTITION_ENTRY_SIZE) / SectorSize; 00177 Count = (Count * SectorSize) / PARTITION_ENTRY_SIZE; 00178 ASSERT(*PartitionCount <= Count); 00179 /* Return result */ 00180 *PartitionCount = Count; 00181 00182 /* One more sanity check */ 00183 if (SectorSize == 512) 00184 { 00185 ASSERT(Count % 4 == 0); 00186 } 00187 } 00188 00189 NTSTATUS 00190 NTAPI 00191 FstubAllocateDiskInformation(IN PDEVICE_OBJECT DeviceObject, 00192 OUT PDISK_INFORMATION * DiskBuffer, 00193 PDISK_GEOMETRY_EX DiskGeometry OPTIONAL) 00194 { 00195 NTSTATUS Status; 00196 PDISK_INFORMATION DiskInformation; 00197 PAGED_CODE(); 00198 00199 ASSERT(DeviceObject); 00200 ASSERT(DiskBuffer); 00201 00202 /* Allocate internal structure */ 00203 DiskInformation = ExAllocatePoolWithTag(NonPagedPool, sizeof(DISK_INFORMATION), TAG_FSTUB); 00204 if (!DiskInformation) 00205 { 00206 return STATUS_INSUFFICIENT_RESOURCES; 00207 } 00208 00209 /* If caller don't pass needed information, let's get them */ 00210 if (!DiskGeometry) 00211 { 00212 Status = FstubGetDiskGeometry(DeviceObject, &(DiskInformation->DiskGeometry)); 00213 if (!NT_SUCCESS(Status)) 00214 { 00215 ExFreePoolWithTag(DiskInformation, TAG_FSTUB); 00216 return Status; 00217 } 00218 } 00219 else 00220 { 00221 DiskInformation->DiskGeometry = *DiskGeometry; 00222 } 00223 00224 /* Ensure read/received information are correct */ 00225 if (DiskInformation->DiskGeometry.Geometry.BytesPerSector == 0 || 00226 DiskInformation->DiskGeometry.DiskSize.QuadPart == 0) 00227 { 00228 ExFreePoolWithTag(DiskInformation, TAG_FSTUB); 00229 return STATUS_DEVICE_NOT_READY; 00230 } 00231 00232 /* Store vital information as well */ 00233 DiskInformation->DeviceObject = DeviceObject; 00234 DiskInformation->SectorSize = DiskInformation->DiskGeometry.Geometry.BytesPerSector; 00235 DiskInformation->SectorCount = DiskInformation->DiskGeometry.DiskSize.QuadPart / DiskInformation->SectorSize; 00236 00237 /* Finally, allocate the buffer that will be used for different read */ 00238 DiskInformation->Buffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, DiskInformation->SectorSize, TAG_FSTUB); 00239 if (!DiskInformation->Buffer) 00240 { 00241 ExFreePoolWithTag(DiskInformation, TAG_FSTUB); 00242 return STATUS_INSUFFICIENT_RESOURCES; 00243 } 00244 00245 /* Return allocated internal structure */ 00246 *DiskBuffer = DiskInformation; 00247 00248 return STATUS_SUCCESS; 00249 } 00250 00251 PDRIVE_LAYOUT_INFORMATION 00252 NTAPI 00253 FstubConvertExtendedToLayout(IN PDRIVE_LAYOUT_INFORMATION_EX LayoutEx) 00254 { 00255 ULONG i; 00256 PDRIVE_LAYOUT_INFORMATION DriveLayout; 00257 PAGED_CODE(); 00258 00259 ASSERT(LayoutEx); 00260 00261 /* Check whether we're dealing with MBR partition table */ 00262 if (LayoutEx->PartitionStyle != PARTITION_STYLE_MBR) 00263 { 00264 ASSERT(FALSE); 00265 return NULL; 00266 } 00267 00268 /* Allocate needed buffer */ 00269 DriveLayout = ExAllocatePoolWithTag(NonPagedPool, 00270 FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry) + 00271 LayoutEx->PartitionCount * sizeof(PARTITION_INFORMATION), 00272 'BtsF'); 00273 if (!DriveLayout) 00274 { 00275 return NULL; 00276 } 00277 00278 /* Convert information about partition table */ 00279 DriveLayout->PartitionCount = LayoutEx->PartitionCount; 00280 DriveLayout->Signature = LayoutEx->Mbr.Signature; 00281 00282 /* Convert each partition */ 00283 for (i = 0; i < LayoutEx->PartitionCount; i++) 00284 { 00285 DriveLayout->PartitionEntry[i].StartingOffset = LayoutEx->PartitionEntry[i].StartingOffset; 00286 DriveLayout->PartitionEntry[i].PartitionLength = LayoutEx->PartitionEntry[i].PartitionLength; 00287 DriveLayout->PartitionEntry[i].HiddenSectors = LayoutEx->PartitionEntry[i].Mbr.HiddenSectors; 00288 DriveLayout->PartitionEntry[i].PartitionNumber = LayoutEx->PartitionEntry[i].PartitionNumber; 00289 DriveLayout->PartitionEntry[i].PartitionType = LayoutEx->PartitionEntry[i].Mbr.PartitionType; 00290 DriveLayout->PartitionEntry[i].BootIndicator = LayoutEx->PartitionEntry[i].Mbr.BootIndicator; 00291 DriveLayout->PartitionEntry[i].RecognizedPartition = LayoutEx->PartitionEntry[i].Mbr.RecognizedPartition; 00292 DriveLayout->PartitionEntry[i].RewritePartition = LayoutEx->PartitionEntry[i].RewritePartition; 00293 } 00294 00295 return DriveLayout; 00296 } 00297 00298 VOID 00299 NTAPI 00300 FstubCopyEntryEFI(OUT PEFI_PARTITION_ENTRY Entry, 00301 IN PPARTITION_INFORMATION_EX Partition, 00302 ULONG SectorSize) 00303 { 00304 PAGED_CODE(); 00305 00306 ASSERT(Entry); 00307 ASSERT(Partition); 00308 ASSERT(SectorSize); 00309 00310 /* Just convert data to EFI partition entry type */ 00311 Entry->PartitionType = Partition->Gpt.PartitionType; 00312 Entry->UniquePartition = Partition->Gpt.PartitionId; 00313 Entry->StartingLBA = Partition->StartingOffset.QuadPart / SectorSize; 00314 Entry->EndingLBA = (Partition->StartingOffset.QuadPart + Partition->PartitionLength.QuadPart - 1) / SectorSize; 00315 Entry->Attributes = Partition->Gpt.Attributes; 00316 RtlCopyMemory(Entry->Name, Partition->Gpt.Name, sizeof(Entry->Name)); 00317 } 00318 00319 NTSTATUS 00320 NTAPI 00321 FstubCreateDiskMBR(IN PDEVICE_OBJECT DeviceObject, 00322 IN PCREATE_DISK_MBR DiskInfo) 00323 { 00324 NTSTATUS Status; 00325 PDISK_INFORMATION Disk = NULL; 00326 PMASTER_BOOT_RECORD MasterBootRecord; 00327 PAGED_CODE(); 00328 00329 ASSERT(DeviceObject); 00330 00331 /* Allocate internal structure */ 00332 Status = FstubAllocateDiskInformation(DeviceObject, &Disk, 0); 00333 if (!NT_SUCCESS(Status)) 00334 { 00335 return Status; 00336 } 00337 00338 /* Read previous MBR, if any */ 00339 Status = FstubReadSector(Disk->DeviceObject, 00340 Disk->SectorSize, 00341 0ULL, 00342 Disk->Buffer); 00343 if (!NT_SUCCESS(Status)) 00344 { 00345 FstubFreeDiskInformation(Disk); 00346 return Status; 00347 } 00348 /* Fill the buffer with needed information, we won't overwrite boot code */ 00349 MasterBootRecord = (PMASTER_BOOT_RECORD)Disk->Buffer; 00350 MasterBootRecord->Signature = DiskInfo->Signature; 00351 RtlZeroMemory(MasterBootRecord->PartitionTable, sizeof(PARTITION_TABLE_ENTRY) * 4); 00352 MasterBootRecord->MasterBootRecordMagic = BOOT_RECORD_SIGNATURE; 00353 00354 /* Finally, write MBR */ 00355 Status = FstubWriteSector(Disk->DeviceObject, 00356 Disk->SectorSize, 00357 0ULL, 00358 Disk->Buffer); 00359 00360 /* Release internal structure and return */ 00361 FstubFreeDiskInformation(Disk); 00362 return Status; 00363 } 00364 00365 NTSTATUS 00366 NTAPI 00367 FstubCreateDiskEFI(IN PDEVICE_OBJECT DeviceObject, 00368 IN PCREATE_DISK_GPT DiskInfo) 00369 { 00370 NTSTATUS Status; 00371 PDISK_INFORMATION Disk = NULL; 00372 ULONGLONG FirstUsableLBA, LastUsableLBA; 00373 ULONG MaxPartitionCount, SectorsForPartitions; 00374 PAGED_CODE(); 00375 00376 ASSERT(DeviceObject); 00377 ASSERT(DiskInfo); 00378 00379 /* Allocate internal structure */ 00380 Status = FstubAllocateDiskInformation(DeviceObject, &Disk, 0); 00381 if (!NT_SUCCESS(Status)) 00382 { 00383 return Status; 00384 } 00385 ASSERT(Disk); 00386 00387 /* Write legacy MBR */ 00388 Status = FstubWriteBootSectorEFI(Disk); 00389 if (!NT_SUCCESS(Status)) 00390 { 00391 FstubFreeDiskInformation(Disk); 00392 return Status; 00393 } 00394 00395 /* Get max entries and adjust its number */ 00396 MaxPartitionCount = DiskInfo->MaxPartitionCount; 00397 FstubAdjustPartitionCount(Disk->SectorSize, &MaxPartitionCount); 00398 00399 /* Count number of sectors needed to store partitions */ 00400 SectorsForPartitions = (MaxPartitionCount * PARTITION_ENTRY_SIZE) / Disk->SectorSize; 00401 /* Set first usable LBA: Legacy MBR + GPT header + Partitions entries */ 00402 FirstUsableLBA = SectorsForPartitions + 2; 00403 /* Set last usable LBA: Last sector - GPT header - Partitions entries */ 00404 LastUsableLBA = Disk->SectorCount - SectorsForPartitions - 1; 00405 00406 /* First, write primary table */ 00407 Status = FstubWritePartitionTableEFI(Disk, 00408 DiskInfo->DiskId, 00409 MaxPartitionCount, 00410 FirstUsableLBA, 00411 LastUsableLBA, 00412 FALSE, 00413 0, 00414 NULL); 00415 /* Then, write backup table */ 00416 if (NT_SUCCESS(Status)) 00417 { 00418 Status = FstubWritePartitionTableEFI(Disk, 00419 DiskInfo->DiskId, 00420 MaxPartitionCount, 00421 FirstUsableLBA, 00422 LastUsableLBA, 00423 TRUE, 00424 0, 00425 NULL); 00426 } 00427 00428 /* Release internal structure and return */ 00429 FstubFreeDiskInformation(Disk); 00430 return Status; 00431 } 00432 00433 NTSTATUS 00434 NTAPI 00435 FstubCreateDiskRaw(IN PDEVICE_OBJECT DeviceObject) 00436 { 00437 NTSTATUS Status; 00438 PDISK_INFORMATION Disk = NULL; 00439 PARTITION_STYLE PartitionStyle; 00440 PMASTER_BOOT_RECORD MasterBootRecord; 00441 PAGED_CODE(); 00442 00443 ASSERT(DeviceObject); 00444 00445 /* Allocate internal structure */ 00446 Status = FstubAllocateDiskInformation(DeviceObject, &Disk, 0); 00447 if (!NT_SUCCESS(Status)) 00448 { 00449 return Status; 00450 } 00451 00452 /* Detect current disk partition style */ 00453 Status = FstubDetectPartitionStyle(Disk, &PartitionStyle); 00454 if (!NT_SUCCESS(Status)) 00455 { 00456 FstubFreeDiskInformation(Disk); 00457 return Status; 00458 } 00459 00460 /* Read MBR, if any */ 00461 Status = FstubReadSector(Disk->DeviceObject, 00462 Disk->SectorSize, 00463 0ULL, 00464 Disk->Buffer); 00465 if (!NT_SUCCESS(Status)) 00466 { 00467 FstubFreeDiskInformation(Disk); 00468 return Status; 00469 } 00470 00471 /* Only zero useful stuff */ 00472 MasterBootRecord = (PMASTER_BOOT_RECORD)Disk->Buffer; 00473 MasterBootRecord->Signature = 0; 00474 RtlZeroMemory(MasterBootRecord->PartitionTable, sizeof(PARTITION_TABLE_ENTRY)); 00475 MasterBootRecord->MasterBootRecordMagic = 0; 00476 00477 /* Write back that destroyed MBR */ 00478 Status = FstubWriteSector(Disk->DeviceObject, 00479 Disk->SectorSize, 00480 0ULL, 00481 Disk->Buffer); 00482 /* If previous style wasn't GPT, we're done here */ 00483 if (PartitionStyle != PARTITION_STYLE_GPT) 00484 { 00485 FstubFreeDiskInformation(Disk); 00486 return Status; 00487 } 00488 00489 /* Otherwise, we've to zero the two GPT headers */ 00490 RtlZeroMemory(Disk->Buffer, Disk->SectorSize); 00491 /* Erase primary header */ 00492 Status = FstubWriteSector(Disk->DeviceObject, 00493 Disk->SectorSize, 00494 1ULL, 00495 Disk->Buffer); 00496 /* In case of success, erase backup header */ 00497 if (NT_SUCCESS(Status)) 00498 { 00499 Status = FstubWriteSector(Disk->DeviceObject, 00500 Disk->SectorSize, 00501 Disk->SectorCount - 1ULL, 00502 Disk->Buffer); 00503 } 00504 00505 /* Release internal structure and return */ 00506 FstubFreeDiskInformation(Disk); 00507 return Status; 00508 } 00509 00510 PCHAR 00511 NTAPI 00512 FstubDbgGuidToString(IN PGUID Guid, 00513 OUT PCHAR String) 00514 { 00515 sprintf(String, 00516 "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", 00517 Guid->Data1, 00518 Guid->Data2, 00519 Guid->Data3, 00520 Guid->Data4[0], 00521 Guid->Data4[1], 00522 Guid->Data4[2], 00523 Guid->Data4[3], 00524 Guid->Data4[4], 00525 Guid->Data4[5], 00526 Guid->Data4[6], 00527 Guid->Data4[7]); 00528 00529 return String; 00530 } 00531 00532 VOID 00533 NTAPI 00534 FstubDbgPrintDriveLayoutEx(IN PDRIVE_LAYOUT_INFORMATION_EX DriveLayout) 00535 { 00536 ULONG i; 00537 CHAR Guid[38]; 00538 PAGED_CODE(); 00539 00540 DPRINT("FSTUB: DRIVE_LAYOUT_INFORMATION_EX: %p\n", DriveLayout); 00541 switch (DriveLayout->PartitionStyle) 00542 { 00543 case PARTITION_STYLE_MBR: 00544 if (DriveLayout->PartitionCount % 4 != 0) 00545 { 00546 DPRINT("Warning: Partition count isn't a 4-factor: %ld!\n", DriveLayout->PartitionCount); 00547 } 00548 00549 DPRINT("Signature: %8.8x\n", DriveLayout->Mbr.Signature); 00550 for (i = 0; i < DriveLayout->PartitionCount; i++) 00551 { 00552 FstubDbgPrintPartitionEx(DriveLayout->PartitionEntry, i); 00553 } 00554 00555 break; 00556 case PARTITION_STYLE_GPT: 00557 FstubDbgGuidToString(&(DriveLayout->Gpt.DiskId), Guid); 00558 DPRINT("DiskId: %s\n", Guid); 00559 DPRINT("StartingUsableOffset: %I64x\n", DriveLayout->Gpt.StartingUsableOffset.QuadPart); 00560 DPRINT("UsableLength: %I64x\n", DriveLayout->Gpt.UsableLength.QuadPart); 00561 DPRINT("MaxPartitionCount: %ld\n", DriveLayout->Gpt.MaxPartitionCount); 00562 for (i = 0; i < DriveLayout->PartitionCount; i++) 00563 { 00564 FstubDbgPrintPartitionEx(DriveLayout->PartitionEntry, i); 00565 } 00566 00567 break; 00568 default: 00569 DPRINT("Unsupported partition style: %ld\n", DriveLayout->PartitionStyle); 00570 } 00571 } 00572 00573 VOID 00574 NTAPI 00575 FstubDbgPrintPartitionEx(IN PPARTITION_INFORMATION_EX PartitionEntry, 00576 IN ULONG PartitionNumber) 00577 { 00578 CHAR Guid[38]; 00579 PAGED_CODE(); 00580 00581 DPRINT("Printing partition %ld\n", PartitionNumber); 00582 00583 switch (PartitionEntry[PartitionNumber].PartitionStyle) 00584 { 00585 case PARTITION_STYLE_MBR: 00586 DPRINT(" StartingOffset: %I64x\n", PartitionEntry[PartitionNumber].StartingOffset.QuadPart); 00587 DPRINT(" PartitionLength: %I64x\n", PartitionEntry[PartitionNumber].PartitionLength.QuadPart); 00588 DPRINT(" RewritePartition: %d\n", PartitionEntry[PartitionNumber].RewritePartition); 00589 DPRINT(" PartitionType: %02x\n", PartitionEntry[PartitionNumber].Mbr.PartitionType); 00590 DPRINT(" BootIndicator: %d\n", PartitionEntry[PartitionNumber].Mbr.BootIndicator); 00591 DPRINT(" RecognizedPartition: %d\n", PartitionEntry[PartitionNumber].Mbr.RecognizedPartition); 00592 DPRINT(" HiddenSectors: %ld\n", PartitionEntry[PartitionNumber].Mbr.HiddenSectors); 00593 00594 break; 00595 case PARTITION_STYLE_GPT: 00596 DPRINT(" StartingOffset: %I64x\n", PartitionEntry[PartitionNumber].StartingOffset.QuadPart); 00597 DPRINT(" PartitionLength: %I64x\n", PartitionEntry[PartitionNumber].PartitionLength.QuadPart); 00598 DPRINT(" RewritePartition: %d\n", PartitionEntry[PartitionNumber].RewritePartition); 00599 FstubDbgGuidToString(&(PartitionEntry[PartitionNumber].Gpt.PartitionType), Guid); 00600 DPRINT(" PartitionType: %s\n", Guid); 00601 FstubDbgGuidToString(&(PartitionEntry[PartitionNumber].Gpt.PartitionId), Guid); 00602 DPRINT(" PartitionId: %s\n", Guid); 00603 DPRINT(" Attributes: %16x\n", PartitionEntry[PartitionNumber].Gpt.Attributes); 00604 DPRINT(" Name: %ws\n", PartitionEntry[PartitionNumber].Gpt.Name); 00605 00606 break; 00607 default: 00608 DPRINT(" Unsupported partition style: %ld\n", PartitionEntry[PartitionNumber].PartitionStyle); 00609 } 00610 } 00611 00612 VOID 00613 NTAPI 00614 FstubDbgPrintSetPartitionEx(IN PSET_PARTITION_INFORMATION_EX PartitionEntry, 00615 IN ULONG PartitionNumber) 00616 { 00617 CHAR Guid[38]; 00618 PAGED_CODE(); 00619 00620 DPRINT("FSTUB: SET_PARTITION_INFORMATION_EX: %p\n", PartitionEntry); 00621 DPRINT("Modifying partition %ld\n", PartitionNumber); 00622 switch (PartitionEntry->PartitionStyle) 00623 { 00624 case PARTITION_STYLE_MBR: 00625 DPRINT(" PartitionType: %02x\n", PartitionEntry->Mbr.PartitionType); 00626 00627 break; 00628 case PARTITION_STYLE_GPT: 00629 FstubDbgGuidToString(&(PartitionEntry->Gpt.PartitionType), Guid); 00630 DPRINT(" PartitionType: %s\n", Guid); 00631 FstubDbgGuidToString(&(PartitionEntry->Gpt.PartitionId), Guid); 00632 DPRINT(" PartitionId: %s\n", Guid); 00633 DPRINT(" Attributes: %16x\n", PartitionEntry->Gpt.Attributes); 00634 DPRINT(" Name: %ws\n", PartitionEntry->Gpt.Name); 00635 00636 break; 00637 default: 00638 DPRINT(" Unsupported partition style: %ld\n", PartitionEntry[PartitionNumber].PartitionStyle); 00639 } 00640 } 00641 00642 NTSTATUS 00643 NTAPI 00644 FstubDetectPartitionStyle(IN PDISK_INFORMATION Disk, 00645 IN PARTITION_STYLE * PartitionStyle) 00646 { 00647 NTSTATUS Status; 00648 PPARTITION_DESCRIPTOR PartitionDescriptor; 00649 PAGED_CODE(); 00650 00651 ASSERT(IS_VALID_DISK_INFO(Disk)); 00652 ASSERT(PartitionStyle); 00653 00654 /* Read disk first sector */ 00655 Status = FstubReadSector(Disk->DeviceObject, 00656 Disk->SectorSize, 00657 0, 00658 Disk->Buffer); 00659 if (!NT_SUCCESS(Status)) 00660 { 00661 return Status; 00662 } 00663 00664 /* Get the partition descriptor array */ 00665 PartitionDescriptor = (PPARTITION_DESCRIPTOR) 00666 &(Disk->Buffer[PARTITION_TABLE_OFFSET]); 00667 /* If we have not the 0xAA55 then it's raw partition */ 00668 if (Disk->Buffer[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) 00669 { 00670 *PartitionStyle = PARTITION_STYLE_RAW; 00671 } 00672 /* Check partitions types: if first is 0xEE and all the others 0, we have GPT */ 00673 else if (PartitionDescriptor[0].PartitionType == EFI_PMBR_OSTYPE_EFI && 00674 PartitionDescriptor[1].PartitionType == 0 && 00675 PartitionDescriptor[2].PartitionType == 0 && 00676 PartitionDescriptor[3].PartitionType == 0) 00677 { 00678 *PartitionStyle = PARTITION_STYLE_GPT; 00679 } 00680 /* Otherwise, partition table is in MBR */ 00681 else 00682 { 00683 *PartitionStyle = PARTITION_STYLE_MBR; 00684 } 00685 00686 return STATUS_SUCCESS; 00687 } 00688 00689 VOID 00690 NTAPI 00691 FstubFreeDiskInformation(IN PDISK_INFORMATION DiskBuffer) 00692 { 00693 if (DiskBuffer) 00694 { 00695 if (DiskBuffer->Buffer) 00696 { 00697 ExFreePoolWithTag(DiskBuffer->Buffer, TAG_FSTUB); 00698 } 00699 ExFreePoolWithTag(DiskBuffer, TAG_FSTUB); 00700 } 00701 } 00702 00703 NTSTATUS 00704 NTAPI 00705 FstubGetDiskGeometry(IN PDEVICE_OBJECT DeviceObject, 00706 OUT PDISK_GEOMETRY_EX Geometry) 00707 { 00708 PIRP Irp; 00709 NTSTATUS Status; 00710 PKEVENT Event = NULL; 00711 PDISK_GEOMETRY_EX DiskGeometry = NULL; 00712 PIO_STATUS_BLOCK IoStatusBlock = NULL; 00713 PAGED_CODE(); 00714 00715 ASSERT(DeviceObject); 00716 ASSERT(Geometry); 00717 00718 /* Allocate needed components */ 00719 DiskGeometry = ExAllocatePoolWithTag(NonPagedPool, sizeof(DISK_GEOMETRY_EX), TAG_FSTUB); 00720 if (!DiskGeometry) 00721 { 00722 Status = STATUS_INSUFFICIENT_RESOURCES; 00723 goto Cleanup; 00724 } 00725 00726 IoStatusBlock = ExAllocatePoolWithTag(NonPagedPool, sizeof(IO_STATUS_BLOCK), TAG_FSTUB); 00727 if (!IoStatusBlock) 00728 { 00729 Status = STATUS_INSUFFICIENT_RESOURCES; 00730 goto Cleanup; 00731 } 00732 00733 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_FSTUB); 00734 if (!Event) 00735 { 00736 Status = STATUS_INSUFFICIENT_RESOURCES; 00737 goto Cleanup; 00738 } 00739 /* Initialize the waiting event */ 00740 KeInitializeEvent(Event, NotificationEvent, FALSE); 00741 00742 /* Build the request to get disk geometry */ 00743 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, 00744 DeviceObject, 00745 0, 00746 0, 00747 DiskGeometry, 00748 sizeof(DISK_GEOMETRY_EX), 00749 FALSE, 00750 Event, 00751 IoStatusBlock); 00752 if (!Irp) 00753 { 00754 Status = STATUS_INSUFFICIENT_RESOURCES; 00755 goto Cleanup; 00756 } 00757 00758 /* Call the driver and wait for completion if needed */ 00759 Status = IoCallDriver(DeviceObject, Irp); 00760 if (Status == STATUS_PENDING) 00761 { 00762 KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL); 00763 Status = IoStatusBlock->Status; 00764 } 00765 00766 /* In case of a success, return read data */ 00767 if (NT_SUCCESS(Status)) 00768 { 00769 *Geometry = *DiskGeometry; 00770 } 00771 00772 Cleanup: 00773 if (DiskGeometry) 00774 { 00775 ExFreePoolWithTag(DiskGeometry, TAG_FSTUB); 00776 00777 if (NT_SUCCESS(Status)) 00778 { 00779 ASSERT(Geometry->Geometry.BytesPerSector % PARTITION_ENTRY_SIZE == 0); 00780 } 00781 } 00782 00783 if (IoStatusBlock) 00784 { 00785 ExFreePoolWithTag(IoStatusBlock, TAG_FSTUB); 00786 } 00787 00788 if (Event) 00789 { 00790 ExFreePoolWithTag(Event, TAG_FSTUB); 00791 } 00792 00793 return Status; 00794 } 00795 00796 NTSTATUS 00797 NTAPI 00798 FstubReadHeaderEFI(IN PDISK_INFORMATION Disk, 00799 IN BOOLEAN ReadBackupTable, 00800 PEFI_PARTITION_HEADER HeaderBuffer) 00801 { 00802 NTSTATUS Status; 00803 PUCHAR Sector = NULL; 00804 ULONGLONG StartingSector; 00805 PEFI_PARTITION_HEADER EFIHeader; 00806 ULONG i, HeaderCRC32, PreviousCRC32, SectoredPartitionEntriesSize, LonelyPartitions; 00807 PAGED_CODE(); 00808 00809 ASSERT(Disk); 00810 ASSERT(IS_VALID_DISK_INFO(Disk)); 00811 ASSERT(HeaderBuffer); 00812 00813 /* In case we want to read backup table, we read last disk sector */ 00814 if (ReadBackupTable) 00815 { 00816 StartingSector = Disk->SectorCount - 1ULL; 00817 } 00818 else 00819 { 00820 /* Otherwise we start at first sector (as sector 0 is the MBR) */ 00821 StartingSector = 1ULL; 00822 } 00823 00824 Status = FstubReadSector(Disk->DeviceObject, 00825 Disk->SectorSize, 00826 StartingSector, 00827 Disk->Buffer); 00828 if (!NT_SUCCESS(Status)) 00829 { 00830 DPRINT("EFI::Failed reading header!\n"); 00831 return Status; 00832 } 00833 /* Let's use read buffer as EFI_PARTITION_HEADER */ 00834 EFIHeader = (PEFI_PARTITION_HEADER)Disk->Buffer; 00835 00836 00837 /* First check signature 00838 * Then, check version (we only support v1) 00839 * Finally check header size 00840 */ 00841 if (EFIHeader->Signature != EFI_HEADER_SIGNATURE || 00842 EFIHeader->Revision != EFI_HEADER_REVISION_1 || 00843 EFIHeader->HeaderSize != sizeof(EFI_PARTITION_HEADER)) 00844 { 00845 DPRINT("EFI::Wrong signature/version/header size!\n"); 00846 DPRINT("%I64x (expected: %I64x)\n", EFIHeader->Signature, EFI_HEADER_SIGNATURE); 00847 DPRINT("%03x (expected: %03x)\n", EFIHeader->Revision, EFI_HEADER_REVISION_1); 00848 DPRINT("%02x (expected: %02x)\n", EFIHeader->HeaderSize, sizeof(EFI_PARTITION_HEADER)); 00849 return STATUS_DISK_CORRUPT_ERROR; 00850 } 00851 00852 /* Save current checksum */ 00853 HeaderCRC32 = EFIHeader->HeaderCRC32; 00854 /* Then zero the one in EFI header. This is needed to compute header checksum */ 00855 EFIHeader->HeaderCRC32 = 0; 00856 /* Compute header checksum and compare with the one present in partition table */ 00857 if (RtlComputeCrc32(0, (PUCHAR)Disk->Buffer, sizeof(EFI_PARTITION_HEADER)) != HeaderCRC32) 00858 { 00859 DPRINT("EFI::Not matching header checksum!\n"); 00860 return STATUS_DISK_CORRUPT_ERROR; 00861 } 00862 /* Put back removed checksum in header */ 00863 EFIHeader->HeaderCRC32 = HeaderCRC32; 00864 00865 /* Check if current LBA is matching with ours */ 00866 if (EFIHeader->MyLBA != StartingSector) 00867 { 00868 DPRINT("EFI::Not matching starting sector!\n"); 00869 return STATUS_DISK_CORRUPT_ERROR; 00870 } 00871 00872 /* Allocate a buffer to read a sector on the disk */ 00873 Sector = ExAllocatePoolWithTag(NonPagedPool, 00874 Disk->SectorSize, 00875 TAG_FSTUB); 00876 if (!Sector) 00877 { 00878 DPRINT("EFI::Lacking resources!\n"); 00879 return STATUS_INSUFFICIENT_RESOURCES; 00880 } 00881 00882 /* Count how much sectors we'll have to read to read the whole partition table */ 00883 SectoredPartitionEntriesSize = (EFIHeader->NumberOfEntries * PARTITION_ENTRY_SIZE) / Disk->SectorSize; 00884 /* Compute partition table checksum */ 00885 for (i = 0, PreviousCRC32 = 0; i < SectoredPartitionEntriesSize; i++) 00886 { 00887 Status = FstubReadSector(Disk->DeviceObject, 00888 Disk->SectorSize, 00889 EFIHeader->PartitionEntryLBA + i, 00890 (PUSHORT)Sector); 00891 if (!NT_SUCCESS(Status)) 00892 { 00893 ExFreePoolWithTag(Sector, TAG_FSTUB); 00894 DPRINT("EFI::Failed reading sector for partition entry!\n"); 00895 return Status; 00896 } 00897 00898 PreviousCRC32 = RtlComputeCrc32(PreviousCRC32, Sector, Disk->SectorSize); 00899 } 00900 00901 /* Check whether we have a last sector not full of partitions */ 00902 LonelyPartitions = (EFIHeader->NumberOfEntries * PARTITION_ENTRY_SIZE) % Disk->SectorSize; 00903 /* In such case, we have to complete checksum computation */ 00904 if (LonelyPartitions != 0) 00905 { 00906 /* Read the sector that contains those partitions */ 00907 Status = FstubReadSector(Disk->DeviceObject, 00908 Disk->SectorSize, 00909 EFIHeader->PartitionEntryLBA + i, 00910 (PUSHORT)Sector); 00911 if (!NT_SUCCESS(Status)) 00912 { 00913 ExFreePoolWithTag(Sector, TAG_FSTUB); 00914 DPRINT("EFI::Failed reading sector for partition entry!\n"); 00915 return Status; 00916 } 00917 00918 /* Then complete checksum by computing on each partition */ 00919 for (i = 0; i < LonelyPartitions; i++) 00920 { 00921 PreviousCRC32 = RtlComputeCrc32(PreviousCRC32, Sector + i * PARTITION_ENTRY_SIZE, PARTITION_ENTRY_SIZE); 00922 } 00923 } 00924 00925 /* Finally, release memory */ 00926 ExFreePoolWithTag(Sector, TAG_FSTUB); 00927 00928 /* Compare checksums */ 00929 if (PreviousCRC32 == EFIHeader->PartitionEntryCRC32) 00930 { 00931 /* In case of a success, return read header */ 00932 *HeaderBuffer = *EFIHeader; 00933 return STATUS_SUCCESS; 00934 } 00935 else 00936 { 00937 DPRINT("EFI::Not matching partition table checksum!\n"); 00938 DPRINT("EFI::Expected: %x, received: %x\n", EFIHeader->PartitionEntryCRC32, PreviousCRC32); 00939 return STATUS_DISK_CORRUPT_ERROR; 00940 } 00941 } 00942 00943 NTSTATUS 00944 NTAPI 00945 FstubReadPartitionTableEFI(IN PDISK_INFORMATION Disk, 00946 IN BOOLEAN ReadBackupTable, 00947 OUT struct _DRIVE_LAYOUT_INFORMATION_EX** DriveLayout) 00948 { 00949 NTSTATUS Status; 00950 EFI_PARTITION_HEADER EfiHeader; 00951 ULONGLONG SectorsForPartitions; 00952 EFI_PARTITION_ENTRY PartitionEntry; 00953 BOOLEAN UpdatedPartitionTable = FALSE; 00954 PDRIVE_LAYOUT_INFORMATION_EX DriveLayoutEx = NULL; 00955 ULONG i, PartitionCount, PartitionIndex, PartitionsPerSector; 00956 PAGED_CODE(); 00957 00958 ASSERT(Disk); 00959 00960 /* Zero output */ 00961 *DriveLayout = NULL; 00962 00963 /* Read EFI header */ 00964 Status = FstubReadHeaderEFI(Disk, 00965 ReadBackupTable, 00966 &EfiHeader); 00967 if (!NT_SUCCESS(Status)) 00968 { 00969 return Status; 00970 } 00971 00972 /* Allocate a DRIVE_LAYOUT_INFORMATION_EX struct big enough */ 00973 DriveLayoutEx = ExAllocatePoolWithTag(NonPagedPool, 00974 FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry) + 00975 EfiHeader.NumberOfEntries * sizeof(PARTITION_INFORMATION_EX), 00976 TAG_FSTUB); 00977 if (!DriveLayoutEx) 00978 { 00979 return STATUS_INSUFFICIENT_RESOURCES; 00980 } 00981 00982 if (ReadBackupTable) 00983 { 00984 /* If we read backup but if it doesn't match with current geometry */ 00985 if ((Disk->SectorCount - 1ULL) != EfiHeader.AlternateLBA) 00986 { 00987 /* We'll update it. First, count number of sectors needed to store partitions */ 00988 SectorsForPartitions = (EfiHeader.NumberOfEntries * PARTITION_ENTRY_SIZE) / Disk->SectorSize; 00989 /* Then set first usable LBA: Legacy MBR + GPT header + Partitions entries */ 00990 EfiHeader.FirstUsableLBA = SectorsForPartitions + 2; 00991 /* Then set last usable LBA: Last sector - GPT header - Partitions entries */ 00992 EfiHeader.LastUsableLBA = Disk->SectorCount - SectorsForPartitions - 1; 00993 /* Inform that we'll rewrite partition table */ 00994 UpdatedPartitionTable = TRUE; 00995 } 00996 } 00997 00998 DriveLayoutEx->PartitionStyle = PARTITION_STYLE_GPT; 00999 /* Translate LBA -> Offset */ 01000 DriveLayoutEx->Gpt.StartingUsableOffset.QuadPart = EfiHeader.FirstUsableLBA * Disk->SectorSize; 01001 DriveLayoutEx->Gpt.UsableLength.QuadPart = EfiHeader.LastUsableLBA - EfiHeader.FirstUsableLBA * Disk->SectorSize; 01002 DriveLayoutEx->Gpt.MaxPartitionCount = EfiHeader.NumberOfEntries; 01003 DriveLayoutEx->Gpt.DiskId = EfiHeader.DiskGUID; 01004 01005 /* Count number of partitions per sector */ 01006 PartitionsPerSector = (Disk->SectorSize / PARTITION_ENTRY_SIZE); 01007 /* Read all partitions and fill in structure */ 01008 for (i = 0, PartitionCount = 0, PartitionIndex = PartitionsPerSector; 01009 i < EfiHeader.NumberOfEntries; 01010 i++) 01011 { 01012 /* Only read following sector if we finished with previous sector */ 01013 if (PartitionIndex == PartitionsPerSector) 01014 { 01015 Status = FstubReadSector(Disk->DeviceObject, 01016 Disk->SectorSize, 01017 EfiHeader.PartitionEntryLBA + (i / PartitionsPerSector), 01018 Disk->Buffer); 01019 if (!NT_SUCCESS(Status)) 01020 { 01021 ExFreePoolWithTag(DriveLayoutEx, TAG_FSTUB); 01022 return Status; 01023 } 01024 01025 PartitionIndex = 0; 01026 } 01027 /* Read following partition */ 01028 PartitionEntry = ((PEFI_PARTITION_ENTRY)Disk->Buffer)[PartitionIndex]; 01029 PartitionIndex++; 01030 01031 /* If partition GUID is 00000000-0000-0000-0000-000000000000, then it's unused, skip it */ 01032 if (PartitionEntry.PartitionType.Data1 == 0 && 01033 PartitionEntry.PartitionType.Data2 == 0 && 01034 PartitionEntry.PartitionType.Data3 == 0 && 01035 ((PULONGLONG)PartitionEntry.PartitionType.Data4)[0] == 0) 01036 { 01037 continue; 01038 } 01039 01040 /* Write data to structure. Don't forget GPT is using sectors, Windows offsets */ 01041 DriveLayoutEx->PartitionEntry[PartitionCount].StartingOffset.QuadPart = PartitionEntry.StartingLBA * Disk->SectorSize; 01042 DriveLayoutEx->PartitionEntry[PartitionCount].PartitionLength.QuadPart = (PartitionEntry.EndingLBA - 01043 PartitionEntry.StartingLBA + 1) * 01044 Disk->SectorSize; 01045 /* This number starts from 1 */ 01046 DriveLayoutEx->PartitionEntry[PartitionCount].PartitionNumber = PartitionCount + 1; 01047 DriveLayoutEx->PartitionEntry[PartitionCount].RewritePartition = FALSE; 01048 DriveLayoutEx->PartitionEntry[PartitionCount].PartitionStyle = PARTITION_STYLE_GPT; 01049 DriveLayoutEx->PartitionEntry[PartitionCount].Gpt.PartitionType = PartitionEntry.PartitionType; 01050 DriveLayoutEx->PartitionEntry[PartitionCount].Gpt.PartitionId = PartitionEntry.UniquePartition; 01051 DriveLayoutEx->PartitionEntry[PartitionCount].Gpt.Attributes = PartitionEntry.Attributes; 01052 RtlCopyMemory(DriveLayoutEx->PartitionEntry[PartitionCount].Gpt.Name, 01053 PartitionEntry.Name, sizeof(PartitionEntry.Name)); 01054 01055 /* Update partition count */ 01056 PartitionCount++; 01057 } 01058 DriveLayoutEx->PartitionCount = PartitionCount; 01059 01060 /* If we updated partition table using backup table, rewrite partition table */ 01061 if (UpdatedPartitionTable) 01062 { 01063 IoWritePartitionTableEx(Disk->DeviceObject, 01064 DriveLayoutEx); 01065 } 01066 01067 /* Finally, return read data */ 01068 *DriveLayout = DriveLayoutEx; 01069 01070 return Status; 01071 } 01072 01073 NTSTATUS 01074 NTAPI 01075 FstubReadPartitionTableMBR(IN PDISK_INFORMATION Disk, 01076 IN BOOLEAN ReturnRecognizedPartitions, 01077 OUT struct _DRIVE_LAYOUT_INFORMATION_EX** ReturnedDriveLayout) 01078 { 01079 ULONG i; 01080 NTSTATUS Status; 01081 PDRIVE_LAYOUT_INFORMATION DriveLayout = NULL; 01082 PDRIVE_LAYOUT_INFORMATION_EX DriveLayoutEx = NULL; 01083 PAGED_CODE(); 01084 01085 ASSERT(IS_VALID_DISK_INFO(Disk)); 01086 ASSERT(ReturnedDriveLayout); 01087 01088 /* Zero output */ 01089 *ReturnedDriveLayout = NULL; 01090 01091 /* Read partition table the old way */ 01092 Status = IoReadPartitionTable(Disk->DeviceObject, 01093 Disk->SectorSize, 01094 ReturnRecognizedPartitions, 01095 &DriveLayout); 01096 if (!NT_SUCCESS(Status)) 01097 { 01098 return Status; 01099 } 01100 01101 /* Allocate a DRIVE_LAYOUT_INFORMATION_EX struct big enough */ 01102 DriveLayoutEx = ExAllocatePoolWithTag(NonPagedPool, 01103 FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry) + 01104 DriveLayout->PartitionCount * sizeof(PARTITION_INFORMATION_EX), 01105 TAG_FSTUB); 01106 if (!DriveLayoutEx) 01107 { 01108 /* Let's not leak memory as in Windows 2003 */ 01109 ExFreePool(DriveLayout); 01110 return STATUS_INSUFFICIENT_RESOURCES; 01111 } 01112 01113 /* Start converting the DRIVE_LAYOUT_INFORMATION structure */ 01114 DriveLayoutEx->PartitionStyle = PARTITION_STYLE_MBR; 01115 DriveLayoutEx->PartitionCount = DriveLayout->PartitionCount; 01116 DriveLayoutEx->Mbr.Signature = DriveLayout->Signature; 01117 01118 /* Convert each found partition */ 01119 for (i = 0; i < DriveLayout->PartitionCount; i++) 01120 { 01121 DriveLayoutEx->PartitionEntry[i].PartitionStyle = PARTITION_STYLE_MBR; 01122 DriveLayoutEx->PartitionEntry[i].StartingOffset = DriveLayout->PartitionEntry[i].StartingOffset; 01123 DriveLayoutEx->PartitionEntry[i].PartitionLength = DriveLayout->PartitionEntry[i].PartitionLength; 01124 DriveLayoutEx->PartitionEntry[i].PartitionNumber = DriveLayout->PartitionEntry[i].PartitionNumber; 01125 DriveLayoutEx->PartitionEntry[i].RewritePartition = DriveLayout->PartitionEntry[i].RewritePartition; 01126 DriveLayoutEx->PartitionEntry[i].Mbr.PartitionType = DriveLayout->PartitionEntry[i].PartitionType; 01127 DriveLayoutEx->PartitionEntry[i].Mbr.BootIndicator = DriveLayout->PartitionEntry[i].BootIndicator; 01128 DriveLayoutEx->PartitionEntry[i].Mbr.RecognizedPartition = DriveLayout->PartitionEntry[i].RecognizedPartition; 01129 DriveLayoutEx->PartitionEntry[i].Mbr.HiddenSectors = DriveLayout->PartitionEntry[i].HiddenSectors; 01130 } 01131 01132 /* Finally, return data and free old structure */ 01133 *ReturnedDriveLayout = DriveLayoutEx; 01134 ExFreePool(DriveLayout); 01135 01136 return STATUS_SUCCESS; 01137 } 01138 01139 NTSTATUS 01140 NTAPI 01141 FstubReadSector(IN PDEVICE_OBJECT DeviceObject, 01142 IN ULONG SectorSize, 01143 IN ULONGLONG StartingSector OPTIONAL, 01144 OUT PUSHORT Buffer) 01145 { 01146 PIRP Irp; 01147 KEVENT Event; 01148 NTSTATUS Status; 01149 LARGE_INTEGER StartingOffset; 01150 IO_STATUS_BLOCK IoStatusBlock; 01151 PIO_STACK_LOCATION IoStackLocation; 01152 PAGED_CODE(); 01153 01154 ASSERT(DeviceObject); 01155 ASSERT(Buffer); 01156 ASSERT(SectorSize); 01157 01158 /* Compute starting offset */ 01159 StartingOffset.QuadPart = StartingSector * SectorSize; 01160 01161 /* Initialize waiting event */ 01162 KeInitializeEvent(&Event, NotificationEvent, FALSE); 01163 01164 /* Prepare IRP */ 01165 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, 01166 DeviceObject, 01167 Buffer, 01168 SectorSize, 01169 &StartingOffset, 01170 &Event, 01171 &IoStatusBlock); 01172 if (!Irp) 01173 { 01174 return STATUS_INSUFFICIENT_RESOURCES; 01175 } 01176 01177 /* Override volume verify */ 01178 IoStackLocation = IoGetNextIrpStackLocation(Irp); 01179 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 01180 01181 /* Then call driver, and wait for completion if needed */ 01182 Status = IoCallDriver(DeviceObject, Irp); 01183 if (Status == STATUS_PENDING) 01184 { 01185 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 01186 Status = IoStatusBlock.Status; 01187 } 01188 01189 return Status; 01190 } 01191 01192 NTSTATUS 01193 NTAPI 01194 FstubSetPartitionInformationEFI(IN PDISK_INFORMATION Disk, 01195 IN ULONG PartitionNumber, 01196 IN SET_PARTITION_INFORMATION_GPT * PartitionInfo) 01197 { 01198 NTSTATUS Status; 01199 PDRIVE_LAYOUT_INFORMATION_EX Layout = NULL; 01200 PAGED_CODE(); 01201 01202 ASSERT(Disk); 01203 ASSERT(PartitionInfo); 01204 01205 /* Partition 0 isn't correct (should start at 1) */ 01206 if (PartitionNumber == 0) 01207 { 01208 return STATUS_INVALID_PARAMETER; 01209 } 01210 01211 /* Read partition table */ 01212 Status = IoReadPartitionTableEx(Disk->DeviceObject, &Layout); 01213 if (!NT_SUCCESS(Status)) 01214 { 01215 return Status; 01216 } 01217 ASSERT(Layout); 01218 01219 /* If our partition (started at 0 now) is higher than partition count, then, there's an issue */ 01220 if (Layout->PartitionCount <= --PartitionNumber) 01221 { 01222 ExFreePool(Layout); 01223 return STATUS_INVALID_PARAMETER; 01224 } 01225 01226 /* Erase actual partition entry data with provided ones */ 01227 Layout->PartitionEntry[PartitionNumber].Gpt.PartitionType = PartitionInfo->PartitionType; 01228 Layout->PartitionEntry[PartitionNumber].Gpt.PartitionId = PartitionInfo->PartitionId; 01229 Layout->PartitionEntry[PartitionNumber].Gpt.Attributes = PartitionInfo->Attributes; 01230 RtlCopyMemory(Layout->PartitionEntry[PartitionNumber].Gpt.Name, PartitionInfo->Name, sizeof(PartitionInfo->Name)); 01231 01232 /* Rewrite the whole partition table to update the modified entry */ 01233 Status = IoWritePartitionTableEx(Disk->DeviceObject, Layout); 01234 01235 /* Free partition table and return */ 01236 ExFreePool(Layout); 01237 return Status; 01238 } 01239 01240 NTSTATUS 01241 NTAPI 01242 FstubVerifyPartitionTableEFI(IN PDISK_INFORMATION Disk, 01243 IN BOOLEAN FixErrors) 01244 { 01245 NTSTATUS Status; 01246 PEFI_PARTITION_HEADER EFIHeader; 01247 EFI_PARTITION_HEADER ReadEFIHeader; 01248 BOOLEAN PrimaryValid = FALSE, BackupValid = FALSE; 01249 PAGED_CODE(); 01250 01251 EFIHeader = ExAllocatePoolWithTag(NonPagedPool, sizeof(EFI_PARTITION_HEADER), TAG_FSTUB); 01252 if (!EFIHeader) 01253 { 01254 return STATUS_INSUFFICIENT_RESOURCES; 01255 } 01256 01257 Status = FstubReadHeaderEFI(Disk, FALSE, &ReadEFIHeader); 01258 if (NT_SUCCESS(Status)) 01259 { 01260 PrimaryValid = TRUE; 01261 } 01262 01263 Status = FstubReadHeaderEFI(Disk, TRUE, &ReadEFIHeader); 01264 if (NT_SUCCESS(Status)) 01265 { 01266 BackupValid = TRUE; 01267 } 01268 01269 if (!PrimaryValid) 01270 { 01271 if (!BackupValid || !FixErrors) 01272 { 01273 ExFreePoolWithTag(EFIHeader, TAG_FSTUB); 01274 return STATUS_DISK_CORRUPT_ERROR; 01275 } 01276 01277 DPRINT1("EFI::Partition table fixing not yet supported!\n"); 01278 ExFreePoolWithTag(EFIHeader, TAG_FSTUB); 01279 return STATUS_NOT_IMPLEMENTED; 01280 } 01281 else if (!BackupValid) 01282 { 01283 if (!PrimaryValid || !FixErrors) 01284 { 01285 ExFreePoolWithTag(EFIHeader, TAG_FSTUB); 01286 return STATUS_DISK_CORRUPT_ERROR; 01287 } 01288 01289 DPRINT1("EFI::Partition table fixing not yet supported!\n"); 01290 ExFreePoolWithTag(EFIHeader, TAG_FSTUB); 01291 return STATUS_NOT_IMPLEMENTED; 01292 } 01293 else 01294 { 01295 ExFreePoolWithTag(EFIHeader, TAG_FSTUB); 01296 return STATUS_SUCCESS; 01297 } 01298 } 01299 01300 NTSTATUS 01301 NTAPI 01302 FstubWriteBootSectorEFI(IN PDISK_INFORMATION Disk) 01303 { 01304 NTSTATUS Status; 01305 ULONG Signature = 0; 01306 PMASTER_BOOT_RECORD MasterBootRecord; 01307 PAGED_CODE(); 01308 01309 ASSERT(Disk); 01310 ASSERT(IS_VALID_DISK_INFO(Disk)); 01311 01312 /* Read if a MBR is already present */ 01313 Status = FstubReadSector(Disk->DeviceObject, 01314 Disk->SectorSize, 01315 0ULL, 01316 Disk->Buffer); 01317 MasterBootRecord = (PMASTER_BOOT_RECORD)Disk->Buffer; 01318 /* If one has been found */ 01319 if (NT_SUCCESS(Status) && MasterBootRecord->MasterBootRecordMagic == BOOT_RECORD_SIGNATURE) 01320 { 01321 /* Save its signature */ 01322 Signature = MasterBootRecord->Signature; 01323 } 01324 01325 /* Reset the MBR */ 01326 RtlZeroMemory(MasterBootRecord, Disk->SectorSize); 01327 /* Then create a fake MBR matching those purposes: 01328 * It must have only partition. Type of this partition 01329 * has to be 0xEE to signal a GPT is following. 01330 * This partition has to cover the whole disk. To prevent 01331 * any disk modification by a program that wouldn't 01332 * understand anything to GPT. 01333 */ 01334 MasterBootRecord->Signature = Signature; 01335 MasterBootRecord->PartitionTable[0].StartSector = 2; 01336 MasterBootRecord->PartitionTable[0].SystemIndicator = EFI_PMBR_OSTYPE_EFI; 01337 MasterBootRecord->PartitionTable[0].EndHead = 0xFF; 01338 MasterBootRecord->PartitionTable[0].EndSector = 0xFF; 01339 MasterBootRecord->PartitionTable[0].EndCylinder = 0xFF; 01340 MasterBootRecord->PartitionTable[0].SectorCountBeforePartition = 1; 01341 MasterBootRecord->PartitionTable[0].PartitionSectorCount = 0xFFFFFFFF; 01342 MasterBootRecord->MasterBootRecordMagic = BOOT_RECORD_SIGNATURE; 01343 01344 /* Finally, write that MBR */ 01345 return FstubWriteSector(Disk->DeviceObject, 01346 Disk->SectorSize, 01347 0, 01348 Disk->Buffer); 01349 } 01350 01351 NTSTATUS 01352 NTAPI 01353 FstubWriteEntryEFI(IN PDISK_INFORMATION Disk, 01354 IN ULONG PartitionsSizeSector, 01355 IN ULONG PartitionEntryNumber, 01356 IN PEFI_PARTITION_ENTRY PartitionEntry, 01357 IN BOOLEAN WriteBackupTable, 01358 IN BOOLEAN ForceWrite, 01359 OUT PULONG PartitionEntryCRC32 OPTIONAL) 01360 { 01361 ULONG Offset; 01362 ULONGLONG FirstEntryLBA; 01363 NTSTATUS Status = STATUS_SUCCESS; 01364 PAGED_CODE(); 01365 01366 ASSERT(Disk); 01367 ASSERT(IS_VALID_DISK_INFO(Disk)); 01368 01369 /* Get the first LBA where the partition table is: 01370 * On primary table, it's sector 2 (skip MBR & Header) 01371 * On backup table, it's ante last sector (Header) minus partition table size 01372 */ 01373 if (!WriteBackupTable) 01374 { 01375 FirstEntryLBA = 2ULL; 01376 } 01377 else 01378 { 01379 FirstEntryLBA = Disk->SectorCount - PartitionsSizeSector - 1; 01380 } 01381 01382 /* Copy the entry at the proper place into the buffer 01383 * That way, we don't erase previous entries 01384 */ 01385 RtlCopyMemory(Disk->Buffer + (((PartitionEntryNumber * PARTITION_ENTRY_SIZE) % Disk->SectorSize) / sizeof(PUSHORT)), 01386 PartitionEntry, 01387 sizeof(EFI_PARTITION_ENTRY)); 01388 /* Compute size of buffer */ 01389 Offset = (PartitionEntryNumber * PARTITION_ENTRY_SIZE) % Disk->SectorSize + PARTITION_ENTRY_SIZE; 01390 ASSERT(Offset <= Disk->SectorSize); 01391 01392 /* If it's full of partition entries, or if call ask for it, write down the data */ 01393 if (Offset == Disk->SectorSize || ForceWrite) 01394 { 01395 /* We will write at first entry LBA + a shift made by already present/written entries */ 01396 Status = FstubWriteSector(Disk->DeviceObject, 01397 Disk->SectorSize, 01398 FirstEntryLBA + ((PartitionEntryNumber * PARTITION_ENTRY_SIZE) / Disk->SectorSize), 01399 Disk->Buffer); 01400 if (!NT_SUCCESS(Status)) 01401 { 01402 return Status; 01403 } 01404 /* We clean buffer */ 01405 RtlZeroMemory(Disk->Buffer, Disk->SectorSize); 01406 } 01407 01408 /* If we have a buffer for CRC32, then compute it */ 01409 if (PartitionEntryCRC32) 01410 { 01411 *PartitionEntryCRC32 = RtlComputeCrc32(*PartitionEntryCRC32, (PUCHAR)PartitionEntry, PARTITION_ENTRY_SIZE); 01412 } 01413 01414 return Status; 01415 } 01416 01417 NTSTATUS 01418 NTAPI 01419 FstubWriteHeaderEFI(IN PDISK_INFORMATION Disk, 01420 IN ULONG PartitionsSizeSector, 01421 IN GUID DiskGUID, 01422 IN ULONG NumberOfEntries, 01423 IN ULONGLONG FirstUsableLBA, 01424 IN ULONGLONG LastUsableLBA, 01425 IN ULONG PartitionEntryCRC32, 01426 IN BOOLEAN WriteBackupTable) 01427 { 01428 PEFI_PARTITION_HEADER EFIHeader; 01429 PAGED_CODE(); 01430 01431 ASSERT(Disk); 01432 ASSERT(IS_VALID_DISK_INFO(Disk)); 01433 01434 /* Let's use read buffer as EFI_PARTITION_HEADER */ 01435 EFIHeader = (PEFI_PARTITION_HEADER)Disk->Buffer; 01436 01437 /* Complete standard header information */ 01438 EFIHeader->Signature = EFI_HEADER_SIGNATURE; 01439 EFIHeader->Revision = EFI_HEADER_REVISION_1; 01440 EFIHeader->HeaderSize = sizeof(EFI_PARTITION_HEADER); 01441 /* Set no CRC32 checksum at the moment */ 01442 EFIHeader->HeaderCRC32 = 0; 01443 EFIHeader->Reserved = 0; 01444 /* Check whether we're writing primary or backup 01445 * That way, we can ajust LBA setting: 01446 * Primary is on first sector 01447 * Backup is on last sector 01448 */ 01449 if (!WriteBackupTable) 01450 { 01451 EFIHeader->MyLBA = 1ULL; 01452 EFIHeader->AlternateLBA = Disk->SectorCount - 1ULL; 01453 } 01454 else 01455 { 01456 EFIHeader->MyLBA = Disk->SectorCount - 1ULL; 01457 EFIHeader->AlternateLBA = 1ULL; 01458 } 01459 /* Fill in with received data */ 01460 EFIHeader->FirstUsableLBA = FirstUsableLBA; 01461 EFIHeader->LastUsableLBA = LastUsableLBA; 01462 EFIHeader->DiskGUID = DiskGUID; 01463 /* Check whether we're writing primary or backup 01464 * That way, we can ajust LBA setting: 01465 * On primary, partition entries are just after header, so sector 2 01466 * On backup, partition entries are just before header, so, last sector minus partition table size 01467 */ 01468 if (!WriteBackupTable) 01469 { 01470 EFIHeader->PartitionEntryLBA = EFIHeader->MyLBA + 1ULL; 01471 } 01472 else 01473 { 01474 EFIHeader->PartitionEntryLBA = EFIHeader->MyLBA - PartitionsSizeSector; 01475 } 01476 /* Complete filling in */ 01477 EFIHeader->NumberOfEntries = NumberOfEntries; 01478 EFIHeader->SizeOfPartitionEntry = PARTITION_ENTRY_SIZE; 01479 EFIHeader->PartitionEntryCRC32 = PartitionEntryCRC32; 01480 /* Finally, compute header checksum */ 01481 EFIHeader->HeaderCRC32 = RtlComputeCrc32(0, (PUCHAR)EFIHeader, sizeof(EFI_PARTITION_HEADER)); 01482 01483 /* Debug the way we'll break disk, to let user pray */ 01484 DPRINT("FSTUB: About to write the following header for %s table\n", (WriteBackupTable ? "backup" : "primary")); 01485 DPRINT(" Signature: %I64x\n Revision: %x\n HeaderSize: %x\n HeaderCRC32: %x\n", 01486 EFIHeader->Signature, EFIHeader->Revision, EFIHeader->HeaderSize, EFIHeader->HeaderCRC32); 01487 DPRINT(" MyLBA: %I64x\n AlternateLBA: %I64x\n FirstUsableLBA: %I64x\n LastUsableLBA: %I64x\n", 01488 EFIHeader->MyLBA, EFIHeader->AlternateLBA, EFIHeader->FirstUsableLBA, EFIHeader->LastUsableLBA); 01489 DPRINT(" PartitionEntryLBA: %I64x\n NumberOfEntries: %x\n SizeOfPartitionEntry: %x\n PartitionEntryCRC32: %x\n", 01490 EFIHeader->PartitionEntryLBA, EFIHeader->NumberOfEntries, 01491 EFIHeader->SizeOfPartitionEntry, EFIHeader->PartitionEntryCRC32); 01492 01493 /* Write header to disk */ 01494 return FstubWriteSector(Disk->DeviceObject, 01495 Disk->SectorSize, 01496 EFIHeader->MyLBA, 01497 Disk->Buffer); 01498 } 01499 01500 NTSTATUS 01501 NTAPI 01502 FstubWritePartitionTableEFI(IN PDISK_INFORMATION Disk, 01503 IN GUID DiskGUID, 01504 IN ULONG MaxPartitionCount, 01505 IN ULONGLONG FirstUsableLBA, 01506 IN ULONGLONG LastUsableLBA, 01507 IN BOOLEAN WriteBackupTable, 01508 IN ULONG PartitionCount, 01509 IN PPARTITION_INFORMATION_EX PartitionEntries OPTIONAL) 01510 { 01511 NTSTATUS Status; 01512 EFI_PARTITION_ENTRY Entry; 01513 ULONG i, WrittenPartitions, SectoredPartitionEntriesSize, PartitionEntryCRC32; 01514 PAGED_CODE(); 01515 01516 ASSERT(Disk); 01517 ASSERT(MaxPartitionCount >= 128); 01518 ASSERT(PartitionCount <= MaxPartitionCount); 01519 01520 PartitionEntryCRC32 = 0; 01521 /* Count how much sectors we'll have to read to read the whole partition table */ 01522 SectoredPartitionEntriesSize = (MaxPartitionCount * PARTITION_ENTRY_SIZE) / Disk->SectorSize; 01523 01524 for (i = 0, WrittenPartitions = 0; i < PartitionCount; i++) 01525 { 01526 /* If partition GUID is 00000000-0000-0000-0000-000000000000, then it's unused, skip it */ 01527 if (PartitionEntries[i].Gpt.PartitionType.Data1 == 0 && 01528 PartitionEntries[i].Gpt.PartitionType.Data2 == 0 && 01529 PartitionEntries[i].Gpt.PartitionType.Data3 == 0 && 01530 ((PULONGLONG)PartitionEntries[i].Gpt.PartitionType.Data4)[0] == 0) 01531 { 01532 continue; 01533 } 01534 01535 /* Copy the entry in the partition entry format */ 01536 FstubCopyEntryEFI(&Entry, &PartitionEntries[i], Disk->SectorSize); 01537 /* Then write the entry to the disk */ 01538 Status = FstubWriteEntryEFI(Disk, 01539 SectoredPartitionEntriesSize, 01540 WrittenPartitions, 01541 &Entry, 01542 WriteBackupTable, 01543 FALSE, 01544 &PartitionEntryCRC32); 01545 if (!NT_SUCCESS(Status)) 01546 { 01547 return Status; 01548 } 01549 WrittenPartitions++; 01550 } 01551 01552 /* Zero the buffer to write zeros to the disk */ 01553 RtlZeroMemory(&Entry, sizeof(EFI_PARTITION_ENTRY)); 01554 /* Write the disks with zeros for every unused remaining partition entry */ 01555 for (i = WrittenPartitions; i < MaxPartitionCount; i++) 01556 { 01557 Status = FstubWriteEntryEFI(Disk, 01558 SectoredPartitionEntriesSize, 01559 i, 01560 &Entry, 01561 WriteBackupTable, 01562 FALSE, 01563 &PartitionEntryCRC32); 01564 if (!NT_SUCCESS(Status)) 01565 { 01566 return Status; 01567 } 01568 } 01569 01570 /* Once we're done, write the GPT header */ 01571 return FstubWriteHeaderEFI(Disk, 01572 SectoredPartitionEntriesSize, 01573 DiskGUID, 01574 MaxPartitionCount, 01575 FirstUsableLBA, 01576 LastUsableLBA, 01577 PartitionEntryCRC32, 01578 WriteBackupTable); 01579 } 01580 01581 NTSTATUS 01582 NTAPI 01583 FstubWritePartitionTableMBR(IN PDISK_INFORMATION Disk, 01584 IN PDRIVE_LAYOUT_INFORMATION_EX LayoutEx) 01585 { 01586 NTSTATUS Status; 01587 PDRIVE_LAYOUT_INFORMATION DriveLayout; 01588 PAGED_CODE(); 01589 01590 ASSERT(IS_VALID_DISK_INFO(Disk)); 01591 ASSERT(LayoutEx); 01592 01593 /* Convert data to the correct format */ 01594 DriveLayout = FstubConvertExtendedToLayout(LayoutEx); 01595 if (!DriveLayout) 01596 { 01597 return STATUS_INSUFFICIENT_RESOURCES; 01598 } 01599 01600 /* Really write information */ 01601 Status = IoWritePartitionTable(Disk->DeviceObject, 01602 Disk->SectorSize, 01603 Disk->DiskGeometry.Geometry.SectorsPerTrack, 01604 Disk->DiskGeometry.Geometry.TracksPerCylinder, 01605 DriveLayout); 01606 01607 /* Free allocated structure and return */ 01608 ExFreePool(DriveLayout); 01609 return Status; 01610 } 01611 01612 NTSTATUS 01613 NTAPI 01614 FstubWriteSector(IN PDEVICE_OBJECT DeviceObject, 01615 IN ULONG SectorSize, 01616 IN ULONGLONG StartingSector OPTIONAL, 01617 IN PUSHORT Buffer) 01618 { 01619 PIRP Irp; 01620 KEVENT Event; 01621 NTSTATUS Status; 01622 LARGE_INTEGER StartingOffset; 01623 IO_STATUS_BLOCK IoStatusBlock; 01624 PIO_STACK_LOCATION IoStackLocation; 01625 PAGED_CODE(); 01626 01627 ASSERT(DeviceObject); 01628 ASSERT(Buffer); 01629 ASSERT(SectorSize); 01630 01631 /* Compute starting offset */ 01632 StartingOffset.QuadPart = StartingSector * SectorSize; 01633 01634 /* Initialize waiting event */ 01635 KeInitializeEvent(&Event, NotificationEvent, FALSE); 01636 01637 /* Prepare IRP */ 01638 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE, 01639 DeviceObject, 01640 Buffer, 01641 SectorSize, 01642 &StartingOffset, 01643 &Event, 01644 &IoStatusBlock); 01645 if (!Irp) 01646 { 01647 return STATUS_INSUFFICIENT_RESOURCES; 01648 } 01649 01650 /* Override volume verify */ 01651 IoStackLocation = IoGetNextIrpStackLocation(Irp); 01652 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 01653 01654 /* Then call driver, and wait for completion if needed */ 01655 Status = IoCallDriver(DeviceObject, Irp); 01656 if (Status == STATUS_PENDING) 01657 { 01658 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 01659 Status = IoStatusBlock.Status; 01660 } 01661 01662 return Status; 01663 } 01664 01665 /* FUNCTIONS *****************************************************************/ 01666 01667 /* 01668 * @implemented 01669 */ 01670 NTSTATUS 01671 NTAPI 01672 IoCreateDisk(IN PDEVICE_OBJECT DeviceObject, 01673 IN struct _CREATE_DISK* Disk) 01674 { 01675 PARTITION_STYLE PartitionStyle; 01676 PAGED_CODE(); 01677 01678 ASSERT(DeviceObject); 01679 01680 /* Get partition style. If caller didn't provided data, assume it's raw */ 01681 PartitionStyle = ((Disk) ? Disk->PartitionStyle : PARTITION_STYLE_RAW); 01682 /* Then, call appropriate internal function */ 01683 switch (PartitionStyle) 01684 { 01685 case PARTITION_STYLE_MBR: 01686 return FstubCreateDiskMBR(DeviceObject, &(Disk->Mbr)); 01687 case PARTITION_STYLE_GPT: 01688 return FstubCreateDiskEFI(DeviceObject, &(Disk->Gpt)); 01689 case PARTITION_STYLE_RAW: 01690 return FstubCreateDiskRaw(DeviceObject); 01691 default: 01692 return STATUS_NOT_SUPPORTED; 01693 } 01694 } 01695 01696 /* 01697 * @implemented 01698 */ 01699 NTSTATUS 01700 NTAPI 01701 IoGetBootDiskInformation(IN OUT PBOOTDISK_INFORMATION BootDiskInformation, 01702 IN ULONG Size) 01703 { 01704 PIRP Irp; 01705 KEVENT Event; 01706 PLIST_ENTRY NextEntry; 01707 PFILE_OBJECT FileObject; 01708 DISK_GEOMETRY DiskGeometry; 01709 PDEVICE_OBJECT DeviceObject; 01710 UNICODE_STRING DeviceStringW; 01711 IO_STATUS_BLOCK IoStatusBlock; 01712 CHAR Buffer[128], ArcBuffer[128]; 01713 NTSTATUS Status = STATUS_SUCCESS; 01714 BOOLEAN SingleDisk, IsBootDiskInfoEx; 01715 PARC_DISK_SIGNATURE ArcDiskSignature; 01716 PARC_DISK_INFORMATION ArcDiskInformation; 01717 PARTITION_INFORMATION_EX PartitionInformation; 01718 PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = NULL; 01719 ULONG DiskCount, DiskNumber, Signature, PartitionNumber; 01720 ANSI_STRING ArcBootString, ArcSystemString, DeviceStringA, ArcNameStringA; 01721 extern PLOADER_PARAMETER_BLOCK IopLoaderBlock; 01722 PAGED_CODE(); 01723 01724 /* Get loader block. If it's null, we come to late */ 01725 if (!IopLoaderBlock) 01726 { 01727 return STATUS_TOO_LATE; 01728 } 01729 01730 /* Check buffer size */ 01731 if (Size < sizeof(BOOTDISK_INFORMATION)) 01732 { 01733 return STATUS_INVALID_PARAMETER; 01734 } 01735 01736 /* Init some useful stuff: 01737 * Get arc disks information 01738 * Check whether we have a single disk 01739 * Check received structure size (extended or not?) 01740 * Init boot strings (system/boot) 01741 * Finaly, get disk count 01742 */ 01743 ArcDiskInformation = IopLoaderBlock->ArcDiskInformation; 01744 SingleDisk = IsListEmpty(&(ArcDiskInformation->DiskSignatureListHead)); 01745 IsBootDiskInfoEx = (Size >= sizeof(BOOTDISK_INFORMATION_EX)); 01746 RtlInitAnsiString(&ArcBootString, IopLoaderBlock->ArcBootDeviceName); 01747 RtlInitAnsiString(&ArcSystemString, IopLoaderBlock->ArcHalDeviceName); 01748 DiskCount = IoGetConfigurationInformation()->DiskCount; 01749 01750 /* If no disk, return success */ 01751 if (DiskCount == 0) 01752 { 01753 return STATUS_SUCCESS; 01754 } 01755 01756 /* Now, browse all disks */ 01757 for (DiskNumber = 0; DiskNumber < DiskCount; DiskNumber++) 01758 { 01759 /* Create the device name */ 01760 sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", DiskNumber); 01761 RtlInitAnsiString(&DeviceStringA, Buffer); 01762 Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE); 01763 if (!NT_SUCCESS(Status)) 01764 { 01765 continue; 01766 } 01767 01768 /* Get its device object */ 01769 Status = IoGetDeviceObjectPointer(&DeviceStringW, 01770 FILE_READ_ATTRIBUTES, 01771 &FileObject, 01772 &DeviceObject); 01773 RtlFreeUnicodeString(&DeviceStringW); 01774 if (!NT_SUCCESS(Status)) 01775 { 01776 continue; 01777 } 01778 01779 /* Prepare for getting disk geometry */ 01780 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY, 01781 DeviceObject, 01782 NULL, 01783 0, 01784 &DiskGeometry, 01785 sizeof(DISK_GEOMETRY), 01786 FALSE, 01787 &Event, 01788 &IoStatusBlock); 01789 if (!Irp) 01790 { 01791 ObDereferenceObject(FileObject); 01792 continue; 01793 } 01794 01795 /* Then, call the drive, and wait for it if needed */ 01796 KeInitializeEvent(&Event, NotificationEvent, FALSE); 01797 Status = IoCallDriver(DeviceObject, Irp); 01798 if (Status == STATUS_PENDING) 01799 { 01800 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 01801 Status = IoStatusBlock.Status; 01802 } 01803 if (!NT_SUCCESS(Status)) 01804 { 01805 ObDereferenceObject(FileObject); 01806 continue; 01807 } 01808 01809 /* Read partition table */ 01810 Status = IoReadPartitionTableEx(DeviceObject, 01811 &DriveLayout); 01812 01813 /* FileObject, you can go! */ 01814 ObDereferenceObject(FileObject); 01815 01816 if (!NT_SUCCESS(Status)) 01817 { 01818 continue; 01819 } 01820 01821 /* Ensure we have at least 512 bytes per sector */ 01822 if (DiskGeometry.BytesPerSector < 512) 01823 { 01824 DiskGeometry.BytesPerSector = 512; 01825 } 01826 01827 /* Now, for each arc disk, try to find the matching */ 01828 for (NextEntry = ArcDiskInformation->DiskSignatureListHead.Flink; 01829 NextEntry != &ArcDiskInformation->DiskSignatureListHead; 01830 NextEntry = NextEntry->Flink) 01831 { 01832 ArcDiskSignature = CONTAINING_RECORD(NextEntry, 01833 ARC_DISK_SIGNATURE, 01834 ListEntry); 01835 /* If they matches, ie 01836 * - There's only one disk for both BIOS and detected 01837 * - Signatures are matching 01838 * - This is MBR 01839 * (We don't check checksums here) 01840 */ 01841 if (((SingleDisk && DiskCount == 1) || 01842 (IopVerifyDiskSignature(DriveLayout, ArcDiskSignature, &Signature))) && 01843 (DriveLayout->PartitionStyle == PARTITION_STYLE_MBR)) 01844 { 01845 /* Create arc name */ 01846 sprintf(ArcBuffer, "\\ArcName\\%s", ArcDiskSignature->ArcName); 01847 RtlInitAnsiString(&ArcNameStringA, ArcBuffer); 01848 01849 /* Browse all partitions */ 01850 for (PartitionNumber = 1; PartitionNumber <= DriveLayout->PartitionCount; PartitionNumber++) 01851 { 01852 /* Create its device name */ 01853 sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition%lu", DiskNumber, PartitionNumber); 01854 RtlInitAnsiString(&DeviceStringA, Buffer); 01855 Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE); 01856 if (!NT_SUCCESS(Status)) 01857 { 01858 continue; 01859 } 01860 01861 /* If IopVerifyDiskSignature returned no signature, take the one from DriveLayout */ 01862 if (!Signature) 01863 { 01864 Signature = DriveLayout->Mbr.Signature; 01865 } 01866 01867 /* Create partial arc name */ 01868 sprintf(ArcBuffer, "%spartition(%lu)", ArcDiskSignature->ArcName, PartitionNumber); 01869 RtlInitAnsiString(&ArcNameStringA, ArcBuffer); 01870 01871 /* If it's matching boot string */ 01872 if (RtlEqualString(&ArcNameStringA, &ArcBootString, TRUE)) 01873 { 01874 /* Then, fill in information about boot device */ 01875 BootDiskInformation->BootDeviceSignature = Signature; 01876 01877 /* Get its device object */ 01878 Status = IoGetDeviceObjectPointer(&DeviceStringW, 01879 FILE_READ_ATTRIBUTES, 01880 &FileObject, 01881 &DeviceObject); 01882 if (!NT_SUCCESS(Status)) 01883 { 01884 RtlFreeUnicodeString(&DeviceStringW); 01885 continue; 01886 } 01887 01888 /* And call the drive to get information about partition */ 01889 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX, 01890 DeviceObject, 01891 NULL, 01892 0, 01893 &PartitionInformation, 01894 sizeof(PARTITION_INFORMATION_EX), 01895 FALSE, 01896 &Event, 01897 &IoStatusBlock); 01898 if (!Irp) 01899 { 01900 ObDereferenceObject(FileObject); 01901 RtlFreeUnicodeString(&DeviceStringW); 01902 continue; 01903 } 01904 01905 /* Call & wait if needed */ 01906 KeInitializeEvent(&Event, NotificationEvent, FALSE); 01907 Status = IoCallDriver(DeviceObject, Irp); 01908 if (Status == STATUS_PENDING) 01909 { 01910 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 01911 Status = IoStatusBlock.Status; 01912 } 01913 if (!NT_SUCCESS(Status)) 01914 { 01915 ObDereferenceObject(FileObject); 01916 RtlFreeUnicodeString(&DeviceStringW); 01917 continue; 01918 } 01919 01920 /* We get partition offset as demanded and return it */ 01921 BootDiskInformation->BootPartitionOffset = PartitionInformation.StartingOffset.QuadPart; 01922 01923 /* If called passed a BOOTDISK_INFORMATION_EX structure, give more intel */ 01924 if (IsBootDiskInfoEx) 01925 { 01926 /* Is PT MBR or GPT? */ 01927 if (DriveLayout->PartitionStyle == PARTITION_STYLE_GPT) 01928 { 01929 ((PBOOTDISK_INFORMATION_EX)BootDiskInformation)->BootDeviceGuid = DriveLayout->Gpt.DiskId; 01930 ((PBOOTDISK_INFORMATION_EX)BootDiskInformation)->BootDeviceIsGpt = TRUE; 01931 } 01932 else 01933 { 01934 ((PBOOTDISK_INFORMATION_EX)BootDiskInformation)->BootDeviceIsGpt = FALSE; 01935 } 01936 } 01937 01938 /* Dereference FileObject */ 01939 ObDereferenceObject(FileObject); 01940 } 01941 01942 /* If it's matching system string */ 01943 if (RtlEqualString(&ArcNameStringA, &ArcSystemString, TRUE)) 01944 { 01945 /* Then, fill in information about the system device */ 01946 BootDiskInformation->SystemDeviceSignature = Signature; 01947 01948 /* Get its device object */ 01949 Status = IoGetDeviceObjectPointer(&DeviceStringW, 01950 FILE_READ_ATTRIBUTES, 01951 &FileObject, 01952 &DeviceObject); 01953 if (!NT_SUCCESS(Status)) 01954 { 01955 RtlFreeUnicodeString(&DeviceStringW); 01956 continue; 01957 } 01958 01959 /* And call the drive to get information about partition */ 01960 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX, 01961 DeviceObject, 01962 NULL, 01963 0, 01964 &PartitionInformation, 01965 sizeof(PARTITION_INFORMATION_EX), 01966 FALSE, 01967 &Event, 01968 &IoStatusBlock); 01969 if (!Irp) 01970 { 01971 ObDereferenceObject(FileObject); 01972 RtlFreeUnicodeString(&DeviceStringW); 01973 continue; 01974 } 01975 01976 /* Call & wait if needed */ 01977 KeInitializeEvent(&Event, NotificationEvent, FALSE); 01978 Status = IoCallDriver(DeviceObject, Irp); 01979 if (Status == STATUS_PENDING) 01980 { 01981 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 01982 Status = IoStatusBlock.Status; 01983 } 01984 if (!NT_SUCCESS(Status)) 01985 { 01986 ObDereferenceObject(FileObject); 01987 RtlFreeUnicodeString(&DeviceStringW); 01988 continue; 01989 } 01990 01991 /* We get partition offset as demanded and return it */ 01992 BootDiskInformation->SystemPartitionOffset = PartitionInformation.StartingOffset.QuadPart; 01993 01994 /* If called passed a BOOTDISK_INFORMATION_EX structure, give more intel */ 01995 if (IsBootDiskInfoEx) 01996 { 01997 /* Is PT MBR or GPT? */ 01998 if (DriveLayout->PartitionStyle == PARTITION_STYLE_GPT) 01999 { 02000 ((PBOOTDISK_INFORMATION_EX)BootDiskInformation)->SystemDeviceGuid = DriveLayout->Gpt.DiskId; 02001 ((PBOOTDISK_INFORMATION_EX)BootDiskInformation)->SystemDeviceIsGpt = TRUE; 02002 } 02003 else 02004 { 02005 ((PBOOTDISK_INFORMATION_EX)BootDiskInformation)->SystemDeviceIsGpt = FALSE; 02006 } 02007 } 02008 02009 /* Dereference FileObject */ 02010 ObDereferenceObject(FileObject); 02011 } 02012 02013 /* Release device string */ 02014 RtlFreeUnicodeString(&DeviceStringW); 02015 } 02016 } 02017 } 02018 02019 /* Finally, release drive layout structure */ 02020 ExFreePool(DriveLayout); 02021 } 02022 02023 /* And return */ 02024 return Status; 02025 } 02026 02027 /* 02028 * @implemented 02029 */ 02030 NTSTATUS 02031 NTAPI 02032 IoReadDiskSignature(IN PDEVICE_OBJECT DeviceObject, 02033 IN ULONG BytesPerSector, 02034 OUT PDISK_SIGNATURE Signature) 02035 { 02036 PULONG Buffer; 02037 NTSTATUS Status; 02038 ULONG HeaderCRC32, i, CheckSum; 02039 PEFI_PARTITION_HEADER EFIHeader; 02040 PPARTITION_DESCRIPTOR PartitionDescriptor; 02041 PAGED_CODE(); 02042 02043 /* Ensure we'll read at least 512 bytes */ 02044 if (BytesPerSector < 512) 02045 { 02046 BytesPerSector = 512; 02047 } 02048 02049 /* Allocate a buffer for reading operations */ 02050 Buffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, BytesPerSector, TAG_FSTUB); 02051 if (!Buffer) 02052 { 02053 return STATUS_NO_MEMORY; 02054 } 02055 02056 /* Read first sector (sector 0) for MBR */ 02057 Status = FstubReadSector(DeviceObject, 02058 BytesPerSector, 02059 0ULL, 02060 (PUSHORT)Buffer); 02061 if (!NT_SUCCESS(Status)) 02062 { 02063 goto Cleanup; 02064 } 02065 02066 /* Get the partition descriptor array */ 02067 PartitionDescriptor = (PPARTITION_DESCRIPTOR) 02068 &(Buffer[PARTITION_TABLE_OFFSET]); 02069 /* Check partitions types: if first is 0xEE and all the others 0, we have GPT */ 02070 if (PartitionDescriptor[0].PartitionType == EFI_PMBR_OSTYPE_EFI && 02071 PartitionDescriptor[1].PartitionType == 0 && 02072 PartitionDescriptor[2].PartitionType == 0 && 02073 PartitionDescriptor[3].PartitionType == 0) 02074 { 02075 /* If we have GPT, read second sector (sector 1) for GPT header */ 02076 Status = FstubReadSector(DeviceObject, 02077 BytesPerSector, 02078 1ULL, 02079 (PUSHORT)Buffer); 02080 if (!NT_SUCCESS(Status)) 02081 { 02082 goto Cleanup; 02083 } 02084 EFIHeader = (PEFI_PARTITION_HEADER)Buffer; 02085 02086 /* First check signature 02087 * Then, check version (we only support v1 02088 * Finally check header size 02089 */ 02090 if (EFIHeader->Signature != EFI_HEADER_SIGNATURE || 02091 EFIHeader->Revision != EFI_HEADER_REVISION_1 || 02092 EFIHeader->HeaderSize != sizeof(EFI_PARTITION_HEADER)) 02093 { 02094 Status = STATUS_DISK_CORRUPT_ERROR; 02095 goto Cleanup; 02096 } 02097 02098 /* Save current checksum */ 02099 HeaderCRC32 = EFIHeader->HeaderCRC32; 02100 /* Then zero the one in EFI header. This is needed to compute header checksum */ 02101 EFIHeader->HeaderCRC32 = 0; 02102 /* Compute header checksum and compare with the one present in partition table */ 02103 if (RtlComputeCrc32(0, (PUCHAR)Buffer, sizeof(EFI_PARTITION_HEADER)) != HeaderCRC32) 02104 { 02105 Status = STATUS_DISK_CORRUPT_ERROR; 02106 goto Cleanup; 02107 } 02108 02109 /* Set partition table style to GPT and return disk GUID */ 02110 Signature->PartitionStyle = PARTITION_STYLE_GPT; 02111 Signature->Gpt.DiskId = EFIHeader->DiskGUID; 02112 } 02113 else 02114 { 02115 /* Compute MBR checksum */ 02116 for (i = 0, CheckSum = 0; i < 512 / sizeof(ULONG) ; i++) 02117 { 02118 CheckSum += Buffer[i]; 02119 } 02120 02121 /* Set partition table style to MBR and return signature (offset 440) and checksum */ 02122 Signature->PartitionStyle = PARTITION_STYLE_MBR; 02123 Signature->Mbr.Signature = Buffer[PARTITION_TABLE_OFFSET / 2 - 1]; 02124 Signature->Mbr.CheckSum = CheckSum; 02125 } 02126 02127 Cleanup: 02128 /* Free buffer and return */ 02129 ExFreePoolWithTag(Buffer, TAG_FSTUB); 02130 return Status; 02131 } 02132 02133 /* 02134 * @implemented 02135 */ 02136 NTSTATUS 02137 NTAPI 02138 IoReadPartitionTableEx(IN PDEVICE_OBJECT DeviceObject, 02139 IN struct _DRIVE_LAYOUT_INFORMATION_EX** DriveLayout) 02140 { 02141 NTSTATUS Status; 02142 PDISK_INFORMATION Disk; 02143 PARTITION_STYLE PartitionStyle; 02144 PAGED_CODE(); 02145 02146 ASSERT(DeviceObject); 02147 ASSERT(DriveLayout); 02148 02149 /* First of all, allocate internal structure */ 02150 Status = FstubAllocateDiskInformation(DeviceObject, &Disk, 0); 02151 if (!NT_SUCCESS(Status)) 02152 { 02153 return Status; 02154 } 02155 ASSERT(Disk); 02156 02157 /* Then, detect partition style (MBR? GTP/EFI? RAW?) */ 02158 Status = FstubDetectPartitionStyle(Disk, &PartitionStyle); 02159 if (!NT_SUCCESS(Status)) 02160 { 02161 FstubFreeDiskInformation(Disk); 02162 return Status; 02163 } 02164 02165 /* Here partition table is really read, depending on its style */ 02166 switch (PartitionStyle) 02167 { 02168 case PARTITION_STYLE_MBR: 02169 case PARTITION_STYLE_RAW: 02170 Status = FstubReadPartitionTableMBR(Disk, FALSE, DriveLayout); 02171 break; 02172 02173 case PARTITION_STYLE_GPT: 02174 /* Read primary table */ 02175 Status = FstubReadPartitionTableEFI(Disk, FALSE, DriveLayout); 02176 /* If it failed, try reading backup table */ 02177 if (!NT_SUCCESS(Status)) 02178 { 02179 Status = FstubReadPartitionTableEFI(Disk, TRUE, DriveLayout); 02180 } 02181 break; 02182 02183 default: 02184 DPRINT("Unknown partition type\n"); 02185 Status = STATUS_UNSUCCESSFUL; 02186 } 02187 02188 /* It's over, internal structure not needed anymore */ 02189 FstubFreeDiskInformation(Disk); 02190 02191 /* In case of success, print data */ 02192 if (NT_SUCCESS(Status)) 02193 { 02194 FstubDbgPrintDriveLayoutEx(*DriveLayout); 02195 } 02196 02197 return Status; 02198 } 02199 02200 /* 02201 * @implemented 02202 */ 02203 NTSTATUS 02204 NTAPI 02205 IoSetPartitionInformationEx(IN PDEVICE_OBJECT DeviceObject, 02206 IN ULONG PartitionNumber, 02207 IN struct _SET_PARTITION_INFORMATION_EX* PartitionInfo) 02208 { 02209 NTSTATUS Status; 02210 PDISK_INFORMATION Disk; 02211 PARTITION_STYLE PartitionStyle; 02212 PAGED_CODE(); 02213 02214 ASSERT(DeviceObject); 02215 ASSERT(PartitionInfo); 02216 02217 /* Debug given modifications */ 02218 FstubDbgPrintSetPartitionEx(PartitionInfo, PartitionNumber); 02219 02220 /* Allocate internal structure */ 02221 Status = FstubAllocateDiskInformation(DeviceObject, &Disk, NULL); 02222 if (!NT_SUCCESS(Status)) 02223 { 02224 return Status; 02225 } 02226 02227 /* Get partition table style on disk */ 02228 Status = FstubDetectPartitionStyle(Disk, &PartitionStyle); 02229 if (!NT_SUCCESS(Status)) 02230 { 02231 FstubFreeDiskInformation(Disk); 02232 return Status; 02233 } 02234 02235 /* If it's not matching partition style given in modifications, give up */ 02236 if (PartitionInfo->PartitionStyle != PartitionStyle) 02237 { 02238 FstubFreeDiskInformation(Disk); 02239 return STATUS_INVALID_PARAMETER; 02240 } 02241 02242 /* Finally, handle modifications using proper function */ 02243 switch (PartitionStyle) 02244 { 02245 case PARTITION_STYLE_MBR: 02246 Status = IoSetPartitionInformation(DeviceObject, 02247 Disk->SectorSize, 02248 PartitionNumber, 02249 PartitionInfo->Mbr.PartitionType); 02250 break; 02251 case PARTITION_STYLE_GPT: 02252 Status = FstubSetPartitionInformationEFI(Disk, 02253 PartitionNumber, 02254 &(PartitionInfo->Gpt)); 02255 break; 02256 default: 02257 Status = STATUS_NOT_SUPPORTED; 02258 } 02259 02260 /* Release internal structure and return */ 02261 FstubFreeDiskInformation(Disk); 02262 return Status; 02263 } 02264 02265 /* 02266 * @implemented 02267 */ 02268 NTSTATUS 02269 NTAPI 02270 IoVerifyPartitionTable(IN PDEVICE_OBJECT DeviceObject, 02271 IN BOOLEAN FixErrors) 02272 { 02273 NTSTATUS Status; 02274 PDISK_INFORMATION Disk; 02275 PARTITION_STYLE PartitionStyle; 02276 PAGED_CODE(); 02277 02278 ASSERT(DeviceObject); 02279 02280 /* Allocate internal structure */ 02281 Status = FstubAllocateDiskInformation(DeviceObject, &Disk, NULL); 02282 if (!NT_SUCCESS(Status)) 02283 { 02284 return Status; 02285 } 02286 ASSERT(Disk); 02287 02288 /* Get partition table style on disk */ 02289 Status = FstubDetectPartitionStyle(Disk, &PartitionStyle); 02290 if (!NT_SUCCESS(Status)) 02291 { 02292 FstubFreeDiskInformation(Disk); 02293 return Status; 02294 } 02295 02296 /* Action will depend on partition style */ 02297 switch (PartitionStyle) 02298 { 02299 /* For MBR, assume it's always OK */ 02300 case PARTITION_STYLE_MBR: 02301 Status = STATUS_SUCCESS; 02302 break; 02303 /* For GPT, call internal function */ 02304 case PARTITION_STYLE_GPT: 02305 Status = FstubVerifyPartitionTableEFI(Disk, FixErrors); 02306 break; 02307 /* Otherwise, signal we can't work */ 02308 default: 02309 Status = STATUS_NOT_SUPPORTED; 02310 } 02311 02312 /* Release internal structure and return */ 02313 FstubFreeDiskInformation(Disk); 02314 return Status; 02315 } 02316 02317 /* 02318 * @implemented 02319 */ 02320 NTSTATUS 02321 NTAPI 02322 IoWritePartitionTableEx(IN PDEVICE_OBJECT DeviceObject, 02323 IN struct _DRIVE_LAYOUT_INFORMATION_EX* DriveLayout) 02324 { 02325 NTSTATUS Status; 02326 PDISK_INFORMATION Disk; 02327 ULONGLONG SectorsForPartitions; 02328 EFI_PARTITION_HEADER EfiHeader; 02329 PAGED_CODE(); 02330 02331 ASSERT(DeviceObject); 02332 ASSERT(DriveLayout); 02333 02334 /* Debug partition table that must be written */ 02335 FstubDbgPrintDriveLayoutEx(DriveLayout); 02336 02337 /* Allocate internal structure */ 02338 Status = FstubAllocateDiskInformation(DeviceObject, &Disk, 0); 02339 if (!NT_SUCCESS(Status)) 02340 { 02341 return Status; 02342 } 02343 ASSERT(Disk); 02344 02345 switch (DriveLayout->PartitionStyle) 02346 { 02347 case PARTITION_STYLE_MBR: 02348 Status = FstubWritePartitionTableMBR(Disk, DriveLayout); 02349 break; 02350 02351 case PARTITION_STYLE_GPT: 02352 /* Read primary table header */ 02353 Status = FstubReadHeaderEFI(Disk, 02354 FALSE, 02355 &EfiHeader); 02356 /* If it failed, try reading back table header */ 02357 if (!NT_SUCCESS(Status)) 02358 { 02359 Status = FstubReadHeaderEFI(Disk, 02360 TRUE, 02361 &EfiHeader); 02362 } 02363 02364 /* We have a header! */ 02365 if (NT_SUCCESS(Status)) 02366 { 02367 /* Check if there are enough places for the partitions to be written */ 02368 if (DriveLayout->PartitionCount <= EfiHeader.NumberOfEntries) 02369 { 02370 /* Count number of sectors needed to store partitions */ 02371 SectorsForPartitions = (EfiHeader.NumberOfEntries * PARTITION_ENTRY_SIZE) / Disk->SectorSize; 02372 /* Set first usable LBA: Legacy MBR + GPT header + Partitions entries */ 02373 EfiHeader.FirstUsableLBA = SectorsForPartitions + 2; 02374 /* Set last usable LBA: Last sector - GPT header - Partitions entries */ 02375 EfiHeader.LastUsableLBA = Disk->SectorCount - SectorsForPartitions - 1; 02376 /* Write primary table */ 02377 Status = FstubWritePartitionTableEFI(Disk, 02378 EfiHeader.DiskGUID, 02379 EfiHeader.NumberOfEntries, 02380 EfiHeader.FirstUsableLBA, 02381 EfiHeader.LastUsableLBA, 02382 FALSE, 02383 DriveLayout->PartitionCount, 02384 DriveLayout->PartitionEntry); 02385 /* If it succeed, also update backup table */ 02386 if (NT_SUCCESS(Status)) 02387 { 02388 Status = FstubWritePartitionTableEFI(Disk, 02389 EfiHeader.DiskGUID, 02390 EfiHeader.NumberOfEntries, 02391 EfiHeader.FirstUsableLBA, 02392 EfiHeader.LastUsableLBA, 02393 TRUE, 02394 DriveLayout->PartitionCount, 02395 DriveLayout->PartitionEntry); 02396 } 02397 } 02398 } 02399 break; 02400 02401 default: 02402 DPRINT("Unsupported partition style: %ld\n", DriveLayout->PartitionStyle); 02403 Status = STATUS_NOT_SUPPORTED; 02404 } 02405 02406 /* It's over, internal structure not needed anymore */ 02407 FstubFreeDiskInformation(Disk); 02408 02409 return Status; 02410 } 02411 02412 /* EOF */ Generated on Mon May 28 2012 04:37:08 for ReactOS by
1.7.6.1
|