xref: /openbmc/u-boot/disk/part.c (revision e04f9d0c)
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: %ld.%ld MB = %ld.%ld GB (%Ld x %ld)\n",
194 			mb_quot, mb_rem,
195 			gb_quot, gb_rem,
196 			lba,
197 			dev_desc->blksz);
198 #else
199 		printf ("            Capacity: %ld.%ld MB = %ld.%ld GB (%ld x %ld)\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 defined(CONFIG_MAC_PARTITION) || \
238 	defined(CONFIG_DOS_PARTITION) || \
239 	defined(CONFIG_ISO_PARTITION) || \
240 	defined(CONFIG_AMIGA_PARTITION) || \
241 	defined(CONFIG_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 #ifdef CONFIG_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 #define MAX_SEARCH_PARTITIONS 16
392 int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
393 			     struct blk_desc **dev_desc,
394 			     disk_partition_t *info, int allow_whole_dev)
395 {
396 	int ret = -1;
397 	const char *part_str;
398 	char *dup_str = NULL;
399 	const char *dev_str;
400 	int dev;
401 	char *ep;
402 	int p;
403 	int part;
404 	disk_partition_t tmpinfo;
405 
406 #ifdef CONFIG_SANDBOX
407 	/*
408 	 * Special-case a pseudo block device "hostfs", to allow access to the
409 	 * host's own filesystem.
410 	 */
411 	if (0 == strcmp(ifname, "hostfs")) {
412 		*dev_desc = NULL;
413 		info->start = 0;
414 		info->size = 0;
415 		info->blksz = 0;
416 		info->bootable = 0;
417 		strcpy((char *)info->type, BOOT_PART_TYPE);
418 		strcpy((char *)info->name, "Sandbox host");
419 #ifdef CONFIG_PARTITION_UUIDS
420 		info->uuid[0] = 0;
421 #endif
422 #ifdef CONFIG_PARTITION_TYPE_GUID
423 		info->type_guid[0] = 0;
424 #endif
425 
426 		return 0;
427 	}
428 #endif
429 
430 #ifdef CONFIG_CMD_UBIFS
431 	/*
432 	 * Special-case ubi, ubi goes through a mtd, rathen then through
433 	 * a regular block device.
434 	 */
435 	if (0 == strcmp(ifname, "ubi")) {
436 		if (!ubifs_is_mounted()) {
437 			printf("UBIFS not mounted, use ubifsmount to mount volume first!\n");
438 			return -1;
439 		}
440 
441 		*dev_desc = NULL;
442 		memset(info, 0, sizeof(*info));
443 		strcpy((char *)info->type, BOOT_PART_TYPE);
444 		strcpy((char *)info->name, "UBI");
445 #ifdef CONFIG_PARTITION_UUIDS
446 		info->uuid[0] = 0;
447 #endif
448 		return 0;
449 	}
450 #endif
451 
452 	/* If no dev_part_str, use bootdevice environment variable */
453 	if (!dev_part_str || !strlen(dev_part_str) ||
454 	    !strcmp(dev_part_str, "-"))
455 		dev_part_str = getenv("bootdevice");
456 
457 	/* If still no dev_part_str, it's an error */
458 	if (!dev_part_str) {
459 		printf("** No device specified **\n");
460 		goto cleanup;
461 	}
462 
463 	/* Separate device and partition ID specification */
464 	part_str = strchr(dev_part_str, ':');
465 	if (part_str) {
466 		dup_str = strdup(dev_part_str);
467 		dup_str[part_str - dev_part_str] = 0;
468 		dev_str = dup_str;
469 		part_str++;
470 	} else {
471 		dev_str = dev_part_str;
472 	}
473 
474 	/* Look up the device */
475 	dev = blk_get_device_by_str(ifname, dev_str, dev_desc);
476 	if (dev < 0)
477 		goto cleanup;
478 
479 	/* Convert partition ID string to number */
480 	if (!part_str || !*part_str) {
481 		part = PART_UNSPECIFIED;
482 	} else if (!strcmp(part_str, "auto")) {
483 		part = PART_AUTO;
484 	} else {
485 		/* Something specified -> use exactly that */
486 		part = (int)simple_strtoul(part_str, &ep, 16);
487 		/*
488 		 * Less than whole string converted,
489 		 * or request for whole device, but caller requires partition.
490 		 */
491 		if (*ep || (part == 0 && !allow_whole_dev)) {
492 			printf("** Bad partition specification %s %s **\n",
493 			    ifname, dev_part_str);
494 			goto cleanup;
495 		}
496 	}
497 
498 	/*
499 	 * No partition table on device,
500 	 * or user requested partition 0 (entire device).
501 	 */
502 	if (((*dev_desc)->part_type == PART_TYPE_UNKNOWN) ||
503 	    (part == 0)) {
504 		if (!(*dev_desc)->lba) {
505 			printf("** Bad device size - %s %s **\n", ifname,
506 			       dev_str);
507 			goto cleanup;
508 		}
509 
510 		/*
511 		 * If user specified a partition ID other than 0,
512 		 * or the calling command only accepts partitions,
513 		 * it's an error.
514 		 */
515 		if ((part > 0) || (!allow_whole_dev)) {
516 			printf("** No partition table - %s %s **\n", ifname,
517 			       dev_str);
518 			goto cleanup;
519 		}
520 
521 		(*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);
522 
523 		info->start = 0;
524 		info->size = (*dev_desc)->lba;
525 		info->blksz = (*dev_desc)->blksz;
526 		info->bootable = 0;
527 		strcpy((char *)info->type, BOOT_PART_TYPE);
528 		strcpy((char *)info->name, "Whole Disk");
529 #ifdef CONFIG_PARTITION_UUIDS
530 		info->uuid[0] = 0;
531 #endif
532 #ifdef CONFIG_PARTITION_TYPE_GUID
533 		info->type_guid[0] = 0;
534 #endif
535 
536 		ret = 0;
537 		goto cleanup;
538 	}
539 
540 	/*
541 	 * Now there's known to be a partition table,
542 	 * not specifying a partition means to pick partition 1.
543 	 */
544 	if (part == PART_UNSPECIFIED)
545 		part = 1;
546 
547 	/*
548 	 * If user didn't specify a partition number, or did specify something
549 	 * other than "auto", use that partition number directly.
550 	 */
551 	if (part != PART_AUTO) {
552 		ret = part_get_info(*dev_desc, part, info);
553 		if (ret) {
554 			printf("** Invalid partition %d **\n", part);
555 			goto cleanup;
556 		}
557 	} else {
558 		/*
559 		 * Find the first bootable partition.
560 		 * If none are bootable, fall back to the first valid partition.
561 		 */
562 		part = 0;
563 		for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
564 			ret = part_get_info(*dev_desc, p, info);
565 			if (ret)
566 				continue;
567 
568 			/*
569 			 * First valid partition, or new better partition?
570 			 * If so, save partition ID.
571 			 */
572 			if (!part || info->bootable)
573 				part = p;
574 
575 			/* Best possible partition? Stop searching. */
576 			if (info->bootable)
577 				break;
578 
579 			/*
580 			 * We now need to search further for best possible.
581 			 * If we what we just queried was the best so far,
582 			 * save the info since we over-write it next loop.
583 			 */
584 			if (part == p)
585 				tmpinfo = *info;
586 		}
587 		/* If we found any acceptable partition */
588 		if (part) {
589 			/*
590 			 * If we searched all possible partition IDs,
591 			 * return the first valid partition we found.
592 			 */
593 			if (p == MAX_SEARCH_PARTITIONS + 1)
594 				*info = tmpinfo;
595 		} else {
596 			printf("** No valid partitions found **\n");
597 			ret = -1;
598 			goto cleanup;
599 		}
600 	}
601 	if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) {
602 		printf("** Invalid partition type \"%.32s\""
603 			" (expect \"" BOOT_PART_TYPE "\")\n",
604 			info->type);
605 		ret  = -1;
606 		goto cleanup;
607 	}
608 
609 	(*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);
610 
611 	ret = part;
612 	goto cleanup;
613 
614 cleanup:
615 	free(dup_str);
616 	return ret;
617 }
618