1
2
3
4
5
6
7#include <common.h>
8#include <blk.h>
9#include <command.h>
10#include <env.h>
11#include <errno.h>
12#include <ide.h>
13#include <log.h>
14#include <malloc.h>
15#include <part.h>
16#include <ubifs_uboot.h>
17
18#undef PART_DEBUG
19
20#ifdef PART_DEBUG
21#define PRINTF(fmt,args...) printf (fmt ,##args)
22#else
23#define PRINTF(fmt,args...)
24#endif
25
26
27#define PART_TYPE_ALL -1
28
29static struct part_driver *part_driver_lookup_type(struct blk_desc *dev_desc)
30{
31 struct part_driver *drv =
32 ll_entry_start(struct part_driver, part_driver);
33 const int n_ents = ll_entry_count(struct part_driver, part_driver);
34 struct part_driver *entry;
35
36 if (dev_desc->part_type == PART_TYPE_UNKNOWN) {
37 for (entry = drv; entry != drv + n_ents; entry++) {
38 int ret;
39
40 ret = entry->test(dev_desc);
41 if (!ret) {
42 dev_desc->part_type = entry->part_type;
43 return entry;
44 }
45 }
46 } else {
47 for (entry = drv; entry != drv + n_ents; entry++) {
48 if (dev_desc->part_type == entry->part_type)
49 return entry;
50 }
51 }
52
53
54 return NULL;
55}
56
57static struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart)
58{
59 struct blk_desc *dev_desc;
60 int ret;
61
62 if (!blk_enabled())
63 return NULL;
64 dev_desc = blk_get_devnum_by_uclass_idname(ifname, dev);
65 if (!dev_desc) {
66 debug("%s: No device for iface '%s', dev %d\n", __func__,
67 ifname, dev);
68 return NULL;
69 }
70 ret = blk_dselect_hwpart(dev_desc, hwpart);
71 if (ret) {
72 debug("%s: Failed to select h/w partition: err-%d\n", __func__,
73 ret);
74 return NULL;
75 }
76
77 return dev_desc;
78}
79
80struct blk_desc *blk_get_dev(const char *ifname, int dev)
81{
82 if (!blk_enabled())
83 return NULL;
84
85 return get_dev_hwpart(ifname, dev, 0);
86}
87
88
89
90
91
92
93#ifdef CONFIG_LBA48
94typedef uint64_t lba512_t;
95#else
96typedef lbaint_t lba512_t;
97#endif
98
99
100
101
102
103static lba512_t lba512_muldiv(lba512_t block_count, lba512_t mul_by,
104 int right_shift)
105{
106 lba512_t bc_quot, bc_rem;
107
108
109 bc_quot = block_count >> right_shift;
110 bc_rem = block_count - (bc_quot << right_shift);
111 return bc_quot * mul_by + ((bc_rem * mul_by) >> right_shift);
112}
113
114void dev_print(struct blk_desc *dev_desc)
115{
116 lba512_t lba512;
117
118 if (dev_desc->type == DEV_TYPE_UNKNOWN) {
119 puts ("not available\n");
120 return;
121 }
122
123 switch (dev_desc->uclass_id) {
124 case UCLASS_SCSI:
125 printf ("(%d:%d) Vendor: %s Prod.: %s Rev: %s\n",
126 dev_desc->target,dev_desc->lun,
127 dev_desc->vendor,
128 dev_desc->product,
129 dev_desc->revision);
130 break;
131 case UCLASS_IDE:
132 case UCLASS_AHCI:
133 printf ("Model: %s Firm: %s Ser#: %s\n",
134 dev_desc->vendor,
135 dev_desc->revision,
136 dev_desc->product);
137 break;
138 case UCLASS_MMC:
139 case UCLASS_USB:
140 case UCLASS_NVME:
141 case UCLASS_PVBLOCK:
142 case UCLASS_HOST:
143 printf ("Vendor: %s Rev: %s Prod: %s\n",
144 dev_desc->vendor,
145 dev_desc->revision,
146 dev_desc->product);
147 break;
148 case UCLASS_VIRTIO:
149 printf("%s VirtIO Block Device\n", dev_desc->vendor);
150 break;
151 case UCLASS_EFI_MEDIA:
152 printf("EFI media Block Device %d\n", dev_desc->devnum);
153 break;
154 case UCLASS_INVALID:
155 puts("device type unknown\n");
156 return;
157 default:
158 printf("Unhandled device type: %i\n", dev_desc->uclass_id);
159 return;
160 }
161 puts (" Type: ");
162 if (dev_desc->removable)
163 puts ("Removable ");
164 switch (dev_desc->type & 0x1F) {
165 case DEV_TYPE_HARDDISK:
166 puts ("Hard Disk");
167 break;
168 case DEV_TYPE_CDROM:
169 puts ("CD ROM");
170 break;
171 case DEV_TYPE_OPDISK:
172 puts ("Optical Device");
173 break;
174 case DEV_TYPE_TAPE:
175 puts ("Tape");
176 break;
177 default:
178 printf ("# %02X #", dev_desc->type & 0x1F);
179 break;
180 }
181 puts ("\n");
182 if (dev_desc->lba > 0L && dev_desc->blksz > 0L) {
183 ulong mb, mb_quot, mb_rem, gb, gb_quot, gb_rem;
184 lbaint_t lba;
185
186 lba = dev_desc->lba;
187
188 lba512 = (lba * (dev_desc->blksz/512));
189
190
191 mb = lba512_muldiv(lba512, 10, 11);
192
193 mb_quot = mb / 10;
194 mb_rem = mb - (10 * mb_quot);
195
196 gb = mb / 1024;
197 gb_quot = gb / 10;
198 gb_rem = gb - (10 * gb_quot);
199#ifdef CONFIG_LBA48
200 if (dev_desc->lba48)
201 printf (" Supports 48-bit addressing\n");
202#endif
203#if defined(CONFIG_SYS_64BIT_LBA)
204 printf (" Capacity: %lu.%lu MB = %lu.%lu GB (%llu x %lu)\n",
205 mb_quot, mb_rem,
206 gb_quot, gb_rem,
207 lba,
208 dev_desc->blksz);
209#else
210 printf (" Capacity: %lu.%lu MB = %lu.%lu GB (%lu x %lu)\n",
211 mb_quot, mb_rem,
212 gb_quot, gb_rem,
213 (ulong)lba,
214 dev_desc->blksz);
215#endif
216 } else {
217 puts (" Capacity: not available\n");
218 }
219}
220
221void part_init(struct blk_desc *dev_desc)
222{
223 struct part_driver *drv =
224 ll_entry_start(struct part_driver, part_driver);
225 const int n_ents = ll_entry_count(struct part_driver, part_driver);
226 struct part_driver *entry;
227
228 blkcache_invalidate(dev_desc->uclass_id, dev_desc->devnum);
229
230 dev_desc->part_type = PART_TYPE_UNKNOWN;
231 for (entry = drv; entry != drv + n_ents; entry++) {
232 int ret;
233
234 ret = entry->test(dev_desc);
235 debug("%s: try '%s': ret=%d\n", __func__, entry->name, ret);
236 if (!ret) {
237 dev_desc->part_type = entry->part_type;
238 break;
239 }
240 }
241}
242
243static void print_part_header(const char *type, struct blk_desc *dev_desc)
244{
245#if CONFIG_IS_ENABLED(MAC_PARTITION) || \
246 CONFIG_IS_ENABLED(DOS_PARTITION) || \
247 CONFIG_IS_ENABLED(ISO_PARTITION) || \
248 CONFIG_IS_ENABLED(AMIGA_PARTITION) || \
249 CONFIG_IS_ENABLED(EFI_PARTITION)
250 puts ("\nPartition Map for ");
251 switch (dev_desc->uclass_id) {
252 case UCLASS_IDE:
253 puts ("IDE");
254 break;
255 case UCLASS_AHCI:
256 puts ("SATA");
257 break;
258 case UCLASS_SCSI:
259 puts ("SCSI");
260 break;
261 case UCLASS_USB:
262 puts ("USB");
263 break;
264 case UCLASS_MMC:
265 puts ("MMC");
266 break;
267 case UCLASS_HOST:
268 puts ("HOST");
269 break;
270 case UCLASS_NVME:
271 puts ("NVMe");
272 break;
273 case UCLASS_PVBLOCK:
274 puts("PV BLOCK");
275 break;
276 case UCLASS_VIRTIO:
277 puts("VirtIO");
278 break;
279 case UCLASS_EFI_MEDIA:
280 puts("EFI");
281 break;
282 default:
283 puts("UNKNOWN");
284 break;
285 }
286 printf (" device %d -- Partition Type: %s\n\n",
287 dev_desc->devnum, type);
288#endif
289}
290
291void part_print(struct blk_desc *dev_desc)
292{
293 struct part_driver *drv;
294
295 drv = part_driver_lookup_type(dev_desc);
296 if (!drv) {
297 printf("## Unknown partition table type %x\n",
298 dev_desc->part_type);
299 return;
300 }
301
302 PRINTF("## Testing for valid %s partition ##\n", drv->name);
303 print_part_header(drv->name, dev_desc);
304 if (drv->print)
305 drv->print(dev_desc);
306}
307
308int part_get_info(struct blk_desc *dev_desc, int part,
309 struct disk_partition *info)
310{
311 struct part_driver *drv;
312
313 if (blk_enabled()) {
314#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
315
316 info->uuid[0] = 0;
317#endif
318#ifdef CONFIG_PARTITION_TYPE_GUID
319 info->type_guid[0] = 0;
320#endif
321
322 drv = part_driver_lookup_type(dev_desc);
323 if (!drv) {
324 debug("## Unknown partition table type %x\n",
325 dev_desc->part_type);
326 return -EPROTONOSUPPORT;
327 }
328 if (!drv->get_info) {
329 PRINTF("## Driver %s does not have the get_info() method\n",
330 drv->name);
331 return -ENOSYS;
332 }
333 if (drv->get_info(dev_desc, part, info) == 0) {
334 PRINTF("## Valid %s partition found ##\n", drv->name);
335 return 0;
336 }
337 }
338
339 return -ENOENT;
340}
341
342int part_get_info_whole_disk(struct blk_desc *dev_desc,
343 struct disk_partition *info)
344{
345 info->start = 0;
346 info->size = dev_desc->lba;
347 info->blksz = dev_desc->blksz;
348 info->bootable = 0;
349 strcpy((char *)info->type, BOOT_PART_TYPE);
350 strcpy((char *)info->name, "Whole Disk");
351#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
352 info->uuid[0] = 0;
353#endif
354#ifdef CONFIG_PARTITION_TYPE_GUID
355 info->type_guid[0] = 0;
356#endif
357
358 return 0;
359}
360
361int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str,
362 struct blk_desc **dev_desc)
363{
364 char *ep;
365 char *dup_str = NULL;
366 const char *dev_str, *hwpart_str;
367 int dev, hwpart;
368
369 hwpart_str = strchr(dev_hwpart_str, '.');
370 if (hwpart_str) {
371 dup_str = strdup(dev_hwpart_str);
372 dup_str[hwpart_str - dev_hwpart_str] = 0;
373 dev_str = dup_str;
374 hwpart_str++;
375 } else {
376 dev_str = dev_hwpart_str;
377 hwpart = 0;
378 }
379
380 dev = hextoul(dev_str, &ep);
381 if (*ep) {
382 printf("** Bad device specification %s %s **\n",
383 ifname, dev_str);
384 dev = -EINVAL;
385 goto cleanup;
386 }
387
388 if (hwpart_str) {
389 hwpart = hextoul(hwpart_str, &ep);
390 if (*ep) {
391 printf("** Bad HW partition specification %s %s **\n",
392 ifname, hwpart_str);
393 dev = -EINVAL;
394 goto cleanup;
395 }
396 }
397
398 *dev_desc = get_dev_hwpart(ifname, dev, hwpart);
399 if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) {
400 debug("** Bad device %s %s **\n", ifname, dev_hwpart_str);
401 dev = -ENODEV;
402 goto cleanup;
403 }
404
405 if (blk_enabled()) {
406
407
408
409
410
411 if ((*dev_desc)->uclass_id == UCLASS_MMC)
412 part_init(*dev_desc);
413 }
414
415cleanup:
416 free(dup_str);
417 return dev;
418}
419
420#define PART_UNSPECIFIED -2
421#define PART_AUTO -1
422int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
423 struct blk_desc **dev_desc,
424 struct disk_partition *info, int allow_whole_dev)
425{
426 int ret;
427 const char *part_str;
428 char *dup_str = NULL;
429 const char *dev_str;
430 int dev;
431 char *ep;
432 int p;
433 int part;
434 struct disk_partition tmpinfo;
435
436 *dev_desc = NULL;
437 memset(info, 0, sizeof(*info));
438
439#if IS_ENABLED(CONFIG_SANDBOX) || IS_ENABLED(CONFIG_SEMIHOSTING)
440
441
442
443
444 if (!strcmp(ifname, "hostfs")) {
445 strcpy((char *)info->type, BOOT_PART_TYPE);
446 strcpy((char *)info->name, "Host filesystem");
447
448 return 0;
449 }
450#endif
451
452#if IS_ENABLED(CONFIG_CMD_UBIFS) && !IS_ENABLED(CONFIG_SPL_BUILD)
453
454
455
456
457 if (!strcmp(ifname, "ubi")) {
458 if (!ubifs_is_mounted()) {
459 printf("UBIFS not mounted, use ubifsmount to mount volume first!\n");
460 return -EINVAL;
461 }
462
463 strcpy((char *)info->type, BOOT_PART_TYPE);
464 strcpy((char *)info->name, "UBI");
465 return 0;
466 }
467#endif
468
469
470 if (!dev_part_str || !strlen(dev_part_str) ||
471 !strcmp(dev_part_str, "-"))
472 dev_part_str = env_get("bootdevice");
473
474
475 if (!dev_part_str) {
476 printf("** No device specified **\n");
477 ret = -ENODEV;
478 goto cleanup;
479 }
480
481
482 part_str = strchr(dev_part_str, ':');
483 if (part_str) {
484 dup_str = strdup(dev_part_str);
485 dup_str[part_str - dev_part_str] = 0;
486 dev_str = dup_str;
487 part_str++;
488 } else {
489 dev_str = dev_part_str;
490 }
491
492
493 dev = blk_get_device_by_str(ifname, dev_str, dev_desc);
494 if (dev < 0) {
495 printf("** Bad device specification %s %s **\n",
496 ifname, dev_str);
497 ret = dev;
498 goto cleanup;
499 }
500
501
502 if (!part_str || !*part_str) {
503 part = PART_UNSPECIFIED;
504 } else if (!strcmp(part_str, "auto")) {
505 part = PART_AUTO;
506 } else {
507
508 part = (int)hextoul(part_str, &ep);
509
510
511
512
513 if (*ep || (part == 0 && !allow_whole_dev)) {
514 printf("** Bad partition specification %s %s **\n",
515 ifname, dev_part_str);
516 ret = -ENOENT;
517 goto cleanup;
518 }
519 }
520
521
522
523
524
525 if (((*dev_desc)->part_type == PART_TYPE_UNKNOWN) ||
526 (part == 0)) {
527 if (!(*dev_desc)->lba) {
528 printf("** Bad device size - %s %s **\n", ifname,
529 dev_str);
530 ret = -EINVAL;
531 goto cleanup;
532 }
533
534
535
536
537
538
539 if ((part > 0) || (!allow_whole_dev)) {
540 printf("** No partition table - %s %s **\n", ifname,
541 dev_str);
542 ret = -EPROTONOSUPPORT;
543 goto cleanup;
544 }
545
546 (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);
547
548 part_get_info_whole_disk(*dev_desc, info);
549
550 ret = 0;
551 goto cleanup;
552 }
553
554
555
556
557
558 if (part == PART_UNSPECIFIED)
559 part = 1;
560
561
562
563
564
565 if (part != PART_AUTO) {
566 ret = part_get_info(*dev_desc, part, info);
567 if (ret) {
568 printf("** Invalid partition %d **\n", part);
569 goto cleanup;
570 }
571 } else {
572
573
574
575
576 part = 0;
577 for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
578 ret = part_get_info(*dev_desc, p, info);
579 if (ret)
580 continue;
581
582
583
584
585
586 if (!part || info->bootable)
587 part = p;
588
589
590 if (info->bootable)
591 break;
592
593
594
595
596
597
598 if (part == p)
599 tmpinfo = *info;
600 }
601
602 if (part) {
603
604
605
606
607 if (p == MAX_SEARCH_PARTITIONS + 1)
608 *info = tmpinfo;
609 } else {
610 printf("** No valid partitions found **\n");
611 goto cleanup;
612 }
613 }
614 if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) {
615 printf("** Invalid partition type \"%.32s\""
616 " (expect \"" BOOT_PART_TYPE "\")\n",
617 info->type);
618 ret = -EINVAL;
619 goto cleanup;
620 }
621
622 (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);
623
624 ret = part;
625 goto cleanup;
626
627cleanup:
628 free(dup_str);
629 return ret;
630}
631
632int part_get_info_by_name_type(struct blk_desc *dev_desc, const char *name,
633 struct disk_partition *info, int part_type)
634{
635 struct part_driver *part_drv;
636 int ret;
637 int i;
638
639 part_drv = part_driver_lookup_type(dev_desc);
640 if (!part_drv)
641 return -1;
642
643 if (!part_drv->get_info) {
644 log_debug("## Driver %s does not have the get_info() method\n",
645 part_drv->name);
646 return -ENOSYS;
647 }
648
649 for (i = 1; i < part_drv->max_entries; i++) {
650 ret = part_drv->get_info(dev_desc, i, info);
651 if (ret != 0) {
652
653 break;
654 }
655 if (strcmp(name, (const char *)info->name) == 0) {
656
657 return i;
658 }
659 }
660
661 return -ENOENT;
662}
663
664int part_get_info_by_name(struct blk_desc *dev_desc, const char *name,
665 struct disk_partition *info)
666{
667 return part_get_info_by_name_type(dev_desc, name, info, PART_TYPE_ALL);
668}
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685static int part_get_info_by_dev_and_name(const char *dev_iface,
686 const char *dev_part_str,
687 struct blk_desc **dev_desc,
688 struct disk_partition *part_info)
689{
690 char *dup_str = NULL;
691 const char *dev_str, *part_str;
692 int ret;
693
694
695 if (dev_part_str)
696 part_str = strchr(dev_part_str, '#');
697 else
698 part_str = NULL;
699
700 if (part_str) {
701 dup_str = strdup(dev_part_str);
702 dup_str[part_str - dev_part_str] = 0;
703 dev_str = dup_str;
704 part_str++;
705 } else {
706 return -EINVAL;
707 }
708
709 ret = blk_get_device_by_str(dev_iface, dev_str, dev_desc);
710 if (ret < 0)
711 goto cleanup;
712
713 ret = part_get_info_by_name(*dev_desc, part_str, part_info);
714 if (ret < 0)
715 printf("Could not find \"%s\" partition\n", part_str);
716
717cleanup:
718 free(dup_str);
719 return ret;
720}
721
722int part_get_info_by_dev_and_name_or_num(const char *dev_iface,
723 const char *dev_part_str,
724 struct blk_desc **dev_desc,
725 struct disk_partition *part_info,
726 int allow_whole_dev)
727{
728 int ret;
729
730
731 ret = part_get_info_by_dev_and_name(dev_iface, dev_part_str,
732 dev_desc, part_info);
733 if (ret >= 0)
734 return ret;
735
736
737
738
739 ret = blk_get_device_part_str(dev_iface, dev_part_str,
740 dev_desc, part_info, allow_whole_dev);
741 if (ret < 0)
742 printf("Couldn't find partition %s %s\n",
743 dev_iface, dev_part_str);
744 return ret;
745}
746
747void part_set_generic_name(const struct blk_desc *dev_desc,
748 int part_num, char *name)
749{
750 char *devtype;
751
752 switch (dev_desc->uclass_id) {
753 case UCLASS_IDE:
754 case UCLASS_AHCI:
755 devtype = "hd";
756 break;
757 case UCLASS_SCSI:
758 devtype = "sd";
759 break;
760 case UCLASS_USB:
761 devtype = "usbd";
762 break;
763 case UCLASS_MMC:
764 devtype = "mmcsd";
765 break;
766 default:
767 devtype = "xx";
768 break;
769 }
770
771 sprintf(name, "%s%c%d", devtype, 'a' + dev_desc->devnum, part_num);
772}
773