partgpt.c 17 KB

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