Leaked source code of windows server 2003
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.

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