1
0

gpt.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  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. */
  10. #include <rtthread.h>
  11. #include <dfs_fs.h>
  12. #include <drivers/gpt.h>
  13. #include <drivers/mmcsd_core.h>
  14. #define DBG_TAG "GPT"
  15. #ifdef RT_SDIO_DEBUG
  16. #define DBG_LVL DBG_LOG
  17. #else
  18. #define DBG_LVL DBG_INFO
  19. #endif /* RT_SDIO_DEBUG */
  20. #include <rtdbg.h>
  21. #define min(a, b) a < b ? a : b
  22. static int force_gpt = 0;
  23. static gpt_header *_gpt;
  24. static gpt_entry *_ptes;
  25. #define GPT_TYPE 1
  26. #define MBR_TYPE 0
  27. static inline int efi_guidcmp (gpt_guid_t left, gpt_guid_t right)
  28. {
  29. return rt_memcmp(&left, &right, sizeof (gpt_guid_t));
  30. }
  31. static uint32_t last_lba(struct rt_mmcsd_card *card)
  32. {
  33. RT_ASSERT(card != RT_NULL);
  34. return (card->card_sec_cnt) - 1;
  35. }
  36. static inline int pmbr_part_valid(gpt_mbr_record *part)
  37. {
  38. if (part->os_type != EFI_PMBR_OSTYPE_EFI_GPT)
  39. {
  40. goto invalid;
  41. }
  42. /* set to 0x00000001 (i.e., the LBA of the GPT Partition Header) */
  43. if ((uint32_t)(part->starting_lba) != GPT_PRIMARY_PARTITION_TABLE_LBA)
  44. {
  45. goto invalid;
  46. }
  47. return GPT_MBR_PROTECTIVE;
  48. invalid:
  49. return 0;
  50. }
  51. /*
  52. *
  53. * return ret
  54. * ret = 0, invalid mbr
  55. * ret = 1, protect mbr
  56. * ret = 2, hybrid mbr
  57. */
  58. int is_pmbr_valid(legacy_mbr *mbr, uint64_t total_sectors)
  59. {
  60. uint32_t sz = 0;
  61. int i, part = 0, ret = 0; /* invalid by default */
  62. if (!mbr || (uint16_t)(mbr->signature) != MSDOS_MBR_SIGNATURE)
  63. {
  64. goto done;
  65. }
  66. for (i = 0; i < 4; i++)
  67. {
  68. ret = pmbr_part_valid(&mbr->partition_record[i]);
  69. if (ret == GPT_MBR_PROTECTIVE)
  70. {
  71. part = i;
  72. /*
  73. * Ok, we at least know that there's a protective MBR,
  74. * now check if there are other partition types for
  75. * hybrid MBR.
  76. */
  77. goto check_hybrid;
  78. }
  79. }
  80. if (ret != GPT_MBR_PROTECTIVE)
  81. {
  82. goto done;
  83. }
  84. check_hybrid:
  85. for (i = 0; i < 4; i++)
  86. {
  87. if ((mbr->partition_record[i].os_type !=
  88. EFI_PMBR_OSTYPE_EFI_GPT) &&
  89. (mbr->partition_record[i].os_type != 0x00))
  90. {
  91. ret = GPT_MBR_HYBRID;
  92. }
  93. }
  94. /*
  95. * Protective MBRs take up the lesser of the whole disk
  96. * or 2 TiB (32bit LBA), ignoring the rest of the disk.
  97. * Some partitioning programs, nonetheless, choose to set
  98. * the size to the maximum 32-bit limitation, disregarding
  99. * the disk size.
  100. *
  101. * Hybrid MBRs do not necessarily comply with this.
  102. *
  103. * Consider a bad value here to be a warning to support dd'ing
  104. * an image from a smaller disk to a larger disk.
  105. */
  106. if (ret == GPT_MBR_PROTECTIVE)
  107. {
  108. sz = (uint32_t)(mbr->partition_record[part].size_in_lba);
  109. if (sz != (uint32_t) total_sectors - 1 && sz != 0xFFFFFFFF)
  110. {
  111. LOG_I("GPT: mbr size in lba (%u) different than whole disk (%u).",
  112. sz, min(total_sectors - 1, 0xFFFFFFFF));
  113. }
  114. }
  115. done:
  116. return ret;
  117. }
  118. static gpt_entry *alloc_read_gpt_entries(struct rt_mmcsd_card *card, gpt_header *gpt)
  119. {
  120. size_t count;
  121. gpt_entry *pte;
  122. if (!gpt)
  123. {
  124. return RT_NULL;
  125. }
  126. count = (size_t)(gpt->num_partition_entries) * (gpt->sizeof_partition_entry);
  127. if (!count)
  128. {
  129. return RT_NULL;
  130. }
  131. pte = rt_malloc(count);
  132. if (!pte)
  133. return RT_NULL;
  134. if (read_lba(card, (size_t)(gpt->partition_entry_lba),(uint8_t *)pte, count/512) != RT_EOK)
  135. {
  136. rt_free(pte);
  137. return RT_NULL;
  138. }
  139. return pte;
  140. }
  141. static gpt_header *alloc_read_gpt_header(struct rt_mmcsd_card *card, size_t lba)
  142. {
  143. gpt_header *gpt;
  144. void *buf;
  145. buf = rt_malloc(512);
  146. if (!buf)
  147. {
  148. return RT_NULL;
  149. }
  150. if (read_lba(card, lba, (uint8_t *)buf, 1) != RT_EOK)
  151. {
  152. rt_free(buf);
  153. return RT_NULL;
  154. }
  155. gpt = (gpt_header *)buf;
  156. return gpt;
  157. }
  158. static int is_gpt_valid(struct rt_mmcsd_card *card, size_t lba, gpt_header **gpt, gpt_entry **ptes)
  159. {
  160. size_t lastlba;
  161. if (!ptes || !gpt)
  162. {
  163. return 0;
  164. }
  165. *gpt = alloc_read_gpt_header(card, lba);
  166. if (!(*gpt))
  167. {
  168. return 0;
  169. }
  170. /* Check the GUID Partition Table signature */
  171. if ((uint64_t)((*gpt)->signature) != GPT_HEADER_SIGNATURE)
  172. {
  173. LOG_E("GUID Partition Table Header signature is wrong:"
  174. "%ld != %ld",(uint64_t)((*gpt)->signature),(uint64_t)GPT_HEADER_SIGNATURE);
  175. goto fail;
  176. }
  177. /* Check the GUID Partition Table header size is too small */
  178. if ((uint32_t)((*gpt)->header_size) < sizeof(gpt_header))
  179. {
  180. LOG_E("GUID Partition Table Header size is too small: %u < %zu",
  181. (uint32_t)((*gpt)->header_size),sizeof(gpt_header));
  182. goto fail;
  183. }
  184. /* Check that the start_lba entry points to the LBA that contains
  185. * the GUID Partition Table */
  186. if ((uint64_t)((*gpt)->start_lba) != lba)
  187. {
  188. LOG_E("GPT start_lba incorrect: %ld != %ld",
  189. (uint64_t)((*gpt)->start_lba),
  190. (uint64_t)lba);
  191. goto fail;
  192. }
  193. /* Check the first_usable_lba and last_usable_lba are
  194. * within the disk.
  195. */
  196. lastlba = last_lba(card);
  197. if ((uint64_t)((*gpt)->first_usable_lba) > lastlba)
  198. {
  199. LOG_E("GPT: first_usable_lba incorrect: %ld > %ld",
  200. ((uint64_t)((*gpt)->first_usable_lba)),
  201. (size_t)lastlba);
  202. goto fail;
  203. }
  204. if ((uint64_t)((*gpt)->last_usable_lba) > lastlba)
  205. {
  206. LOG_E("GPT: last_usable_lba incorrect: %ld > %ld",
  207. (uint64_t)((*gpt)->last_usable_lba),
  208. (size_t)lastlba);
  209. goto fail;
  210. }
  211. if ((uint64_t)((*gpt)->last_usable_lba) < (uint64_t)((*gpt)->first_usable_lba))
  212. {
  213. LOG_E("GPT: last_usable_lba incorrect: %ld > %ld",
  214. (uint64_t)((*gpt)->last_usable_lba),
  215. (uint64_t)((*gpt)->first_usable_lba));
  216. goto fail;
  217. }
  218. /* Check that sizeof_partition_entry has the correct value */
  219. if ((uint32_t)((*gpt)->sizeof_partition_entry) != sizeof(gpt_entry)) {
  220. LOG_E("GUID Partition Entry Size check failed.");
  221. goto fail;
  222. }
  223. *ptes = alloc_read_gpt_entries(card, *gpt);
  224. if (!(*ptes))
  225. {
  226. goto fail;
  227. }
  228. /* We're done, all's well */
  229. return 1;
  230. fail:
  231. rt_free(*gpt);
  232. *gpt = RT_NULL;
  233. return 0;
  234. }
  235. /**
  236. * is_pte_valid() - tests one PTE for validity
  237. * pte:pte to check
  238. * lastlba: last lba of the disk
  239. *
  240. * Description: returns 1 if valid, 0 on error.
  241. */
  242. static inline int is_pte_valid(const gpt_entry *pte, const size_t lastlba)
  243. {
  244. if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) ||
  245. (uint64_t)(pte->starting_lba) > lastlba ||
  246. (uint64_t)(pte->ending_lba) > lastlba)
  247. {
  248. return 0;
  249. }
  250. return 1;
  251. }
  252. /**
  253. * compare_gpts() - Search disk for valid GPT headers and PTEs
  254. * pgpt: primary GPT header
  255. * agpt: alternate GPT header
  256. * lastlba: last LBA number
  257. *
  258. * Description: Returns nothing. Sanity checks pgpt and agpt fields
  259. * and prints warnings on discrepancies.
  260. *
  261. */
  262. static void compare_gpts(gpt_header *pgpt, gpt_header *agpt, size_t lastlba)
  263. {
  264. int error_found = 0;
  265. if (!pgpt || !agpt)
  266. {
  267. return;
  268. }
  269. if ((uint64_t)(pgpt->start_lba) != (uint64_t)(agpt->alternate_lba))
  270. {
  271. LOG_I("GPT:Primary header LBA != Alt. header alternate_lba");
  272. LOG_I("GPT:%lld != %lld",
  273. (uint64_t)(pgpt->start_lba),
  274. (uint64_t)(agpt->alternate_lba));
  275. error_found++;
  276. }
  277. if ((uint64_t)(pgpt->alternate_lba) != (uint64_t)(agpt->start_lba))
  278. {
  279. LOG_I("GPT:Primary header alternate_lba != Alt. header start_lba");
  280. LOG_I("GPT:%lld != %lld",
  281. (uint64_t)(pgpt->alternate_lba),
  282. (uint64_t)(agpt->start_lba));
  283. error_found++;
  284. }
  285. if ((uint64_t)(pgpt->first_usable_lba) != (uint64_t)(agpt->first_usable_lba))
  286. {
  287. LOG_I("GPT:first_usable_lbas don't match.");
  288. LOG_I("GPT:%lld != %lld",
  289. (uint64_t)(pgpt->first_usable_lba),
  290. (uint64_t)(agpt->first_usable_lba));
  291. error_found++;
  292. }
  293. if ((uint64_t)(pgpt->last_usable_lba) != (uint64_t)(agpt->last_usable_lba))
  294. {
  295. LOG_I("GPT:last_usable_lbas don't match.");
  296. LOG_I("GPT:%lld != %lld",
  297. (uint64_t)(pgpt->last_usable_lba),
  298. (uint64_t)(agpt->last_usable_lba));
  299. error_found++;
  300. }
  301. if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid))
  302. {
  303. LOG_I("GPT:disk_guids don't match.");
  304. error_found++;
  305. }
  306. if ((pgpt->num_partition_entries) != (agpt->num_partition_entries))
  307. {
  308. LOG_I("GPT:num_partition_entries don't match: "
  309. "0x%x != 0x%x",
  310. (pgpt->num_partition_entries),
  311. (agpt->num_partition_entries));
  312. error_found++;
  313. }
  314. if ((pgpt->sizeof_partition_entry) != (agpt->sizeof_partition_entry))
  315. {
  316. LOG_I("GPT:sizeof_partition_entry values don't match: "
  317. "0x%x != 0x%x",
  318. (pgpt->sizeof_partition_entry),
  319. (agpt->sizeof_partition_entry));
  320. error_found++;
  321. }
  322. if ((pgpt->partition_entry_array_crc32) != (agpt->partition_entry_array_crc32))
  323. {
  324. LOG_I("GPT:partition_entry_array_crc32 values don't match: "
  325. "0x%x != 0x%x",
  326. (pgpt->partition_entry_array_crc32),
  327. (agpt->partition_entry_array_crc32));
  328. error_found++;
  329. }
  330. if ((pgpt->alternate_lba) != lastlba)
  331. {
  332. LOG_I("GPT:Primary header thinks Alt. header is not at the end of the disk.");
  333. LOG_I("GPT:%lld != %lld",
  334. (uint64_t)(pgpt->alternate_lba),
  335. (size_t)lastlba);
  336. error_found++;
  337. }
  338. if ((agpt->start_lba) != lastlba)
  339. {
  340. LOG_I("GPT:Alternate GPT header not at the end of the disk.");
  341. LOG_I("GPT:%lld != %lld",
  342. (uint64_t)(agpt->start_lba),
  343. (size_t)lastlba);
  344. error_found++;
  345. }
  346. if (error_found)
  347. {
  348. LOG_I("GPT: Use GNU Parted to correct GPT errors.");
  349. }
  350. return;
  351. }
  352. /**
  353. * find_valid_gpt() - Search disk for valid GPT headers and PTEs
  354. * state: disk parsed partitions
  355. * gpt: GPT header ptr, filled on return.
  356. * ptes: PTEs ptr, filled on return.
  357. *
  358. * Description: Returns 1 if valid, 0 on error.
  359. * If valid, returns pointers to newly allocated GPT header and PTEs.
  360. * Validity depends on PMBR being valid (or being overridden by the
  361. * 'gpt' kernel command line option) and finding either the Primary
  362. * GPT header and PTEs valid, or the Alternate GPT header and PTEs
  363. * valid. If the Primary GPT header is not valid, the Alternate GPT header
  364. * is not checked unless the 'gpt' kernel command line option is passed.
  365. * This protects against devices which misreport their size, and forces
  366. * the user to decide to use the Alternate GPT.
  367. */
  368. static int find_valid_gpt(struct rt_mmcsd_card *card, gpt_header **gpt,
  369. gpt_entry **ptes)
  370. {
  371. int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
  372. gpt_header *pgpt = RT_NULL, *agpt = RT_NULL;
  373. gpt_entry *pptes = RT_NULL, *aptes = RT_NULL;
  374. legacy_mbr *legacymbr;
  375. size_t total_sectors = last_lba(card) + 1;
  376. size_t lastlba;
  377. int status = 0;
  378. if (!ptes)
  379. {
  380. return 0;
  381. }
  382. lastlba = last_lba(card);
  383. if (!force_gpt)
  384. {
  385. /* This will be added to the EFI Spec. per Intel after v1.02. */
  386. legacymbr = rt_malloc(512);
  387. if (!legacymbr)
  388. {
  389. goto fail;
  390. }
  391. status = read_lba(card, 0, (uint8_t *)legacymbr, 1);
  392. if (status)
  393. {
  394. LOG_I("status:%d", status);
  395. goto fail;
  396. }
  397. good_pmbr = is_pmbr_valid(legacymbr, total_sectors);
  398. rt_free(legacymbr);
  399. if (!good_pmbr)
  400. {
  401. goto fail;
  402. }
  403. rt_kprintf("Device has a %s MBR\n",
  404. good_pmbr == GPT_MBR_PROTECTIVE ?
  405. "protective" : "hybrid");
  406. }
  407. good_pgpt = is_gpt_valid(card, GPT_PRIMARY_PARTITION_TABLE_LBA,
  408. &pgpt, &pptes);
  409. if (good_pgpt)
  410. {
  411. good_agpt = is_gpt_valid(card, (pgpt->alternate_lba), &agpt, &aptes);
  412. if (!good_agpt && force_gpt)
  413. {
  414. good_agpt = is_gpt_valid(card, lastlba, &agpt, &aptes);
  415. }
  416. /* The obviously unsuccessful case */
  417. if (!good_pgpt && !good_agpt)
  418. {
  419. goto fail;
  420. }
  421. compare_gpts(pgpt, agpt, lastlba);
  422. /* The good cases */
  423. if (good_pgpt)
  424. {
  425. *gpt = pgpt;
  426. *ptes = pptes;
  427. rt_free(agpt);
  428. rt_free(aptes);
  429. if (!good_agpt)
  430. {
  431. LOG_D("Alternate GPT is invalid, using primary GPT.");
  432. }
  433. return 1;
  434. }
  435. else if (good_agpt)
  436. {
  437. *gpt = agpt;
  438. *ptes = aptes;
  439. rt_free(pgpt);
  440. rt_free(pptes);
  441. LOG_D("Primary GPT is invalid, using alternate GPT.");
  442. return 1;
  443. }
  444. }
  445. fail:
  446. rt_free(pgpt);
  447. rt_free(agpt);
  448. rt_free(pptes);
  449. rt_free(aptes);
  450. *gpt = RT_NULL;
  451. *ptes = RT_NULL;
  452. return 0;
  453. }
  454. int check_gpt(struct rt_mmcsd_card *card)
  455. {
  456. if (!find_valid_gpt(card, &_gpt, &_ptes) || !_gpt || !_ptes)
  457. {
  458. rt_free(_gpt);
  459. rt_free(_ptes);
  460. return MBR_TYPE;
  461. }
  462. return GPT_TYPE;
  463. }
  464. int gpt_get_partition_param(struct rt_mmcsd_card *card, struct dfs_partition *part, uint32_t pindex)
  465. {
  466. if (!is_pte_valid(&_ptes[pindex], last_lba(card)))
  467. {
  468. return -1;
  469. }
  470. part->offset = (off_t)(_ptes[pindex].starting_lba);
  471. part->size = (_ptes[pindex].ending_lba) - (_ptes[pindex].starting_lba) + 1ULL;
  472. rt_kprintf("found part[%d], begin(sector): %d, end(sector):%d size: ",
  473. pindex, _ptes[pindex].starting_lba, _ptes[pindex].ending_lba);
  474. if ((part->size >> 11) == 0)
  475. {
  476. rt_kprintf("%d%s", part->size >> 1, "KB\n"); /* KB */
  477. }
  478. else
  479. {
  480. unsigned int part_size;
  481. part_size = part->size >> 11; /* MB */
  482. if ((part_size >> 10) == 0)
  483. rt_kprintf("%d.%d%s", part_size, (part->size >> 1) & 0x3FF, "MB\n");
  484. else
  485. rt_kprintf("%d.%d%s", part_size >> 10, part_size & 0x3FF, "GB\n");
  486. }
  487. return 0;
  488. }
  489. void gpt_free(void)
  490. {
  491. rt_free(_ptes);
  492. rt_free(_gpt);
  493. }