Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4385 lines
101 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. ex.c
  5. Abstract:
  6. Extended routines for reading and writing new partition table types like
  7. EFI partitioned disks.
  8. The following routines are exported from this file:
  9. IoCreateDisk - Initialize an empty disk.
  10. IoWritePartitionTableEx - Write a partition table for either a
  11. legacy AT-style disk or an EFI partitioned disk.
  12. IoReadPartitionTableEx - Read the partition table for a disk.
  13. IoSetPartitionInformation - Set information for a specific
  14. partition.
  15. Author:
  16. Matthew D Hendel (math) 07-Sept-1999
  17. Revision History:
  18. --*/
  19. #include <ntos.h>
  20. #include <zwapi.h>
  21. #include <hal.h>
  22. #include <ntdddisk.h>
  23. #include <ntddft.h>
  24. #include <setupblk.h>
  25. #include <stdio.h>
  26. #include "fstub.h"
  27. #include "efi.h"
  28. #include "ex.h"
  29. #include "haldisp.h"
  30. #ifdef ALLOC_PRAGMA
  31. #pragma alloc_text(PAGE, IoCreateDisk)
  32. #pragma alloc_text(PAGE, IoReadPartitionTableEx)
  33. #pragma alloc_text(PAGE, IoWritePartitionTableEx)
  34. #pragma alloc_text(PAGE, IoSetPartitionInformationEx)
  35. #pragma alloc_text(PAGE, IoUpdateDiskGeometry)
  36. #pragma alloc_text(PAGE, IoVerifyPartitionTable)
  37. #pragma alloc_text(PAGE, FstubSetPartitionInformationEFI)
  38. #pragma alloc_text(PAGE, FstubReadPartitionTableMBR)
  39. #pragma alloc_text(PAGE, FstubDetectPartitionStyle)
  40. #pragma alloc_text(PAGE, FstubGetDiskGeometry)
  41. #pragma alloc_text(PAGE, FstubAllocateDiskInformation)
  42. #pragma alloc_text(PAGE, FstubFreeDiskInformation)
  43. #pragma alloc_text(PAGE, FstubWriteBootSectorEFI)
  44. #pragma alloc_text(PAGE, FstubConvertExtendedToLayout)
  45. #pragma alloc_text(PAGE, FstubWritePartitionTableMBR)
  46. #pragma alloc_text(PAGE, FstubWriteEntryEFI)
  47. #pragma alloc_text(PAGE, FstubWriteHeaderEFI)
  48. #pragma alloc_text(PAGE, FstubAdjustPartitionCount)
  49. #pragma alloc_text(PAGE, FstubCreateDiskEFI)
  50. #pragma alloc_text(PAGE, FstubCreateDiskMBR)
  51. #pragma alloc_text(PAGE, FstubCreateDiskRaw)
  52. #pragma alloc_text(PAGE, FstubCopyEntryEFI)
  53. #pragma alloc_text(PAGE, FstubWritePartitionTableEFI)
  54. #pragma alloc_text(PAGE, FstubReadHeaderEFI)
  55. #pragma alloc_text(PAGE, FstubReadPartitionTableEFI)
  56. #pragma alloc_text(PAGE, FstubVerifyPartitionTableEFI)
  57. #pragma alloc_text(PAGE, FstubUpdateDiskGeometryEFI)
  58. #pragma alloc_text(PAGE, FstubWriteSector)
  59. #pragma alloc_text(PAGE, FstubReadSector)
  60. #if DBG
  61. #pragma alloc_text(PAGE, FstubDbgPrintPartition)
  62. #pragma alloc_text(PAGE, FstubDbgPrintDriveLayout)
  63. #pragma alloc_text(PAGE, FstubDbgPrintPartitionEx)
  64. #pragma alloc_text(PAGE, FstubDbgPrintDriveLayoutEx)
  65. #pragma alloc_text(PAGE, FstubDbgPrintSetPartitionEx)
  66. #endif // DBG
  67. #endif
  68. NTSTATUS
  69. IoCreateDisk(
  70. IN PDEVICE_OBJECT DeviceObject,
  71. IN PCREATE_DISK DiskInfo
  72. )
  73. /*++
  74. Routine Description:
  75. This routine creates an empty disk for the device object. It can operate
  76. on either an EFI disk or an MBR disk. The parameters necessary to create
  77. an empty disk vary for different type of partition tables the disks
  78. contain.
  79. Arguments:
  80. DeviceObject - Device object to initialize disk for.
  81. DiskInfo - The information necessary to create the disk. This will vary
  82. for different partition types; e.g., MBR partitioned disks and
  83. EFI partitioned disks. If DiskInfo is NULL, then we default
  84. to initializing the disk to raw.
  85. Return Values:
  86. NTSTATUS code.
  87. --*/
  88. {
  89. NTSTATUS Status;
  90. ULONG PartitionStyle;
  91. PAGED_CODE ();
  92. ASSERT ( DeviceObject != NULL );
  93. //
  94. // If DiskInfo is NULL, we default to RAW.
  95. //
  96. if ( DiskInfo == NULL ) {
  97. PartitionStyle = PARTITION_STYLE_RAW;
  98. } else {
  99. PartitionStyle = DiskInfo->PartitionStyle;
  100. }
  101. //
  102. // Call the lower level routine for EFI, MBR or RAW disks.
  103. //
  104. switch ( PartitionStyle ) {
  105. case PARTITION_STYLE_GPT:
  106. Status = FstubCreateDiskEFI ( DeviceObject, &DiskInfo->Gpt );
  107. break;
  108. case PARTITION_STYLE_MBR:
  109. Status = FstubCreateDiskMBR ( DeviceObject, &DiskInfo->Mbr );
  110. break;
  111. case PARTITION_STYLE_RAW:
  112. Status = FstubCreateDiskRaw ( DeviceObject );
  113. break;
  114. default:
  115. Status = STATUS_NOT_SUPPORTED;
  116. }
  117. return Status;
  118. }
  119. NTSTATUS
  120. IoWritePartitionTableEx(
  121. IN PDEVICE_OBJECT DeviceObject,
  122. IN PDRIVE_LAYOUT_INFORMATION_EX DriveLayout
  123. )
  124. /*++
  125. Routine Description:
  126. Write a partition table to the disk.
  127. Arguments:
  128. DeviceObject - The device object for the disk we want to write the
  129. partition table for.
  130. DriveLayout - The partition table information.
  131. Return Values:
  132. NTSTATUS code.
  133. --*/
  134. {
  135. NTSTATUS Status;
  136. PDISK_INFORMATION Disk;
  137. PAGED_CODE ();
  138. ASSERT ( DeviceObject != NULL );
  139. ASSERT ( DriveLayout != NULL );
  140. FstubDbgPrintDriveLayoutEx ( DriveLayout );
  141. //
  142. // Initialize a Disk structure.
  143. //
  144. Disk = NULL;
  145. Status = FstubAllocateDiskInformation (
  146. DeviceObject,
  147. &Disk,
  148. NULL
  149. );
  150. if (!NT_SUCCESS (Status)) {
  151. return Status;
  152. }
  153. //
  154. // ISSUE - 2000/03/17 - math: Check partition type.
  155. // We need to check the partition type so people don't write an MBR
  156. // drive layout over a GPT partition table. Detect the partition style
  157. // and if it doesn't match the one we're passed in, fail the call.
  158. //
  159. ASSERT ( Disk != NULL );
  160. switch ( DriveLayout->PartitionStyle ) {
  161. case PARTITION_STYLE_GPT: {
  162. ULONG MaxPartitionCount;
  163. PEFI_PARTITION_HEADER Header;
  164. //
  165. // Read the partition table header from the primary partition
  166. // table.
  167. //
  168. Header = NULL;
  169. //
  170. // NB: Header is allocated in the disk's scratch buffer. Thus,
  171. // it does not explicitly need to be deallocated.
  172. //
  173. Status = FstubReadHeaderEFI (
  174. Disk,
  175. PRIMARY_PARTITION_TABLE,
  176. &Header
  177. );
  178. if (!NT_SUCCESS (Status)) {
  179. //
  180. // Failed reading the header from the primary partition table.
  181. // Try the backup table.
  182. //
  183. Status = FstubReadHeaderEFI (
  184. Disk,
  185. BACKUP_PARTITION_TABLE,
  186. &Header
  187. );
  188. if (!NT_SUCCESS (Status)) {
  189. break;
  190. }
  191. }
  192. MaxPartitionCount = Header->NumberOfEntries;
  193. //
  194. // You cannot write more partition table entries that the
  195. // table will hold.
  196. //
  197. if (DriveLayout->PartitionCount > MaxPartitionCount) {
  198. KdPrintEx((DPFLTR_FSTUB_ID,
  199. DPFLTR_WARNING_LEVEL,
  200. "FSTUB: ERROR: Requested to write %d partitions\n"
  201. "\tto a table that can hold a maximum of %d entries\n",
  202. DriveLayout->PartitionCount,
  203. MaxPartitionCount));
  204. Status = STATUS_INVALID_PARAMETER;
  205. break;
  206. }
  207. //
  208. // Write the primary partition table.
  209. //
  210. Status = FstubWritePartitionTableEFI (
  211. Disk,
  212. DriveLayout->Gpt.DiskId,
  213. MaxPartitionCount,
  214. Header->FirstUsableLBA,
  215. Header->LastUsableLBA,
  216. PRIMARY_PARTITION_TABLE,
  217. DriveLayout->PartitionCount,
  218. DriveLayout->PartitionEntry
  219. );
  220. if (!NT_SUCCESS (Status)) {
  221. break;
  222. }
  223. //
  224. // Write the backup partition table.
  225. //
  226. Status = FstubWritePartitionTableEFI (
  227. Disk,
  228. DriveLayout->Gpt.DiskId,
  229. MaxPartitionCount,
  230. Header->FirstUsableLBA,
  231. Header->LastUsableLBA,
  232. BACKUP_PARTITION_TABLE,
  233. DriveLayout->PartitionCount,
  234. DriveLayout->PartitionEntry
  235. );
  236. break;
  237. }
  238. case PARTITION_STYLE_MBR:
  239. Status = FstubWritePartitionTableMBR (
  240. Disk,
  241. DriveLayout
  242. );
  243. break;
  244. default:
  245. Status = STATUS_NOT_SUPPORTED;
  246. }
  247. if ( Disk != NULL ) {
  248. FstubFreeDiskInformation ( Disk );
  249. }
  250. #if 0
  251. //
  252. // If we successfully wrote a new partition table. Verify that it is
  253. // valid.
  254. //
  255. if ( NT_SUCCESS (Status)) {
  256. NTSTATUS VerifyStatus;
  257. VerifyStatus = IoVerifyPartitionTable ( DeviceObject, FALSE );
  258. //
  259. // STATUS_NOT_SUPPORTED is returned for MBR disks.
  260. //
  261. if (VerifyStatus != STATUS_NOT_SUPPORTED) {
  262. ASSERT (NT_SUCCESS (VerifyStatus));
  263. }
  264. }
  265. #endif
  266. return Status;
  267. }
  268. NTSTATUS
  269. IoReadPartitionTableEx(
  270. IN PDEVICE_OBJECT DeviceObject,
  271. IN PDRIVE_LAYOUT_INFORMATION_EX* DriveLayout
  272. )
  273. /*++
  274. Routine Description:
  275. This routine reads the partition table for the disk. Unlike
  276. IoReadPartitionTable, this routine understands both EFI and MBR
  277. partitioned disks.
  278. The partition list is built in nonpaged pool that is allocated by this
  279. routine. It is the caller's responsability to free this memory when it
  280. is finished with the data.
  281. Arguments:
  282. DeviceObject - Pointer for device object for this disk.
  283. DriveLayout - Pointer to the pointer that will return the patition list.
  284. This buffer is allocated in nonpaged pool by this routine. It is
  285. the responsability of the caller to free this memory if this
  286. routine is successful.
  287. Return Values:
  288. NTSTATUS code.
  289. --*/
  290. {
  291. NTSTATUS Status;
  292. PDISK_INFORMATION Disk;
  293. PARTITION_STYLE Style;
  294. BOOLEAN FoundGptPartition;
  295. PAGED_CODE ();
  296. ASSERT ( DeviceObject != NULL );
  297. ASSERT ( DriveLayout != NULL );
  298. Status = FstubAllocateDiskInformation (
  299. DeviceObject,
  300. &Disk,
  301. NULL
  302. );
  303. if ( !NT_SUCCESS ( Status ) ) {
  304. return Status;
  305. }
  306. ASSERT ( Disk != NULL );
  307. Status = FstubDetectPartitionStyle (
  308. Disk,
  309. &Style
  310. );
  311. //
  312. // To include oddities such as super-floppies, EZDrive disks and
  313. // raw disks (which get a fake MBR partition created for them),
  314. // we use the following algorithm:
  315. //
  316. // if ( valid gpt partition table)
  317. // return GPT partition information
  318. // else
  319. // return MBR partition information
  320. //
  321. // When this code (especially FstubDetectPartitionStyle) is made
  322. // to understand such things as super-floppies and raw disks, this
  323. // will no longer be necessary.
  324. //
  325. FoundGptPartition = FALSE;
  326. if ( NT_SUCCESS (Status) && Style == PARTITION_STYLE_GPT ) {
  327. //
  328. // First, read the primary partition table.
  329. //
  330. Status = FstubReadPartitionTableEFI (
  331. Disk,
  332. PRIMARY_PARTITION_TABLE,
  333. DriveLayout
  334. );
  335. if (NT_SUCCESS (Status)) {
  336. FoundGptPartition = TRUE;
  337. } else {
  338. //
  339. // If the primary EFI partition table is invalid, try reading
  340. // the backup partition table instead. We should find a way
  341. // to notify the caller that the primary partition table is
  342. // invalid so it can take the steps to fix it.
  343. //
  344. Status = FstubReadPartitionTableEFI (
  345. Disk,
  346. BACKUP_PARTITION_TABLE,
  347. DriveLayout
  348. );
  349. if ( NT_SUCCESS (Status) ) {
  350. FoundGptPartition = TRUE;
  351. }
  352. }
  353. }
  354. if ( !FoundGptPartition ) {
  355. Status = FstubReadPartitionTableMBR (
  356. Disk,
  357. FALSE,
  358. DriveLayout
  359. );
  360. }
  361. if ( Disk ) {
  362. FstubFreeDiskInformation ( Disk );
  363. }
  364. #if DBG
  365. if (NT_SUCCESS (Status)) {
  366. FstubDbgPrintDriveLayoutEx ( *DriveLayout );
  367. }
  368. #endif
  369. return Status;
  370. }
  371. NTSTATUS
  372. IoSetPartitionInformationEx(
  373. IN PDEVICE_OBJECT DeviceObject,
  374. IN ULONG PartitionNumber,
  375. IN PSET_PARTITION_INFORMATION_EX PartitionInfo
  376. )
  377. /*++
  378. Routine Description:
  379. Set the partition information for a specific partition.
  380. Arguments:
  381. DeviceObject - Pointer to the device object for the disk.
  382. PartitionNumber - A valid partition number we want to set the partition
  383. information for.
  384. PartitionInfo - The partition information.
  385. Return Values:
  386. NTSTATUS code.
  387. --*/
  388. {
  389. NTSTATUS Status;
  390. PDISK_INFORMATION Disk;
  391. PARTITION_STYLE Style;
  392. ASSERT ( DeviceObject != NULL );
  393. ASSERT ( PartitionInfo != NULL );
  394. PAGED_CODE ();
  395. //
  396. // Initialization
  397. //
  398. Disk = NULL;
  399. FstubDbgPrintSetPartitionEx (PartitionInfo, PartitionNumber);
  400. Status = FstubAllocateDiskInformation (
  401. DeviceObject,
  402. &Disk,
  403. NULL
  404. );
  405. if (!NT_SUCCESS (Status)) {
  406. return Status;
  407. }
  408. Status = FstubDetectPartitionStyle ( Disk, &Style );
  409. if (!NT_SUCCESS (Status)) {
  410. goto done;
  411. }
  412. if ( Style != PartitionInfo->PartitionStyle ) {
  413. Status = STATUS_INVALID_PARAMETER;
  414. goto done;
  415. }
  416. switch ( Style ) {
  417. case PARTITION_STYLE_MBR:
  418. Status = IoSetPartitionInformation (
  419. DeviceObject,
  420. Disk->SectorSize,
  421. PartitionNumber,
  422. PartitionInfo->Mbr.PartitionType
  423. );
  424. break;
  425. case PARTITION_STYLE_GPT:
  426. Status = FstubSetPartitionInformationEFI (
  427. Disk,
  428. PartitionNumber,
  429. &PartitionInfo->Gpt
  430. );
  431. break;
  432. default:
  433. Status = STATUS_NOT_SUPPORTED;
  434. }
  435. done:
  436. if ( Disk != NULL ) {
  437. FstubFreeDiskInformation ( Disk );
  438. Disk = NULL;
  439. }
  440. return Status;
  441. }
  442. NTSTATUS
  443. IoUpdateDiskGeometry(
  444. IN PDEVICE_OBJECT DeviceObject,
  445. IN PDISK_GEOMETRY_EX OldDiskGeometry,
  446. IN PDISK_GEOMETRY_EX NewDiskGeometry
  447. )
  448. /*++
  449. Routine Description:
  450. Update the disk geometry for the specific device. On an EFI disk the EFI
  451. partition table will be moved to the end of the disk, so the final sectors
  452. must be writable by the time this routine is called.
  453. The primary and backup partition tables must be valid for this function to
  454. succeed.
  455. Arguments:
  456. DeviceObject - The device whose geometry has changed.
  457. OldDiskGeometry - The old disk geometry.
  458. NewDiskGeometry - The new disk geometry.
  459. Return Value:
  460. NTSTATUS code
  461. --*/
  462. {
  463. NTSTATUS Status;
  464. PARTITION_STYLE Style;
  465. PDISK_INFORMATION OldDisk;
  466. PDISK_INFORMATION NewDisk;
  467. PAGED_CODE ();
  468. ASSERT ( DeviceObject != NULL );
  469. ASSERT ( OldDiskGeometry != NULL );
  470. ASSERT ( NewDiskGeometry != NULL );
  471. //
  472. // Initialization.
  473. //
  474. OldDisk = NULL;
  475. NewDisk = NULL;
  476. //
  477. // Allocate objects representing the old disk and the new disk.
  478. //
  479. Status = FstubAllocateDiskInformation (
  480. DeviceObject,
  481. &OldDisk,
  482. (PINTERNAL_DISK_GEOMETRY) OldDiskGeometry
  483. );
  484. if ( !NT_SUCCESS (Status) ) {
  485. goto done;
  486. }
  487. Status = FstubAllocateDiskInformation (
  488. DeviceObject,
  489. &NewDisk,
  490. (PINTERNAL_DISK_GEOMETRY) NewDiskGeometry
  491. );
  492. if ( !NT_SUCCESS (Status) ) {
  493. goto done;
  494. }
  495. Status = FstubDetectPartitionStyle (
  496. OldDisk,
  497. &Style
  498. );
  499. if ( !NT_SUCCESS (Status) ) {
  500. goto done;
  501. }
  502. switch ( Style ) {
  503. case PARTITION_STYLE_GPT:
  504. //
  505. // Update the geometry for an EFI disk.
  506. //
  507. Status = FstubUpdateDiskGeometryEFI (
  508. OldDisk,
  509. NewDisk
  510. );
  511. break;
  512. case PARTITION_STYLE_MBR:
  513. //
  514. // For MBR partitioned drives, there is nothing to do, so
  515. // we succeed by default.
  516. //
  517. Status = STATUS_SUCCESS;
  518. break;
  519. default:
  520. Status = STATUS_NOT_SUPPORTED;
  521. }
  522. done:
  523. if ( OldDisk ) {
  524. FstubFreeDiskInformation ( OldDisk );
  525. OldDisk = NULL;
  526. }
  527. if ( NewDisk ) {
  528. FstubFreeDiskInformation ( NewDisk );
  529. NewDisk = NULL;
  530. }
  531. return Status;
  532. }
  533. NTSTATUS
  534. IoReadDiskSignature(
  535. IN PDEVICE_OBJECT DeviceObject,
  536. IN ULONG BytesPerSector,
  537. OUT PDISK_SIGNATURE Signature
  538. )
  539. /*++
  540. Routine Description:
  541. This routine will read the disk signature information from the disk. For
  542. MBR disks, it will read the disk signature and calculate a checksum of the
  543. contents of the MBR. For GPT disks, it will obtain the EFI DiskId from
  544. the disk.
  545. Arguments:
  546. DeviceObject - A disk device object.
  547. BytesPerSector - The number of bytes per sector on this disk.
  548. DiskSignature - A buffer where the disk information will be stored.
  549. Return Value:
  550. NT Status code.
  551. --*/
  552. {
  553. NTSTATUS Status;
  554. PULONG Mbr;
  555. PAGED_CODE();
  556. //
  557. // Make sure sector size is at least 512 bytes.
  558. //
  559. if (BytesPerSector < 512) {
  560. BytesPerSector = 512;
  561. }
  562. //
  563. // Allocate buffer for sector read.
  564. //
  565. Mbr = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  566. BytesPerSector,
  567. FSTUB_TAG);
  568. if (Mbr == NULL) {
  569. return STATUS_NO_MEMORY;
  570. }
  571. Status = FstubReadSector (
  572. DeviceObject,
  573. BytesPerSector,
  574. 0,
  575. Mbr);
  576. if (!NT_SUCCESS (Status)) {
  577. ExFreePool (Mbr);
  578. return Status;
  579. }
  580. //
  581. // If this is an EFI disk get the EFI disk signature instead.
  582. //
  583. if ( ((MASTER_BOOT_RECORD*)Mbr)->Partition[0].OSIndicator == EFI_MBR_PARTITION_TYPE &&
  584. ((MASTER_BOOT_RECORD*)Mbr)->Partition[1].OSIndicator == 0 &&
  585. ((MASTER_BOOT_RECORD*)Mbr)->Partition[2].OSIndicator == 0 &&
  586. ((MASTER_BOOT_RECORD*)Mbr)->Partition[3].OSIndicator == 0 ) {
  587. PEFI_PARTITION_HEADER EfiHeader;
  588. ULONG32 Temp;
  589. ULONG32 CheckSum;
  590. //
  591. // Get the EFI disk guid.
  592. //
  593. Status = FstubReadSector (
  594. DeviceObject,
  595. BytesPerSector,
  596. 1,
  597. Mbr);
  598. if (!NT_SUCCESS (Status)) {
  599. ExFreePool (Mbr);
  600. return Status;
  601. }
  602. EfiHeader = (PEFI_PARTITION_HEADER) Mbr;
  603. //
  604. // Compute the CRC32 CheckSum of the header block. This is used to
  605. // verify that we have a valid EFI disk.
  606. //
  607. Temp = EfiHeader->HeaderCRC32;
  608. EfiHeader->HeaderCRC32 = 0;
  609. CheckSum = RtlComputeCrc32 (0, EfiHeader, EfiHeader->HeaderSize);
  610. EfiHeader->HeaderCRC32 = Temp;
  611. //
  612. // The EFI CheckSum doesn't match what was in it's header. Return
  613. // failure.
  614. //
  615. if (CheckSum != EfiHeader->HeaderCRC32) {
  616. ExFreePool (Mbr);
  617. return STATUS_DISK_CORRUPT_ERROR;
  618. }
  619. //
  620. // This is a valid EFI disk. Copy the disk signature from the
  621. // EFI Header sector.
  622. //
  623. Signature->PartitionStyle = PARTITION_STYLE_GPT;
  624. Signature->Gpt.DiskId = EfiHeader->DiskGUID;
  625. } else {
  626. ULONG i;
  627. ULONG MbrCheckSum;
  628. //
  629. // Calculate MBR checksum.
  630. //
  631. MbrCheckSum = 0;
  632. for (i = 0; i < 128; i++) {
  633. MbrCheckSum += Mbr[i];
  634. }
  635. MbrCheckSum = ~(MbrCheckSum) + 1;
  636. //
  637. // Get the signature out of the sector and save it in the disk data block.
  638. //
  639. Signature->PartitionStyle = PARTITION_STYLE_MBR;
  640. Signature->Mbr.Signature = Mbr [PARTITION_TABLE_OFFSET/2-1];
  641. Signature->Mbr.CheckSum = MbrCheckSum;
  642. }
  643. ExFreePool (Mbr);
  644. return Status;
  645. }
  646. NTSTATUS
  647. IoVerifyPartitionTable(
  648. IN PDEVICE_OBJECT DeviceObject,
  649. IN BOOLEAN FixErrors
  650. )
  651. /*++
  652. Routine Description:
  653. Verify that the partition table and backup partition table (if present)
  654. is valid. If these tables are NOT valid, and FixErrors is TRUE, and the
  655. errors are recoverable errors, fix them.
  656. Arguments:
  657. DeviceObject - A disk whose partition table should be verified and/or
  658. fixed.
  659. FixErrors - If the partition table contains errors and these errors are
  660. recoverable errors, fix the errors. Otherwise, the disk will not
  661. be modified.
  662. Return Value:
  663. STATUS_SUCCESS - If the final partition table, after any modifications
  664. done by this routine, is valid.
  665. STATUS_DISK_CORRUPT_ERROR - If the final partition table, after any
  666. modifications done by this routine, is not valid.
  667. Other NTSTATUS code - Some other failure.
  668. --*/
  669. {
  670. NTSTATUS Status;
  671. PDISK_INFORMATION Disk;
  672. PARTITION_STYLE Style;
  673. PAGED_CODE ();
  674. ASSERT ( DeviceObject != NULL );
  675. Status = FstubAllocateDiskInformation (
  676. DeviceObject,
  677. &Disk,
  678. NULL
  679. );
  680. if ( !NT_SUCCESS ( Status ) ) {
  681. return Status;
  682. }
  683. ASSERT ( Disk != NULL );
  684. Status = FstubDetectPartitionStyle (
  685. Disk,
  686. &Style
  687. );
  688. if ( !NT_SUCCESS (Status) ) {
  689. FstubFreeDiskInformation ( Disk );
  690. Disk = NULL;
  691. return Status;
  692. }
  693. switch ( Style ) {
  694. case PARTITION_STYLE_GPT:
  695. Status = FstubVerifyPartitionTableEFI (
  696. Disk,
  697. FixErrors
  698. );
  699. break;
  700. case PARTITION_STYLE_MBR:
  701. Status = STATUS_SUCCESS;
  702. break;
  703. default:
  704. Status = STATUS_NOT_SUPPORTED;
  705. }
  706. if ( Disk ) {
  707. FstubFreeDiskInformation ( Disk );
  708. }
  709. return Status;
  710. }
  711. //
  712. // Internal Routines
  713. //
  714. NTSTATUS
  715. FstubSetPartitionInformationEFI(
  716. IN PDISK_INFORMATION Disk,
  717. IN ULONG PartitionNumber,
  718. IN SET_PARTITION_INFORMATION_GPT* PartitionInfo
  719. )
  720. /*++
  721. Routine Description:
  722. Update the partition information for a specific EFI partition.
  723. The algorithm we use reads the entire partition table and writes it back
  724. again. This makes sense, because the entire table will have to be read in
  725. ANYWAY, since we have to checksum the table.
  726. NB: this algorithm assumes that the partition table hasn't changed since
  727. the time GetDriveLayout was called. Probably a safe assumption.
  728. Arguments:
  729. Disk -
  730. PartitionNumber -
  731. PartitionInfo -
  732. Return Values:
  733. NTSTATUS code.
  734. --*/
  735. {
  736. NTSTATUS Status;
  737. PPARTITION_INFORMATION_GPT EntryInfo;
  738. PDRIVE_LAYOUT_INFORMATION_EX Layout;
  739. ULONG PartitionOrdinal;
  740. ASSERT ( Disk != NULL );
  741. ASSERT ( PartitionInfo != NULL );
  742. PAGED_CODE ();
  743. //
  744. // Initialization
  745. //
  746. Layout = NULL;
  747. if ( PartitionNumber == 0 ) {
  748. return STATUS_INVALID_PARAMETER;
  749. }
  750. PartitionOrdinal = PartitionNumber - 1;
  751. //
  752. // Read in the entire partition table.
  753. //
  754. Status = IoReadPartitionTableEx (
  755. Disk->DeviceObject,
  756. &Layout
  757. );
  758. if (!NT_SUCCESS (Status)) {
  759. return Status;
  760. }
  761. ASSERT ( Layout != NULL );
  762. //
  763. // If it's out of range, fail.
  764. //
  765. if ( PartitionOrdinal >= Layout->PartitionCount ) {
  766. ExFreePool ( Layout );
  767. return STATUS_INVALID_PARAMETER;
  768. }
  769. //
  770. // Copy the information into the partition array.
  771. //
  772. EntryInfo = &Layout->PartitionEntry [PartitionOrdinal].Gpt;
  773. EntryInfo->PartitionType = PartitionInfo->PartitionType;
  774. EntryInfo->PartitionId = PartitionInfo->PartitionId;
  775. EntryInfo->Attributes = PartitionInfo->Attributes;
  776. RtlCopyMemory (
  777. EntryInfo->Name,
  778. PartitionInfo->Name,
  779. sizeof (EntryInfo->Name)
  780. );
  781. //
  782. // And rewrite the partition table.
  783. //
  784. Status = IoWritePartitionTableEx (
  785. Disk->DeviceObject,
  786. Layout
  787. );
  788. ExFreePool ( Layout );
  789. Layout = NULL;
  790. return Status;
  791. }
  792. NTSTATUS
  793. FstubReadPartitionTableMBR(
  794. IN PDISK_INFORMATION Disk,
  795. IN BOOLEAN RecognizedPartitionsOnly,
  796. OUT PDRIVE_LAYOUT_INFORMATION_EX* ReturnedDriveLayout
  797. )
  798. /*++
  799. Routine Description:
  800. Read the MBR partition table.
  801. Arguments:
  802. Disk - The disk we want to obtain the partition information for.
  803. RecognizedPartitionsOnly - Whether to return information for all
  804. partitions or only recognized partitions.
  805. ReturnedDriveLayout - A pointer to pointer where the drive layout
  806. information will be returned. The caller of this function is
  807. responsible for freeing this memory using ExFreePool.
  808. Return Values:
  809. NTSTATUS code.
  810. --*/
  811. {
  812. NTSTATUS Status;
  813. ULONG i;
  814. ULONG Size;
  815. PDRIVE_LAYOUT_INFORMATION Layout;
  816. PDRIVE_LAYOUT_INFORMATION_EX LayoutEx;
  817. PPARTITION_INFORMATION Entry;
  818. PPARTITION_INFORMATION_EX EntryEx;
  819. PAGED_CODE ();
  820. ASSERT ( IS_VALID_DISK_INFO ( Disk ) );
  821. ASSERT ( ReturnedDriveLayout != NULL );
  822. //
  823. // Initialization
  824. //
  825. *ReturnedDriveLayout = NULL;
  826. Layout = NULL;
  827. Status = IoReadPartitionTable (
  828. Disk->DeviceObject,
  829. Disk->SectorSize,
  830. RecognizedPartitionsOnly,
  831. &Layout
  832. );
  833. if (!NT_SUCCESS (Status)) {
  834. return Status;
  835. }
  836. Size = FIELD_OFFSET (DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[0]) +
  837. Layout->PartitionCount * sizeof (PARTITION_INFORMATION_EX);
  838. LayoutEx = ExAllocatePoolWithTag (
  839. NonPagedPool,
  840. Size,
  841. FSTUB_TAG
  842. );
  843. if ( LayoutEx == NULL ) {
  844. return STATUS_INSUFFICIENT_RESOURCES;
  845. }
  846. //
  847. // Tranlated the drive layout information to the extended drive layout
  848. // information.
  849. //
  850. LayoutEx->PartitionStyle = PARTITION_STYLE_MBR;
  851. LayoutEx->PartitionCount = Layout->PartitionCount;
  852. LayoutEx->Mbr.Signature = Layout->Signature;
  853. //
  854. // Translate each entry in the table.
  855. //
  856. for (i = 0; i < Layout->PartitionCount; i++) {
  857. EntryEx = &LayoutEx->PartitionEntry[i];
  858. Entry = &Layout->PartitionEntry[i];
  859. EntryEx->PartitionStyle = PARTITION_STYLE_MBR;
  860. EntryEx->StartingOffset = Entry->StartingOffset;
  861. EntryEx->PartitionLength = Entry->PartitionLength;
  862. EntryEx->RewritePartition = Entry->RewritePartition;
  863. EntryEx->PartitionNumber = Entry->PartitionNumber;
  864. EntryEx->Mbr.PartitionType = Entry->PartitionType;
  865. EntryEx->Mbr.BootIndicator = Entry->BootIndicator;
  866. EntryEx->Mbr.RecognizedPartition = Entry->RecognizedPartition;
  867. EntryEx->Mbr.HiddenSectors = Entry->HiddenSectors;
  868. }
  869. //
  870. // Free layout information allocated by IoReadPartitionTable.
  871. //
  872. ExFreePool ( Layout );
  873. //
  874. // And return the translated, EX information.
  875. //
  876. *ReturnedDriveLayout = LayoutEx;
  877. return Status;
  878. }
  879. NTSTATUS
  880. FstubDetectPartitionStyle(
  881. IN PDISK_INFORMATION Disk,
  882. OUT PARTITION_STYLE* PartitionStyle
  883. )
  884. /*++
  885. Routine Description:
  886. Detect how a disk has been partitioned. For an MBR partitioned disk,
  887. sector zero contains the MBR signature. For an EFI partitioned disk,
  888. sector zero contains a legacy style MBR with a single partition that
  889. consumes the entire disk.
  890. Arguments:
  891. Disk - The disk to determine the partition style for.
  892. PartitionStyle - A buffer to
  893. Return Values:
  894. STATUS_SUCCESS - If the disk has been partitioned by a recognized
  895. partitioning scheme EFI or MBR.
  896. STATUS_UNSUCCESSFUL - If partitioning scheme was not recognized.
  897. --*/
  898. {
  899. NTSTATUS Status;
  900. MASTER_BOOT_RECORD* Mbr;
  901. PAGED_CODE ();
  902. ASSERT ( IS_VALID_DISK_INFO ( Disk ) );
  903. ASSERT ( PartitionStyle != NULL );
  904. //
  905. // Read sector 0. This will contan the mbr on an mbr-partition disk
  906. // or the legacy mbr on an efi-partitioned disk.
  907. //
  908. Status = FstubReadSector (
  909. Disk->DeviceObject,
  910. Disk->SectorSize,
  911. 0,
  912. Disk->ScratchBuffer
  913. );
  914. if ( !NT_SUCCESS ( Status ) ) {
  915. return Status;
  916. }
  917. Mbr = Disk->ScratchBuffer;
  918. //
  919. // If the disk has an MBR
  920. //
  921. *PartitionStyle = -1;
  922. if (Mbr->Signature == MBR_SIGNATURE) {
  923. if (Mbr->Partition[0].OSIndicator == EFI_MBR_PARTITION_TYPE &&
  924. Mbr->Partition[1].OSIndicator == 0 &&
  925. Mbr->Partition[2].OSIndicator == 0 &&
  926. Mbr->Partition[3].OSIndicator == 0) {
  927. *PartitionStyle = PARTITION_STYLE_GPT;
  928. Status = STATUS_SUCCESS;
  929. } else {
  930. *PartitionStyle = PARTITION_STYLE_MBR;
  931. Status = STATUS_SUCCESS;
  932. }
  933. } else {
  934. Status = STATUS_UNSUCCESSFUL;
  935. }
  936. return Status;
  937. }
  938. NTSTATUS
  939. FstubGetDiskGeometry(
  940. IN PDEVICE_OBJECT DeviceObject,
  941. IN PINTERNAL_DISK_GEOMETRY Geometry
  942. )
  943. /*++
  944. Routine Description:
  945. We need this routine to get the number of cylinders that the disk driver
  946. thinks is on the drive. We will need this to calculate CHS values
  947. when we fill in the partition table entries.
  948. Arguments:
  949. DeviceObject - The device object describing the entire drive.
  950. Return Value:
  951. None.
  952. --*/
  953. {
  954. PIRP localIrp;
  955. PINTERNAL_DISK_GEOMETRY diskGeometry;
  956. PIO_STATUS_BLOCK iosb;
  957. PKEVENT eventPtr;
  958. NTSTATUS status;
  959. PAGED_CODE ();
  960. ASSERT ( DeviceObject != NULL );
  961. ASSERT ( Geometry != NULL );
  962. //
  963. // Initialization
  964. //
  965. eventPtr = NULL;
  966. iosb = NULL;
  967. diskGeometry = NULL;
  968. diskGeometry = ExAllocatePoolWithTag(
  969. NonPagedPool,
  970. sizeof (*diskGeometry),
  971. 'btsF'
  972. );
  973. if (!diskGeometry) {
  974. status = STATUS_INSUFFICIENT_RESOURCES;
  975. goto done;
  976. }
  977. iosb = ExAllocatePoolWithTag(
  978. NonPagedPool,
  979. sizeof(IO_STATUS_BLOCK),
  980. 'btsF'
  981. );
  982. if (!iosb) {
  983. status = STATUS_INSUFFICIENT_RESOURCES;
  984. goto done;
  985. }
  986. eventPtr = ExAllocatePoolWithTag(
  987. NonPagedPool,
  988. sizeof(KEVENT),
  989. 'btsF'
  990. );
  991. if (!eventPtr) {
  992. status = STATUS_INSUFFICIENT_RESOURCES;
  993. goto done;
  994. }
  995. KeInitializeEvent(
  996. eventPtr,
  997. NotificationEvent,
  998. FALSE
  999. );
  1000. localIrp = IoBuildDeviceIoControlRequest(
  1001. IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
  1002. DeviceObject,
  1003. NULL,
  1004. 0UL,
  1005. diskGeometry,
  1006. sizeof (*diskGeometry),
  1007. FALSE,
  1008. eventPtr,
  1009. iosb
  1010. );
  1011. if (!localIrp) {
  1012. status = STATUS_INSUFFICIENT_RESOURCES;
  1013. goto done;
  1014. }
  1015. //
  1016. // Call the lower level driver, wait for the opertion
  1017. // to finish.
  1018. //
  1019. status = IoCallDriver(
  1020. DeviceObject,
  1021. localIrp
  1022. );
  1023. if (status == STATUS_PENDING) {
  1024. KeWaitForSingleObject(
  1025. eventPtr,
  1026. Executive,
  1027. KernelMode,
  1028. FALSE,
  1029. (PLARGE_INTEGER) NULL
  1030. );
  1031. status = iosb->Status;
  1032. }
  1033. if (NT_SUCCESS(status)) {
  1034. RtlCopyMemory (Geometry, diskGeometry, sizeof (*Geometry));
  1035. }
  1036. done:
  1037. if ( eventPtr ) {
  1038. ExFreePool (eventPtr);
  1039. eventPtr = NULL;
  1040. }
  1041. if ( iosb ) {
  1042. ExFreePool(iosb);
  1043. iosb = NULL;
  1044. }
  1045. if ( diskGeometry ) {
  1046. ExFreePool (diskGeometry);
  1047. diskGeometry = NULL;
  1048. }
  1049. if ( NT_SUCCESS ( status ) ) {
  1050. //
  1051. // If the the partition entry size is not a factor of the disk block
  1052. // size, we will need to add code to deal with partition entries that
  1053. // span physical sectors. This may happen if you change the size of
  1054. // the partition entry or if you have a disk with a block size less
  1055. // than 128 bytes.
  1056. //
  1057. ASSERT ( (Geometry->Geometry.BytesPerSector % PARTITION_ENTRY_SIZE) == 0);
  1058. }
  1059. return status;
  1060. }
  1061. NTSTATUS
  1062. FstubAllocateDiskInformation(
  1063. IN PDEVICE_OBJECT DeviceObject,
  1064. OUT PDISK_INFORMATION * DiskBuffer,
  1065. IN PINTERNAL_DISK_GEOMETRY Geometry OPTIONAL
  1066. )
  1067. /*++
  1068. Routine Description:
  1069. Allocate and initialize a DISK_INFORMATION structure describing the
  1070. disk DeviceObject.
  1071. Arguments:
  1072. DeviceObject - A device object describing the entire disk.
  1073. DiskBuffer - A buffer to a recieve the allocated DISK_INFORMATION pointer.
  1074. Geometry - An optional pointer to an INTERNAL_DISK_GEOMETRY structure. If
  1075. this pointer is NULL, the disk will be querried for it's geometry
  1076. using IOCTL_DISK_GET_DRIVE_GEOMETRY_EX.
  1077. Return Values:
  1078. NTSTATUS code.
  1079. --*/
  1080. {
  1081. NTSTATUS Status;
  1082. PDISK_INFORMATION Disk;
  1083. PVOID Buffer;
  1084. PAGED_CODE ();
  1085. ASSERT ( DeviceObject != NULL );
  1086. ASSERT ( DiskBuffer != NULL );
  1087. Disk = ExAllocatePoolWithTag (
  1088. NonPagedPool,
  1089. sizeof (DISK_INFORMATION),
  1090. FSTUB_TAG
  1091. );
  1092. if ( Disk == NULL ) {
  1093. return STATUS_INSUFFICIENT_RESOURCES;
  1094. }
  1095. if ( Geometry ) {
  1096. RtlCopyMemory (
  1097. &Disk->Geometry,
  1098. Geometry,
  1099. sizeof (Disk->Geometry)
  1100. );
  1101. } else {
  1102. Status = FstubGetDiskGeometry (
  1103. DeviceObject,
  1104. &Disk->Geometry
  1105. );
  1106. if (!NT_SUCCESS (Status)) {
  1107. KdPrintEx ((DPFLTR_FSTUB_ID,
  1108. DPFLTR_ERROR_LEVEL,
  1109. "FSTUB: disk %p failed to report geometry.\n",
  1110. DeviceObject));
  1111. ExFreePool ( Disk );
  1112. return Status;
  1113. }
  1114. }
  1115. //
  1116. // Check the geometry. Sometimes drives report incorrect geometry.
  1117. // Removable drives without media report a size of zero.
  1118. //
  1119. if (Disk->Geometry.Geometry.BytesPerSector == 0 ||
  1120. Disk->Geometry.DiskSize.QuadPart == 0) {
  1121. KdPrintEx ((DPFLTR_FSTUB_ID,
  1122. DPFLTR_WARNING_LEVEL,
  1123. "FSTUB: disk %p reported invalid geometry. Probably a removable.\n"
  1124. " SectorSize %d\n"
  1125. " DiskSize %I64x\n",
  1126. DeviceObject,
  1127. Disk->Geometry.Geometry.BytesPerSector,
  1128. Disk->Geometry.DiskSize.QuadPart));
  1129. ExFreePool ( Disk );
  1130. return STATUS_DEVICE_NOT_READY;
  1131. }
  1132. Disk->DeviceObject = DeviceObject;
  1133. Disk->SectorSize = Disk->Geometry.Geometry.BytesPerSector;
  1134. //
  1135. // Do not use sector-count = cylinders * tracks * sector-size. Devices
  1136. // like the memory stick can report a correct disk size and a more or
  1137. // less correct sector size, a completely invalid number of cylinders
  1138. // or tracks. Since the only thing we really need here is the sector
  1139. // count, avoid using these potentially incorrect values.
  1140. //
  1141. Disk->SectorCount = Disk->Geometry.DiskSize.QuadPart /
  1142. (ULONGLONG) Disk->Geometry.Geometry.BytesPerSector;
  1143. //
  1144. // NOTE: This does not need to be nonpaged or cache aligned, does it?
  1145. //
  1146. Buffer = ExAllocatePoolWithTag (
  1147. NonPagedPoolCacheAligned,
  1148. Disk->SectorSize,
  1149. FSTUB_TAG
  1150. );
  1151. if ( Buffer == NULL ) {
  1152. ExFreePool ( Disk );
  1153. return STATUS_INSUFFICIENT_RESOURCES;
  1154. }
  1155. Disk->ScratchBuffer = Buffer;
  1156. *DiskBuffer = Disk;
  1157. return STATUS_SUCCESS;
  1158. }
  1159. NTSTATUS
  1160. FstubFreeDiskInformation(
  1161. IN OUT PDISK_INFORMATION Disk
  1162. )
  1163. /*++
  1164. Routine Description:
  1165. Free the allocated disk information.
  1166. Arguments:
  1167. Disk - Disk information previously allocated
  1168. with FstubAllocateDiskInformation().
  1169. Return Value:
  1170. NTSTATUS code.
  1171. --*/
  1172. {
  1173. //
  1174. // Free up disk scratch buffer and disk object.
  1175. //
  1176. if ( Disk && Disk->ScratchBuffer ) {
  1177. ExFreePool (Disk->ScratchBuffer);
  1178. Disk->ScratchBuffer = NULL;
  1179. }
  1180. if ( Disk ) {
  1181. ExFreePool (Disk);
  1182. Disk = NULL;
  1183. }
  1184. return STATUS_SUCCESS;
  1185. }
  1186. NTSTATUS
  1187. FstubWriteBootSectorEFI(
  1188. IN CONST PDISK_INFORMATION Disk
  1189. )
  1190. /*++
  1191. Routine Description:
  1192. Write the boot sector for an EFI partitioned disk. Note that the EFI
  1193. boot sector uses the structure as the legacy AT-style MBR, but it
  1194. contains only one partition entry and that entry covers the entire disk.
  1195. Arguments:
  1196. Disk - The disk to write the MBR for.
  1197. Return Values:
  1198. NTSTATUS code.
  1199. --*/
  1200. {
  1201. NTSTATUS Status;
  1202. MASTER_BOOT_RECORD* Mbr;
  1203. PAGED_CODE ();
  1204. ASSERT ( Disk );
  1205. ASSERT ( IS_VALID_DISK_INFO ( Disk ) );
  1206. //
  1207. // Construct an EFI Master Boot Record. The EFI Master Boot Record has
  1208. // one partition entry which is setup to consume the entire disk. The
  1209. // MBR we are writing is configured to boot using only the EFI firmware.
  1210. // It will not via the legacy BIOS because we do not write valid
  1211. // instructions to it.
  1212. //
  1213. Mbr = Disk->ScratchBuffer;
  1214. //
  1215. // The rest of this sector is not accessed by EFI. Zero it out so
  1216. // other tools do not get confused. Especially, we need to make sure
  1217. // the NTFT signature is NULL.
  1218. //
  1219. RtlZeroMemory (Mbr, Disk->SectorSize);
  1220. //
  1221. // NB: the cylinder and head values are 0-based, but the sector
  1222. // value is 1-based.
  1223. //
  1224. //
  1225. // ISSUE - 2000/02/01 - math: Is it necessary to properly initialize the
  1226. // Head, Track, Sector and SizeInLba field for legacy BIOS compatability?
  1227. // We are not doing this in the diskpart program, so probably not.
  1228. //
  1229. Mbr->Signature = MBR_SIGNATURE;
  1230. Mbr->Partition[0].BootIndicator = 0;
  1231. Mbr->Partition[0].StartHead = 0;
  1232. Mbr->Partition[0].StartSector = 2;
  1233. Mbr->Partition[0].StartTrack = 0;
  1234. Mbr->Partition[0].OSIndicator = EFI_MBR_PARTITION_TYPE;
  1235. Mbr->Partition[0].EndHead = 0xFF;
  1236. Mbr->Partition[0].EndSector = 0xFF;
  1237. Mbr->Partition[0].EndTrack = 0xFF;
  1238. Mbr->Partition[0].StartingLBA = 1;
  1239. Mbr->Partition[0].SizeInLBA = 0xFFFFFFFF;
  1240. //
  1241. // Zero out the remaining partitions as per the EFI spec.
  1242. //
  1243. RtlZeroMemory (&Mbr->Partition[1], sizeof (Mbr->Partition[1]));
  1244. RtlZeroMemory (&Mbr->Partition[2], sizeof (Mbr->Partition[2]));
  1245. RtlZeroMemory (&Mbr->Partition[3], sizeof (Mbr->Partition[3]));
  1246. //
  1247. // Write the EFI MBR to the zeroth sector of the disk.
  1248. //
  1249. Status = FstubWriteSector (
  1250. Disk->DeviceObject,
  1251. Disk->SectorSize,
  1252. 0,
  1253. Mbr
  1254. );
  1255. return Status;
  1256. }
  1257. PDRIVE_LAYOUT_INFORMATION
  1258. FstubConvertExtendedToLayout(
  1259. IN PDRIVE_LAYOUT_INFORMATION_EX LayoutEx
  1260. )
  1261. /*++
  1262. Routine Description:
  1263. Convert an extended drive layout structure to a (old) drive
  1264. layout structure. Necessarily, the LayoutEx structure must
  1265. represent an MBR layout, not a GPT layout.
  1266. Arguments:
  1267. LayoutEx - The extended drive layout structure to be converted.
  1268. Return Value:
  1269. The converted drive layout structure.
  1270. --*/
  1271. {
  1272. ULONG i;
  1273. ULONG LayoutSize;
  1274. PDRIVE_LAYOUT_INFORMATION Layout;
  1275. PPARTITION_INFORMATION Partition;
  1276. PPARTITION_INFORMATION_EX PartitionEx;
  1277. PAGED_CODE ();
  1278. ASSERT ( LayoutEx );
  1279. //
  1280. // The only valid conversion is from an MBR extended layout structure to
  1281. // the old structure.
  1282. //
  1283. if (LayoutEx->PartitionStyle != PARTITION_STYLE_MBR) {
  1284. ASSERT ( FALSE );
  1285. return NULL;
  1286. }
  1287. LayoutSize = FIELD_OFFSET (DRIVE_LAYOUT_INFORMATION, PartitionEntry[0]) +
  1288. LayoutEx->PartitionCount * sizeof (PARTITION_INFORMATION);
  1289. Layout = ExAllocatePoolWithTag (
  1290. NonPagedPool,
  1291. LayoutSize,
  1292. FSTUB_TAG
  1293. );
  1294. if ( Layout == NULL ) {
  1295. return NULL;
  1296. }
  1297. Layout->Signature = LayoutEx->Mbr.Signature;
  1298. Layout->PartitionCount = LayoutEx->PartitionCount;
  1299. for (i = 0; i < LayoutEx->PartitionCount; i++) {
  1300. Partition = &Layout->PartitionEntry[i];
  1301. PartitionEx = &LayoutEx->PartitionEntry[i];
  1302. Partition->StartingOffset = PartitionEx->StartingOffset;
  1303. Partition->PartitionLength = PartitionEx->PartitionLength;
  1304. Partition->RewritePartition = PartitionEx->RewritePartition;
  1305. Partition->PartitionNumber = PartitionEx->PartitionNumber;
  1306. Partition->PartitionType = PartitionEx->Mbr.PartitionType;
  1307. Partition->BootIndicator = PartitionEx->Mbr.BootIndicator;
  1308. Partition->RecognizedPartition = PartitionEx->Mbr.RecognizedPartition;
  1309. Partition->HiddenSectors = PartitionEx->Mbr.HiddenSectors;
  1310. }
  1311. return Layout;
  1312. }
  1313. NTSTATUS
  1314. FstubWritePartitionTableMBR(
  1315. IN PDISK_INFORMATION Disk,
  1316. IN PDRIVE_LAYOUT_INFORMATION_EX LayoutEx
  1317. )
  1318. /*++
  1319. Routine Description:
  1320. Write the MBR partition table represented by LayoutEx to
  1321. the disk.
  1322. Arguments:
  1323. Disk - The disk where the partition table should be written.
  1324. LayoutEx - The new layout information.
  1325. Return Value:
  1326. NTSTATUS code
  1327. --*/
  1328. {
  1329. NTSTATUS Status;
  1330. PDRIVE_LAYOUT_INFORMATION Layout;
  1331. PAGED_CODE ();
  1332. ASSERT ( IS_VALID_DISK_INFO ( Disk ) );
  1333. ASSERT ( LayoutEx != NULL );
  1334. //
  1335. // Convert extended layout structure to old layout structure.
  1336. //
  1337. Layout = FstubConvertExtendedToLayout ( LayoutEx );
  1338. if ( Layout == NULL ) {
  1339. return STATUS_INSUFFICIENT_RESOURCES;
  1340. }
  1341. Status = IoWritePartitionTable (
  1342. Disk->DeviceObject,
  1343. Disk->SectorSize,
  1344. Disk->Geometry.Geometry.SectorsPerTrack,
  1345. Disk->Geometry.Geometry.TracksPerCylinder,
  1346. Layout
  1347. );
  1348. return Status;
  1349. }
  1350. NTSTATUS
  1351. FstubWriteEntryEFI(
  1352. IN PDISK_INFORMATION Disk,
  1353. IN ULONG PartitionEntrySectorCount,
  1354. IN ULONG EntryNumber,
  1355. IN PEFI_PARTITION_ENTRY PartitionEntry,
  1356. IN ULONG Partition,
  1357. IN BOOLEAN Flush,
  1358. IN OUT ULONG32* PartialCheckSum
  1359. )
  1360. /*++
  1361. Routine Description:
  1362. Write an EFI partition entry to the EFI partition table for this disk.
  1363. The partition table writes are buffered until an entire disk block's worth
  1364. of entries have been written, then written to the disk.
  1365. Arguments:
  1366. Disk - The disk to write the partition entry for.
  1367. PartitionEntrySectorCount - The count of blocks that the partition table
  1368. occupies.
  1369. EntryNumber - The index into the partition table array to write this
  1370. entry.
  1371. PartitionEntry - The partition entry data.
  1372. Partition - Whether this is the main partition table or the backup
  1373. partition table.
  1374. Flush - Boolean to force the flushing of the table now (TRUE) or wait
  1375. until a complete block's worth of data is ready to be written
  1376. (FALSE).
  1377. PartialCheckSum - The updated partial checksum including this entry.
  1378. Return Values:
  1379. NTSTATUS code.
  1380. --*/
  1381. {
  1382. ULONG Offset;
  1383. ULONGLONG Lba;
  1384. ULONGLONG StartOfEntryArray;
  1385. NTSTATUS Status;
  1386. PAGED_CODE ();
  1387. ASSERT ( Disk );
  1388. ASSERT ( IS_VALID_DISK_INFO ( Disk ) );
  1389. //
  1390. // The primary partition table begins after the EFI Master Boot Record
  1391. // (block 0) and the EFI partition table header (block 1). The backup
  1392. // partition table ends at the last block of the disk, hence it begins
  1393. // in (from the end) as many blocks as it ocupies on the disk.
  1394. //
  1395. if ( Partition == PRIMARY_PARTITION_TABLE ) {
  1396. StartOfEntryArray = 2;
  1397. } else {
  1398. StartOfEntryArray = Disk->SectorCount - PartitionEntrySectorCount - 1;
  1399. }
  1400. Lba = ( EntryNumber * PARTITION_ENTRY_SIZE ) / Disk->SectorSize;
  1401. Offset = ( EntryNumber * PARTITION_ENTRY_SIZE ) % Disk->SectorSize;
  1402. RtlCopyMemory (
  1403. ((PUCHAR) Disk->ScratchBuffer) + Offset,
  1404. PartitionEntry,
  1405. PARTITION_ENTRY_SIZE
  1406. );
  1407. Offset += PARTITION_ENTRY_SIZE;
  1408. ASSERT ( Offset <= Disk->SectorSize );
  1409. //
  1410. // Flush the buffer if necessary.
  1411. //
  1412. if ( Offset == Disk->SectorSize || Flush ) {
  1413. Status = FstubWriteSector (
  1414. Disk->DeviceObject,
  1415. Disk->SectorSize,
  1416. StartOfEntryArray + Lba,
  1417. Disk->ScratchBuffer
  1418. );
  1419. if (!NT_SUCCESS (Status)) {
  1420. return Status;
  1421. }
  1422. RtlZeroMemory ( Disk->ScratchBuffer, Disk->SectorSize );
  1423. }
  1424. if ( PartialCheckSum ) {
  1425. *PartialCheckSum = RtlComputeCrc32 (
  1426. *PartialCheckSum,
  1427. PartitionEntry,
  1428. PARTITION_ENTRY_SIZE
  1429. );
  1430. }
  1431. return STATUS_SUCCESS;
  1432. }
  1433. NTSTATUS
  1434. FstubWriteHeaderEFI(
  1435. IN PDISK_INFORMATION Disk,
  1436. IN ULONG PartitionEntrySectorCount,
  1437. IN GUID DiskGUID,
  1438. IN ULONG32 MaxPartitionCount,
  1439. IN ULONG64 FirstUsableLBA,
  1440. IN ULONG64 LastUsableLBA,
  1441. IN ULONG32 CheckSum,
  1442. IN ULONG Partition
  1443. )
  1444. /*++
  1445. Routine Description:
  1446. Write an EFI partition table header to the disk.
  1447. Arguments:
  1448. Disk - The disk the partition table header should be written to.
  1449. PartitionEntrySectorCount - The number of sectors that the partition
  1450. table array occupies. These must be complete sectors.
  1451. DiskGUID - The Unique GUID for this disk.
  1452. MaxPartitionCount - The maximum number of partitions allowed for this
  1453. disk.
  1454. FirstUsableLBA - The beginning sector of partitionable space for this
  1455. disk. This value must be larger than the space consumed by the
  1456. MBR, and partition table. This value is never validated for
  1457. correctness.
  1458. LastUsableLBA - The last sector of partitionable space on this disk. This
  1459. value must be smaller than the last disk sector less space
  1460. necessary for the backup partition table. This value is not
  1461. validated for correctness.
  1462. CheckSum - The CRC32 checksum for the partition entry array.
  1463. Partition - Which partition we are writing, the primary partition or
  1464. the backup partition.
  1465. Return Values:
  1466. NTSTATUS code.
  1467. Notes:
  1468. PartitionEntrySectorCount could be derived from MaxPartitionCount.
  1469. --*/
  1470. {
  1471. NTSTATUS Status;
  1472. PEFI_PARTITION_HEADER TableHeader;
  1473. ULONG32 HeaderCheckSum;
  1474. ASSERT ( Disk != NULL );
  1475. ASSERT ( IS_VALID_DISK_INFO ( Disk ) );
  1476. PAGED_CODE ();
  1477. TableHeader = Disk->ScratchBuffer;
  1478. TableHeader->Signature = EFI_PARTITION_TABLE_SIGNATURE;
  1479. TableHeader->Revision = EFI_PARTITION_TABLE_REVISION;
  1480. TableHeader->HeaderSize = sizeof (EFI_PARTITION_HEADER);
  1481. TableHeader->HeaderCRC32 = 0;
  1482. TableHeader->Reserved = 0;
  1483. //
  1484. // The primary partition table starts at block 1. The backup partition
  1485. // table ends at the end of the disk.
  1486. //
  1487. if ( Partition == PRIMARY_PARTITION_TABLE ) {
  1488. TableHeader->MyLBA = 1;
  1489. TableHeader->AlternateLBA = Disk->SectorCount - 1;
  1490. } else {
  1491. TableHeader->MyLBA = Disk->SectorCount - 1;
  1492. TableHeader->AlternateLBA = 1;
  1493. }
  1494. TableHeader->FirstUsableLBA = FirstUsableLBA;
  1495. TableHeader->LastUsableLBA = LastUsableLBA;
  1496. TableHeader->DiskGUID = DiskGUID;
  1497. TableHeader->NumberOfEntries = MaxPartitionCount;
  1498. TableHeader->SizeOfPartitionEntry = PARTITION_ENTRY_SIZE;
  1499. TableHeader->PartitionEntryCRC32 = CheckSum;
  1500. //
  1501. // For the primary partition table the partition entry array begins the
  1502. // sector directly following the partition table header sector. For the
  1503. // backup partition table, the partition table header sector directly
  1504. // follows the partition entry array. The partition table header for
  1505. // a backup partition is located on the last sector of the disk.
  1506. //
  1507. if ( Partition == PRIMARY_PARTITION_TABLE ) {
  1508. TableHeader->PartitionEntryLBA = TableHeader->MyLBA + 1;
  1509. } else {
  1510. TableHeader->PartitionEntryLBA = TableHeader->MyLBA - PartitionEntrySectorCount;
  1511. }
  1512. TableHeader->HeaderCRC32 = RtlComputeCrc32 (
  1513. 0,
  1514. TableHeader,
  1515. TableHeader->HeaderSize
  1516. );
  1517. KdPrintEx((DPFLTR_FSTUB_ID,
  1518. DPFLTR_WARNING_LEVEL,
  1519. "FSTUB: Dump of %s EFI partition table\n"
  1520. " Signature: %I64x\n"
  1521. " Revision: %x\n"
  1522. " HeaderSize: %x\n"
  1523. " HeaderCRC32: %x\n"
  1524. " MyLBA: %I64x\n"
  1525. " AlternateLBA: %I64x\n",
  1526. (Partition == PRIMARY_PARTITION_TABLE) ? "Primary" : "Backup",
  1527. TableHeader->Signature,
  1528. TableHeader->Revision,
  1529. TableHeader->HeaderSize,
  1530. TableHeader->HeaderCRC32,
  1531. TableHeader->MyLBA,
  1532. TableHeader->AlternateLBA));
  1533. KdPrintEx((DPFLTR_FSTUB_ID,
  1534. DPFLTR_WARNING_LEVEL,
  1535. " FirstUsableLBA: %I64x\n"
  1536. " LastUsableLBA: %I64x\n"
  1537. " NumberOfEntries: %x\n"
  1538. " SizeOfPartitionEntry: %x\n"
  1539. " PartitionEntryCRC32: %x\n\n",
  1540. TableHeader->FirstUsableLBA,
  1541. TableHeader->LastUsableLBA,
  1542. TableHeader->NumberOfEntries,
  1543. TableHeader->SizeOfPartitionEntry,
  1544. TableHeader->PartitionEntryCRC32));
  1545. Status = FstubWriteSector (
  1546. Disk->DeviceObject,
  1547. Disk->SectorSize,
  1548. TableHeader->MyLBA,
  1549. TableHeader
  1550. );
  1551. return Status;
  1552. }
  1553. VOID
  1554. FstubAdjustPartitionCount(
  1555. IN ULONG SectorSize,
  1556. IN OUT PULONG PartitionCount
  1557. )
  1558. /*++
  1559. Routine Description:
  1560. Adjust the PartitionCount to be a valid EFI Maximum Partition Count.
  1561. A valid value for the partition must be larger than MIN_PARTITOIN_COUNT,
  1562. currently 128, and adjusted to take up as much of the remaining disk
  1563. sector as is possible.
  1564. Arguments:
  1565. SectorSize - The disk sector size.
  1566. PartitionCount - The count to be adjusted.
  1567. Return Values:
  1568. None.
  1569. --*/
  1570. {
  1571. ULONG Count;
  1572. ULONG EntrySize;
  1573. PAGED_CODE ();
  1574. ASSERT ( SectorSize != 0 );
  1575. ASSERT ( PartitionCount != NULL );
  1576. EntrySize = PARTITION_ENTRY_SIZE;
  1577. Count = max (*PartitionCount, MIN_PARTITION_COUNT);
  1578. Count = ROUND_TO ( EntrySize * Count, SectorSize ) / EntrySize;
  1579. ASSERT ( *PartitionCount <= Count );
  1580. *PartitionCount = Count;
  1581. #if DBG
  1582. //
  1583. // If we're on a machine with a 512 byte block (nearly every machine),
  1584. // verify that we've calculated a reasonable Count.
  1585. //
  1586. if (SectorSize == 512) {
  1587. ASSERT ( Count % 4 == 0 );
  1588. }
  1589. #endif
  1590. }
  1591. NTSTATUS
  1592. FstubCreateDiskEFI(
  1593. IN PDEVICE_OBJECT DeviceObject,
  1594. IN PCREATE_DISK_GPT DiskInfo
  1595. )
  1596. /*++
  1597. Routine Description:
  1598. Lay down an empty EFI partition table on a virgin disk.
  1599. Arguments:
  1600. DeviceObject - The device object describing the drive.
  1601. Layout - The EFI disk layout information.
  1602. Return Values:
  1603. NTSTATUS code.
  1604. --*/
  1605. {
  1606. NTSTATUS Status;
  1607. PDISK_INFORMATION Disk;
  1608. ULONG64 FirstUsableLBA;
  1609. ULONG64 LastUsableLBA;
  1610. ULONG64 PartitionBlocks;
  1611. ULONG32 MaxPartitionCount;
  1612. PAGED_CODE ();
  1613. ASSERT ( DeviceObject != NULL );
  1614. ASSERT ( DiskInfo != NULL );
  1615. //
  1616. // Initialization
  1617. //
  1618. Disk = NULL;
  1619. Status = FstubAllocateDiskInformation (
  1620. DeviceObject,
  1621. &Disk,
  1622. NULL
  1623. );
  1624. if (!NT_SUCCESS (Status)) {
  1625. return Status;
  1626. }
  1627. ASSERT ( Disk != NULL );
  1628. //
  1629. // Write the EFI MBR to the disk.
  1630. //
  1631. Status = FstubWriteBootSectorEFI ( Disk );
  1632. if ( !NT_SUCCESS (Status) ) {
  1633. FstubFreeDiskInformation ( Disk );
  1634. Disk = NULL;
  1635. return Status;
  1636. }
  1637. MaxPartitionCount = DiskInfo->MaxPartitionCount;
  1638. FstubAdjustPartitionCount (
  1639. Disk->SectorSize,
  1640. &MaxPartitionCount
  1641. );
  1642. //
  1643. // Initialize the start of partitionable space and the length of
  1644. // partitionable space on this drive.
  1645. //
  1646. PartitionBlocks = ( MaxPartitionCount * PARTITION_ENTRY_SIZE ) / Disk->SectorSize;
  1647. FirstUsableLBA = PartitionBlocks + 2;
  1648. LastUsableLBA = Disk->SectorCount - ( PartitionBlocks + 1 );
  1649. KdPrintEx((DPFLTR_FSTUB_ID,
  1650. DPFLTR_TRACE_LEVEL,
  1651. "FSTUB: Disk Information\n"
  1652. " SectorCount: %I64x\n\n",
  1653. Disk->SectorCount));
  1654. //
  1655. // Write the primary partition table.
  1656. //
  1657. Status = FstubWritePartitionTableEFI (
  1658. Disk,
  1659. DiskInfo->DiskId,
  1660. MaxPartitionCount,
  1661. FirstUsableLBA,
  1662. LastUsableLBA,
  1663. PRIMARY_PARTITION_TABLE,
  1664. 0,
  1665. NULL
  1666. );
  1667. if (NT_SUCCESS (Status)) {
  1668. //
  1669. // Write the backup partition table.
  1670. //
  1671. Status = FstubWritePartitionTableEFI (
  1672. Disk,
  1673. DiskInfo->DiskId,
  1674. MaxPartitionCount,
  1675. FirstUsableLBA,
  1676. LastUsableLBA,
  1677. BACKUP_PARTITION_TABLE,
  1678. 0,
  1679. NULL
  1680. );
  1681. }
  1682. FstubFreeDiskInformation ( Disk );
  1683. return Status;
  1684. }
  1685. NTSTATUS
  1686. FstubCreateDiskMBR(
  1687. IN PDEVICE_OBJECT DeviceObject,
  1688. IN PCREATE_DISK_MBR DiskInfo
  1689. )
  1690. /*++
  1691. Routine Description:
  1692. Create an empty MBR partition table on the disk. Note
  1693. that when creating an empty MBR disk, we do not overwrite
  1694. the bootstrapping code at the beginning of the MBR.
  1695. Arguments:
  1696. DeviceObject - The device that should
  1697. Return Value:
  1698. NTSTATUS code
  1699. --*/
  1700. {
  1701. NTSTATUS Status;
  1702. PDISK_INFORMATION Disk;
  1703. PMASTER_BOOT_RECORD Mbr;
  1704. PAGED_CODE ();
  1705. ASSERT ( DeviceObject != NULL );
  1706. //
  1707. // Initialization
  1708. //
  1709. Disk = NULL;
  1710. Status = FstubAllocateDiskInformation (
  1711. DeviceObject,
  1712. &Disk,
  1713. NULL
  1714. );
  1715. if (!NT_SUCCESS (Status)) {
  1716. return Status;
  1717. }
  1718. Status = FstubReadSector (
  1719. Disk->DeviceObject,
  1720. Disk->SectorSize,
  1721. 0,
  1722. Disk->ScratchBuffer
  1723. );
  1724. if ( !NT_SUCCESS ( Status ) ) {
  1725. goto done;
  1726. }
  1727. Mbr = (PMASTER_BOOT_RECORD) Disk->ScratchBuffer;
  1728. //
  1729. // Zero out all partition entries, set the AA55 signature
  1730. // and set the NTFT signature.
  1731. //
  1732. RtlZeroMemory (&Mbr->Partition, sizeof (Mbr->Partition));
  1733. Mbr->Signature = MBR_SIGNATURE;
  1734. Mbr->DiskSignature = DiskInfo->Signature;
  1735. //
  1736. // Then write the sector back to the drive.
  1737. //
  1738. Status = FstubWriteSector (
  1739. Disk->DeviceObject,
  1740. Disk->SectorSize,
  1741. 0,
  1742. Mbr
  1743. );
  1744. done:
  1745. if ( Disk ) {
  1746. FstubFreeDiskInformation ( Disk );
  1747. Disk = NULL;
  1748. }
  1749. return Status;
  1750. }
  1751. NTSTATUS
  1752. FstubCreateDiskRaw(
  1753. IN PDEVICE_OBJECT DeviceObject
  1754. )
  1755. /*++
  1756. Routine Description:
  1757. Erase all partition information from the disk.
  1758. Arguments:
  1759. DeviceObject - Device object representing a disk to remove
  1760. partition table from.
  1761. Return Value:
  1762. NTSTATUS code.
  1763. --*/
  1764. {
  1765. NTSTATUS Status;
  1766. PDISK_INFORMATION Disk;
  1767. PMASTER_BOOT_RECORD Mbr;
  1768. PARTITION_STYLE PartitionStyle;
  1769. PAGED_CODE ();
  1770. ASSERT ( DeviceObject != NULL );
  1771. //
  1772. // Initialization
  1773. //
  1774. Disk = NULL;
  1775. Status = FstubAllocateDiskInformation (
  1776. DeviceObject,
  1777. &Disk,
  1778. NULL
  1779. );
  1780. if (!NT_SUCCESS (Status)) {
  1781. return Status;
  1782. }
  1783. //
  1784. // Figure out whether this is an MBR or GPT disk.
  1785. //
  1786. Status = FstubDetectPartitionStyle (
  1787. Disk,
  1788. &PartitionStyle
  1789. );
  1790. if (!NT_SUCCESS (Status)) {
  1791. goto done;
  1792. }
  1793. Status = FstubReadSector (
  1794. Disk->DeviceObject,
  1795. Disk->SectorSize,
  1796. 0,
  1797. Disk->ScratchBuffer
  1798. );
  1799. if (!NT_SUCCESS (Status)) {
  1800. goto done;
  1801. }
  1802. Mbr = (PMASTER_BOOT_RECORD) Disk->ScratchBuffer;
  1803. //
  1804. // Zero out all partition entries, the AA55 signature
  1805. // and the NTFT disk signature.
  1806. //
  1807. RtlZeroMemory (&Mbr->Partition, sizeof (Mbr->Partition));
  1808. Mbr->Signature = 0;
  1809. Mbr->DiskSignature = 0;
  1810. //
  1811. // Then write the sector back to the drive.
  1812. //
  1813. Status = FstubWriteSector (
  1814. Disk->DeviceObject,
  1815. Disk->SectorSize,
  1816. 0,
  1817. Mbr
  1818. );
  1819. //
  1820. // If this was a GPT disk, we null out the primary and backup partition
  1821. // table header.
  1822. //
  1823. if (PartitionStyle == PARTITION_STYLE_GPT) {
  1824. RtlZeroMemory (Disk->ScratchBuffer, Disk->SectorSize);
  1825. //
  1826. // Erase the primary partition table header.
  1827. //
  1828. Status = FstubWriteSector (
  1829. Disk->DeviceObject,
  1830. Disk->SectorSize,
  1831. 1,
  1832. Disk->ScratchBuffer
  1833. );
  1834. if (!NT_SUCCESS (Status)) {
  1835. goto done;
  1836. }
  1837. //
  1838. // Erase the backup partition table header.
  1839. //
  1840. Status = FstubWriteSector (
  1841. Disk->DeviceObject,
  1842. Disk->SectorSize,
  1843. Disk->SectorCount - 1,
  1844. Disk->ScratchBuffer
  1845. );
  1846. }
  1847. done:
  1848. if (Disk) {
  1849. FstubFreeDiskInformation (Disk);
  1850. Disk = NULL;
  1851. }
  1852. return Status;
  1853. }
  1854. VOID
  1855. FstubCopyEntryEFI(
  1856. OUT PEFI_PARTITION_ENTRY Entry,
  1857. IN PPARTITION_INFORMATION_EX Partition,
  1858. IN ULONG SectorSize
  1859. )
  1860. {
  1861. ULONG64 StartingLBA;
  1862. ULONG64 EndingLBA;
  1863. PAGED_CODE ();
  1864. ASSERT ( Entry != NULL );
  1865. ASSERT ( Partition != NULL );
  1866. ASSERT ( SectorSize != 0 );
  1867. //
  1868. // Translate and copy the Starting and Ending LBA.
  1869. //
  1870. StartingLBA = Partition->StartingOffset.QuadPart / SectorSize;
  1871. EndingLBA = Partition->StartingOffset.QuadPart + Partition->PartitionLength.QuadPart - 1;
  1872. EndingLBA /= (ULONG64) SectorSize;
  1873. Entry->StartingLBA = StartingLBA;
  1874. Entry->EndingLBA = EndingLBA;
  1875. //
  1876. // Copy the Type and Id GUIDs. Copy the attributes.
  1877. //
  1878. Entry->PartitionType = Partition->Gpt.PartitionType;
  1879. Entry->UniquePartition = Partition->Gpt.PartitionId;
  1880. Entry->Attributes = Partition->Gpt.Attributes;
  1881. //
  1882. // Copy the partition name.
  1883. //
  1884. RtlCopyMemory (
  1885. Entry->Name,
  1886. Partition->Gpt.Name,
  1887. sizeof (Entry->Name)
  1888. );
  1889. }
  1890. NTSTATUS
  1891. FstubWritePartitionTableEFI(
  1892. IN PDISK_INFORMATION Disk,
  1893. IN GUID DiskGUID,
  1894. IN ULONG32 MaxPartitionCount,
  1895. IN ULONG64 FirstUsableLBA,
  1896. IN ULONG64 LastUsableLBA,
  1897. IN ULONG PartitionTable,
  1898. IN ULONG PartitionCount,
  1899. IN PPARTITION_INFORMATION_EX PartitionArray
  1900. )
  1901. /*++
  1902. Routine Description:
  1903. Write an EFI partition table to the disk.
  1904. Arguments:
  1905. Disk - The disk we want to write the partition table to.
  1906. MaxPartitionCount -
  1907. FirstUsableLBA -
  1908. LastUsableLBA -
  1909. PartitionTable - Which partition table to write to, either the primary
  1910. partition table or the backup partition table.
  1911. PartitionCount - The count of partitions in the partiton array.
  1912. Partitions entries 0 through PartitionCount - 1 will be
  1913. initialized from the array. Partition entries PartitionCount
  1914. through MaxPartitionCount will be initialized to null.
  1915. PartitionArray - The array of partition entries to be written to disk.
  1916. The value can be NULL only if PartitionCount is 0. In that case
  1917. we will write an empty partition array.
  1918. Return Values:
  1919. NTSTATUS code.
  1920. --*/
  1921. {
  1922. NTSTATUS Status;
  1923. ULONG i;
  1924. ULONG EntrySlot;
  1925. ULONG TableSectorCount;
  1926. ULONG SectorSize;
  1927. ULONG32 CheckSum;
  1928. EFI_PARTITION_ENTRY Entry;
  1929. PAGED_CODE ();
  1930. ASSERT ( Disk != NULL );
  1931. SectorSize = Disk->SectorSize;
  1932. ASSERT ( MaxPartitionCount >= 128 );
  1933. ASSERT ( PartitionCount <= MaxPartitionCount );
  1934. //
  1935. // TableSectorCount is the number of blocks that the partition table
  1936. // occupies.
  1937. //
  1938. TableSectorCount =
  1939. ( PARTITION_ENTRY_SIZE * MaxPartitionCount + SectorSize - 1 ) / SectorSize;
  1940. //
  1941. // Write the partition table entry array before writing the partition
  1942. // table header so we can calculate the checksum along the way.
  1943. //
  1944. CheckSum = 0;
  1945. EntrySlot = 0;
  1946. //
  1947. // First, copy all non-NULL entries.
  1948. //
  1949. for (i = 0; i < PartitionCount ; i++) {
  1950. //
  1951. // Do not write NULL entries to disk. Note that this does not
  1952. // prevent other tools from writing valid, NULL entries to the
  1953. // drive. It just prevents us from doing it.
  1954. //
  1955. if ( IS_NULL_GUID ( PartitionArray [ i ].Gpt.PartitionType) ) {
  1956. continue;
  1957. }
  1958. FstubCopyEntryEFI ( &Entry, &PartitionArray [i], SectorSize );
  1959. Status = FstubWriteEntryEFI (
  1960. Disk,
  1961. TableSectorCount,
  1962. EntrySlot,
  1963. &Entry,
  1964. PartitionTable,
  1965. FALSE,
  1966. &CheckSum
  1967. );
  1968. if ( !NT_SUCCESS (Status) ) {
  1969. return Status;
  1970. }
  1971. EntrySlot++;
  1972. }
  1973. //
  1974. // Next, copy all NULL entries at the end.
  1975. //
  1976. for (i = EntrySlot; i < MaxPartitionCount; i++) {
  1977. RtlZeroMemory (&Entry, sizeof (Entry));
  1978. Status = FstubWriteEntryEFI (
  1979. Disk,
  1980. TableSectorCount,
  1981. i,
  1982. &Entry,
  1983. PartitionTable,
  1984. FALSE,
  1985. &CheckSum
  1986. );
  1987. if ( !NT_SUCCESS (Status) ) {
  1988. return Status;
  1989. }
  1990. }
  1991. //
  1992. // Write the partition table header to disk.
  1993. //
  1994. Status = FstubWriteHeaderEFI (
  1995. Disk,
  1996. TableSectorCount,
  1997. DiskGUID,
  1998. MaxPartitionCount,
  1999. FirstUsableLBA,
  2000. LastUsableLBA,
  2001. CheckSum,
  2002. PartitionTable
  2003. );
  2004. return Status;
  2005. }
  2006. NTSTATUS
  2007. FstubReadHeaderEFI(
  2008. IN PDISK_INFORMATION Disk,
  2009. IN ULONG PartitionTable,
  2010. OUT PEFI_PARTITION_HEADER* HeaderBuffer
  2011. )
  2012. /*++
  2013. Routine Description:
  2014. Read in and validate the EFI partition table header.
  2015. The algorithm for validating the partition table header is as follows:
  2016. 1) Check the Partitin Table Signature, Revision and Size.
  2017. 2) Check the Partition Table CRC.
  2018. 3) Check that the MyLBA entry to the LBA that contains the Partition
  2019. Table.
  2020. 4) Check that the CRC of the partition Entry Array is correct.
  2021. Arguments:
  2022. Disk - The disk to read the EFI partition table header from.
  2023. PartitionTable - Whether to read the primary or backup partition table.
  2024. HeaderBuffer - Pointer to a buffer when the header table pointer will be
  2025. copied on success. Note that, the header table is physically
  2026. stored in the disk's scratch buffer.
  2027. Return Values:
  2028. STATUS_SUCCESS - If the header was successfully read.
  2029. STATUS_DISK_CORRUPT_ERROR - If the specified header is invalid and/or
  2030. corrupt.
  2031. NTSTATUS code - For other errors.
  2032. --*/
  2033. {
  2034. NTSTATUS Status;
  2035. ULONG64 MyLBA;
  2036. ULONG64 AlternateLBA;
  2037. ULONG32 CheckSum;
  2038. ULONG32 Temp;
  2039. ULONG FullSectorCount;
  2040. ULONG MaxPartitionCount;
  2041. PVOID Buffer;
  2042. ULONG i;
  2043. ULONG PartialSectorEntries;
  2044. PEFI_PARTITION_HEADER Header;
  2045. PAGED_CODE ();
  2046. ASSERT ( Disk != NULL );
  2047. ASSERT ( IS_VALID_DISK_INFO ( Disk ) );
  2048. ASSERT ( HeaderBuffer != NULL );
  2049. //
  2050. // Initialization
  2051. //
  2052. Buffer = NULL;
  2053. *HeaderBuffer = NULL;
  2054. if ( PartitionTable == PRIMARY_PARTITION_TABLE) {
  2055. MyLBA = 1;
  2056. AlternateLBA = Disk->SectorCount - 1;
  2057. } else {
  2058. MyLBA = Disk->SectorCount - 1;
  2059. AlternateLBA = 1;
  2060. }
  2061. //
  2062. // Read in the primary partition table header.
  2063. //
  2064. Status = FstubReadSector (
  2065. Disk->DeviceObject,
  2066. Disk->SectorSize,
  2067. MyLBA,
  2068. Disk->ScratchBuffer
  2069. );
  2070. if ( !NT_SUCCESS ( Status ) ) {
  2071. KdPrintEx((DPFLTR_FSTUB_ID,
  2072. DPFLTR_WARNING_LEVEL,
  2073. "FSTUB: Could not read sector %I64x\n",
  2074. MyLBA));
  2075. goto done;
  2076. }
  2077. Header = (PEFI_PARTITION_HEADER) Disk->ScratchBuffer;
  2078. //
  2079. // Check Signature, Revision and size.
  2080. //
  2081. if ( Header->Signature != EFI_PARTITION_TABLE_SIGNATURE ||
  2082. Header->Revision != EFI_PARTITION_TABLE_REVISION ||
  2083. Header->HeaderSize != sizeof (EFI_PARTITION_HEADER) ) {
  2084. Status = STATUS_DISK_CORRUPT_ERROR;
  2085. KdPrintEx((DPFLTR_FSTUB_ID,
  2086. DPFLTR_WARNING_LEVEL,
  2087. "FSTUB: Partition Header Invalid\n"
  2088. " Header Signature / Revision / Size mismatch\n"));
  2089. goto done;
  2090. }
  2091. //
  2092. // Check the partition table CRC. The assumption here is that the
  2093. // CRC is computed with a value of 0 for the HeaderCRC field.
  2094. //
  2095. Temp = Header->HeaderCRC32;
  2096. Header->HeaderCRC32 = 0;
  2097. CheckSum = RtlComputeCrc32 ( 0, Header, Header->HeaderSize );
  2098. Header->HeaderCRC32 = Temp;
  2099. if (CheckSum != Header->HeaderCRC32) {
  2100. Status = STATUS_DISK_CORRUPT_ERROR;
  2101. goto done;
  2102. }
  2103. //
  2104. // Validate the MyLBA.
  2105. //
  2106. //
  2107. // NB: We CANNOT validate AlternateLBA here. If we do, then when a disk
  2108. // is grown or shrunk we will fail.
  2109. //
  2110. if ( Header->MyLBA != MyLBA ) {
  2111. Status = STATUS_DISK_CORRUPT_ERROR;
  2112. KdPrintEx((DPFLTR_FSTUB_ID,
  2113. DPFLTR_WARNING_LEVEL,
  2114. "FSTUB: Partition Header Invalid\n"
  2115. " MyLBA or AlternateLBA is incorrect\n"));
  2116. goto done;
  2117. }
  2118. //
  2119. // Read and CRC the Partition Entry Array.
  2120. //
  2121. //
  2122. // First we read and checksum all full sectors.
  2123. //
  2124. FullSectorCount = Header->NumberOfEntries * PARTITION_ENTRY_SIZE;
  2125. FullSectorCount /= Disk->SectorSize;
  2126. Buffer = ExAllocatePoolWithTag (
  2127. NonPagedPool,
  2128. Disk->SectorSize,
  2129. FSTUB_TAG
  2130. );
  2131. if ( Buffer == NULL ) {
  2132. Status = STATUS_INSUFFICIENT_RESOURCES;
  2133. goto done;
  2134. }
  2135. CheckSum = 0;
  2136. for (i = 0; i < FullSectorCount; i++) {
  2137. Status = FstubReadSector (
  2138. Disk->DeviceObject,
  2139. Disk->SectorSize,
  2140. Header->PartitionEntryLBA + i,
  2141. Buffer
  2142. );
  2143. if (!NT_SUCCESS (Status)) {
  2144. goto done;
  2145. }
  2146. CheckSum = RtlComputeCrc32 (
  2147. CheckSum,
  2148. Buffer,
  2149. Disk->SectorSize
  2150. );
  2151. }
  2152. //
  2153. // Next we read and checksum the final, partial sector. Note that this
  2154. // is not very likely to ever get executed. The way we write the partition
  2155. // table, it will never contain partial sectors as a part of the partition
  2156. // array.
  2157. //
  2158. PartialSectorEntries = Header->NumberOfEntries * PARTITION_ENTRY_SIZE;
  2159. PartialSectorEntries %= FullSectorCount;
  2160. if ( PartialSectorEntries ) {
  2161. //
  2162. // Read the remaining sector which contains some partition entries.
  2163. //
  2164. Status = FstubReadSector (
  2165. Disk->DeviceObject,
  2166. Disk->SectorSize,
  2167. Header->PartitionEntryLBA + FullSectorCount,
  2168. Buffer
  2169. );
  2170. if (!NT_SUCCESS (Status)) {
  2171. goto done;
  2172. }
  2173. for (i = 0; i < PartialSectorEntries; i++) {
  2174. CheckSum = RtlComputeCrc32 (
  2175. CheckSum,
  2176. &(((PEFI_PARTITION_ENTRY)Buffer)[ i ]),
  2177. Disk->SectorSize
  2178. );
  2179. }
  2180. }
  2181. if ( Header->PartitionEntryCRC32 != CheckSum ) {
  2182. Status = STATUS_DISK_CORRUPT_ERROR;
  2183. KdPrintEx((DPFLTR_FSTUB_ID,
  2184. DPFLTR_WARNING_LEVEL,
  2185. "FSTUB: Partition Table Invalid\n"
  2186. " Partition Array CRC invalid\n"));
  2187. goto done;
  2188. }
  2189. *HeaderBuffer = Header;
  2190. Status = STATUS_SUCCESS;
  2191. done:
  2192. if ( Buffer != NULL ) {
  2193. ExFreePool ( Buffer );
  2194. Buffer = NULL;
  2195. }
  2196. if (!NT_SUCCESS (Status)) {
  2197. KdPrintEx((DPFLTR_FSTUB_ID,
  2198. DPFLTR_ERROR_LEVEL,
  2199. "FSTUB: %s EFI Partition table is bad.\n",
  2200. PartitionTable == PRIMARY_PARTITION_TABLE ?
  2201. "Primary" : "Backup"));
  2202. }
  2203. return Status;
  2204. }
  2205. NTSTATUS
  2206. FstubReadPartitionTableEFI(
  2207. IN PDISK_INFORMATION Disk,
  2208. IN ULONG PartitionTable,
  2209. OUT PDRIVE_LAYOUT_INFORMATION_EX* ReturnedDriveLayout
  2210. )
  2211. /*++
  2212. Routine Description:
  2213. This routine is called to read the partition table on an EFI-partitioned
  2214. disk.
  2215. Arguments:
  2216. Disk - The disk we should read the partition table from.
  2217. PartitionTable - Which partition table to read, the primary or backup
  2218. table.
  2219. ReturnedDriveLayout - Pointer to pointer to the buffer where
  2220. the partition information will be stored.
  2221. Return Values:
  2222. STATUS_SUCCESS - If the partition table information was succesfully read
  2223. into ReturnedDriveLayoutInformation.
  2224. Otherwise - Failure.
  2225. Notes:
  2226. The memory allocated by this routine must be free by the caller using
  2227. ExFreePool().
  2228. --*/
  2229. {
  2230. NTSTATUS Status;
  2231. ULONG i;
  2232. ULONG j;
  2233. ULONG PartitionCount;
  2234. ULONG CurrentSector;
  2235. ULONG SectorNumber;
  2236. ULONG SectorIndex;
  2237. PVOID Block;
  2238. ULONG MaxPartitionCount;
  2239. ULONG DriveLayoutSize;
  2240. ULONG PartitionsPerBlock;
  2241. PEFI_PARTITION_ENTRY EntryArray;
  2242. PEFI_PARTITION_ENTRY Entry;
  2243. PEFI_PARTITION_HEADER Header;
  2244. PDRIVE_LAYOUT_INFORMATION_EX DriveLayout;
  2245. PPARTITION_INFORMATION_EX PartitionInfo;
  2246. ULONG64 PartitionEntryLBA;
  2247. PAGED_CODE ();
  2248. ASSERT ( Disk != NULL );
  2249. //
  2250. // Initialization
  2251. //
  2252. DriveLayout = NULL;
  2253. //
  2254. // Read the partition table header.
  2255. //
  2256. Status = FstubReadHeaderEFI ( Disk, PartitionTable, &Header );
  2257. if (!NT_SUCCESS (Status)) {
  2258. goto done;
  2259. }
  2260. //
  2261. // Allocate space the maximum number of EFI partitions on this drive.
  2262. //
  2263. MaxPartitionCount = Header->NumberOfEntries;
  2264. DriveLayoutSize = FIELD_OFFSET (DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[0]) +
  2265. MaxPartitionCount * sizeof (PARTITION_INFORMATION_EX);
  2266. DriveLayout = ExAllocatePoolWithTag ( NonPagedPool,
  2267. DriveLayoutSize,
  2268. FSTUB_TAG
  2269. );
  2270. if ( DriveLayout == NULL ) {
  2271. Status = STATUS_INSUFFICIENT_RESOURCES;
  2272. goto done;
  2273. }
  2274. //
  2275. // Copy the EFI disk layout information.
  2276. //
  2277. DriveLayout->PartitionStyle = PARTITION_STYLE_GPT;
  2278. DriveLayout->Gpt.StartingUsableOffset.QuadPart =
  2279. Header->FirstUsableLBA * Disk->SectorSize;
  2280. DriveLayout->Gpt.UsableLength.QuadPart =
  2281. (Header->LastUsableLBA - Header->FirstUsableLBA) * Disk->SectorSize;
  2282. DriveLayout->Gpt.MaxPartitionCount = MaxPartitionCount;
  2283. RtlCopyMemory (
  2284. &DriveLayout->Gpt.DiskId,
  2285. &Header->DiskGUID,
  2286. sizeof (GUID)
  2287. );
  2288. //
  2289. // Read in each block that contains entries in the partition table
  2290. // array, then iterate through the partition table array and map
  2291. // each EFI_PARTITION_ENTRY structure into an PARTITION_INFORMATION_GPT
  2292. // structure.
  2293. //
  2294. PartitionEntryLBA = Header->PartitionEntryLBA;
  2295. Header = NULL;
  2296. EntryArray = (PEFI_PARTITION_ENTRY) Disk->ScratchBuffer;
  2297. PartitionCount = 0;
  2298. CurrentSector = -1;
  2299. PartitionsPerBlock = (ULONG) (Disk->SectorSize / PARTITION_ENTRY_SIZE);
  2300. for (i = 0; i < MaxPartitionCount; i++) {
  2301. SectorNumber = i / PartitionsPerBlock ;
  2302. SectorIndex = i % PartitionsPerBlock ;
  2303. //
  2304. // If we have a sector other than the current sector read in,
  2305. // read in the current sector at this time.
  2306. //
  2307. if ( SectorNumber != CurrentSector ) {
  2308. Status = FstubReadSector (
  2309. Disk->DeviceObject,
  2310. Disk->SectorSize,
  2311. PartitionEntryLBA + SectorNumber,
  2312. EntryArray
  2313. );
  2314. if ( !NT_SUCCESS (Status) ) {
  2315. goto done;
  2316. }
  2317. CurrentSector = SectorNumber;
  2318. }
  2319. Entry = &EntryArray[ SectorIndex ];
  2320. //
  2321. // We ignore NULL entries in the partition table. NOTE: Is this
  2322. // dangerous?
  2323. //
  2324. if ( IS_NULL_GUID (Entry->PartitionType ) ) {
  2325. continue;
  2326. }
  2327. //
  2328. // Copy the data into the EFI partition array.
  2329. //
  2330. PartitionInfo = &DriveLayout->PartitionEntry[PartitionCount];
  2331. PartitionInfo->StartingOffset.QuadPart = Entry->StartingLBA;
  2332. PartitionInfo->StartingOffset.QuadPart *= (ULONG64) Disk->SectorSize;
  2333. PartitionInfo->PartitionLength.QuadPart =
  2334. (Entry->EndingLBA - Entry->StartingLBA) + 1;
  2335. PartitionInfo->PartitionLength.QuadPart *= (ULONG64) Disk->SectorSize;
  2336. PartitionInfo->PartitionStyle = PARTITION_STYLE_GPT;
  2337. PartitionInfo->Gpt.PartitionType = Entry->PartitionType;
  2338. PartitionInfo->Gpt.PartitionId = Entry->UniquePartition;
  2339. PartitionInfo->Gpt.Attributes = Entry->Attributes;
  2340. RtlCopyMemory (PartitionInfo->Gpt.Name,
  2341. Entry->Name,
  2342. sizeof (PartitionInfo->Gpt.Name)
  2343. );
  2344. PartitionInfo->RewritePartition = FALSE;
  2345. //
  2346. // The PartitionNumber field of PARTITION_INFORMATION_EX is
  2347. // not initialized by us. Instead, it is initialized in the
  2348. // calling driver
  2349. //
  2350. PartitionInfo->PartitionNumber = -1;
  2351. PartitionCount++;
  2352. }
  2353. //
  2354. // Fill in the remaining fields of the DRIVE_LAYOUT structure.
  2355. //
  2356. DriveLayout->PartitionCount = PartitionCount;
  2357. done:
  2358. //
  2359. // Free all resources
  2360. //
  2361. if (!NT_SUCCESS (Status)) {
  2362. //
  2363. // DriveLayout is not being returned, so deallocate it if it has
  2364. // be allocated.
  2365. //
  2366. if ( DriveLayout ) {
  2367. ExFreePool (DriveLayout);
  2368. DriveLayout = NULL;
  2369. }
  2370. *ReturnedDriveLayout = NULL;
  2371. } else {
  2372. *ReturnedDriveLayout = DriveLayout;
  2373. DriveLayout = NULL;
  2374. }
  2375. return Status;
  2376. }
  2377. NTSTATUS
  2378. FstubVerifyPartitionTableEFI(
  2379. IN PDISK_INFORMATION Disk,
  2380. IN BOOLEAN FixErrors
  2381. )
  2382. /*++
  2383. Routine Description:
  2384. Verify that a partition table is correct.
  2385. Arguments:
  2386. Disk - The disk whose partition table(s) should be verified.
  2387. FixErrors - If, TRUE, this routine attempts to fix any errors in the
  2388. partition table. Otherwise, this routine only checkes whether
  2389. there are errrors in the partition table, "read only".
  2390. Return Value:
  2391. STATUS_SUCCESS - If the final partition table, after any changes (only
  2392. when FixErrors is TRUE), is valid.
  2393. STATUS_DISK_CORRUPT - If the final partition table, after any changes (only
  2394. when FixErrors is TRUE) is not valid.
  2395. Other NTSTATUS code - Other type of failure.
  2396. --*/
  2397. {
  2398. NTSTATUS Status;
  2399. ULONG64 i;
  2400. ULONG64 SourceStartingLBA;
  2401. ULONG64 DestStartingLBA;
  2402. ULONG SectorCount;
  2403. BOOLEAN PrimaryValid;
  2404. BOOLEAN BackupValid;
  2405. ULONG GoodTable;
  2406. ULONG BadTable;
  2407. PEFI_PARTITION_HEADER Header;
  2408. PEFI_PARTITION_HEADER GoodHeader;
  2409. PAGED_CODE ();
  2410. //
  2411. // Initialization
  2412. //
  2413. Header = NULL;
  2414. GoodHeader = NULL;
  2415. PrimaryValid = FALSE;
  2416. BackupValid = FALSE;
  2417. GoodHeader = ExAllocatePoolWithTag (
  2418. NonPagedPool,
  2419. sizeof (EFI_PARTITION_HEADER),
  2420. FSTUB_TAG
  2421. );
  2422. if ( GoodHeader == NULL ) {
  2423. return STATUS_INSUFFICIENT_RESOURCES;
  2424. }
  2425. Status = FstubReadHeaderEFI (
  2426. Disk,
  2427. PRIMARY_PARTITION_TABLE,
  2428. &Header
  2429. );
  2430. if ( NT_SUCCESS (Status) ) {
  2431. PrimaryValid = TRUE;
  2432. ASSERT (Header != NULL);
  2433. RtlCopyMemory (GoodHeader,
  2434. Header,
  2435. sizeof (EFI_PARTITION_HEADER)
  2436. );
  2437. }
  2438. Status = FstubReadHeaderEFI (
  2439. Disk,
  2440. BACKUP_PARTITION_TABLE,
  2441. &Header
  2442. );
  2443. if ( NT_SUCCESS (Status) ) {
  2444. BackupValid = TRUE;
  2445. ASSERT (Header != NULL);
  2446. RtlCopyMemory (GoodHeader,
  2447. Header,
  2448. sizeof (EFI_PARTITION_HEADER)
  2449. );
  2450. }
  2451. //
  2452. // If both primary and backup partition tables are valid, return success.
  2453. //
  2454. if ( PrimaryValid && BackupValid ) {
  2455. Status = STATUS_SUCCESS;
  2456. goto done;
  2457. }
  2458. //
  2459. // If both primary and backup partition tables are bad, return failure.
  2460. if ( !PrimaryValid && !BackupValid ) {
  2461. Status = STATUS_DISK_CORRUPT_ERROR;
  2462. goto done;
  2463. }
  2464. //
  2465. // If one of the partition tables is bad, and we were not instructed to
  2466. // fix it, return failure.
  2467. //
  2468. if ( !FixErrors ) {
  2469. Status = STATUS_DISK_CORRUPT_ERROR;
  2470. goto done;
  2471. }
  2472. //
  2473. // If we've reached this point, one or the other of the tables is
  2474. // bad and we've been instructed to fix it.
  2475. //
  2476. ASSERT ( GoodHeader != NULL );
  2477. //
  2478. // SectorCount is the number of sectors occupied by the partition table.
  2479. //
  2480. SectorCount = ( PARTITION_ENTRY_SIZE * Header->NumberOfEntries + Disk->SectorSize - 1 ) / Disk->SectorSize;
  2481. if ( PrimaryValid ) {
  2482. GoodTable = PRIMARY_PARTITION_TABLE;
  2483. BadTable = BACKUP_PARTITION_TABLE;
  2484. SourceStartingLBA = 2;
  2485. DestStartingLBA = Disk->SectorCount - SectorCount - 1;
  2486. KdPrintEx((DPFLTR_FSTUB_ID,
  2487. DPFLTR_ERROR_LEVEL,
  2488. "FSTUB: Restoring backup partition table from primary\n"));
  2489. } else {
  2490. ASSERT ( BackupValid );
  2491. GoodTable = BACKUP_PARTITION_TABLE;
  2492. BadTable = PRIMARY_PARTITION_TABLE;
  2493. SourceStartingLBA = Disk->SectorCount - SectorCount - 1;
  2494. DestStartingLBA = 2;
  2495. KdPrintEx((DPFLTR_FSTUB_ID,
  2496. DPFLTR_ERROR_LEVEL,
  2497. "FSTUB: Restoring primary partition table from backup\n"));
  2498. }
  2499. //
  2500. // First copy the good partition table array over the bad partition table
  2501. // array. This does not need to be checksummed since the checksum in
  2502. // the good header will still be valid for this one.
  2503. //
  2504. for (i = 0; i < SectorCount; i++) {
  2505. Status = FstubReadSector (
  2506. Disk->DeviceObject,
  2507. Disk->SectorSize,
  2508. SourceStartingLBA + i,
  2509. Disk->ScratchBuffer
  2510. );
  2511. if ( !NT_SUCCESS (Status) ) {
  2512. goto done;
  2513. }
  2514. Status = FstubWriteSector (
  2515. Disk->DeviceObject,
  2516. Disk->SectorSize,
  2517. DestStartingLBA + i,
  2518. Disk->ScratchBuffer
  2519. );
  2520. if ( !NT_SUCCESS (Status) ) {
  2521. goto done;
  2522. }
  2523. }
  2524. //
  2525. // Next, write out the header.
  2526. //
  2527. Status = FstubWriteHeaderEFI (
  2528. Disk,
  2529. SectorCount,
  2530. GoodHeader->DiskGUID,
  2531. GoodHeader->NumberOfEntries,
  2532. GoodHeader->FirstUsableLBA,
  2533. GoodHeader->LastUsableLBA,
  2534. GoodHeader->PartitionEntryCRC32,
  2535. BadTable
  2536. );
  2537. done:
  2538. if ( GoodHeader ) {
  2539. ExFreePool ( GoodHeader );
  2540. GoodHeader = NULL;
  2541. }
  2542. return Status;
  2543. }
  2544. NTSTATUS
  2545. FstubUpdateDiskGeometryEFI(
  2546. IN PDISK_INFORMATION OldDisk,
  2547. IN PDISK_INFORMATION NewDisk
  2548. )
  2549. /*++
  2550. Routine Description:
  2551. When a disk is grown or shrunk this API needs to be called to properly
  2552. update the EFI partition tables. In particular, the backup partition table
  2553. needs to be moved to be at the end of the disk.
  2554. Algorithm:
  2555. We read in the old partition table, updat the size of the disk, then
  2556. write out the new partition table given the changed disk size.
  2557. Arguments:
  2558. OldDisk - A disk information object representing the old geometry.
  2559. NewDisk - A disk information object representing the new goemetry.
  2560. Return Values:
  2561. NTSTATUS Code.
  2562. --*/
  2563. {
  2564. NTSTATUS Status;
  2565. ULONG64 i;
  2566. ULONG64 SourceStartingLBA;
  2567. ULONG64 DestStartingLBA;
  2568. ULONG SectorCount;
  2569. PEFI_PARTITION_HEADER Header;
  2570. PAGED_CODE ();
  2571. //
  2572. // Initialization
  2573. //
  2574. Header = NULL;
  2575. Status = FstubReadHeaderEFI (
  2576. OldDisk,
  2577. BACKUP_PARTITION_TABLE,
  2578. &Header
  2579. );
  2580. if ( !NT_SUCCESS (Status) ) {
  2581. return Status;
  2582. }
  2583. //
  2584. // SectorCount is the number of sectors occupied by the partition table.
  2585. //
  2586. SectorCount = ( PARTITION_ENTRY_SIZE * Header->NumberOfEntries + OldDisk->SectorSize - 1 ) / OldDisk->SectorSize;
  2587. //
  2588. // Write the partition table header for the primary partition table. Note
  2589. // that the primary partition table does not need to be moved since it
  2590. // is at the beginning of the disk.
  2591. //
  2592. Status = FstubWriteHeaderEFI (
  2593. NewDisk,
  2594. SectorCount,
  2595. Header->DiskGUID,
  2596. Header->NumberOfEntries,
  2597. Header->FirstUsableLBA,
  2598. Header->LastUsableLBA,
  2599. Header->PartitionEntryCRC32,
  2600. PRIMARY_PARTITION_TABLE
  2601. );
  2602. //
  2603. // Write the partition table header for the backup table.
  2604. //
  2605. Status = FstubWriteHeaderEFI (
  2606. NewDisk,
  2607. SectorCount,
  2608. Header->DiskGUID,
  2609. Header->NumberOfEntries,
  2610. Header->FirstUsableLBA,
  2611. Header->LastUsableLBA,
  2612. Header->PartitionEntryCRC32,
  2613. BACKUP_PARTITION_TABLE
  2614. );
  2615. if ( !NT_SUCCESS (Status) ) {
  2616. return Status;
  2617. }
  2618. //
  2619. // Calculate the location of the backup table.
  2620. //
  2621. SourceStartingLBA = OldDisk->SectorCount - SectorCount - 1;
  2622. DestStartingLBA = NewDisk->SectorCount - SectorCount - 1;
  2623. //
  2624. // And write the backup table.
  2625. //
  2626. for (i = 0; i < SectorCount; i++) {
  2627. Status = FstubReadSector (
  2628. OldDisk->DeviceObject,
  2629. OldDisk->SectorSize,
  2630. SourceStartingLBA + i,
  2631. OldDisk->ScratchBuffer
  2632. );
  2633. if ( !NT_SUCCESS (Status) ) {
  2634. return Status;
  2635. }
  2636. Status = FstubWriteSector (
  2637. NewDisk->DeviceObject,
  2638. NewDisk->SectorSize,
  2639. DestStartingLBA + i,
  2640. OldDisk->ScratchBuffer
  2641. );
  2642. if ( !NT_SUCCESS (Status) ) {
  2643. return Status;
  2644. }
  2645. }
  2646. #if DBG
  2647. //
  2648. // Make a sanity check that we actually did this correctly.
  2649. //
  2650. Status = FstubVerifyPartitionTableEFI ( NewDisk, FALSE );
  2651. ASSERT ( NT_SUCCESS ( Status ) );
  2652. #endif
  2653. return Status;
  2654. }
  2655. NTSTATUS
  2656. FstubWriteSector(
  2657. IN PDEVICE_OBJECT DeviceObject,
  2658. IN ULONG SectorSize,
  2659. IN ULONG64 SectorNumber,
  2660. IN PVOID Buffer
  2661. )
  2662. /*++
  2663. Routine Description:
  2664. Read a sector from the device DeviceObject.
  2665. Arguments:
  2666. DeviceObject - The object representing the device.
  2667. SectorSize - The size of one sector on the device.
  2668. SectorNumber - The sector number to write.
  2669. Buffer - The buffer to write. The buffer must be of size SectorSize.
  2670. Return Values:
  2671. NTSTATUS code.
  2672. --*/
  2673. {
  2674. NTSTATUS Status;
  2675. PIRP Irp;
  2676. IO_STATUS_BLOCK IoStatus;
  2677. PIO_STACK_LOCATION IrpStack;
  2678. KEVENT Event;
  2679. LARGE_INTEGER Offset;
  2680. PAGED_CODE ();
  2681. ASSERT ( DeviceObject );
  2682. ASSERT ( Buffer );
  2683. ASSERT ( SectorSize != 0 );
  2684. Offset.QuadPart = (SectorNumber * SectorSize);
  2685. KeInitializeEvent (&Event, NotificationEvent, FALSE);
  2686. Irp = IoBuildSynchronousFsdRequest ( IRP_MJ_WRITE,
  2687. DeviceObject,
  2688. Buffer,
  2689. SectorSize,
  2690. &Offset,
  2691. &Event,
  2692. &IoStatus
  2693. );
  2694. if ( Irp == NULL ) {
  2695. return STATUS_INSUFFICIENT_RESOURCES;
  2696. }
  2697. IrpStack = IoGetNextIrpStackLocation (Irp);
  2698. IrpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
  2699. Status = IoCallDriver( DeviceObject, Irp );
  2700. if (Status == STATUS_PENDING) {
  2701. Status = KeWaitForSingleObject (
  2702. &Event,
  2703. Executive,
  2704. KernelMode,
  2705. FALSE,
  2706. NULL
  2707. );
  2708. Status = IoStatus.Status;
  2709. }
  2710. return Status;
  2711. }
  2712. NTSTATUS
  2713. FstubReadSector(
  2714. IN PDEVICE_OBJECT DeviceObject,
  2715. IN ULONG SectorSize,
  2716. IN ULONG64 SectorNumber,
  2717. OUT PVOID Buffer
  2718. )
  2719. /*++
  2720. Routine Description:
  2721. Read a logical block from the device (disk).
  2722. Arguments:
  2723. DeviceObject - The device that we are going to read from.
  2724. SectorSize - The size of the block and the size of the Buffer.
  2725. SectorNumber - The Logical Block Number we are going to read.
  2726. Buffer - The buffer into which we are going to read the block.
  2727. Return Values:
  2728. NTSTATUS
  2729. --*/
  2730. {
  2731. NTSTATUS Status;
  2732. PIRP Irp;
  2733. IO_STATUS_BLOCK IoStatus;
  2734. PIO_STACK_LOCATION IrpStack;
  2735. KEVENT Event;
  2736. LARGE_INTEGER Offset;
  2737. PAGED_CODE ();
  2738. ASSERT ( DeviceObject );
  2739. ASSERT ( Buffer );
  2740. ASSERT ( SectorSize != 0 );
  2741. Offset.QuadPart = (SectorNumber * SectorSize);
  2742. KeInitializeEvent (&Event, NotificationEvent, FALSE);
  2743. Irp = IoBuildSynchronousFsdRequest ( IRP_MJ_READ,
  2744. DeviceObject,
  2745. Buffer,
  2746. SectorSize,
  2747. &Offset,
  2748. &Event,
  2749. &IoStatus
  2750. );
  2751. if ( Irp == NULL ) {
  2752. return STATUS_INSUFFICIENT_RESOURCES;
  2753. }
  2754. IrpStack = IoGetNextIrpStackLocation (Irp);
  2755. IrpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
  2756. Status = IoCallDriver( DeviceObject, Irp );
  2757. if (Status == STATUS_PENDING) {
  2758. KeWaitForSingleObject ( &Event,
  2759. Executive,
  2760. KernelMode,
  2761. FALSE,
  2762. NULL
  2763. );
  2764. Status = IoStatus.Status;
  2765. }
  2766. return Status;
  2767. }
  2768. //
  2769. // Debugging functions.
  2770. //
  2771. #if DBG
  2772. PCHAR
  2773. FstubDbgGuidToString(
  2774. IN GUID* Guid,
  2775. PCHAR StringBuffer
  2776. )
  2777. {
  2778. sprintf (StringBuffer,
  2779. "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
  2780. Guid->Data1,
  2781. Guid->Data2,
  2782. Guid->Data3,
  2783. Guid->Data4[0],
  2784. Guid->Data4[1],
  2785. Guid->Data4[2],
  2786. Guid->Data4[3],
  2787. Guid->Data4[4],
  2788. Guid->Data4[5],
  2789. Guid->Data4[6],
  2790. Guid->Data4[7]
  2791. );
  2792. return StringBuffer;
  2793. }
  2794. VOID
  2795. FstubDbgPrintSetPartitionEx(
  2796. IN PSET_PARTITION_INFORMATION_EX SetPartition,
  2797. IN ULONG PartitionNumber
  2798. )
  2799. /*++
  2800. Routine Description:
  2801. Print contents of the SET_PARTITION_INFORMATION structure to the
  2802. debugger.
  2803. Arguments:
  2804. SetPartition - A valid SET_PARTITION_INFORMATION_EX structure.
  2805. Return Value:
  2806. None.
  2807. Mode:
  2808. Checked build only.
  2809. --*/
  2810. {
  2811. CHAR GuidStringBuffer [40];
  2812. PAGED_CODE ();
  2813. KdPrintEx((DPFLTR_FSTUB_ID,
  2814. FSTUB_VERBOSE_LEVEL,
  2815. "\n"
  2816. "FSTUB:\n"
  2817. "SET_PARTITION_INFORMATION_EX %p\n"));
  2818. if ( SetPartition->PartitionStyle != PARTITION_STYLE_MBR &&
  2819. SetPartition->PartitionStyle != PARTITION_STYLE_GPT ) {
  2820. KdPrintEx((DPFLTR_FSTUB_ID,
  2821. FSTUB_VERBOSE_LEVEL,
  2822. "ERROR: PartitionStyle is invalid %d\n",
  2823. SetPartition->PartitionStyle));
  2824. }
  2825. if ( SetPartition->PartitionStyle == PARTITION_STYLE_MBR ) {
  2826. KdPrintEx((DPFLTR_FSTUB_ID,
  2827. FSTUB_VERBOSE_LEVEL,
  2828. "Type: %8.8x\n\n",
  2829. SetPartition->Mbr.PartitionType));
  2830. } else {
  2831. KdPrintEx((DPFLTR_FSTUB_ID,
  2832. FSTUB_VERBOSE_LEVEL,
  2833. "[%d] %ws\n",
  2834. PartitionNumber,
  2835. SetPartition->Gpt.Name));
  2836. KdPrintEx((DPFLTR_FSTUB_ID,
  2837. FSTUB_VERBOSE_LEVEL,
  2838. " ATTR %-16I64x\n",
  2839. SetPartition->Gpt.Attributes));
  2840. KdPrintEx((DPFLTR_FSTUB_ID,
  2841. FSTUB_VERBOSE_LEVEL,
  2842. " TYPE %s\n",
  2843. FstubDbgGuidToString(&SetPartition->Gpt.PartitionType,
  2844. GuidStringBuffer)));
  2845. KdPrintEx((DPFLTR_FSTUB_ID,
  2846. FSTUB_VERBOSE_LEVEL,
  2847. " ID %s\n",
  2848. FstubDbgGuidToString(&SetPartition->Gpt.PartitionId,
  2849. GuidStringBuffer)));
  2850. }
  2851. KdPrintEx((DPFLTR_FSTUB_ID, FSTUB_VERBOSE_LEVEL, "\n"));
  2852. }
  2853. VOID
  2854. FstubDbgPrintPartition(
  2855. IN PPARTITION_INFORMATION Partition,
  2856. IN ULONG PartitionCount
  2857. )
  2858. /*++
  2859. Routine Description:
  2860. Print a PARTITION_INFORMATION structure to the debugger.
  2861. Arguments:
  2862. Partition - Pointer to a valid PARTITION_INFORMATION structure.
  2863. PartitionCount - The number of partitions in the partition table or
  2864. zero if unknown.
  2865. Return Value:
  2866. None.
  2867. --*/
  2868. {
  2869. ULONG PartitionNumber;
  2870. PAGED_CODE ();
  2871. //
  2872. // Sanity check the data.
  2873. //
  2874. if ( (Partition->BootIndicator != TRUE &&
  2875. Partition->BootIndicator != FALSE) ||
  2876. (Partition->RecognizedPartition != TRUE &&
  2877. Partition->RecognizedPartition != FALSE) ||
  2878. (Partition->RewritePartition != TRUE &&
  2879. Partition->RewritePartition != FALSE) ) {
  2880. KdPrintEx((DPFLTR_FSTUB_ID,
  2881. FSTUB_VERBOSE_LEVEL,
  2882. "Invalid partition information at %p\n",
  2883. Partition));
  2884. }
  2885. if (Partition->PartitionNumber > PartitionCount) {
  2886. PartitionNumber = -1;
  2887. } else {
  2888. PartitionNumber = Partition->PartitionNumber;
  2889. }
  2890. KdPrintEx((DPFLTR_FSTUB_ID,
  2891. FSTUB_VERBOSE_LEVEL,
  2892. "[%-2d] %-16I64x %-16I64x %2.2x %c %c %c\n",
  2893. PartitionNumber,
  2894. Partition->StartingOffset.QuadPart,
  2895. Partition->PartitionLength.QuadPart,
  2896. Partition->PartitionType,
  2897. Partition->BootIndicator ? 'x' : ' ',
  2898. Partition->RecognizedPartition ? 'x' : ' ',
  2899. Partition->RewritePartition ? 'x' : ' '));
  2900. }
  2901. VOID
  2902. FstubDbgPrintDriveLayout(
  2903. IN PDRIVE_LAYOUT_INFORMATION Layout
  2904. )
  2905. /*++
  2906. Routine Description:
  2907. Print out a DRIVE_LAYOUT_INFORMATION structure to the debugger.
  2908. Arguments:
  2909. Layout - Pointer to a valid DRIVE_LAYOUT_INFORMATION structure.
  2910. Return Value:
  2911. None.
  2912. Mode:
  2913. Checked build only.
  2914. --*/
  2915. {
  2916. ULONG i;
  2917. PAGED_CODE ();
  2918. KdPrintEx((DPFLTR_FSTUB_ID,
  2919. FSTUB_VERBOSE_LEVEL,
  2920. "\n"
  2921. "FSTUB:\n"
  2922. "DRIVE_LAYOUT %p\n",
  2923. Layout));
  2924. //
  2925. // Warn if the partition count is not a factor of 4. This is probably a
  2926. // bad partition information structure, but we'll continue on anyway.
  2927. //
  2928. if (Layout->PartitionCount % 4 != 0) {
  2929. KdPrintEx((DPFLTR_FSTUB_ID,
  2930. FSTUB_VERBOSE_LEVEL,
  2931. "WARNING: Partition count should be a factor of 4.\n"));
  2932. }
  2933. KdPrintEx((DPFLTR_FSTUB_ID,
  2934. FSTUB_VERBOSE_LEVEL,
  2935. "PartitionCount: %d\n",
  2936. Layout->PartitionCount));
  2937. KdPrintEx((DPFLTR_FSTUB_ID,
  2938. FSTUB_VERBOSE_LEVEL,
  2939. "Signature: %8.8x\n\n",
  2940. Layout->Signature));
  2941. KdPrintEx((DPFLTR_FSTUB_ID,
  2942. FSTUB_VERBOSE_LEVEL,
  2943. " ORD Offset Length Type BI RP RW\n"));
  2944. KdPrintEx((DPFLTR_FSTUB_ID,
  2945. FSTUB_VERBOSE_LEVEL,
  2946. " ------------------------------------------------------------\n"));
  2947. for (i = 0; i < Layout->PartitionCount; i++) {
  2948. FstubDbgPrintPartition (
  2949. &Layout->PartitionEntry[i],
  2950. Layout->PartitionCount
  2951. );
  2952. }
  2953. KdPrintEx((DPFLTR_FSTUB_ID, FSTUB_VERBOSE_LEVEL, "\n"));
  2954. }
  2955. VOID
  2956. FstubDbgPrintPartitionEx(
  2957. IN PPARTITION_INFORMATION_EX PartitionEx,
  2958. IN ULONG PartitionCount
  2959. )
  2960. /*++
  2961. Routine Description:
  2962. Dump a PARTITION_INFORMATION_EX structure.
  2963. Arguments:
  2964. PartitionEx - Pointer to a partition to dump.
  2965. PartitionCount - The number of partitions. This is used to determine
  2966. whether a particular partition ordinal is valid or not.
  2967. Return Value:
  2968. None.
  2969. --*/
  2970. {
  2971. ULONG Style;
  2972. ULONG PartitionNumber;
  2973. CHAR GuidStringBuffer [40];
  2974. PAGED_CODE ();
  2975. Style = PartitionEx->PartitionStyle;
  2976. if (Style != PARTITION_STYLE_MBR &&
  2977. Style != PARTITION_STYLE_GPT) {
  2978. KdPrintEx((DPFLTR_FSTUB_ID,
  2979. DPFLTR_ERROR_LEVEL,
  2980. "ERROR: PartitionStyle is invalid %d for partition %p\n",
  2981. PartitionEx));
  2982. return;
  2983. }
  2984. //
  2985. // We use -1 to denote an invalid partition ordinal.
  2986. //
  2987. if (PartitionEx->PartitionNumber < PartitionCount) {
  2988. PartitionNumber = PartitionEx->PartitionNumber;
  2989. } else {
  2990. PartitionNumber = -1;
  2991. }
  2992. if (Style == PARTITION_STYLE_MBR) {
  2993. KdPrintEx((DPFLTR_FSTUB_ID,
  2994. FSTUB_VERBOSE_LEVEL,
  2995. " [%-2d] %-16I64x %-16I64x %2.2x %c %c %c\n",
  2996. PartitionNumber,
  2997. PartitionEx->StartingOffset.QuadPart,
  2998. PartitionEx->PartitionLength.QuadPart,
  2999. PartitionEx->Mbr.PartitionType,
  3000. PartitionEx->Mbr.BootIndicator ? 'x' : ' ',
  3001. PartitionEx->Mbr.RecognizedPartition ? 'x' : ' ',
  3002. PartitionEx->RewritePartition ? 'x' : ' '));
  3003. } else {
  3004. KdPrintEx((DPFLTR_FSTUB_ID,
  3005. FSTUB_VERBOSE_LEVEL,
  3006. "[%-2d] %ws\n",
  3007. PartitionNumber,
  3008. PartitionEx->Gpt.Name));
  3009. KdPrintEx((DPFLTR_FSTUB_ID,
  3010. FSTUB_VERBOSE_LEVEL,
  3011. " OFF %-16I64x LEN %-16I64x ATTR %-16I64x %s\n",
  3012. PartitionEx->StartingOffset.QuadPart,
  3013. PartitionEx->PartitionLength.QuadPart,
  3014. PartitionEx->Gpt.Attributes,
  3015. PartitionEx->RewritePartition ? "R/W" : ""));
  3016. KdPrintEx((DPFLTR_FSTUB_ID,
  3017. FSTUB_VERBOSE_LEVEL,
  3018. " TYPE %s\n",
  3019. FstubDbgGuidToString(&PartitionEx->Gpt.PartitionType,
  3020. GuidStringBuffer)));
  3021. KdPrintEx((DPFLTR_FSTUB_ID,
  3022. FSTUB_VERBOSE_LEVEL,
  3023. " ID %s\n",
  3024. FstubDbgGuidToString(&PartitionEx->Gpt.PartitionId,
  3025. GuidStringBuffer)));
  3026. KdPrintEx((DPFLTR_FSTUB_ID,
  3027. FSTUB_VERBOSE_LEVEL,
  3028. "\n"));
  3029. }
  3030. }
  3031. VOID
  3032. FstubDbgPrintDriveLayoutEx(
  3033. IN PDRIVE_LAYOUT_INFORMATION_EX LayoutEx
  3034. )
  3035. /*++
  3036. Routine Description:
  3037. Print the DRIVE_LAYOUT_INFORMATION_EX to the debugger.
  3038. Arguments:
  3039. LayoutEx - A pointer to a valid DRIVE_LAYOUT_INFORMATION_EX structure.
  3040. Return Value:
  3041. None.
  3042. Mode:
  3043. Debugging function. Checked build only.
  3044. --*/
  3045. {
  3046. ULONG i;
  3047. ULONG Style;
  3048. CHAR GuidStringBuffer[40];
  3049. PAGED_CODE ();
  3050. KdPrintEx((DPFLTR_FSTUB_ID,
  3051. FSTUB_VERBOSE_LEVEL,
  3052. "\n"
  3053. "FSTUB:\n"
  3054. "DRIVE_LAYOUT_EX %p\n",
  3055. LayoutEx));
  3056. Style = LayoutEx->PartitionStyle;
  3057. if (Style != PARTITION_STYLE_MBR && Style != PARTITION_STYLE_GPT) {
  3058. KdPrintEx((DPFLTR_FSTUB_ID,
  3059. DPFLTR_ERROR_LEVEL,
  3060. "ERROR: invalid partition style %d for layout %p\n",
  3061. Style,
  3062. LayoutEx));
  3063. return;
  3064. }
  3065. if (Style == PARTITION_STYLE_MBR &&
  3066. LayoutEx->PartitionCount % 4 != 0) {
  3067. KdPrintEx((DPFLTR_FSTUB_ID,
  3068. DPFLTR_WARNING_LEVEL,
  3069. "WARNING: Partition count is not a factor of 4, (%d)\n",
  3070. LayoutEx->PartitionCount));
  3071. }
  3072. if (Style == PARTITION_STYLE_MBR) {
  3073. KdPrintEx((DPFLTR_FSTUB_ID,
  3074. FSTUB_VERBOSE_LEVEL,
  3075. "Signature: %8.8x\n",
  3076. LayoutEx->Mbr.Signature));
  3077. KdPrintEx((DPFLTR_FSTUB_ID,
  3078. FSTUB_VERBOSE_LEVEL,
  3079. "PartitionCount %d\n\n",
  3080. LayoutEx->PartitionCount));
  3081. KdPrintEx((DPFLTR_FSTUB_ID,
  3082. FSTUB_VERBOSE_LEVEL,
  3083. " ORD Offset Length Type BI RP RW\n"));
  3084. KdPrintEx((DPFLTR_FSTUB_ID,
  3085. FSTUB_VERBOSE_LEVEL,
  3086. "------------------------------------------------------------\n"));
  3087. } else {
  3088. KdPrintEx((DPFLTR_FSTUB_ID,
  3089. FSTUB_VERBOSE_LEVEL,
  3090. "DiskId: %s\n",
  3091. FstubDbgGuidToString(&LayoutEx->Gpt.DiskId,
  3092. GuidStringBuffer)));
  3093. KdPrintEx((DPFLTR_FSTUB_ID,
  3094. FSTUB_VERBOSE_LEVEL,
  3095. "StartingUsableOffset: %I64x\n",
  3096. LayoutEx->Gpt.StartingUsableOffset.QuadPart));
  3097. KdPrintEx((DPFLTR_FSTUB_ID,
  3098. FSTUB_VERBOSE_LEVEL,
  3099. "UsableLength: %I64x\n",
  3100. LayoutEx->Gpt.UsableLength));
  3101. KdPrintEx((DPFLTR_FSTUB_ID,
  3102. FSTUB_VERBOSE_LEVEL,
  3103. "MaxPartitionCount: %d\n",
  3104. LayoutEx->Gpt.MaxPartitionCount));
  3105. KdPrintEx((DPFLTR_FSTUB_ID,
  3106. FSTUB_VERBOSE_LEVEL,
  3107. "PartitionCount %d\n\n",
  3108. LayoutEx->PartitionCount));
  3109. }
  3110. for (i = 0; i < LayoutEx->PartitionCount; i++) {
  3111. FstubDbgPrintPartitionEx (
  3112. &LayoutEx->PartitionEntry[i],
  3113. LayoutEx->PartitionCount
  3114. );
  3115. }
  3116. }
  3117. #endif // DBG