efi.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2022-05-05 linzhenxing first version
  9. * 2023-02-25 GuEe-GUI make blk interface
  10. */
  11. #include "efi.h"
  12. #define DBG_TAG "blk.part.efi"
  13. #define DBG_LVL DBG_INFO
  14. #include <rtdbg.h>
  15. static rt_bool_t force_gpt = 0;
  16. static int force_gpt_setup(void)
  17. {
  18. #ifdef RT_USING_OFW
  19. force_gpt = !!rt_ofw_bootargs_select("gpt", 0);
  20. #endif
  21. return 0;
  22. }
  23. INIT_CORE_EXPORT(force_gpt_setup);
  24. /**
  25. * @brief This function is EFI version of crc32 function.
  26. *
  27. * @param buf the buffer to calculate crc32 of.
  28. * @param len the length of buf.
  29. * @return EFI-style CRC32 value for @buf.
  30. */
  31. rt_inline rt_uint32_t efi_crc32(const rt_uint8_t *buf, rt_size_t len)
  32. {
  33. rt_ubase_t crc = 0xffffffffUL;
  34. for (rt_size_t i = 0; i < len; ++i)
  35. {
  36. crc ^= buf[i];
  37. for (int j = 0; j < 8; ++j)
  38. {
  39. crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320L : 0);
  40. }
  41. }
  42. return ~crc;
  43. }
  44. /**
  45. * @brief This function get number of last logical block of device.
  46. *
  47. * @param disk the blk of disk.
  48. * @return last LBA value on success, 0 on error.
  49. * This is stored (by sd and ide-geometry) in
  50. * the part[0] entry for this disk, and is the number of
  51. * physical sectors available on the disk.
  52. */
  53. static rt_size_t last_lba(struct rt_blk_disk *disk)
  54. {
  55. return rt_blk_disk_get_capacity(disk) - 1ULL;
  56. }
  57. rt_inline int pmbr_part_valid(gpt_mbr_record *part)
  58. {
  59. if (part->os_type != EFI_PMBR_OSTYPE_EFI_GPT)
  60. {
  61. return 0;
  62. }
  63. /* set to 0x00000001 (i.e., the LBA of the GPT Partition Header) */
  64. if (rt_le32_to_cpu(part->starting_lba) != GPT_PRIMARY_PARTITION_TABLE_LBA)
  65. {
  66. return 0;
  67. }
  68. return GPT_MBR_PROTECTIVE;
  69. }
  70. /**
  71. * @brief This function test Protective MBR for validity.
  72. *
  73. * @param mbr the pointer to a legacy mbr structure.
  74. * @param total_sectors the amount of sectors in the device
  75. * @return
  76. * 0 -> Invalid MBR
  77. * 1 -> GPT_MBR_PROTECTIVE
  78. * 2 -> GPT_MBR_HYBRID
  79. */
  80. static int is_pmbr_valid(legacy_mbr *mbr, rt_size_t total_sectors)
  81. {
  82. rt_uint32_t sz = 0;
  83. int part = 0, ret = 0; /* invalid by default */
  84. if (!mbr || rt_le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE)
  85. {
  86. goto _done;
  87. }
  88. for (int i = 0; i < 4; ++i)
  89. {
  90. ret = pmbr_part_valid(&mbr->partition_record[i]);
  91. if (ret == GPT_MBR_PROTECTIVE)
  92. {
  93. part = i;
  94. /*
  95. * Ok, we at least know that there's a protective MBR,
  96. * now check if there are other partition types for
  97. * hybrid MBR.
  98. */
  99. goto _check_hybrid;
  100. }
  101. }
  102. if (ret != GPT_MBR_PROTECTIVE)
  103. {
  104. goto _done;
  105. }
  106. _check_hybrid:
  107. for (int i = 0; i < 4; i++)
  108. {
  109. if (mbr->partition_record[i].os_type != EFI_PMBR_OSTYPE_EFI_GPT &&
  110. mbr->partition_record[i].os_type != 0x00)
  111. {
  112. ret = GPT_MBR_HYBRID;
  113. }
  114. }
  115. /*
  116. * Protective MBRs take up the lesser of the whole disk
  117. * or 2 TiB (32bit LBA), ignoring the rest of the disk.
  118. * Some partitioning programs, nonetheless, choose to set
  119. * the size to the maximum 32-bit limitation, disregarding
  120. * the disk size.
  121. *
  122. * Hybrid MBRs do not necessarily comply with this.
  123. *
  124. * Consider a bad value here to be a warning to support dd'ing
  125. * an image from a smaller disk to a larger disk.
  126. */
  127. if (ret == GPT_MBR_PROTECTIVE)
  128. {
  129. sz = rt_le32_to_cpu(mbr->partition_record[part].size_in_lba);
  130. if (sz != (rt_uint32_t)total_sectors - 1 && sz != 0xffffffff)
  131. {
  132. LOG_W("GPT: mbr size in lba (%u) different than whole disk (%u)",
  133. sz, rt_min_t(rt_uint32_t, total_sectors - 1, 0xffffffff));
  134. }
  135. }
  136. _done:
  137. return ret;
  138. }
  139. /**
  140. * @brief This function read bytes from disk, starting at given LBA.
  141. *
  142. * @param disk the blk of disk.
  143. * @param lba the Logical Block Address of the partition table.
  144. * @param buffer the destination buffer.
  145. * @param count the bytes to read.
  146. * @return number of bytes read on success, 0 on error.
  147. */
  148. static rt_size_t read_lba(struct rt_blk_disk *disk,
  149. rt_uint64_t lba, rt_uint8_t *buffer, rt_size_t count)
  150. {
  151. rt_size_t totalreadcount = 0;
  152. if (!buffer || lba > last_lba(disk))
  153. {
  154. return 0;
  155. }
  156. for (rt_uint64_t n = lba; count; ++n)
  157. {
  158. int copied = 512;
  159. disk->ops->read(disk, n, buffer, 1);
  160. if (copied > count)
  161. {
  162. copied = count;
  163. }
  164. buffer += copied;
  165. totalreadcount += copied;
  166. count -= copied;
  167. }
  168. return totalreadcount;
  169. }
  170. /**
  171. * @brief This function reads partition entries from disk.
  172. *
  173. * @param disk the blk of disk.
  174. * @param gpt the GPT header
  175. * @return ptes on success, null on error.
  176. */
  177. static gpt_entry *alloc_read_gpt_entries(struct rt_blk_disk *disk,
  178. gpt_header *gpt)
  179. {
  180. rt_size_t count;
  181. gpt_entry *pte;
  182. rt_uint64_t entry_lba;
  183. if (!gpt)
  184. {
  185. return RT_NULL;
  186. }
  187. count = (rt_size_t)rt_le32_to_cpu(gpt->num_partition_entries) *
  188. rt_le32_to_cpu(gpt->sizeof_partition_entry);
  189. if (!count)
  190. {
  191. return RT_NULL;
  192. }
  193. pte = rt_malloc(count);
  194. if (!pte)
  195. {
  196. return RT_NULL;
  197. }
  198. entry_lba = rt_le64_to_cpu(gpt->partition_entry_lba);
  199. if (read_lba(disk, entry_lba, (rt_uint8_t *)pte, count) < count)
  200. {
  201. rt_free(pte);
  202. pte = RT_NULL;
  203. return RT_NULL;
  204. }
  205. /* Remember to free pte when done */
  206. return pte;
  207. }
  208. /**
  209. * @brief This function allocates GPT header, reads into it from disk.
  210. *
  211. * @param disk the blk of disk.
  212. * @param lba the Logical Block Address of the partition table
  213. * @return GPT header on success, null on error.
  214. */
  215. static gpt_header *alloc_read_gpt_header(struct rt_blk_disk *disk, rt_uint64_t lba)
  216. {
  217. gpt_header *gpt;
  218. rt_uint32_t ssz = rt_blk_disk_get_logical_block_size(disk);
  219. gpt = rt_malloc(ssz);
  220. if (!gpt)
  221. {
  222. return RT_NULL;
  223. }
  224. if (read_lba(disk, lba, (rt_uint8_t *)gpt, ssz) < ssz)
  225. {
  226. rt_free(gpt);
  227. gpt = RT_NULL;
  228. return RT_NULL;
  229. }
  230. /* Remember to free gpt when finished with it */
  231. return gpt;
  232. }
  233. /**
  234. * @brief This function tests one GPT header and PTEs for validity.
  235. *
  236. * @param disk the blk of disk.
  237. * @param lba the Logical Block Address of the GPT header to test.
  238. * @param gpt the GPT header ptr, filled on return.
  239. * @param ptes the PTEs ptr, filled on return.
  240. * @returns true if valid, false on error.
  241. * If valid, returns pointers to newly allocated GPT header and PTEs.
  242. */
  243. static rt_bool_t is_gpt_valid(struct rt_blk_disk *disk,
  244. rt_uint64_t lba, gpt_header **gpt, gpt_entry **ptes)
  245. {
  246. rt_uint32_t crc, origcrc;
  247. rt_uint64_t lastlba, pt_size;
  248. rt_ssize_t logical_block_size;
  249. if (!ptes)
  250. {
  251. return RT_FALSE;
  252. }
  253. if (!(*gpt = alloc_read_gpt_header(disk, lba)))
  254. {
  255. return RT_FALSE;
  256. }
  257. /* Check the GUID Partition Table signature */
  258. if (rt_le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE)
  259. {
  260. LOG_D("%s: GUID Partition Table Header signature is wrong: %lld != %lld",
  261. to_disk_name(disk),
  262. (rt_uint64_t)rt_le64_to_cpu((*gpt)->signature),
  263. (rt_uint64_t)GPT_HEADER_SIGNATURE);
  264. goto _fail;
  265. }
  266. /* Check the GUID Partition Table header size is too big */
  267. logical_block_size = rt_blk_disk_get_logical_block_size(disk);
  268. if (rt_le32_to_cpu((*gpt)->header_size) > logical_block_size)
  269. {
  270. LOG_D("%s: GUID Partition Table Header size is too large: %u > %u",
  271. to_disk_name(disk),
  272. rt_le32_to_cpu((*gpt)->header_size),
  273. logical_block_size);
  274. goto _fail;
  275. }
  276. /* Check the GUID Partition Table header size is too small */
  277. if (rt_le32_to_cpu((*gpt)->header_size) < sizeof(gpt_header))
  278. {
  279. LOG_D("%s: GUID Partition Table Header size is too small: %u < %u",
  280. to_disk_name(disk),
  281. rt_le32_to_cpu((*gpt)->header_size),
  282. sizeof(gpt_header));
  283. goto _fail;
  284. }
  285. /* Check the GUID Partition Table CRC */
  286. origcrc = rt_le32_to_cpu((*gpt)->header_crc32);
  287. (*gpt)->header_crc32 = 0;
  288. crc = efi_crc32((const rt_uint8_t *)(*gpt), rt_le32_to_cpu((*gpt)->header_size));
  289. if (crc != origcrc)
  290. {
  291. LOG_D("%s: GUID Partition Table Header CRC is wrong: %x != %x",
  292. to_disk_name(disk), crc, origcrc);
  293. goto _fail;
  294. }
  295. (*gpt)->header_crc32 = rt_cpu_to_le32(origcrc);
  296. /*
  297. * Check that the start_lba entry points to the LBA that contains
  298. * the GUID Partition Table
  299. */
  300. if (rt_le64_to_cpu((*gpt)->start_lba) != lba)
  301. {
  302. LOG_D("%s: GPT start_lba incorrect: %lld != %lld",
  303. to_disk_name(disk),
  304. (rt_uint64_t)rt_le64_to_cpu((*gpt)->start_lba),
  305. (rt_uint64_t)lba);
  306. goto _fail;
  307. }
  308. /* Check the first_usable_lba and last_usable_lba are within the disk */
  309. lastlba = last_lba(disk);
  310. if (rt_le64_to_cpu((*gpt)->first_usable_lba) > lastlba)
  311. {
  312. LOG_D("%s: GPT: first_usable_lba incorrect: %lld > %lld",
  313. to_disk_name(disk),
  314. (rt_uint64_t)rt_le64_to_cpu((*gpt)->first_usable_lba),
  315. (rt_uint64_t)lastlba);
  316. goto _fail;
  317. }
  318. if (rt_le64_to_cpu((*gpt)->last_usable_lba) > lastlba)
  319. {
  320. LOG_D("%s: GPT: last_usable_lba incorrect: %lld > %lld",
  321. to_disk_name(disk),
  322. (rt_uint64_t)rt_le64_to_cpu((*gpt)->last_usable_lba),
  323. (rt_uint64_t)lastlba);
  324. goto _fail;
  325. }
  326. if (rt_le64_to_cpu((*gpt)->last_usable_lba) < rt_le64_to_cpu((*gpt)->first_usable_lba))
  327. {
  328. LOG_D("%s: GPT: last_usable_lba incorrect: %lld > %lld",
  329. to_disk_name(disk),
  330. (rt_uint64_t)rt_le64_to_cpu((*gpt)->last_usable_lba),
  331. (rt_uint64_t)rt_le64_to_cpu((*gpt)->first_usable_lba));
  332. goto _fail;
  333. }
  334. /* Check that sizeof_partition_entry has the correct value */
  335. if (rt_le32_to_cpu((*gpt)->sizeof_partition_entry) != sizeof(gpt_entry))
  336. {
  337. LOG_D("%s: GUID Partition Entry Size check failed", to_disk_name(disk));
  338. goto _fail;
  339. }
  340. /* Sanity check partition table size */
  341. pt_size = (rt_uint64_t)rt_le32_to_cpu((*gpt)->num_partition_entries) *
  342. rt_le32_to_cpu((*gpt)->sizeof_partition_entry);
  343. if (!(*ptes = alloc_read_gpt_entries(disk, *gpt)))
  344. {
  345. goto _fail;
  346. }
  347. /* Check the GUID Partition Entry Array CRC */
  348. crc = efi_crc32((const rt_uint8_t *)(*ptes), pt_size);
  349. if (crc != rt_le32_to_cpu((*gpt)->partition_entry_array_crc32))
  350. {
  351. LOG_D("%s: GUID Partition Entry Array CRC check failed", to_disk_name(disk));
  352. goto _fail_ptes;
  353. }
  354. /* We're done, all's well */
  355. return RT_TRUE;
  356. _fail_ptes:
  357. rt_free(*ptes);
  358. *ptes = RT_NULL;
  359. _fail:
  360. rt_free(*gpt);
  361. *gpt = RT_NULL;
  362. return RT_FALSE;
  363. }
  364. /**
  365. * @brief This function tests one PTE for validity.
  366. *
  367. * @param pte the pte to check.
  368. * @param lastlba the last lba of the disk.
  369. * @return valid boolean of pte.
  370. */
  371. rt_inline rt_bool_t is_pte_valid(const gpt_entry *pte, const rt_size_t lastlba)
  372. {
  373. if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) ||
  374. rt_le64_to_cpu(pte->starting_lba) > lastlba ||
  375. rt_le64_to_cpu(pte->ending_lba) > lastlba)
  376. {
  377. return RT_FALSE;
  378. }
  379. return RT_TRUE;
  380. }
  381. /**
  382. * @brief This function search disk for valid GPT headers and PTEs.
  383. *
  384. * @param disk the blk of disk.
  385. * @param pgpt the primary GPT header.
  386. * @param agpt the alternate GPT header.
  387. * @param lastlba the last LBA number.
  388. */
  389. static void compare_gpts(struct rt_blk_disk *disk,
  390. gpt_header *pgpt, gpt_header *agpt, rt_uint64_t lastlba)
  391. {
  392. int error_found = 0;
  393. if (!pgpt || !agpt)
  394. {
  395. return;
  396. }
  397. if (rt_le64_to_cpu(pgpt->start_lba) != rt_le64_to_cpu(agpt->alternate_lba))
  398. {
  399. LOG_W("%s: GPT:Primary header LBA(%lld) != Alt(%lld), header alternate_lba",
  400. to_disk_name(disk),
  401. (rt_uint64_t)rt_le64_to_cpu(pgpt->start_lba),
  402. (rt_uint64_t)rt_le64_to_cpu(agpt->alternate_lba));
  403. ++error_found;
  404. }
  405. if (rt_le64_to_cpu(pgpt->alternate_lba) != rt_le64_to_cpu(agpt->start_lba))
  406. {
  407. LOG_W("%s: GPT:Primary header alternate_lba(%lld) != Alt(%lld), header start_lba",
  408. to_disk_name(disk),
  409. (rt_uint64_t)rt_le64_to_cpu(pgpt->alternate_lba),
  410. (rt_uint64_t)rt_le64_to_cpu(agpt->start_lba));
  411. ++error_found;
  412. }
  413. if (rt_le64_to_cpu(pgpt->first_usable_lba) != rt_le64_to_cpu(agpt->first_usable_lba))
  414. {
  415. LOG_W("%s: GPT:first_usable_lbas don't match %lld != %lld",
  416. to_disk_name(disk),
  417. (rt_uint64_t)rt_le64_to_cpu(pgpt->first_usable_lba),
  418. (rt_uint64_t)rt_le64_to_cpu(agpt->first_usable_lba));
  419. ++error_found;
  420. }
  421. if (rt_le64_to_cpu(pgpt->last_usable_lba) != rt_le64_to_cpu(agpt->last_usable_lba))
  422. {
  423. LOG_W("%s: GPT:last_usable_lbas don't match %lld != %lld",
  424. to_disk_name(disk),
  425. (rt_uint64_t)rt_le64_to_cpu(pgpt->last_usable_lba),
  426. (rt_uint64_t)rt_le64_to_cpu(agpt->last_usable_lba));
  427. ++error_found;
  428. }
  429. if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid))
  430. {
  431. LOG_W("%s: GPT:disk_guids don't match", to_disk_name(disk));
  432. ++error_found;
  433. }
  434. if (rt_le32_to_cpu(pgpt->num_partition_entries) !=
  435. rt_le32_to_cpu(agpt->num_partition_entries))
  436. {
  437. LOG_W("%s: GPT:num_partition_entries don't match: 0x%x != 0x%x",
  438. to_disk_name(disk),
  439. rt_le32_to_cpu(pgpt->num_partition_entries),
  440. rt_le32_to_cpu(agpt->num_partition_entries));
  441. ++error_found;
  442. }
  443. if (rt_le32_to_cpu(pgpt->sizeof_partition_entry) !=
  444. rt_le32_to_cpu(agpt->sizeof_partition_entry))
  445. {
  446. LOG_W("%s: GPT:sizeof_partition_entry values don't match: 0x%x != 0x%x",
  447. to_disk_name(disk),
  448. rt_le32_to_cpu(pgpt->sizeof_partition_entry),
  449. rt_le32_to_cpu(agpt->sizeof_partition_entry));
  450. ++error_found;
  451. }
  452. if (rt_le32_to_cpu(pgpt->partition_entry_array_crc32) !=
  453. rt_le32_to_cpu(agpt->partition_entry_array_crc32))
  454. {
  455. LOG_W("%s: GPT:partition_entry_array_crc32 values don't match: 0x%x != 0x%x",
  456. to_disk_name(disk),
  457. rt_le32_to_cpu(pgpt->partition_entry_array_crc32),
  458. rt_le32_to_cpu(agpt->partition_entry_array_crc32));
  459. ++error_found;
  460. }
  461. if (rt_le64_to_cpu(pgpt->alternate_lba) != lastlba)
  462. {
  463. LOG_W("%s: GPT:Primary header thinks Alt. header is not at the end of the disk: %lld != %lld",
  464. to_disk_name(disk),
  465. (rt_uint64_t)rt_le64_to_cpu(pgpt->alternate_lba),
  466. (rt_uint64_t)lastlba);
  467. ++error_found;
  468. }
  469. if (rt_le64_to_cpu(agpt->start_lba) != lastlba)
  470. {
  471. LOG_W("%s: GPT:Alternate GPT header not at the end of the disk: %lld != %lld",
  472. to_disk_name(disk),
  473. (rt_uint64_t)rt_le64_to_cpu(agpt->start_lba),
  474. (rt_uint64_t)lastlba);
  475. ++error_found;
  476. }
  477. if (error_found)
  478. {
  479. LOG_W("GPT: Use GNU Parted to correct GPT errors");
  480. }
  481. }
  482. /**
  483. * @brief This function search disk for valid GPT headers and PTEs.
  484. *
  485. * @param disk the disk parsed partitions.
  486. * @param gpt the GPT header ptr, filled on return.
  487. * @param ptes the PTEs ptr, filled on return.
  488. * @return 1 if valid, 0 on error.
  489. * If valid, returns pointers to newly allocated GPT header and PTEs.
  490. * Validity depends on PMBR being valid (or being overridden by the
  491. * 'gpt' kernel command line option) and finding either the Primary
  492. * GPT header and PTEs valid, or the Alternate GPT header and PTEs
  493. * valid. If the Primary GPT header is not valid, the Alternate GPT header
  494. * is not checked unless the 'gpt' kernel command line option is passed.
  495. * This protects against devices which misreport their size, and forces
  496. * the user to decide to use the Alternate GPT.
  497. */
  498. static rt_bool_t find_valid_gpt(struct rt_blk_disk *disk,
  499. gpt_header **gpt, gpt_entry **ptes)
  500. {
  501. int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
  502. gpt_header *pgpt = RT_NULL, *agpt = RT_NULL;
  503. gpt_entry *pptes = RT_NULL, *aptes = RT_NULL;
  504. legacy_mbr *legacymbr;
  505. rt_size_t total_sectors = rt_blk_disk_get_capacity(disk);
  506. rt_size_t lastlba;
  507. if (!ptes)
  508. {
  509. return RT_FALSE;
  510. }
  511. lastlba = last_lba(disk);
  512. if (!force_gpt)
  513. {
  514. /* This will be added to the EFI Spec. per Intel after v1.02. */
  515. legacymbr = rt_malloc(sizeof(*legacymbr));
  516. if (!legacymbr)
  517. {
  518. return RT_FALSE;
  519. }
  520. read_lba(disk, 0, (rt_uint8_t *)legacymbr, sizeof(*legacymbr));
  521. good_pmbr = is_pmbr_valid(legacymbr, total_sectors);
  522. rt_free(legacymbr);
  523. if (!good_pmbr)
  524. {
  525. return RT_FALSE;
  526. }
  527. LOG_D("%s: Device has a %s MBR", to_disk_name(disk),
  528. good_pmbr == GPT_MBR_PROTECTIVE ? "protective" : "hybrid");
  529. }
  530. good_pgpt = is_gpt_valid(disk, GPT_PRIMARY_PARTITION_TABLE_LBA, &pgpt, &pptes);
  531. if (good_pgpt)
  532. {
  533. good_agpt = is_gpt_valid(disk, rt_le64_to_cpu(pgpt->alternate_lba), &agpt, &aptes);
  534. }
  535. if (!good_agpt && force_gpt)
  536. {
  537. good_agpt = is_gpt_valid(disk, lastlba, &agpt, &aptes);
  538. }
  539. /* The obviously unsuccessful case */
  540. if (!good_pgpt && !good_agpt)
  541. {
  542. goto _fail;
  543. }
  544. compare_gpts(disk, pgpt, agpt, lastlba);
  545. /* The good cases */
  546. if (good_pgpt)
  547. {
  548. *gpt = pgpt;
  549. *ptes = pptes;
  550. rt_free(agpt);
  551. rt_free(aptes);
  552. if (!good_agpt)
  553. {
  554. LOG_D("%s: Alternate GPT is invalid, using primary GPT", to_disk_name(disk));
  555. }
  556. return RT_TRUE;
  557. }
  558. else if (good_agpt)
  559. {
  560. *gpt = agpt;
  561. *ptes = aptes;
  562. rt_free(pgpt);
  563. rt_free(pptes);
  564. LOG_D("%s: Primary GPT is invalid, using alternate GPT", to_disk_name(disk));
  565. return RT_TRUE;
  566. }
  567. _fail:
  568. rt_free(pgpt);
  569. rt_free(agpt);
  570. rt_free(pptes);
  571. rt_free(aptes);
  572. *gpt = RT_NULL;
  573. *ptes = RT_NULL;
  574. return RT_FALSE;
  575. }
  576. rt_err_t efi_partition(struct rt_blk_disk *disk)
  577. {
  578. rt_uint32_t entries_nr;
  579. gpt_header *gpt = RT_NULL;
  580. gpt_entry *ptes = RT_NULL;
  581. if (!find_valid_gpt(disk, &gpt, &ptes) || !gpt || !ptes)
  582. {
  583. rt_free(gpt);
  584. rt_free(ptes);
  585. return -RT_EINVAL;
  586. }
  587. entries_nr = rt_le32_to_cpu(gpt->num_partition_entries);
  588. for (int i = 0; i < entries_nr && i < disk->max_partitions; ++i)
  589. {
  590. rt_uint64_t start = rt_le64_to_cpu(ptes[i].starting_lba);
  591. rt_uint64_t size = rt_le64_to_cpu(ptes[i].ending_lba) -
  592. rt_le64_to_cpu(ptes[i].starting_lba) + 1ULL;
  593. if (!is_pte_valid(&ptes[i], last_lba(disk)))
  594. {
  595. continue;
  596. }
  597. if (blk_put_partition(disk, "gpt", start, size, i) == -RT_ENOMEM)
  598. {
  599. break;
  600. }
  601. }
  602. rt_free(gpt);
  603. rt_free(ptes);
  604. return RT_EOK;
  605. }