xref: /rk3399_rockchip-uboot/disk/part.c (revision 336b6f90482f23b149323b698c05c2713fe55701)
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 }
672