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