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

233 lines
6.6 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. blgpt.c
  5. Abstract:
  6. This module implements routines relating to GPT partitions.
  7. Author:
  8. Andrew Ritz (andrewr) 20-March-2001
  9. Revision History:
  10. Andrew Ritz (andrewr) 20-March-2001 - Created based on existing code.
  11. --*/
  12. #include "bldr.h" // defines EFI_PARTITION_SUPPORT
  13. #ifdef EFI_PARTITION_SUPPORT
  14. #include "bootlib.h"
  15. #ifndef MIN
  16. #define MIN(a,b) ((a < b) ? a : b)
  17. #endif
  18. #if 0 && DBG
  19. ULONG
  20. BlGetKey(
  21. VOID
  22. );
  23. #define DBG_PRINT(x) BlPrint(x);
  24. //{\
  25. // BlPrint(x); \
  26. // while (!BlGetKey()); \
  27. //}
  28. #else
  29. #define DBG_PRINT(x)
  30. #endif
  31. #ifdef UNICODE
  32. #define STR_PREFIX L
  33. #else
  34. #define STR_PREFIX
  35. #endif
  36. UCHAR GptScratchBuffer[1024*17];
  37. //
  38. // we read 16K chunks at a time.
  39. //
  40. #define GPT_READ_SIZE 1024*16
  41. UCHAR GptScratchBuffer2[1024];
  42. BOOLEAN
  43. BlIsValidGUIDPartitionTableHelper(
  44. IN UNALIGNED EFI_PARTITION_TABLE *PartitionTableHeader,
  45. IN ULONGLONG LBAOfPartitionTable,
  46. IN PVOID Context,
  47. IN PGPT_READ_CALLBACK DiskReadFunction
  48. )
  49. /*++
  50. Routine Description:
  51. This function checks the validity of a GUID Partition table.
  52. Per EFI Spec, the following tests must be performed to determine if a GUID
  53. Partition Table is valid:
  54. 1) Check the GUID Partition Table Signature
  55. 2) Check the GUID Partition Table CRC
  56. 3) Check that the MyLBA entry points to the LBA that contains the GUID
  57. partition table
  58. 4) Check the CRC of the GUID Partition Entry Array
  59. Arguments:
  60. PartitionTableHeader - pointer to header for partition table.
  61. LBAOfPartitionTable - logical block address that the header was read from.
  62. Context - pass through value to callback function used to read from disk
  63. DiskReadFunction - callback function used to read from the disk.
  64. Return Value:
  65. TRUE indicates that the table is valid.
  66. --*/
  67. {
  68. CHAR *PartitionEntryArray = &GptScratchBuffer[0];
  69. ULONG Crc32, CalculatedCrc32;
  70. ULONG TotalSize,CurrentSize;
  71. ULONGLONG CurrentLBA;
  72. DBG_PRINT(STR_PREFIX"Verifying GPT PT\r\n");
  73. //
  74. // 1) Check the GUID Partition Table Signature
  75. //
  76. if (memcmp(PartitionTableHeader->Signature, EFI_SIGNATURE, sizeof(EFI_SIGNATURE))) {
  77. DBG_PRINT(STR_PREFIX"Signature does not match, invalid partition table\r\n");
  78. return(FALSE);
  79. }
  80. //
  81. // 2) Check the GUID Partition Table CRC
  82. //
  83. // To do this we save off the old CRC value, calculate the CRC, and compare
  84. // the results (remembering that we need to put the CRC back when we're
  85. // done with it).
  86. //
  87. Crc32 = PartitionTableHeader->HeaderCRC;
  88. PartitionTableHeader->HeaderCRC = 0;
  89. CalculatedCrc32 = RtlComputeCrc32( 0, PartitionTableHeader, PartitionTableHeader->HeaderSize );
  90. PartitionTableHeader->HeaderCRC = Crc32;
  91. if (CalculatedCrc32 != Crc32) {
  92. DBG_PRINT(STR_PREFIX"Partition table CRC does not calculate, invalid partition table\r\n");
  93. return(FALSE);
  94. }
  95. //
  96. // 3) Check that the MyLBA entry points to the LBA that contains the GUID Partition Table
  97. //
  98. if (LBAOfPartitionTable != PartitionTableHeader->MyLBA) {
  99. DBG_PRINT(STR_PREFIX"LBA of Partition table does not match LBA in partition table header, invalid partition table\r\n");
  100. return(FALSE);
  101. }
  102. //
  103. // 4) Check the CRC of the GUID Partition Entry Array
  104. //
  105. //
  106. // first read the GUID Partition Entry Array
  107. //
  108. CurrentLBA = PartitionTableHeader->PartitionEntryLBA;
  109. TotalSize = PartitionTableHeader->PartitionEntrySize * PartitionTableHeader->PartitionCount;
  110. CurrentSize = 0;
  111. CalculatedCrc32 = 0;
  112. while (TotalSize != 0) {
  113. CurrentSize = MIN(TotalSize, GPT_READ_SIZE);
  114. if (DiskReadFunction(
  115. (ULONGLONG)CurrentLBA,
  116. CurrentSize,
  117. Context,
  118. PartitionEntryArray )) {
  119. CalculatedCrc32 = RtlComputeCrc32(
  120. CalculatedCrc32,
  121. PartitionEntryArray,
  122. CurrentSize);
  123. } else {
  124. DBG_PRINT(STR_PREFIX"DiskReadFunction for PartitionTableHeader failed, invalid partition table\r\n");
  125. return(FALSE);
  126. break;
  127. }
  128. TotalSize -= CurrentSize;
  129. CurrentLBA += CurrentSize*SECTOR_SIZE;
  130. }
  131. if (CalculatedCrc32 == ((UNALIGNED EFI_PARTITION_TABLE *)PartitionTableHeader)->PartitionEntryArrayCRC) {
  132. return(TRUE);
  133. } else {
  134. DBG_PRINT(STR_PREFIX"CRC for PartitionEntryArray does not calculate, invalid partition table\r\n");
  135. return(FALSE);
  136. }
  137. return(FALSE);
  138. }
  139. BOOLEAN
  140. BlIsValidGUIDPartitionTable(
  141. IN UNALIGNED EFI_PARTITION_TABLE *PartitionTableHeader,
  142. IN ULONGLONG LBAOfPartitionTable,
  143. IN PVOID Context,
  144. IN PGPT_READ_CALLBACK DiskReadFunction
  145. )
  146. {
  147. UNALIGNED EFI_PARTITION_TABLE *BackupPartitionTableHeader = (EFI_PARTITION_TABLE *)&GptScratchBuffer2;
  148. BOOLEAN RetVal = FALSE;
  149. if (BlIsValidGUIDPartitionTableHelper(
  150. PartitionTableHeader,
  151. LBAOfPartitionTable,
  152. Context,
  153. DiskReadFunction)) {
  154. //
  155. // If the primary table @ LBA 1, check the AlternateLBA to see if it
  156. // is valid.
  157. //
  158. if (LBAOfPartitionTable == 1) {
  159. //
  160. // Read the backup partition table into memory and validate it as
  161. // well.
  162. //
  163. if (DiskReadFunction(
  164. PartitionTableHeader->AlternateLBA,
  165. PartitionTableHeader->HeaderSize,
  166. Context,
  167. BackupPartitionTableHeader)) {
  168. if (BlIsValidGUIDPartitionTableHelper(
  169. (UNALIGNED EFI_PARTITION_TABLE *)BackupPartitionTableHeader,
  170. PartitionTableHeader->AlternateLBA,
  171. Context,
  172. DiskReadFunction)) {
  173. RetVal = TRUE;
  174. DBG_PRINT(STR_PREFIX"BlIsValidGUIDPartitionTable succeeded\r\n");
  175. }
  176. } else {
  177. DBG_PRINT(STR_PREFIX"DiskReadFunction for BackupPartitionTableHeader failed, invalid partition table\r\n");
  178. }
  179. } else {
  180. DBG_PRINT(STR_PREFIX"WARNING: LBA of PartitionTableHeader is not 1.\r\n");
  181. RetVal = TRUE;
  182. }
  183. }
  184. return(RetVal);
  185. }
  186. #endif