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