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