]> git.ipfire.org Git - people/ms/u-boot.git/blob - disk/part.c
5e10cae015e54e7dc7b5193cd67d5f76ee631582
[people/ms/u-boot.git] / disk / part.c
1 /*
2 * (C) Copyright 2001
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
5 * SPDX-License-Identifier: GPL-2.0+
6 */
7
8 #include <common.h>
9 #include <command.h>
10 #include <ide.h>
11 #include <malloc.h>
12 #include <part.h>
13
14 #undef PART_DEBUG
15
16 #ifdef PART_DEBUG
17 #define PRINTF(fmt,args...) printf (fmt ,##args)
18 #else
19 #define PRINTF(fmt,args...)
20 #endif
21
22 struct block_drvr {
23 char *name;
24 block_dev_desc_t* (*get_dev)(int dev);
25 int (*select_hwpart)(int dev_num, int hwpart);
26 };
27
28 static const struct block_drvr block_drvr[] = {
29 #if defined(CONFIG_CMD_IDE)
30 { .name = "ide", .get_dev = ide_get_dev, },
31 #endif
32 #if defined(CONFIG_CMD_SATA)
33 {.name = "sata", .get_dev = sata_get_dev, },
34 #endif
35 #if defined(CONFIG_CMD_SCSI)
36 { .name = "scsi", .get_dev = scsi_get_dev, },
37 #endif
38 #if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE)
39 { .name = "usb", .get_dev = usb_stor_get_dev, },
40 #endif
41 #if defined(CONFIG_MMC)
42 { .name = "mmc", .get_dev = mmc_get_dev, },
43 #endif
44 #if defined(CONFIG_SYSTEMACE)
45 { .name = "ace", .get_dev = systemace_get_dev, },
46 #endif
47 #if defined(CONFIG_SANDBOX)
48 { .name = "host", .get_dev = host_get_dev, },
49 #endif
50 { },
51 };
52
53 DECLARE_GLOBAL_DATA_PTR;
54
55 #ifdef HAVE_BLOCK_DEVICE
56 block_dev_desc_t *get_dev_hwpart(const char *ifname, int dev, int hwpart)
57 {
58 const struct block_drvr *drvr = block_drvr;
59 block_dev_desc_t* (*reloc_get_dev)(int dev);
60 int (*select_hwpart)(int dev_num, int hwpart);
61 char *name;
62 int ret;
63
64 if (!ifname)
65 return NULL;
66
67 name = drvr->name;
68 #ifdef CONFIG_NEEDS_MANUAL_RELOC
69 name += gd->reloc_off;
70 #endif
71 while (drvr->name) {
72 name = drvr->name;
73 reloc_get_dev = drvr->get_dev;
74 select_hwpart = drvr->select_hwpart;
75 #ifdef CONFIG_NEEDS_MANUAL_RELOC
76 name += gd->reloc_off;
77 reloc_get_dev += gd->reloc_off;
78 if (select_hwpart)
79 select_hwpart += gd->reloc_off;
80 #endif
81 if (strncmp(ifname, name, strlen(name)) == 0) {
82 block_dev_desc_t *dev_desc = reloc_get_dev(dev);
83 if (!dev_desc)
84 return NULL;
85 if (hwpart == -1)
86 return dev_desc;
87 if (!select_hwpart)
88 return NULL;
89 ret = select_hwpart(dev_desc->dev, hwpart);
90 if (ret < 0)
91 return NULL;
92 return dev_desc;
93 }
94 drvr++;
95 }
96 return NULL;
97 }
98
99 block_dev_desc_t *get_dev(const char *ifname, int dev)
100 {
101 return get_dev_hwpart(ifname, dev, -1);
102 }
103 #else
104 block_dev_desc_t *get_dev_hwpart(const char *ifname, int dev, int hwpart)
105 {
106 return NULL;
107 }
108
109 block_dev_desc_t *get_dev(const char *ifname, int dev)
110 {
111 return NULL;
112 }
113 #endif
114
115 #ifdef HAVE_BLOCK_DEVICE
116
117 /* ------------------------------------------------------------------------- */
118 /*
119 * reports device info to the user
120 */
121
122 #ifdef CONFIG_LBA48
123 typedef uint64_t lba512_t;
124 #else
125 typedef lbaint_t lba512_t;
126 #endif
127
128 /*
129 * Overflowless variant of (block_count * mul_by / div_by)
130 * when div_by > mul_by
131 */
132 static lba512_t lba512_muldiv (lba512_t block_count, lba512_t mul_by, lba512_t div_by)
133 {
134 lba512_t bc_quot, bc_rem;
135
136 /* x * m / d == x / d * m + (x % d) * m / d */
137 bc_quot = block_count / div_by;
138 bc_rem = block_count - div_by * bc_quot;
139 return bc_quot * mul_by + (bc_rem * mul_by) / div_by;
140 }
141
142 void dev_print (block_dev_desc_t *dev_desc)
143 {
144 lba512_t lba512; /* number of blocks if 512bytes block size */
145
146 if (dev_desc->type == DEV_TYPE_UNKNOWN) {
147 puts ("not available\n");
148 return;
149 }
150
151 switch (dev_desc->if_type) {
152 case IF_TYPE_SCSI:
153 printf ("(%d:%d) Vendor: %s Prod.: %s Rev: %s\n",
154 dev_desc->target,dev_desc->lun,
155 dev_desc->vendor,
156 dev_desc->product,
157 dev_desc->revision);
158 break;
159 case IF_TYPE_ATAPI:
160 case IF_TYPE_IDE:
161 case IF_TYPE_SATA:
162 printf ("Model: %s Firm: %s Ser#: %s\n",
163 dev_desc->vendor,
164 dev_desc->revision,
165 dev_desc->product);
166 break;
167 case IF_TYPE_SD:
168 case IF_TYPE_MMC:
169 case IF_TYPE_USB:
170 printf ("Vendor: %s Rev: %s Prod: %s\n",
171 dev_desc->vendor,
172 dev_desc->revision,
173 dev_desc->product);
174 break;
175 case IF_TYPE_DOC:
176 puts("device type DOC\n");
177 return;
178 case IF_TYPE_UNKNOWN:
179 puts("device type unknown\n");
180 return;
181 default:
182 printf("Unhandled device type: %i\n", dev_desc->if_type);
183 return;
184 }
185 puts (" Type: ");
186 if (dev_desc->removable)
187 puts ("Removable ");
188 switch (dev_desc->type & 0x1F) {
189 case DEV_TYPE_HARDDISK:
190 puts ("Hard Disk");
191 break;
192 case DEV_TYPE_CDROM:
193 puts ("CD ROM");
194 break;
195 case DEV_TYPE_OPDISK:
196 puts ("Optical Device");
197 break;
198 case DEV_TYPE_TAPE:
199 puts ("Tape");
200 break;
201 default:
202 printf ("# %02X #", dev_desc->type & 0x1F);
203 break;
204 }
205 puts ("\n");
206 if (dev_desc->lba > 0L && dev_desc->blksz > 0L) {
207 ulong mb, mb_quot, mb_rem, gb, gb_quot, gb_rem;
208 lbaint_t lba;
209
210 lba = dev_desc->lba;
211
212 lba512 = (lba * (dev_desc->blksz/512));
213 /* round to 1 digit */
214 mb = lba512_muldiv(lba512, 10, 2048); /* 2048 = (1024 * 1024) / 512 MB */
215
216 mb_quot = mb / 10;
217 mb_rem = mb - (10 * mb_quot);
218
219 gb = mb / 1024;
220 gb_quot = gb / 10;
221 gb_rem = gb - (10 * gb_quot);
222 #ifdef CONFIG_LBA48
223 if (dev_desc->lba48)
224 printf (" Supports 48-bit addressing\n");
225 #endif
226 #if defined(CONFIG_SYS_64BIT_LBA)
227 printf (" Capacity: %ld.%ld MB = %ld.%ld GB (%Ld x %ld)\n",
228 mb_quot, mb_rem,
229 gb_quot, gb_rem,
230 lba,
231 dev_desc->blksz);
232 #else
233 printf (" Capacity: %ld.%ld MB = %ld.%ld GB (%ld x %ld)\n",
234 mb_quot, mb_rem,
235 gb_quot, gb_rem,
236 (ulong)lba,
237 dev_desc->blksz);
238 #endif
239 } else {
240 puts (" Capacity: not available\n");
241 }
242 }
243 #endif
244
245 #ifdef HAVE_BLOCK_DEVICE
246
247 void init_part (block_dev_desc_t * dev_desc)
248 {
249 #ifdef CONFIG_ISO_PARTITION
250 if (test_part_iso(dev_desc) == 0) {
251 dev_desc->part_type = PART_TYPE_ISO;
252 return;
253 }
254 #endif
255
256 #ifdef CONFIG_MAC_PARTITION
257 if (test_part_mac(dev_desc) == 0) {
258 dev_desc->part_type = PART_TYPE_MAC;
259 return;
260 }
261 #endif
262
263 /* must be placed before DOS partition detection */
264 #ifdef CONFIG_EFI_PARTITION
265 if (test_part_efi(dev_desc) == 0) {
266 dev_desc->part_type = PART_TYPE_EFI;
267 return;
268 }
269 #endif
270
271 #ifdef CONFIG_DOS_PARTITION
272 if (test_part_dos(dev_desc) == 0) {
273 dev_desc->part_type = PART_TYPE_DOS;
274 return;
275 }
276 #endif
277
278 #ifdef CONFIG_AMIGA_PARTITION
279 if (test_part_amiga(dev_desc) == 0) {
280 dev_desc->part_type = PART_TYPE_AMIGA;
281 return;
282 }
283 #endif
284 dev_desc->part_type = PART_TYPE_UNKNOWN;
285 }
286
287
288 #if defined(CONFIG_MAC_PARTITION) || \
289 defined(CONFIG_DOS_PARTITION) || \
290 defined(CONFIG_ISO_PARTITION) || \
291 defined(CONFIG_AMIGA_PARTITION) || \
292 defined(CONFIG_EFI_PARTITION)
293
294 static void print_part_header (const char *type, block_dev_desc_t * dev_desc)
295 {
296 puts ("\nPartition Map for ");
297 switch (dev_desc->if_type) {
298 case IF_TYPE_IDE:
299 puts ("IDE");
300 break;
301 case IF_TYPE_SATA:
302 puts ("SATA");
303 break;
304 case IF_TYPE_SCSI:
305 puts ("SCSI");
306 break;
307 case IF_TYPE_ATAPI:
308 puts ("ATAPI");
309 break;
310 case IF_TYPE_USB:
311 puts ("USB");
312 break;
313 case IF_TYPE_DOC:
314 puts ("DOC");
315 break;
316 case IF_TYPE_MMC:
317 puts ("MMC");
318 break;
319 case IF_TYPE_HOST:
320 puts("HOST");
321 break;
322 default:
323 puts ("UNKNOWN");
324 break;
325 }
326 printf (" device %d -- Partition Type: %s\n\n",
327 dev_desc->dev, type);
328 }
329
330 #endif /* any CONFIG_..._PARTITION */
331
332 void print_part (block_dev_desc_t * dev_desc)
333 {
334
335 switch (dev_desc->part_type) {
336 #ifdef CONFIG_MAC_PARTITION
337 case PART_TYPE_MAC:
338 PRINTF ("## Testing for valid MAC partition ##\n");
339 print_part_header ("MAC", dev_desc);
340 print_part_mac (dev_desc);
341 return;
342 #endif
343 #ifdef CONFIG_DOS_PARTITION
344 case PART_TYPE_DOS:
345 PRINTF ("## Testing for valid DOS partition ##\n");
346 print_part_header ("DOS", dev_desc);
347 print_part_dos (dev_desc);
348 return;
349 #endif
350
351 #ifdef CONFIG_ISO_PARTITION
352 case PART_TYPE_ISO:
353 PRINTF ("## Testing for valid ISO Boot partition ##\n");
354 print_part_header ("ISO", dev_desc);
355 print_part_iso (dev_desc);
356 return;
357 #endif
358
359 #ifdef CONFIG_AMIGA_PARTITION
360 case PART_TYPE_AMIGA:
361 PRINTF ("## Testing for a valid Amiga partition ##\n");
362 print_part_header ("AMIGA", dev_desc);
363 print_part_amiga (dev_desc);
364 return;
365 #endif
366
367 #ifdef CONFIG_EFI_PARTITION
368 case PART_TYPE_EFI:
369 PRINTF ("## Testing for valid EFI partition ##\n");
370 print_part_header ("EFI", dev_desc);
371 print_part_efi (dev_desc);
372 return;
373 #endif
374 }
375 puts ("## Unknown partition table\n");
376 }
377
378 #endif /* HAVE_BLOCK_DEVICE */
379
380 int get_partition_info(block_dev_desc_t *dev_desc, int part
381 , disk_partition_t *info)
382 {
383 #ifdef HAVE_BLOCK_DEVICE
384
385 #ifdef CONFIG_PARTITION_UUIDS
386 /* The common case is no UUID support */
387 info->uuid[0] = 0;
388 #endif
389
390 switch (dev_desc->part_type) {
391 #ifdef CONFIG_MAC_PARTITION
392 case PART_TYPE_MAC:
393 if (get_partition_info_mac(dev_desc, part, info) == 0) {
394 PRINTF("## Valid MAC partition found ##\n");
395 return 0;
396 }
397 break;
398 #endif
399
400 #ifdef CONFIG_DOS_PARTITION
401 case PART_TYPE_DOS:
402 if (get_partition_info_dos(dev_desc, part, info) == 0) {
403 PRINTF("## Valid DOS partition found ##\n");
404 return 0;
405 }
406 break;
407 #endif
408
409 #ifdef CONFIG_ISO_PARTITION
410 case PART_TYPE_ISO:
411 if (get_partition_info_iso(dev_desc, part, info) == 0) {
412 PRINTF("## Valid ISO boot partition found ##\n");
413 return 0;
414 }
415 break;
416 #endif
417
418 #ifdef CONFIG_AMIGA_PARTITION
419 case PART_TYPE_AMIGA:
420 if (get_partition_info_amiga(dev_desc, part, info) == 0) {
421 PRINTF("## Valid Amiga partition found ##\n");
422 return 0;
423 }
424 break;
425 #endif
426
427 #ifdef CONFIG_EFI_PARTITION
428 case PART_TYPE_EFI:
429 if (get_partition_info_efi(dev_desc, part, info) == 0) {
430 PRINTF("## Valid EFI partition found ##\n");
431 return 0;
432 }
433 break;
434 #endif
435 default:
436 break;
437 }
438 #endif /* HAVE_BLOCK_DEVICE */
439
440 return -1;
441 }
442
443 int get_device(const char *ifname, const char *dev_hwpart_str,
444 block_dev_desc_t **dev_desc)
445 {
446 char *ep;
447 char *dup_str = NULL;
448 const char *dev_str, *hwpart_str;
449 int dev, hwpart;
450
451 hwpart_str = strchr(dev_hwpart_str, '.');
452 if (hwpart_str) {
453 dup_str = strdup(dev_hwpart_str);
454 dup_str[hwpart_str - dev_hwpart_str] = 0;
455 dev_str = dup_str;
456 hwpart_str++;
457 } else {
458 dev_str = dev_hwpart_str;
459 hwpart = -1;
460 }
461
462 dev = simple_strtoul(dev_str, &ep, 16);
463 if (*ep) {
464 printf("** Bad device specification %s %s **\n",
465 ifname, dev_str);
466 dev = -1;
467 goto cleanup;
468 }
469
470 if (hwpart_str) {
471 hwpart = simple_strtoul(hwpart_str, &ep, 16);
472 if (*ep) {
473 printf("** Bad HW partition specification %s %s **\n",
474 ifname, hwpart_str);
475 dev = -1;
476 goto cleanup;
477 }
478 }
479
480 *dev_desc = get_dev_hwpart(ifname, dev, hwpart);
481 if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) {
482 printf("** Bad device %s %s **\n", ifname, dev_hwpart_str);
483 dev = -1;
484 goto cleanup;
485 }
486
487 cleanup:
488 free(dup_str);
489 return dev;
490 }
491
492 #define PART_UNSPECIFIED -2
493 #define PART_AUTO -1
494 #define MAX_SEARCH_PARTITIONS 16
495 int get_device_and_partition(const char *ifname, const char *dev_part_str,
496 block_dev_desc_t **dev_desc,
497 disk_partition_t *info, int allow_whole_dev)
498 {
499 int ret = -1;
500 const char *part_str;
501 char *dup_str = NULL;
502 const char *dev_str;
503 int dev;
504 char *ep;
505 int p;
506 int part;
507 disk_partition_t tmpinfo;
508
509 /* If no dev_part_str, use bootdevice environment variable */
510 if (!dev_part_str || !strlen(dev_part_str) ||
511 !strcmp(dev_part_str, "-"))
512 dev_part_str = getenv("bootdevice");
513
514 /* If still no dev_part_str, it's an error */
515 if (!dev_part_str) {
516 printf("** No device specified **\n");
517 goto cleanup;
518 }
519
520 /* Separate device and partition ID specification */
521 part_str = strchr(dev_part_str, ':');
522 if (part_str) {
523 dup_str = strdup(dev_part_str);
524 dup_str[part_str - dev_part_str] = 0;
525 dev_str = dup_str;
526 part_str++;
527 } else {
528 dev_str = dev_part_str;
529 }
530
531 /* Look up the device */
532 dev = get_device(ifname, dev_str, dev_desc);
533 if (dev < 0)
534 goto cleanup;
535
536 /* Convert partition ID string to number */
537 if (!part_str || !*part_str) {
538 part = PART_UNSPECIFIED;
539 } else if (!strcmp(part_str, "auto")) {
540 part = PART_AUTO;
541 } else {
542 /* Something specified -> use exactly that */
543 part = (int)simple_strtoul(part_str, &ep, 16);
544 /*
545 * Less than whole string converted,
546 * or request for whole device, but caller requires partition.
547 */
548 if (*ep || (part == 0 && !allow_whole_dev)) {
549 printf("** Bad partition specification %s %s **\n",
550 ifname, dev_part_str);
551 goto cleanup;
552 }
553 }
554
555 /*
556 * No partition table on device,
557 * or user requested partition 0 (entire device).
558 */
559 if (((*dev_desc)->part_type == PART_TYPE_UNKNOWN) ||
560 (part == 0)) {
561 if (!(*dev_desc)->lba) {
562 printf("** Bad device size - %s %s **\n", ifname,
563 dev_str);
564 goto cleanup;
565 }
566
567 /*
568 * If user specified a partition ID other than 0,
569 * or the calling command only accepts partitions,
570 * it's an error.
571 */
572 if ((part > 0) || (!allow_whole_dev)) {
573 printf("** No partition table - %s %s **\n", ifname,
574 dev_str);
575 goto cleanup;
576 }
577
578 (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);
579
580 info->start = 0;
581 info->size = (*dev_desc)->lba;
582 info->blksz = (*dev_desc)->blksz;
583 info->bootable = 0;
584 strcpy((char *)info->type, BOOT_PART_TYPE);
585 strcpy((char *)info->name, "Whole Disk");
586 #ifdef CONFIG_PARTITION_UUIDS
587 info->uuid[0] = 0;
588 #endif
589
590 ret = 0;
591 goto cleanup;
592 }
593
594 /*
595 * Now there's known to be a partition table,
596 * not specifying a partition means to pick partition 1.
597 */
598 if (part == PART_UNSPECIFIED)
599 part = 1;
600
601 /*
602 * If user didn't specify a partition number, or did specify something
603 * other than "auto", use that partition number directly.
604 */
605 if (part != PART_AUTO) {
606 ret = get_partition_info(*dev_desc, part, info);
607 if (ret) {
608 printf("** Invalid partition %d **\n", part);
609 goto cleanup;
610 }
611 } else {
612 /*
613 * Find the first bootable partition.
614 * If none are bootable, fall back to the first valid partition.
615 */
616 part = 0;
617 for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
618 ret = get_partition_info(*dev_desc, p, info);
619 if (ret)
620 continue;
621
622 /*
623 * First valid partition, or new better partition?
624 * If so, save partition ID.
625 */
626 if (!part || info->bootable)
627 part = p;
628
629 /* Best possible partition? Stop searching. */
630 if (info->bootable)
631 break;
632
633 /*
634 * We now need to search further for best possible.
635 * If we what we just queried was the best so far,
636 * save the info since we over-write it next loop.
637 */
638 if (part == p)
639 tmpinfo = *info;
640 }
641 /* If we found any acceptable partition */
642 if (part) {
643 /*
644 * If we searched all possible partition IDs,
645 * return the first valid partition we found.
646 */
647 if (p == MAX_SEARCH_PARTITIONS + 1)
648 *info = tmpinfo;
649 } else {
650 printf("** No valid partitions found **\n");
651 ret = -1;
652 goto cleanup;
653 }
654 }
655 if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) {
656 printf("** Invalid partition type \"%.32s\""
657 " (expect \"" BOOT_PART_TYPE "\")\n",
658 info->type);
659 ret = -1;
660 goto cleanup;
661 }
662
663 (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);
664
665 ret = part;
666 goto cleanup;
667
668 cleanup:
669 free(dup_str);
670 return ret;
671 }