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