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