+// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2001
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
- *
- * SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
+#include <blk.h>
#include <command.h>
+#include <env.h>
#include <errno.h>
#include <ide.h>
+#include <log.h>
#include <malloc.h>
#include <part.h>
#include <ubifs_uboot.h>
/* Check all partition types */
#define PART_TYPE_ALL -1
-DECLARE_GLOBAL_DATA_PTR;
-
-#ifdef HAVE_BLOCK_DEVICE
-static struct part_driver *part_driver_lookup_type(int part_type)
+static struct part_driver *part_driver_lookup_type(struct blk_desc *dev_desc)
{
struct part_driver *drv =
ll_entry_start(struct part_driver, part_driver);
const int n_ents = ll_entry_count(struct part_driver, part_driver);
struct part_driver *entry;
- for (entry = drv; entry != drv + n_ents; entry++) {
- if (part_type == entry->part_type)
- return entry;
+ if (dev_desc->part_type == PART_TYPE_UNKNOWN) {
+ for (entry = drv; entry != drv + n_ents; entry++) {
+ int ret;
+
+ ret = entry->test(dev_desc);
+ if (!ret) {
+ dev_desc->part_type = entry->part_type;
+ return entry;
+ }
+ }
+ } else {
+ for (entry = drv; entry != drv + n_ents; entry++) {
+ if (dev_desc->part_type == entry->part_type)
+ return entry;
+ }
}
/* Not found */
return NULL;
}
+#ifdef CONFIG_HAVE_BLOCK_DEVICE
static struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart)
{
struct blk_desc *dev_desc;
}
#endif
-#ifdef HAVE_BLOCK_DEVICE
+#ifdef CONFIG_HAVE_BLOCK_DEVICE
/* ------------------------------------------------------------------------- */
/*
#endif
/*
- * Overflowless variant of (block_count * mul_by / div_by)
- * when div_by > mul_by
+ * Overflowless variant of (block_count * mul_by / 2**right_shift)
+ * when 2**right_shift > mul_by
*/
-static lba512_t lba512_muldiv(lba512_t block_count, lba512_t mul_by, lba512_t div_by)
+static lba512_t lba512_muldiv(lba512_t block_count, lba512_t mul_by,
+ int right_shift)
{
lba512_t bc_quot, bc_rem;
/* x * m / d == x / d * m + (x % d) * m / d */
- bc_quot = block_count / div_by;
- bc_rem = block_count - div_by * bc_quot;
- return bc_quot * mul_by + (bc_rem * mul_by) / div_by;
+ bc_quot = block_count >> right_shift;
+ bc_rem = block_count - (bc_quot << right_shift);
+ return bc_quot * mul_by + ((bc_rem * mul_by) >> right_shift);
}
void dev_print (struct blk_desc *dev_desc)
case IF_TYPE_MMC:
case IF_TYPE_USB:
case IF_TYPE_NVME:
+ case IF_TYPE_PVBLOCK:
printf ("Vendor: %s Rev: %s Prod: %s\n",
dev_desc->vendor,
dev_desc->revision,
dev_desc->product);
break;
+ case IF_TYPE_VIRTIO:
+ printf("%s VirtIO Block Device\n", dev_desc->vendor);
+ break;
case IF_TYPE_DOC:
puts("device type DOC\n");
return;
lba512 = (lba * (dev_desc->blksz/512));
/* round to 1 digit */
/* 2048 = (1024 * 1024) / 512 MB */
- mb = lba512_muldiv(lba512, 10, 2048);
+ mb = lba512_muldiv(lba512, 10, 11);
mb_quot = mb / 10;
mb_rem = mb - (10 * mb_quot);
}
#endif
-#ifdef HAVE_BLOCK_DEVICE
+#ifdef CONFIG_HAVE_BLOCK_DEVICE
void part_init(struct blk_desc *dev_desc)
{
case IF_TYPE_NVME:
puts ("NVMe");
break;
+ case IF_TYPE_PVBLOCK:
+ puts("PV BLOCK");
+ break;
+ case IF_TYPE_VIRTIO:
+ puts("VirtIO");
+ break;
default:
puts ("UNKNOWN");
break;
{
struct part_driver *drv;
- drv = part_driver_lookup_type(dev_desc->part_type);
+ drv = part_driver_lookup_type(dev_desc);
if (!drv) {
printf("## Unknown partition table type %x\n",
dev_desc->part_type);
drv->print(dev_desc);
}
-#endif /* HAVE_BLOCK_DEVICE */
+#endif /* CONFIG_HAVE_BLOCK_DEVICE */
int part_get_info(struct blk_desc *dev_desc, int part,
- disk_partition_t *info)
+ struct disk_partition *info)
{
-#ifdef HAVE_BLOCK_DEVICE
+#ifdef CONFIG_HAVE_BLOCK_DEVICE
struct part_driver *drv;
#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
info->type_guid[0] = 0;
#endif
- drv = part_driver_lookup_type(dev_desc->part_type);
+ drv = part_driver_lookup_type(dev_desc);
if (!drv) {
debug("## Unknown partition table type %x\n",
dev_desc->part_type);
PRINTF("## Valid %s partition found ##\n", drv->name);
return 0;
}
-#endif /* HAVE_BLOCK_DEVICE */
+#endif /* CONFIG_HAVE_BLOCK_DEVICE */
return -1;
}
-int part_get_info_whole_disk(struct blk_desc *dev_desc, disk_partition_t *info)
+int part_get_info_whole_disk(struct blk_desc *dev_desc,
+ struct disk_partition *info)
{
info->start = 0;
info->size = dev_desc->lba;
*dev_desc = get_dev_hwpart(ifname, dev, hwpart);
if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) {
- printf("** Bad device %s %s **\n", ifname, dev_hwpart_str);
+ debug("** Bad device %s %s **\n", ifname, dev_hwpart_str);
dev = -ENOENT;
goto cleanup;
}
-#ifdef HAVE_BLOCK_DEVICE
+#ifdef CONFIG_HAVE_BLOCK_DEVICE
/*
* Updates the partition table for the specified hw partition.
- * Does not need to be done for hwpart 0 since it is default and
- * already loaded.
+ * Always should be done, otherwise hw partition 0 will return stale
+ * data after displaying a non-zero hw partition.
*/
- if(hwpart != 0)
- part_init(*dev_desc);
+ part_init(*dev_desc);
#endif
cleanup:
#define PART_AUTO -1
int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
struct blk_desc **dev_desc,
- disk_partition_t *info, int allow_whole_dev)
+ struct disk_partition *info, int allow_whole_dev)
{
int ret = -1;
const char *part_str;
char *ep;
int p;
int part;
- disk_partition_t tmpinfo;
+ struct disk_partition tmpinfo;
#ifdef CONFIG_SANDBOX
/*
#ifdef CONFIG_CMD_UBIFS
/*
- * Special-case ubi, ubi goes through a mtd, rathen then through
+ * Special-case ubi, ubi goes through a mtd, rather than through
* a regular block device.
*/
if (0 == strcmp(ifname, "ubi")) {
}
int part_get_info_by_name_type(struct blk_desc *dev_desc, const char *name,
- disk_partition_t *info, int part_type)
+ struct disk_partition *info, int part_type)
{
- struct part_driver *first_drv =
- ll_entry_start(struct part_driver, part_driver);
- const int n_drvs = ll_entry_count(struct part_driver, part_driver);
struct part_driver *part_drv;
-
- for (part_drv = first_drv; part_drv != first_drv + n_drvs; part_drv++) {
- int ret;
- int i;
- for (i = 1; i < part_drv->max_entries; i++) {
- if (part_type >= 0 && part_type != part_drv->part_type)
- break;
- ret = part_drv->get_info(dev_desc, i, info);
- if (ret != 0) {
- /* no more entries in table */
- break;
- }
- if (strcmp(name, (const char *)info->name) == 0) {
- /* matched */
- return i;
- }
+ int ret;
+ int i;
+
+ part_drv = part_driver_lookup_type(dev_desc);
+ if (!part_drv)
+ return -1;
+ for (i = 1; i < part_drv->max_entries; i++) {
+ ret = part_drv->get_info(dev_desc, i, info);
+ if (ret != 0) {
+ /* no more entries in table */
+ break;
+ }
+ if (strcmp(name, (const char *)info->name) == 0) {
+ /* matched */
+ return i;
}
}
+
return -1;
}
int part_get_info_by_name(struct blk_desc *dev_desc, const char *name,
- disk_partition_t *info)
+ struct disk_partition *info)
{
return part_get_info_by_name_type(dev_desc, name, info, PART_TYPE_ALL);
}
+/**
+ * Get partition info from device number and partition name.
+ *
+ * Parse a device number and partition name string in the form of
+ * "device_num#partition_name", for example "0#misc". If the partition
+ * is found, sets dev_desc and part_info accordingly with the information
+ * of the partition with the given partition_name.
+ *
+ * @param[in] dev_iface Device interface
+ * @param[in] dev_part_str Input string argument, like "0#misc"
+ * @param[out] dev_desc Place to store the device description pointer
+ * @param[out] part_info Place to store the partition information
+ * @return 0 on success, or a negative on error
+ */
+static int part_get_info_by_dev_and_name(const char *dev_iface,
+ const char *dev_part_str,
+ struct blk_desc **dev_desc,
+ struct disk_partition *part_info)
+{
+ char *ep;
+ const char *part_str;
+ int dev_num;
+
+ part_str = strchr(dev_part_str, '#');
+ if (!part_str || part_str == dev_part_str)
+ return -EINVAL;
+
+ dev_num = simple_strtoul(dev_part_str, &ep, 16);
+ if (ep != part_str) {
+ /* Not all the first part before the # was parsed. */
+ return -EINVAL;
+ }
+ part_str++;
+
+ *dev_desc = blk_get_dev(dev_iface, dev_num);
+ if (!*dev_desc) {
+ printf("Could not find %s %d\n", dev_iface, dev_num);
+ return -EINVAL;
+ }
+ if (part_get_info_by_name(*dev_desc, part_str, part_info) < 0) {
+ printf("Could not find \"%s\" partition\n", part_str);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int part_get_info_by_dev_and_name_or_num(const char *dev_iface,
+ const char *dev_part_str,
+ struct blk_desc **dev_desc,
+ struct disk_partition *part_info)
+{
+ /* Split the part_name if passed as "$dev_num#part_name". */
+ if (!part_get_info_by_dev_and_name(dev_iface, dev_part_str,
+ dev_desc, part_info))
+ return 0;
+ /*
+ * Couldn't lookup by name, try looking up the partition description
+ * directly.
+ */
+ if (blk_get_device_part_str(dev_iface, dev_part_str,
+ dev_desc, part_info, 1) < 0) {
+ printf("Couldn't find partition %s %s\n",
+ dev_iface, dev_part_str);
+ return -EINVAL;
+ }
+ return 0;
+}
+
void part_set_generic_name(const struct blk_desc *dev_desc,
int part_num, char *name)
{