partgpt.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. /*++
  2. Copyright (c) 2014 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. partgpt.c
  5. Abstract:
  6. This module implements UEFI GPT partition support.
  7. Author:
  8. Evan Green 19-Mar-2014
  9. Environment:
  10. Firmware
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include "ueficore.h"
  16. #include "part.h"
  17. //
  18. // ---------------------------------------------------------------- Definitions
  19. //
  20. //
  21. // ------------------------------------------------------ Data Type Definitions
  22. //
  23. //
  24. // ----------------------------------------------- Internal Function Prototypes
  25. //
  26. BOOLEAN
  27. EfipPartitionValidGptTable (
  28. EFI_BLOCK_IO_PROTOCOL *BlockIo,
  29. EFI_DISK_IO_PROTOCOL *DiskIo,
  30. EFI_LBA Lba,
  31. EFI_PARTITION_TABLE_HEADER *PartitionHeader
  32. );
  33. BOOLEAN
  34. EfipPartitionCheckCrc (
  35. UINTN MaxSize,
  36. EFI_TABLE_HEADER *Header
  37. );
  38. BOOLEAN
  39. EfipPartitionCheckPartitionEntriesCrc (
  40. EFI_BLOCK_IO_PROTOCOL *BlockIo,
  41. EFI_DISK_IO_PROTOCOL *DiskIo,
  42. EFI_PARTITION_TABLE_HEADER *PartitionHeader
  43. );
  44. VOID
  45. EfipPartitionCheckGptEntries (
  46. EFI_PARTITION_TABLE_HEADER *Header,
  47. EFI_PARTITION_ENTRY *Entries,
  48. EFI_PARTITION_ENTRY_STATUS *EntryStatus
  49. );
  50. //
  51. // -------------------------------------------------------------------- Globals
  52. //
  53. EFI_GUID EfiPartitionTypeUnusedGuid = EFI_PARTITION_TYPE_UNUSED_GUID;
  54. EFI_GUID EfiPartitionTypeSystemPartitionGuid =
  55. EFI_PARTITION_TYPE_EFI_SYSTEM_GUID;
  56. //
  57. // ------------------------------------------------------------------ Functions
  58. //
  59. EFI_STATUS
  60. EfiPartitionDetectGpt (
  61. EFI_DRIVER_BINDING_PROTOCOL *This,
  62. EFI_HANDLE Handle,
  63. EFI_DISK_IO_PROTOCOL *DiskIo,
  64. EFI_BLOCK_IO_PROTOCOL *BlockIo,
  65. EFI_DEVICE_PATH_PROTOCOL *DevicePath
  66. )
  67. /*++
  68. Routine Description:
  69. This routine attempts to detect a GPT partitioned disk, and exposes child
  70. block devices for each partition it finds.
  71. Arguments:
  72. This - Supplies the driver binding protocol instance.
  73. Handle - Supplies the new controller handle.
  74. DiskIo - Supplies a pointer to the disk I/O protocol.
  75. BlockIo - Supplies a pointer to the block I/O protocol.
  76. DevicePath - Supplies a pointer to the device path.
  77. Return Value:
  78. EFI status code.
  79. --*/
  80. {
  81. PEFI_PARTITION_TABLE_HEADER BackupHeader;
  82. UINT32 BlockSize;
  83. HARDDRIVE_DEVICE_PATH DrivePath;
  84. UINT32 EntriesSize;
  85. PEFI_PARTITION_ENTRY Entry;
  86. EFI_STATUS GptValidStatus;
  87. UINTN Index;
  88. EFI_LBA LastBlock;
  89. BOOLEAN Match;
  90. UINT32 MediaId;
  91. PEFI_PARTITION_ENTRY PartitionEntry;
  92. PEFI_PARTITION_ENTRY_STATUS PartitionEntryStatus;
  93. UINTN PartitionEntryStatusSize;
  94. PEFI_PARTITION_TABLE_HEADER PrimaryHeader;
  95. PEFI_MASTER_BOOT_RECORD ProtectiveMbr;
  96. EFI_STATUS Status;
  97. BOOLEAN SystemPartition;
  98. BOOLEAN Valid;
  99. ProtectiveMbr = NULL;
  100. PrimaryHeader = NULL;
  101. BackupHeader = NULL;
  102. PartitionEntry = NULL;
  103. PartitionEntryStatus = NULL;
  104. BlockSize = BlockIo->Media->BlockSize;
  105. LastBlock = BlockIo->Media->LastBlock;
  106. MediaId = BlockIo->Media->MediaId;
  107. GptValidStatus = EFI_NOT_FOUND;
  108. ProtectiveMbr = EfiCoreAllocateBootPool(BlockSize);
  109. if (ProtectiveMbr == NULL) {
  110. return EFI_NOT_FOUND;
  111. }
  112. //
  113. // Read the protective MBR from LBA zero.
  114. //
  115. Status = DiskIo->ReadDisk(DiskIo,
  116. MediaId,
  117. 0,
  118. BlockSize,
  119. ProtectiveMbr);
  120. if (EFI_ERROR(Status)) {
  121. GptValidStatus = Status;
  122. goto PartitionDetectGptEnd;
  123. }
  124. //
  125. // Verify that the protective MBR is valid.
  126. //
  127. for (Index = 0; Index < EFI_MAX_MBR_PARTITIONS; Index += 1) {
  128. if ((ProtectiveMbr->Partition[Index].BootIndicator == 0x00) &&
  129. (ProtectiveMbr->Partition[Index].OsIndicator ==
  130. EFI_PROTECTIVE_MBR_PARTITION) &&
  131. (EFI_UNPACK_UINT32(ProtectiveMbr->Partition[Index].StartingLba) ==
  132. 1)) {
  133. break;
  134. }
  135. }
  136. if (Index == EFI_MAX_MBR_PARTITIONS) {
  137. goto PartitionDetectGptEnd;
  138. }
  139. //
  140. // Allocate the GPT structures.
  141. //
  142. PrimaryHeader = EfiCoreAllocateBootPool(sizeof(EFI_PARTITION_TABLE_HEADER));
  143. if (PrimaryHeader == NULL) {
  144. goto PartitionDetectGptEnd;
  145. }
  146. BackupHeader = EfiCoreAllocateBootPool(sizeof(EFI_PARTITION_TABLE_HEADER));
  147. if (BackupHeader == NULL) {
  148. goto PartitionDetectGptEnd;
  149. }
  150. //
  151. // Check the primary and backup headers.
  152. //
  153. Valid = EfipPartitionValidGptTable(BlockIo,
  154. DiskIo,
  155. EFI_PRIMARY_PARTITION_HEADER_LBA,
  156. PrimaryHeader);
  157. if (Valid == FALSE) {
  158. Valid = EfipPartitionValidGptTable(BlockIo,
  159. DiskIo,
  160. LastBlock,
  161. BackupHeader);
  162. //
  163. // End now if neither the primary nor the backup header was valid.
  164. //
  165. if (Valid == FALSE) {
  166. goto PartitionDetectGptEnd;
  167. //
  168. // The primary header was bad but the backup header is valid.
  169. //
  170. } else {
  171. RtlDebugPrint("Warning: Primary GPT header was bad, using backup "
  172. "header.\n");
  173. EfiCopyMem(PrimaryHeader,
  174. BackupHeader,
  175. sizeof(EFI_PARTITION_TABLE_HEADER));
  176. }
  177. //
  178. // The primary partition header is valid. Check the backup header.
  179. //
  180. } else {
  181. Valid = EfipPartitionValidGptTable(BlockIo,
  182. DiskIo,
  183. PrimaryHeader->AlternateLba,
  184. BackupHeader);
  185. if (Valid == FALSE) {
  186. RtlDebugPrint("Warning: Backup GPT header is invalid!\n");
  187. }
  188. }
  189. //
  190. // Read the EFI partition entries.
  191. //
  192. EntriesSize = PrimaryHeader->NumberOfPartitionEntries *
  193. PrimaryHeader->SizeOfPartitionEntry;
  194. PartitionEntry = EfiCoreAllocateBootPool(EntriesSize);
  195. if (PartitionEntry == NULL) {
  196. goto PartitionDetectGptEnd;
  197. }
  198. Status = DiskIo->ReadDisk(DiskIo,
  199. MediaId,
  200. PrimaryHeader->PartitionEntryLba * BlockSize,
  201. EntriesSize,
  202. PartitionEntry);
  203. if (EFI_ERROR(Status)) {
  204. GptValidStatus = Status;
  205. goto PartitionDetectGptEnd;
  206. }
  207. PartitionEntryStatusSize = PrimaryHeader->NumberOfPartitionEntries *
  208. sizeof(EFI_PARTITION_ENTRY_STATUS);
  209. PartitionEntryStatus = EfiCoreAllocateBootPool(PartitionEntryStatusSize);
  210. if (PartitionEntryStatus == NULL) {
  211. goto PartitionDetectGptEnd;
  212. }
  213. EfiSetMem(PartitionEntryStatus, PartitionEntryStatusSize, 0);
  214. //
  215. // Check the integrity of the partition entries.
  216. //
  217. EfipPartitionCheckGptEntries(PrimaryHeader,
  218. PartitionEntry,
  219. PartitionEntryStatus);
  220. //
  221. // Everything looks pretty valid.
  222. //
  223. GptValidStatus = EFI_SUCCESS;
  224. //
  225. // Create child device handles.
  226. //
  227. for (Index = 0;
  228. Index < PrimaryHeader->NumberOfPartitionEntries;
  229. Index += 1) {
  230. Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry +
  231. (Index *
  232. PrimaryHeader->SizeOfPartitionEntry));
  233. Match = EfiCoreCompareGuids(&(Entry->PartitionTypeGuid),
  234. &EfiPartitionTypeUnusedGuid);
  235. if ((Match != FALSE) ||
  236. (PartitionEntryStatus[Index].OutOfRange != FALSE) ||
  237. (PartitionEntryStatus[Index].Overlap != FALSE) ||
  238. (PartitionEntryStatus[Index].OsSpecific != FALSE)) {
  239. //
  240. // Don't use null entries, invalid entries, or OS-specific entries.
  241. //
  242. continue;
  243. }
  244. EfiSetMem(&DrivePath, sizeof(DrivePath), 0);
  245. DrivePath.Header.Type = MEDIA_DEVICE_PATH;
  246. DrivePath.Header.SubType = MEDIA_HARDDRIVE_DP;
  247. EfiCoreSetDevicePathNodeLength(&(DrivePath.Header), sizeof(DrivePath));
  248. DrivePath.PartitionNumber = (UINT32)Index + 1;
  249. DrivePath.MBRType = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
  250. DrivePath.SignatureType = SIGNATURE_TYPE_GUID;
  251. DrivePath.PartitionStart = Entry->StartingLba;
  252. DrivePath.PartitionSize = Entry->EndingLba - Entry->StartingLba + 1;
  253. EfiCopyMem(&(DrivePath.Signature),
  254. &(Entry->UniquePartitionGuid), sizeof(EFI_GUID));
  255. SystemPartition =
  256. EfiCoreCompareGuids(&(Entry->PartitionTypeGuid),
  257. &EfiPartitionTypeSystemPartitionGuid);
  258. Status = EfiPartitionInstallChildHandle(
  259. This,
  260. Handle,
  261. DiskIo,
  262. BlockIo,
  263. DevicePath,
  264. (EFI_DEVICE_PATH_PROTOCOL *)&DrivePath,
  265. Entry->StartingLba,
  266. Entry->EndingLba,
  267. BlockSize,
  268. SystemPartition);
  269. }
  270. PartitionDetectGptEnd:
  271. if (ProtectiveMbr != NULL) {
  272. EfiFreePool(ProtectiveMbr);
  273. }
  274. if (PrimaryHeader != NULL) {
  275. EfiFreePool(PrimaryHeader);
  276. }
  277. if (BackupHeader != NULL) {
  278. EfiFreePool(BackupHeader);
  279. }
  280. if (PartitionEntry != NULL) {
  281. EfiFreePool(PartitionEntry);
  282. }
  283. if (PartitionEntryStatus != NULL) {
  284. EfiFreePool(PartitionEntryStatus);
  285. }
  286. return GptValidStatus;
  287. }
  288. //
  289. // --------------------------------------------------------- Internal Functions
  290. //
  291. BOOLEAN
  292. EfipPartitionValidGptTable (
  293. EFI_BLOCK_IO_PROTOCOL *BlockIo,
  294. EFI_DISK_IO_PROTOCOL *DiskIo,
  295. EFI_LBA Lba,
  296. EFI_PARTITION_TABLE_HEADER *PartitionHeader
  297. )
  298. /*++
  299. Routine Description:
  300. This routine determines if the given partition table header is valid.
  301. Arguments:
  302. BlockIo - Supplies a pointer to the block I/O protocol.
  303. DiskIo - Supplies a pointer to the disk I/O protocol.
  304. Lba - Supplies the LBA to read.
  305. PartitionHeader - Supplies a pointer where the partition table will be read
  306. and returned.
  307. Return Value:
  308. TRUE if the header is valid.
  309. FALSE if the header is invalid.
  310. --*/
  311. {
  312. UINT32 BlockSize;
  313. EFI_PARTITION_TABLE_HEADER *Header;
  314. UINT32 MediaId;
  315. EFI_STATUS Status;
  316. BOOLEAN Valid;
  317. BlockSize = BlockIo->Media->BlockSize;
  318. MediaId = BlockIo->Media->MediaId;
  319. Header = EfiCoreAllocateBootPool(BlockSize);
  320. if (Header == NULL) {
  321. return FALSE;
  322. }
  323. EfiSetMem(Header, BlockSize, 0);
  324. Status = DiskIo->ReadDisk(DiskIo,
  325. MediaId,
  326. Lba * BlockSize,
  327. BlockSize,
  328. Header);
  329. if (EFI_ERROR(Status)) {
  330. EfiFreePool(Header);
  331. return FALSE;
  332. }
  333. if ((Header->Header.Signature != EFI_GPT_HEADER_SIGNATURE) ||
  334. (EfipPartitionCheckCrc(BlockSize, &(Header->Header)) == FALSE) ||
  335. (Header->MyLba != Lba) ||
  336. (Header->SizeOfPartitionEntry < sizeof(EFI_PARTITION_ENTRY))) {
  337. EfiFreePool(Header);
  338. return FALSE;
  339. }
  340. EfiCopyMem(PartitionHeader, Header, sizeof(EFI_PARTITION_TABLE_HEADER));
  341. Valid = EfipPartitionCheckPartitionEntriesCrc(BlockIo,
  342. DiskIo,
  343. PartitionHeader);
  344. EfiFreePool(Header);
  345. return Valid;
  346. }
  347. BOOLEAN
  348. EfipPartitionCheckCrc (
  349. UINTN MaxSize,
  350. EFI_TABLE_HEADER *Header
  351. )
  352. /*++
  353. Routine Description:
  354. This routine validates the CRC of the partition header.
  355. Arguments:
  356. MaxSize - Supplies the maximum size of the buffer.
  357. Header - Supplies a pointer to the header to validate.
  358. Return Value:
  359. TRUE if the CRC is valid.
  360. FALSE if the CRC is invalid.
  361. --*/
  362. {
  363. UINT32 Crc;
  364. UINT32 OriginalCrc;
  365. UINTN Size;
  366. Size = Header->HeaderSize;
  367. Crc = 0;
  368. if (Size == 0) {
  369. return FALSE;
  370. }
  371. if ((MaxSize != 0) && (Size > MaxSize)) {
  372. return FALSE;
  373. }
  374. OriginalCrc = Header->CRC32;
  375. Header->CRC32 = 0;
  376. EfiCalculateCrc32((UINT8 *)Header, Size, &Crc);
  377. Header->CRC32 = Crc;
  378. if (Crc != OriginalCrc) {
  379. return FALSE;
  380. }
  381. return TRUE;
  382. }
  383. BOOLEAN
  384. EfipPartitionCheckPartitionEntriesCrc (
  385. EFI_BLOCK_IO_PROTOCOL *BlockIo,
  386. EFI_DISK_IO_PROTOCOL *DiskIo,
  387. EFI_PARTITION_TABLE_HEADER *PartitionHeader
  388. )
  389. /*++
  390. Routine Description:
  391. This routine validates the CRC of the partition entries.
  392. Arguments:
  393. BlockIo - Supplies a pointer to the block I/O protocol.
  394. DiskIo - Supplies a pointer to the disk I/O protocol.
  395. PartitionHeader - Supplies a pointer to the GPT header.
  396. Return Value:
  397. TRUE if the CRC is valid.
  398. FALSE if the CRC is invalid.
  399. --*/
  400. {
  401. UINT8 *Buffer;
  402. UINT32 Crc;
  403. UINTN EntriesSize;
  404. UINT64 Offset;
  405. EFI_STATUS Status;
  406. BOOLEAN Valid;
  407. EntriesSize = PartitionHeader->NumberOfPartitionEntries *
  408. PartitionHeader->SizeOfPartitionEntry;
  409. Buffer = EfiCoreAllocateBootPool(EntriesSize);
  410. if (Buffer == NULL) {
  411. return FALSE;
  412. }
  413. Offset = PartitionHeader->PartitionEntryLba *
  414. BlockIo->Media->BlockSize;
  415. Status = DiskIo->ReadDisk(DiskIo,
  416. BlockIo->Media->MediaId,
  417. Offset,
  418. EntriesSize,
  419. Buffer);
  420. if (EFI_ERROR(Status)) {
  421. EfiFreePool(Buffer);
  422. return FALSE;
  423. }
  424. Valid = FALSE;
  425. Status = EfiCalculateCrc32(Buffer, EntriesSize, &Crc);
  426. if (EFI_ERROR(Status)) {
  427. RtlDebugPrint("GPT: Needed CRC and it wasn't there!\n");
  428. } else if (PartitionHeader->PartitionEntryArrayCrc32 == Crc) {
  429. Valid = TRUE;
  430. }
  431. EfiFreePool(Buffer);
  432. return Valid;
  433. }
  434. VOID
  435. EfipPartitionCheckGptEntries (
  436. EFI_PARTITION_TABLE_HEADER *Header,
  437. EFI_PARTITION_ENTRY *Entries,
  438. EFI_PARTITION_ENTRY_STATUS *EntryStatus
  439. )
  440. /*++
  441. Routine Description:
  442. This routine checks the validity of the partition entry array.
  443. Arguments:
  444. Header - Supplies a pointer to the partition entry header.
  445. Entries - Supplies a pointer to the partition entries to validate.
  446. EntryStatus - Supplies a pointer where the validity information of each
  447. partition will be returned.
  448. Return Value:
  449. None.
  450. --*/
  451. {
  452. UINTN CompareIndex;
  453. EFI_LBA EndingLba;
  454. EFI_PARTITION_ENTRY *Entry;
  455. UINTN EntryIndex;
  456. BOOLEAN Match;
  457. EFI_LBA StartingLba;
  458. for (EntryIndex = 0;
  459. EntryIndex < Header->NumberOfPartitionEntries;
  460. EntryIndex += 1) {
  461. Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)Entries +
  462. (EntryIndex *
  463. Header->SizeOfPartitionEntry));
  464. Match = EfiCoreCompareGuids(&(Entry->PartitionTypeGuid),
  465. &EfiPartitionTypeUnusedGuid);
  466. if (Match != FALSE) {
  467. continue;
  468. }
  469. StartingLba = Entry->StartingLba;
  470. EndingLba = Entry->EndingLba;
  471. if ((StartingLba > EndingLba) ||
  472. (StartingLba < Header->FirstUsableLba) ||
  473. (EndingLba < Header->FirstUsableLba) ||
  474. (EndingLba > Header->LastUsableLba)) {
  475. EntryStatus[EntryIndex].OutOfRange = TRUE;
  476. continue;
  477. }
  478. if ((Entry->Attributes & EFI_GPT_ATTRIBUTE_OS_SPECIFIC) != 0) {
  479. EntryStatus[EntryIndex].OsSpecific = TRUE;
  480. }
  481. for (CompareIndex = EntryIndex + 1;
  482. CompareIndex < Header->NumberOfPartitionEntries;
  483. CompareIndex += 1) {
  484. Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)Entries +
  485. (CompareIndex *
  486. Header->SizeOfPartitionEntry));
  487. Match = EfiCoreCompareGuids(&(Entry->PartitionTypeGuid),
  488. &EfiPartitionTypeUnusedGuid);
  489. if (Match != FALSE) {
  490. continue;
  491. }
  492. if ((Entry->EndingLba >= StartingLba) &&
  493. (Entry->StartingLba <= EndingLba)) {
  494. EntryStatus[CompareIndex].Overlap = TRUE;
  495. EntryStatus[EntryIndex].Overlap = TRUE;
  496. }
  497. }
  498. }
  499. return;
  500. }