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