From 3f6fb771751e560931c05b845fcb305a9b8eb071 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Fri, 5 Feb 2021 09:38:53 -0500 Subject: [PATCH 01/13] mmc: sandbox: Add support for writing This adds support writing to the sandbox mmc backed by an in-memory buffer. The unit test has been updated to test reading, writing, and erasing. I'm not sure what MMCs erase to; I picked 0, but if it's 0xFF then that can be easily changed. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass --- drivers/mmc/sandbox_mmc.c | 43 +++++++++++++++++++++++++++++++++------ test/dm/mmc.c | 19 ++++++++++++----- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/drivers/mmc/sandbox_mmc.c b/drivers/mmc/sandbox_mmc.c index 8a2391d651..18ba020aac 100644 --- a/drivers/mmc/sandbox_mmc.c +++ b/drivers/mmc/sandbox_mmc.c @@ -17,6 +17,17 @@ struct sandbox_mmc_plat { struct mmc mmc; }; +#define MMC_CSIZE 0 +#define MMC_CMULT 8 /* 8 because the card is high-capacity */ +#define MMC_BL_LEN_SHIFT 10 +#define MMC_BL_LEN BIT(MMC_BL_LEN_SHIFT) +#define MMC_CAPACITY (((MMC_CSIZE + 1) << (MMC_CMULT + 2)) \ + * MMC_BL_LEN) /* 1 MiB */ + +struct sandbox_mmc_priv { + u8 buf[MMC_CAPACITY]; +}; + /** * sandbox_mmc_send_cmd() - Emulate SD commands * @@ -26,6 +37,10 @@ struct sandbox_mmc_plat { static int sandbox_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, struct mmc_data *data) { + struct sandbox_mmc_priv *priv = dev_get_priv(dev); + struct mmc *mmc = mmc_get_mmc_dev(dev); + static ulong erase_start, erase_end; + switch (cmd->cmdidx) { case MMC_CMD_ALL_SEND_CID: memset(cmd->response, '\0', sizeof(cmd->response)); @@ -44,8 +59,9 @@ static int sandbox_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, break; case MMC_CMD_SEND_CSD: cmd->response[0] = 0; - cmd->response[1] = 10 << 16; /* 1 << block_len */ - cmd->response[2] = 0; + cmd->response[1] = (MMC_BL_LEN_SHIFT << 16) | + ((MMC_CSIZE >> 16) & 0x3f); + cmd->response[2] = (MMC_CSIZE & 0xffff) << 16; cmd->response[3] = 0; break; case SD_CMD_SWITCH_FUNC: { @@ -59,13 +75,27 @@ static int sandbox_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, break; } case MMC_CMD_READ_SINGLE_BLOCK: - memset(data->dest, '\0', data->blocksize); - break; case MMC_CMD_READ_MULTIPLE_BLOCK: - strcpy(data->dest, "this is a test"); + memcpy(data->dest, &priv->buf[cmd->cmdarg * data->blocksize], + data->blocks * data->blocksize); + break; + case MMC_CMD_WRITE_SINGLE_BLOCK: + case MMC_CMD_WRITE_MULTIPLE_BLOCK: + memcpy(&priv->buf[cmd->cmdarg * data->blocksize], data->src, + data->blocks * data->blocksize); break; case MMC_CMD_STOP_TRANSMISSION: break; + case SD_CMD_ERASE_WR_BLK_START: + erase_start = cmd->cmdarg; + break; + case SD_CMD_ERASE_WR_BLK_END: + erase_end = cmd->cmdarg; + break; + case MMC_CMD_ERASE: + memset(&priv->buf[erase_start * mmc->write_bl_len], '\0', + (erase_end - erase_start + 1) * mmc->write_bl_len); + break; case SD_CMD_APP_SEND_OP_COND: cmd->response[0] = OCR_BUSY | OCR_HCS; cmd->response[1] = 0; @@ -148,5 +178,6 @@ U_BOOT_DRIVER(mmc_sandbox) = { .bind = sandbox_mmc_bind, .unbind = sandbox_mmc_unbind, .probe = sandbox_mmc_probe, - .plat_auto = sizeof(struct sandbox_mmc_plat), + .priv_auto = sizeof(struct sandbox_mmc_priv), + .plat_auto = sizeof(struct sandbox_mmc_plat), }; diff --git a/test/dm/mmc.c b/test/dm/mmc.c index 4e5136c850..f744452ff2 100644 --- a/test/dm/mmc.c +++ b/test/dm/mmc.c @@ -29,16 +29,25 @@ static int dm_test_mmc_blk(struct unit_test_state *uts) { struct udevice *dev; struct blk_desc *dev_desc; - char cmp[1024]; + int i; + char write[1024], read[1024]; ut_assertok(uclass_get_device(UCLASS_MMC, 0, &dev)); ut_assertok(blk_get_device_by_str("mmc", "0", &dev_desc)); - /* Read a few blocks and look for the string we expect */ + /* Write a few blocks and verify that we get the same data back */ ut_asserteq(512, dev_desc->blksz); - memset(cmp, '\0', sizeof(cmp)); - ut_asserteq(2, blk_dread(dev_desc, 0, 2, cmp)); - ut_assertok(strcmp(cmp, "this is a test")); + for (i = 0; i < sizeof(write); i++) + write[i] = i; + ut_asserteq(2, blk_dwrite(dev_desc, 0, 2, write)); + ut_asserteq(2, blk_dread(dev_desc, 0, 2, read)); + ut_asserteq_mem(write, read, sizeof(write)); + + /* Now erase them */ + memset(write, '\0', sizeof(write)); + ut_asserteq(2, blk_derase(dev_desc, 0, 2)); + ut_asserteq(2, blk_dread(dev_desc, 0, 2, read)); + ut_asserteq_mem(write, read, sizeof(write)); return 0; } From d4f22cb39e92ebfce74003b5779d6d6addc797e2 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Fri, 5 Feb 2021 09:38:54 -0500 Subject: [PATCH 02/13] test: dm: Add test for fastboot mmc partition naming This test verifies the mapping between fastboot partitions and partitions as understood by U-Boot. It also tests the creation of GPT partitions, though that is not the primary goal. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass --- configs/sandbox64_defconfig | 2 ++ configs/sandbox_defconfig | 2 ++ test/dm/Makefile | 3 ++ test/dm/fastboot.c | 64 +++++++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+) create mode 100644 test/dm/fastboot.c diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig index 634c19502c..cfda83474b 100644 --- a/configs/sandbox64_defconfig +++ b/configs/sandbox64_defconfig @@ -111,6 +111,8 @@ CONFIG_DM_DEMO=y CONFIG_DM_DEMO_SIMPLE=y CONFIG_DM_DEMO_SHAPE=y CONFIG_DFU_SF=y +CONFIG_FASTBOOT_FLASH=y +CONFIG_FASTBOOT_FLASH_MMC_DEV=0 CONFIG_GPIO_HOG=y CONFIG_DM_GPIO_LOOKUP_LABEL=y CONFIG_PM8916_GPIO=y diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index a485b38f41..5bc90d09a8 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -137,6 +137,8 @@ CONFIG_DFU_SF=y CONFIG_DMA=y CONFIG_DMA_CHANNELS=y CONFIG_SANDBOX_DMA=y +CONFIG_FASTBOOT_FLASH=y +CONFIG_FASTBOOT_FLASH_MMC_DEV=0 CONFIG_GPIO_HOG=y CONFIG_DM_GPIO_LOOKUP_LABEL=y CONFIG_PM8916_GPIO=y diff --git a/test/dm/Makefile b/test/dm/Makefile index 6275ec56ea..fd1455109d 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -95,5 +95,8 @@ obj-$(CONFIG_SCMI_FIRMWARE) += scmi.o ifneq ($(CONFIG_PINMUX),) obj-$(CONFIG_PINCONF) += pinmux.o endif +ifneq ($(CONFIG_EFI_PARTITION),) +obj-$(CONFIG_FASTBOOT_FLASH_MMC) += fastboot.o +endif endif endif # !SPL diff --git a/test/dm/fastboot.c b/test/dm/fastboot.c new file mode 100644 index 0000000000..8f905d8fa8 --- /dev/null +++ b/test/dm/fastboot.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2015 Google, Inc + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FB_ALIAS_PREFIX "fastboot_partition_alias_" + +static int dm_test_fastboot_mmc_part(struct unit_test_state *uts) +{ + char response[FASTBOOT_RESPONSE_LEN] = {0}; + char str_disk_guid[UUID_STR_LEN + 1]; + struct blk_desc *mmc_dev_desc, *fb_dev_desc; + struct disk_partition part_info; + struct disk_partition parts[2] = { + { + .start = 48, /* GPT data takes up the first 34 blocks or so */ + .size = 1, + .name = "test1", + }, + { + .start = 49, + .size = 1, + .name = "test2", + }, + }; + + ut_assertok(blk_get_device_by_str("mmc", + __stringify(CONFIG_FASTBOOT_FLASH_MMC_DEV), + &mmc_dev_desc)); + if (CONFIG_IS_ENABLED(RANDOM_UUID)) { + gen_rand_uuid_str(parts[0].uuid, UUID_STR_FORMAT_STD); + gen_rand_uuid_str(parts[1].uuid, UUID_STR_FORMAT_STD); + gen_rand_uuid_str(str_disk_guid, UUID_STR_FORMAT_STD); + } + ut_assertok(gpt_restore(mmc_dev_desc, str_disk_guid, parts, + ARRAY_SIZE(parts))); + + /* "Classic" partition labels */ + ut_asserteq(1, fastboot_mmc_get_part_info("test1", &fb_dev_desc, + &part_info, response)); + ut_asserteq(2, fastboot_mmc_get_part_info("test2", &fb_dev_desc, + &part_info, response)); + + /* Test aliases */ + ut_assertnull(env_get(FB_ALIAS_PREFIX "test3")); + ut_assertok(env_set(FB_ALIAS_PREFIX "test3", "test1")); + ut_asserteq(1, fastboot_mmc_get_part_info("test3", &fb_dev_desc, + &part_info, response)); + ut_assertok(env_set(FB_ALIAS_PREFIX "test3", NULL)); + + return 0; +} +DM_TEST(dm_test_fastboot_mmc_part, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); From 59715754e1d1d9279f38d70df1c3c2949a5e5203 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Fri, 5 Feb 2021 09:38:55 -0500 Subject: [PATCH 03/13] part: Give several functions more useful return values Several functions in disk/part.c just return -1 on error. This makes them return different errnos for different failures. This helps callers differentiate between failures, even if they cannot read stdout. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass --- disk/part.c | 50 ++++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/disk/part.c b/disk/part.c index 85b1af55e2..2a6b85e81b 100644 --- a/disk/part.c +++ b/disk/part.c @@ -355,7 +355,7 @@ int part_get_info(struct blk_desc *dev_desc, int part, } #endif /* CONFIG_HAVE_BLOCK_DEVICE */ - return -1; + return -ENOENT; } int part_get_info_whole_disk(struct blk_desc *dev_desc, @@ -417,7 +417,7 @@ int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str, *dev_desc = get_dev_hwpart(ifname, dev, hwpart); if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) { debug("** Bad device %s %s **\n", ifname, dev_hwpart_str); - dev = -ENOENT; + dev = -ENODEV; goto cleanup; } @@ -441,7 +441,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str, struct blk_desc **dev_desc, struct disk_partition *info, int allow_whole_dev) { - int ret = -1; + int ret; const char *part_str; char *dup_str = NULL; const char *dev_str; @@ -483,7 +483,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str, if (0 == strcmp(ifname, "ubi")) { if (!ubifs_is_mounted()) { printf("UBIFS not mounted, use ubifsmount to mount volume first!\n"); - return -1; + return -EINVAL; } *dev_desc = NULL; @@ -505,6 +505,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str, /* If still no dev_part_str, it's an error */ if (!dev_part_str) { printf("** No device specified **\n"); + ret = -ENODEV; goto cleanup; } @@ -521,8 +522,10 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str, /* Look up the device */ dev = blk_get_device_by_str(ifname, dev_str, dev_desc); - if (dev < 0) + if (dev < 0) { + ret = dev; goto cleanup; + } /* Convert partition ID string to number */ if (!part_str || !*part_str) { @@ -539,6 +542,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str, if (*ep || (part == 0 && !allow_whole_dev)) { printf("** Bad partition specification %s %s **\n", ifname, dev_part_str); + ret = -ENOENT; goto cleanup; } } @@ -552,6 +556,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str, if (!(*dev_desc)->lba) { printf("** Bad device size - %s %s **\n", ifname, dev_str); + ret = -EINVAL; goto cleanup; } @@ -563,6 +568,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str, if ((part > 0) || (!allow_whole_dev)) { printf("** No partition table - %s %s **\n", ifname, dev_str); + ret = -EPROTONOSUPPORT; goto cleanup; } @@ -631,7 +637,6 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str, *info = tmpinfo; } else { printf("** No valid partitions found **\n"); - ret = -1; goto cleanup; } } @@ -639,7 +644,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str, printf("** Invalid partition type \"%.32s\"" " (expect \"" BOOT_PART_TYPE "\")\n", info->type); - ret = -1; + ret = -EINVAL; goto cleanup; } @@ -675,7 +680,7 @@ int part_get_info_by_name_type(struct blk_desc *dev_desc, const char *name, } } - return -1; + return -ENOENT; } int part_get_info_by_name(struct blk_desc *dev_desc, const char *name, @@ -705,7 +710,7 @@ static int part_get_info_by_dev_and_name(const char *dev_iface, { char *ep; const char *part_str; - int dev_num; + int dev_num, ret; part_str = strchr(dev_part_str, '#'); if (!part_str || part_str == dev_part_str) @@ -721,13 +726,12 @@ static int part_get_info_by_dev_and_name(const char *dev_iface, *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; + return -ENODEV; } - if (part_get_info_by_name(*dev_desc, part_str, part_info) < 0) { + ret = part_get_info_by_name(*dev_desc, part_str, part_info); + if (ret < 0) printf("Could not find \"%s\" partition\n", part_str); - return -EINVAL; - } - return 0; + return ret; } int part_get_info_by_dev_and_name_or_num(const char *dev_iface, @@ -735,21 +739,23 @@ int part_get_info_by_dev_and_name_or_num(const char *dev_iface, struct blk_desc **dev_desc, struct disk_partition *part_info) { + int ret; + /* 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; + ret = part_get_info_by_dev_and_name(dev_iface, dev_part_str, + dev_desc, part_info); + if (ret >= 0) + return ret; /* * 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) { + ret = blk_get_device_part_str(dev_iface, dev_part_str, + dev_desc, part_info, 1); + if (ret < 0) printf("Couldn't find partition %s %s\n", dev_iface, dev_part_str); - return -EINVAL; - } - return 0; + return ret; } void part_set_generic_name(const struct blk_desc *dev_desc, From 9f7bb2825b81680c0bc3cb4b0376e6a230501242 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Fri, 5 Feb 2021 09:38:56 -0500 Subject: [PATCH 04/13] part: Support getting whole disk from part_get_info_by_dev_and_name_or_num This adds an option to part_get_info_by_dev_and_name_or_num to allow callers to specify whether whole-disk partitions are fine. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass --- cmd/ab_select.c | 3 ++- disk/part.c | 5 +++-- include/part.h | 6 +++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cmd/ab_select.c b/cmd/ab_select.c index 6298fcfb60..3e46663d6e 100644 --- a/cmd/ab_select.c +++ b/cmd/ab_select.c @@ -22,7 +22,8 @@ static int do_ab_select(struct cmd_tbl *cmdtp, int flag, int argc, /* Lookup the "misc" partition from argv[2] and argv[3] */ if (part_get_info_by_dev_and_name_or_num(argv[2], argv[3], - &dev_desc, &part_info) < 0) { + &dev_desc, &part_info, + false) < 0) { return CMD_RET_FAILURE; } diff --git a/disk/part.c b/disk/part.c index 2a6b85e81b..03f283307f 100644 --- a/disk/part.c +++ b/disk/part.c @@ -737,7 +737,8 @@ static int part_get_info_by_dev_and_name(const char *dev_iface, 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) + struct disk_partition *part_info, + int allow_whole_dev) { int ret; @@ -751,7 +752,7 @@ int part_get_info_by_dev_and_name_or_num(const char *dev_iface, * directly. */ ret = blk_get_device_part_str(dev_iface, dev_part_str, - dev_desc, part_info, 1); + dev_desc, part_info, allow_whole_dev); if (ret < 0) printf("Couldn't find partition %s %s\n", dev_iface, dev_part_str); diff --git a/include/part.h b/include/part.h index 815515aa80..7f78271a98 100644 --- a/include/part.h +++ b/include/part.h @@ -227,12 +227,16 @@ int part_get_info_by_name(struct blk_desc *dev_desc, * @param[in] dev_part_str Input partition description, like "0#misc" or "0:1" * @param[out] dev_desc Place to store the device description pointer * @param[out] part_info Place to store the partition information + * @param[in] allow_whole_dev true to allow the user to select partition 0 + * (which means the whole device), false to require a valid + * partition number >= 1 * @return 0 on success, or a negative on error */ 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); + struct disk_partition *part_info, + int allow_whole_dev); /** * part_set_generic_name() - create generic partition like hda1 or sdb2 From 81c1aa89e17a73a899e0e55a3459f236909f2baf Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Fri, 5 Feb 2021 09:38:57 -0500 Subject: [PATCH 05/13] part: Support string block devices in part_get_info_by_dev_and_name This adds support for things like "#partname" and "0.1#partname". The block device parsing is done like in blk_get_device_part_str. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass --- disk/part.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/disk/part.c b/disk/part.c index 03f283307f..80ced2ba88 100644 --- a/disk/part.c +++ b/disk/part.c @@ -693,12 +693,13 @@ int part_get_info_by_name(struct blk_desc *dev_desc, const char *name, * 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. + * "devicenum.hwpartnum#partition_name", for example "0.1#misc". devicenum and + * hwpartnum are both optional, defaulting to 0. 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[in] dev_part_str Input string argument, like "0.1#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 @@ -708,29 +709,31 @@ static int part_get_info_by_dev_and_name(const char *dev_iface, struct blk_desc **dev_desc, struct disk_partition *part_info) { - char *ep; - const char *part_str; - int dev_num, ret; + char *dup_str = NULL; + const char *dev_str, *part_str; + int ret; + /* Separate device and partition name specification */ 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. */ + if (part_str) { + dup_str = strdup(dev_part_str); + dup_str[part_str - dev_part_str] = 0; + dev_str = dup_str; + part_str++; + } else { 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 -ENODEV; - } + ret = blk_get_device_by_str(dev_iface, dev_str, dev_desc); + if (ret) + goto cleanup; + ret = part_get_info_by_name(*dev_desc, part_str, part_info); if (ret < 0) printf("Could not find \"%s\" partition\n", part_str); + +cleanup: + free(dup_str); return ret; } From f3cf964f2d3588281342469b9bf722fea90daa0c Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Fri, 5 Feb 2021 09:38:58 -0500 Subject: [PATCH 06/13] fastboot: Remove mmcpart argument from raw_part_get_info_by_name The only thing mmcpart was used for was to pass to blk_dselect_hwpart. This calls blk_dselect_hwpart directly from raw_part_get_info_by_name. The error handling is dropped, but it is reintroduced in the next commit (albeit less specificly). Signed-off-by: Sean Anderson Reviewed-by: Simon Glass --- drivers/fastboot/fb_mmc.c | 41 +++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c index 50532acb84..75347bb99b 100644 --- a/drivers/fastboot/fb_mmc.c +++ b/drivers/fastboot/fb_mmc.c @@ -51,7 +51,8 @@ static int part_get_info_by_name_or_alias(struct blk_desc *dev_desc, } static int raw_part_get_info_by_name(struct blk_desc *dev_desc, - const char *name, struct disk_partition *info, int *mmcpart) + const char *name, + struct disk_partition *info) { /* strlen("fastboot_raw_partition_") + PART_NAME_LEN + 1 */ char env_desc_name[23 + PART_NAME_LEN + 1]; @@ -85,8 +86,13 @@ static int raw_part_get_info_by_name(struct blk_desc *dev_desc, strncpy((char *)info->name, name, PART_NAME_LEN); if (raw_part_desc) { - if (strcmp(strsep(&raw_part_desc, " "), "mmcpart") == 0) - *mmcpart = simple_strtoul(raw_part_desc, NULL, 0); + if (strcmp(strsep(&raw_part_desc, " "), "mmcpart") == 0) { + ulong mmcpart = simple_strtoul(raw_part_desc, NULL, 0); + int ret = blk_dselect_hwpart(dev_desc, mmcpart); + + if (ret) + return ret; + } } return 0; @@ -425,7 +431,6 @@ int fastboot_mmc_get_part_info(const char *part_name, struct disk_partition *part_info, char *response) { int r = 0; - int mmcpart; *dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV); if (!*dev_desc) { @@ -437,7 +442,7 @@ int fastboot_mmc_get_part_info(const char *part_name, return -ENOENT; } - if (raw_part_get_info_by_name(*dev_desc, part_name, part_info, &mmcpart) < 0) { + if (raw_part_get_info_by_name(*dev_desc, part_name, part_info) < 0) { r = part_get_info_by_name_or_alias(*dev_desc, part_name, part_info); if (r < 0) { fastboot_fail("partition not found", response); @@ -461,7 +466,6 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer, { struct blk_desc *dev_desc; struct disk_partition info; - int mmcpart = 0; dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV); if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) { @@ -541,16 +545,12 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer, } #endif - if (raw_part_get_info_by_name(dev_desc, cmd, &info, &mmcpart) == 0) { - if (blk_dselect_hwpart(dev_desc, mmcpart)) { - pr_err("Failed to select hwpart\n"); - fastboot_fail("Failed to select hwpart", response); + if (raw_part_get_info_by_name(dev_desc, cmd, &info) != 0) { + if (part_get_info_by_name_or_alias(dev_desc, cmd, &info) < 0) { + pr_err("cannot find partition: '%s'\n", cmd); + fastboot_fail("cannot find partition", response); return; } - } else if (part_get_info_by_name_or_alias(dev_desc, cmd, &info) < 0) { - pr_err("cannot find partition: '%s'\n", cmd); - fastboot_fail("cannot find partition", response); - return; } if (is_sparse_image(download_buffer)) { @@ -593,7 +593,6 @@ void fastboot_mmc_erase(const char *cmd, char *response) struct disk_partition info; lbaint_t blks, blks_start, blks_size, grp_size; struct mmc *mmc = find_mmc_device(CONFIG_FASTBOOT_FLASH_MMC_DEV); - int mmcpart = 0; if (mmc == NULL) { pr_err("invalid mmc device\n"); @@ -632,16 +631,12 @@ void fastboot_mmc_erase(const char *cmd, char *response) } #endif - if (raw_part_get_info_by_name(dev_desc, cmd, &info, &mmcpart) == 0) { - if (blk_dselect_hwpart(dev_desc, mmcpart)) { - pr_err("Failed to select hwpart\n"); - fastboot_fail("Failed to select hwpart", response); + if (raw_part_get_info_by_name(dev_desc, cmd, &info) != 0) { + if (part_get_info_by_name_or_alias(dev_desc, cmd, &info) < 0) { + pr_err("cannot find partition: '%s'\n", cmd); + fastboot_fail("cannot find partition", response); return; } - } else if (part_get_info_by_name_or_alias(dev_desc, cmd, &info) < 0) { - pr_err("cannot find partition: '%s'\n", cmd); - fastboot_fail("cannot find partition", response); - return; } /* Align blocks to erase group size to avoid erasing other partitions */ From ae5e6b4e8f91c4de7814c0308097b05c8e5358a1 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Fri, 5 Feb 2021 09:38:59 -0500 Subject: [PATCH 07/13] fastboot: Move part_get_info_by_name_or_alias after raw_part_get_info_by_name This makes the next commit more readable by doing the move now. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass --- drivers/fastboot/fb_mmc.c | 44 +++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c index 75347bb99b..71eeb02c8f 100644 --- a/drivers/fastboot/fb_mmc.c +++ b/drivers/fastboot/fb_mmc.c @@ -28,28 +28,6 @@ struct fb_mmc_sparse { struct blk_desc *dev_desc; }; -static int part_get_info_by_name_or_alias(struct blk_desc *dev_desc, - const char *name, struct disk_partition *info) -{ - int ret; - - ret = part_get_info_by_name(dev_desc, name, info); - if (ret < 0) { - /* strlen("fastboot_partition_alias_") + PART_NAME_LEN + 1 */ - char env_alias_name[25 + PART_NAME_LEN + 1]; - char *aliased_part_name; - - /* check for alias */ - strcpy(env_alias_name, "fastboot_partition_alias_"); - strncat(env_alias_name, name, PART_NAME_LEN); - aliased_part_name = env_get(env_alias_name); - if (aliased_part_name != NULL) - ret = part_get_info_by_name(dev_desc, - aliased_part_name, info); - } - return ret; -} - static int raw_part_get_info_by_name(struct blk_desc *dev_desc, const char *name, struct disk_partition *info) @@ -98,6 +76,28 @@ static int raw_part_get_info_by_name(struct blk_desc *dev_desc, return 0; } +static int part_get_info_by_name_or_alias(struct blk_desc *dev_desc, + const char *name, struct disk_partition *info) +{ + int ret; + + ret = part_get_info_by_name(dev_desc, name, info); + if (ret < 0) { + /* strlen("fastboot_partition_alias_") + PART_NAME_LEN + 1 */ + char env_alias_name[25 + PART_NAME_LEN + 1]; + char *aliased_part_name; + + /* check for alias */ + strcpy(env_alias_name, "fastboot_partition_alias_"); + strncat(env_alias_name, name, PART_NAME_LEN); + aliased_part_name = env_get(env_alias_name); + if (aliased_part_name != NULL) + ret = part_get_info_by_name(dev_desc, + aliased_part_name, info); + } + return ret; +} + /** * fb_mmc_blk_write() - Write/erase MMC in chunks of FASTBOOT_MAX_BLK_WRITE * From de1728ce4c86e77fd77e0b4f4f16eecaf8c00f8d Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Fri, 5 Feb 2021 09:39:00 -0500 Subject: [PATCH 08/13] fastboot: Allow u-boot-style partitions This adds support for partitions of the form "dev.hwpart:part" and "dev#partname". This allows one to flash to eMMC boot partitions without having to use CONFIG_FASTBOOT_MMC_BOOT1_SUPPORT. It also allows one to flash to an entire device without needing CONFIG_FASTBOOT_MMC_USER_NAME. Lastly, one can also flash MMC devices other than CONFIG_FASTBOOT_FLASH_MMC_DEV. Because devices can be specified explicitly, CONFIG_FASTBOOT_FLASH_MMC_DEV is used only when necessary for existing functionality. For those cases, fastboot_mmc_get_dev has been added as a helper function. This allows There should be no conflicts with the existing system, but just in case, I have ordered detection of these names after all existing names. The fastboot_mmc_part test has been updated for these new names. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass --- drivers/fastboot/fb_mmc.c | 157 ++++++++++++++++++++++++-------------- test/dm/fastboot.c | 37 ++++++++- 2 files changed, 132 insertions(+), 62 deletions(-) diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c index 71eeb02c8f..8e74e50e91 100644 --- a/drivers/fastboot/fb_mmc.c +++ b/drivers/fastboot/fb_mmc.c @@ -76,12 +76,37 @@ static int raw_part_get_info_by_name(struct blk_desc *dev_desc, return 0; } -static int part_get_info_by_name_or_alias(struct blk_desc *dev_desc, - const char *name, struct disk_partition *info) +static int do_get_part_info(struct blk_desc **dev_desc, const char *name, + struct disk_partition *info) { int ret; - ret = part_get_info_by_name(dev_desc, name, info); + /* First try partition names on the default device */ + *dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV); + if (*dev_desc) { + ret = part_get_info_by_name(*dev_desc, name, info); + if (ret >= 0) + return ret; + + /* Then try raw partitions */ + ret = raw_part_get_info_by_name(*dev_desc, name, info); + if (ret >= 0) + return ret; + } + + /* Then try dev.hwpart:part */ + ret = part_get_info_by_dev_and_name_or_num("mmc", name, dev_desc, + info, true); + return ret; +} + +static int part_get_info_by_name_or_alias(struct blk_desc **dev_desc, + const char *name, + struct disk_partition *info) +{ + int ret; + + ret = do_get_part_info(dev_desc, name, info); if (ret < 0) { /* strlen("fastboot_partition_alias_") + PART_NAME_LEN + 1 */ char env_alias_name[25 + PART_NAME_LEN + 1]; @@ -92,8 +117,8 @@ static int part_get_info_by_name_or_alias(struct blk_desc *dev_desc, strncat(env_alias_name, name, PART_NAME_LEN); aliased_part_name = env_get(env_alias_name); if (aliased_part_name != NULL) - ret = part_get_info_by_name(dev_desc, - aliased_part_name, info); + ret = do_get_part_info(dev_desc, aliased_part_name, + info); } return ret; } @@ -430,27 +455,49 @@ int fastboot_mmc_get_part_info(const char *part_name, struct blk_desc **dev_desc, struct disk_partition *part_info, char *response) { - int r = 0; + int ret; - *dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV); - if (!*dev_desc) { - fastboot_fail("block device not found", response); - return -ENOENT; - } if (!part_name || !strcmp(part_name, "")) { fastboot_fail("partition not given", response); return -ENOENT; } - if (raw_part_get_info_by_name(*dev_desc, part_name, part_info) < 0) { - r = part_get_info_by_name_or_alias(*dev_desc, part_name, part_info); - if (r < 0) { - fastboot_fail("partition not found", response); - return r; + ret = part_get_info_by_name_or_alias(dev_desc, part_name, part_info); + if (ret < 0) { + switch (ret) { + case -ENOSYS: + case -EINVAL: + fastboot_fail("invalid partition or device", response); + break; + case -ENODEV: + fastboot_fail("no such device", response); + break; + case -ENOENT: + fastboot_fail("no such partition", response); + break; + case -EPROTONOSUPPORT: + fastboot_fail("unknown partition table type", response); + break; + default: + fastboot_fail("unanticipated error", response); + break; } } - return r; + return ret; +} + +static struct blk_desc *fastboot_mmc_get_dev(char *response) +{ + struct blk_desc *ret = blk_get_dev("mmc", + CONFIG_FASTBOOT_FLASH_MMC_DEV); + + if (!ret || ret->type == DEV_TYPE_UNKNOWN) { + pr_err("invalid mmc device\n"); + fastboot_fail("invalid mmc device", response); + return NULL; + } + return ret; } /** @@ -467,22 +514,19 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer, struct blk_desc *dev_desc; struct disk_partition info; - dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV); - if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) { - pr_err("invalid mmc device\n"); - fastboot_fail("invalid mmc device", response); - return; - } - #ifdef CONFIG_FASTBOOT_MMC_BOOT_SUPPORT if (strcmp(cmd, CONFIG_FASTBOOT_MMC_BOOT1_NAME) == 0) { - fb_mmc_boot_ops(dev_desc, download_buffer, 1, - download_bytes, response); + dev_desc = fastboot_mmc_get_dev(response); + if (dev_desc) + fb_mmc_boot_ops(dev_desc, download_buffer, 1, + download_bytes, response); return; } if (strcmp(cmd, CONFIG_FASTBOOT_MMC_BOOT2_NAME) == 0) { - fb_mmc_boot_ops(dev_desc, download_buffer, 2, - download_bytes, response); + dev_desc = fastboot_mmc_get_dev(response); + if (dev_desc) + fb_mmc_boot_ops(dev_desc, download_buffer, 1, + download_bytes, response); return; } #endif @@ -494,6 +538,10 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer, if (strcmp(cmd, CONFIG_FASTBOOT_GPT_NAME) == 0 || strcmp(cmd, CONFIG_FASTBOOT_MMC_USER_NAME) == 0) { #endif + dev_desc = fastboot_mmc_get_dev(response); + if (!dev_desc) + return; + printf("%s: updating MBR, Primary and Backup GPT(s)\n", __func__); if (is_valid_gpt_buf(dev_desc, download_buffer)) { @@ -517,6 +565,10 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer, #if CONFIG_IS_ENABLED(DOS_PARTITION) if (strcmp(cmd, CONFIG_FASTBOOT_MBR_NAME) == 0) { + dev_desc = fastboot_mmc_get_dev(response); + if (!dev_desc) + return; + printf("%s: updating MBR\n", __func__); if (is_valid_dos_buf(download_buffer)) { printf("%s: invalid MBR - refusing to write to flash\n", @@ -539,19 +591,16 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer, #ifdef CONFIG_ANDROID_BOOT_IMAGE if (strncasecmp(cmd, "zimage", 6) == 0) { - fb_mmc_update_zimage(dev_desc, download_buffer, - download_bytes, response); + dev_desc = fastboot_mmc_get_dev(response); + if (dev_desc) + fb_mmc_update_zimage(dev_desc, download_buffer, + download_bytes, response); return; } #endif - if (raw_part_get_info_by_name(dev_desc, cmd, &info) != 0) { - if (part_get_info_by_name_or_alias(dev_desc, cmd, &info) < 0) { - pr_err("cannot find partition: '%s'\n", cmd); - fastboot_fail("cannot find partition", response); - return; - } - } + if (fastboot_mmc_get_part_info(cmd, &dev_desc, &info, response) < 0) + return; if (is_sparse_image(download_buffer)) { struct fb_mmc_sparse sparse_priv; @@ -594,28 +643,19 @@ void fastboot_mmc_erase(const char *cmd, char *response) lbaint_t blks, blks_start, blks_size, grp_size; struct mmc *mmc = find_mmc_device(CONFIG_FASTBOOT_FLASH_MMC_DEV); - if (mmc == NULL) { - pr_err("invalid mmc device\n"); - fastboot_fail("invalid mmc device", response); - return; - } - - dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV); - if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) { - pr_err("invalid mmc device\n"); - fastboot_fail("invalid mmc device", response); - return; - } - #ifdef CONFIG_FASTBOOT_MMC_BOOT_SUPPORT if (strcmp(cmd, CONFIG_FASTBOOT_MMC_BOOT1_NAME) == 0) { /* erase EMMC boot1 */ - fb_mmc_boot_ops(dev_desc, NULL, 1, 0, response); + dev_desc = fastboot_mmc_get_dev(response); + if (dev_desc) + fb_mmc_boot_ops(dev_desc, NULL, 1, 0, response); return; } if (strcmp(cmd, CONFIG_FASTBOOT_MMC_BOOT2_NAME) == 0) { /* erase EMMC boot2 */ - fb_mmc_boot_ops(dev_desc, NULL, 2, 0, response); + dev_desc = fastboot_mmc_get_dev(response); + if (dev_desc) + fb_mmc_boot_ops(dev_desc, NULL, 1, 0, response); return; } #endif @@ -623,6 +663,10 @@ void fastboot_mmc_erase(const char *cmd, char *response) #ifdef CONFIG_FASTBOOT_MMC_USER_SUPPORT if (strcmp(cmd, CONFIG_FASTBOOT_MMC_USER_NAME) == 0) { /* erase EMMC userdata */ + dev_desc = fastboot_mmc_get_dev(response); + if (!dev_desc) + return; + if (fb_mmc_erase_mmc_hwpart(dev_desc)) fastboot_fail("Failed to erase EMMC_USER", response); else @@ -631,13 +675,8 @@ void fastboot_mmc_erase(const char *cmd, char *response) } #endif - if (raw_part_get_info_by_name(dev_desc, cmd, &info) != 0) { - if (part_get_info_by_name_or_alias(dev_desc, cmd, &info) < 0) { - pr_err("cannot find partition: '%s'\n", cmd); - fastboot_fail("cannot find partition", response); - return; - } - } + if (fastboot_mmc_get_part_info(cmd, &dev_desc, &info, response) < 0) + return; /* Align blocks to erase group size to avoid erasing other partitions */ grp_size = mmc->erase_grp_size; diff --git a/test/dm/fastboot.c b/test/dm/fastboot.c index 8f905d8fa8..e7f8c362b8 100644 --- a/test/dm/fastboot.c +++ b/test/dm/fastboot.c @@ -35,9 +35,12 @@ static int dm_test_fastboot_mmc_part(struct unit_test_state *uts) }, }; - ut_assertok(blk_get_device_by_str("mmc", - __stringify(CONFIG_FASTBOOT_FLASH_MMC_DEV), - &mmc_dev_desc)); + /* + * There are a lot of literal 0s I don't want to have to construct from + * MMC_DEV. + */ + ut_asserteq(0, CONFIG_FASTBOOT_FLASH_MMC_DEV); + ut_assertok(blk_get_device_by_str("mmc", "0", &mmc_dev_desc)); if (CONFIG_IS_ENABLED(RANDOM_UUID)) { gen_rand_uuid_str(parts[0].uuid, UUID_STR_FORMAT_STD); gen_rand_uuid_str(parts[1].uuid, UUID_STR_FORMAT_STD); @@ -59,6 +62,34 @@ static int dm_test_fastboot_mmc_part(struct unit_test_state *uts) &part_info, response)); ut_assertok(env_set(FB_ALIAS_PREFIX "test3", NULL)); + /* "New" partition labels */ + ut_asserteq(1, fastboot_mmc_get_part_info("#test1", &fb_dev_desc, + &part_info, response)); + ut_asserteq(1, fastboot_mmc_get_part_info("0#test1", &fb_dev_desc, + &part_info, response)); + ut_asserteq(1, fastboot_mmc_get_part_info("0.0#test1", &fb_dev_desc, + &part_info, response)); + ut_asserteq(1, fastboot_mmc_get_part_info("0:1", &fb_dev_desc, + &part_info, response)); + ut_asserteq(1, fastboot_mmc_get_part_info("0.0:1", &fb_dev_desc, + &part_info, response)); + ut_asserteq(1, fastboot_mmc_get_part_info("0", &fb_dev_desc, + &part_info, response)); + ut_asserteq(1, fastboot_mmc_get_part_info("0.0", &fb_dev_desc, + &part_info, response)); + ut_asserteq(0, fastboot_mmc_get_part_info("0:0", &fb_dev_desc, + &part_info, response)); + ut_asserteq(0, fastboot_mmc_get_part_info("0.0:0", &fb_dev_desc, + &part_info, response)); + ut_asserteq(0, fastboot_mmc_get_part_info("1", &fb_dev_desc, + &part_info, response)); + ut_asserteq(0, fastboot_mmc_get_part_info("1.0", &fb_dev_desc, + &part_info, response)); + ut_asserteq(1, fastboot_mmc_get_part_info(":1", &fb_dev_desc, + &part_info, response)); + ut_asserteq(0, fastboot_mmc_get_part_info(":0", &fb_dev_desc, + &part_info, response)); + return 0; } DM_TEST(dm_test_fastboot_mmc_part, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); From 1500c79dc3b1c67c492abec14badbb8efc576478 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Fri, 5 Feb 2021 09:39:01 -0500 Subject: [PATCH 09/13] doc: Rename k210 partitions anchor This anchor is only for the k210 partition layout, so rename it appropriately. This keeps it from conflicting with the (to be added) anchor for U-Boot partitions in general. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass --- doc/board/sipeed/maix.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/board/sipeed/maix.rst b/doc/board/sipeed/maix.rst index bf945b3458..ef79297ef0 100644 --- a/doc/board/sipeed/maix.rst +++ b/doc/board/sipeed/maix.rst @@ -258,7 +258,7 @@ SPI Flash """"""""" To load an image off of SPI flash, first set up a partition as described in -:ref:`partitions`. Then, use ``mtd`` to load that partition +:ref:`k210_partitions`. Then, use ``mtd`` to load that partition .. code-block:: none @@ -401,7 +401,7 @@ Sipeed MAIX boards typically provide around 16 MiB of SPI NOR flash. U-Boot is stored in the first 1 MiB or so of this flash. U-Boot's environment is stored at the end of flash. -.. _partitions: +.. _k210_partitions: Partitions """""""""" From 403c2e46b4e99e87901f90fb879081e5baa6bb0b Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Fri, 5 Feb 2021 09:39:02 -0500 Subject: [PATCH 10/13] doc: Document partition specifications This documents the way U-Boot understands partitions specifications. This also updates the fastboot documentation for the changes in the previous commit. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass --- doc/android/fastboot.rst | 4 ++ doc/usage/index.rst | 1 + doc/usage/partitions.rst | 80 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 doc/usage/partitions.rst diff --git a/doc/android/fastboot.rst b/doc/android/fastboot.rst index 16b11399b3..ce513a2a0f 100644 --- a/doc/android/fastboot.rst +++ b/doc/android/fastboot.rst @@ -154,6 +154,10 @@ The device index starts from ``a`` and refers to the interface (e.g. USB controller, SD/MMC controller) or disk index. The partition index starts from ``1`` and describes the partition number on the particular device. +Alternatively, partition types may be specified using :ref:`U-Boot's partition +syntax `. This allows specifying partitions like ``0.1``, +``0#boot``, or ``:3``. The interface is always ``mmc``. + Writing Partition Table ----------------------- diff --git a/doc/usage/index.rst b/doc/usage/index.rst index a8842bf9fb..09372d4a96 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -6,6 +6,7 @@ Use U-Boot fdt_overlays netconsole + partitions Shell commands -------------- diff --git a/doc/usage/partitions.rst b/doc/usage/partitions.rst new file mode 100644 index 0000000000..2c1a12b6bf --- /dev/null +++ b/doc/usage/partitions.rst @@ -0,0 +1,80 @@ +.. SPDX-License-Identifier: GPL-2.0+ +.. _partitions: + +Partitions +========== + +Synopsis +-------- + +:: + + [devnum][.hwpartnum][:partnum|#partname] + +Description +----------- + +Many U-Boot commands allow specifying partitions (or whole disks) using a +generic syntax. + +interface + The interface used to access the partition's device, like ``mmc`` or + ``scsi``. For a full list of supported interfaces, consult the + ``if_typename_str`` array in ``drivers/block/blk-uclass.c`` + +devnum + The device number. This defaults to 0. + +hwpartnum + The hardware partition number. All devices have at least one hardware + partition. On most devices, hardware partition 0 specifies the whole + device. On eMMC devices, hardware partition 0 is the user partition, + hardware partitions 1 and 2 are the boot partitions, hardware partition + 3 is the RPMB partition, and further partitions are general-purpose + user-created partitions. The default hardware partition number is 0. + +partnum + The partition number, starting from 1. The partition number 0 specifies + that the whole device is to be used as one "partition." + +partname + The partition name. This is the partition label for GPT partitions. For + MBR partitions, the following syntax is used:: + + + + devtype + A device type like ``mmcsd`` or ``hd``. See the + ``part_set_generic_name`` function in ``disk/part.c`` for a + complete list. + + devletter + The device number as an offset from ``a``. For example, device + number 2 would have a device letter of ``c``. + + partnum + The partition number. This is the same as above. + +If neither ``partname`` nor ``partnum`` is specified and there is a partition +table, then partition 1 is used. If there is no partition table, then the whole +device is used as one "partition." If none of ``devnum``, ``hwpartnum``, +``partnum``, or ``partname`` is specified, or only ``-`` is specified, then +``devnum`` defaults to the value of the ``bootdevice`` environmental variable. + +Examples +-------- + +List the root directory contents on MMC device 2, hardware partition 1, +and partition number 3:: + + ls mmc 2.1:3 / + +Load ``/kernel.itb`` to address ``0x80000000`` from SCSI device 0, hardware partition +0, and the partition labeled ``boot``:: + + load scsi #boot 0x80000000 /kernel.itb + +Print the partition UUID of the SATA device ``$bootdevice``, hardware partition +0, and partition number 0:: + + part uuid sata - From bc820d5bcc507366677c592e400e120481748c05 Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Wed, 10 Feb 2021 09:29:03 +0100 Subject: [PATCH 11/13] fastboot: add UUU command UCmd and ACmd support add support for the UUU commands ACmd and UCmd. Enable them through the Kconfig option CONFIG_FASTBOOT_UUU_SUPPORT base was commit in NXP kernel 9b149c2a2882: ("MLK-18591-3 android: Add FSL android fastboot support") and ported it to current mainline. Tested this patch on imx6ul based board. Signed-off-by: Heiko Schocher Acked-by: Patrick Delaunay --- doc/android/fastboot-protocol.rst | 5 +++ doc/android/fastboot.rst | 2 + drivers/fastboot/Kconfig | 9 ++++ drivers/fastboot/fb_command.c | 68 +++++++++++++++++++++++++++++++ drivers/usb/gadget/f_fastboot.c | 17 ++++++++ include/fastboot.h | 7 ++++ 6 files changed, 108 insertions(+) diff --git a/doc/android/fastboot-protocol.rst b/doc/android/fastboot-protocol.rst index e723659e49..e8cbd7f24e 100644 --- a/doc/android/fastboot-protocol.rst +++ b/doc/android/fastboot-protocol.rst @@ -144,6 +144,11 @@ Command Reference "powerdown" Power off the device. + "ucmd" execute any bootloader command and wait until it + finishs. + + "acmd" execute any bootloader command, do not wait. + Client Variables ---------------- diff --git a/doc/android/fastboot.rst b/doc/android/fastboot.rst index ce513a2a0f..7611f07038 100644 --- a/doc/android/fastboot.rst +++ b/doc/android/fastboot.rst @@ -19,6 +19,8 @@ The current implementation supports the following standard commands: - ``reboot`` - ``reboot-bootloader`` - ``set_active`` (only a stub implementation which always succeeds) +- ``ucmd`` (if enabled) +- ``acmd`` (if enabled) The following OEM commands are supported (if enabled): diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig index a17e488714..2d1836a80e 100644 --- a/drivers/fastboot/Kconfig +++ b/drivers/fastboot/Kconfig @@ -72,6 +72,15 @@ config FASTBOOT_FLASH the downloaded image to a non-volatile storage device. Define this to enable the "fastboot flash" command. +config FASTBOOT_UUU_SUPPORT + bool "Enable FASTBOOT i.MX UUU special command" + default n + help + The fastboot protocol includes "UCmd" and "ACmd" command. + Be aware that you provide full access to any U-Boot command, + including working with memory and may open a huge backdoor, + when enabling this option. + choice prompt "Flash provider for FASTBOOT" depends on FASTBOOT_FLASH diff --git a/drivers/fastboot/fb_command.c b/drivers/fastboot/fb_command.c index 41fc8d7904..3a5db5b08f 100644 --- a/drivers/fastboot/fb_command.c +++ b/drivers/fastboot/fb_command.c @@ -49,6 +49,11 @@ static void oem_partconf(char *, char *); static void oem_bootbus(char *, char *); #endif +#if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT) +static void run_ucmd(char *, char *); +static void run_acmd(char *, char *); +#endif + static const struct { const char *command; void (*dispatch)(char *cmd_parameter, char *response); @@ -117,6 +122,16 @@ static const struct { .dispatch = oem_bootbus, }, #endif +#if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT) + [FASTBOOT_COMMAND_UCMD] = { + .command = "UCmd", + .dispatch = run_ucmd, + }, + [FASTBOOT_COMMAND_ACMD] = { + .command = "ACmd", + .dispatch = run_acmd, + }, +#endif }; /** @@ -327,6 +342,59 @@ static void erase(char *cmd_parameter, char *response) } #endif +#if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT) +/** + * run_ucmd() - Execute the UCmd command + * + * @cmd_parameter: Pointer to command parameter + * @response: Pointer to fastboot response buffer + */ +static void run_ucmd(char *cmd_parameter, char *response) +{ + if (!cmd_parameter) { + pr_err("missing slot suffix\n"); + fastboot_fail("missing command", response); + return; + } + + if (run_command(cmd_parameter, 0)) + fastboot_fail("", response); + else + fastboot_okay(NULL, response); +} + +static char g_a_cmd_buff[64]; + +void fastboot_acmd_complete(void) +{ + run_command(g_a_cmd_buff, 0); +} + +/** + * run_acmd() - Execute the ACmd command + * + * @cmd_parameter: Pointer to command parameter + * @response: Pointer to fastboot response buffer + */ +static void run_acmd(char *cmd_parameter, char *response) +{ + if (!cmd_parameter) { + pr_err("missing slot suffix\n"); + fastboot_fail("missing command", response); + return; + } + + if (strlen(cmd_parameter) > sizeof(g_a_cmd_buff)) { + pr_err("too long command\n"); + fastboot_fail("too long command", response); + return; + } + + strcpy(g_a_cmd_buff, cmd_parameter); + fastboot_okay(NULL, response); +} +#endif + /** * reboot_bootloader() - Sets reboot bootloader flag. * diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 950cc11949..8ba55aab9f 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -494,6 +494,18 @@ static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req) do_exit_on_complete(ep, req); } +#if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT) +static void do_acmd_complete(struct usb_ep *ep, struct usb_request *req) +{ + /* When usb dequeue complete will be called + * Need status value before call run_command. + * otherwise, host can't get last message. + */ + if (req->status == 0) + fastboot_acmd_complete(); +} +#endif + static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) { char *cmdbuf = req->buf; @@ -532,6 +544,11 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) case FASTBOOT_COMMAND_REBOOT_RECOVERY: fastboot_func->in_req->complete = compl_do_reset; break; +#if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT) + case FASTBOOT_COMMAND_ACMD: + fastboot_func->in_req->complete = do_acmd_complete; + break; +#endif } } diff --git a/include/fastboot.h b/include/fastboot.h index 797d7dfd52..57daaf1298 100644 --- a/include/fastboot.h +++ b/include/fastboot.h @@ -44,6 +44,10 @@ enum { #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_BOOTBUS) FASTBOOT_COMMAND_OEM_BOOTBUS, #endif +#if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT) + FASTBOOT_COMMAND_ACMD, + FASTBOOT_COMMAND_UCMD, +#endif FASTBOOT_COMMAND_COUNT }; @@ -169,4 +173,7 @@ void fastboot_data_download(const void *fastboot_data, */ void fastboot_data_complete(char *response); +#if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT) +void fastboot_acmd_complete(void); +#endif #endif /* _FASTBOOT_H_ */ From ba0b984bb0246b5ceea29fd0ac9d8b011a30f77b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Sat, 20 Feb 2021 17:26:06 +0100 Subject: [PATCH 12/13] usb: kbd: Also accept keyboards with Interrupt OUT endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The OUT endpoint can just be ignored as it is not used, just as the corresponding Set_Report request for IN-only interfaces. E.g. the Linux gadget hid keyboard also provides an interrupt endpoint. Also cleanup confusing debug messages like "found set protocol", which is printed when a keyboard device is found, while the Set_Protocol request is issued quite some time later. Signed-off-by: Stefan BrĂ¼ns --- common/usb_kbd.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/common/usb_kbd.c b/common/usb_kbd.c index 60c6027e04..afad260d3d 100644 --- a/common/usb_kbd.c +++ b/common/usb_kbd.c @@ -443,6 +443,7 @@ static int usb_kbd_probe_dev(struct usb_device *dev, unsigned int ifnum) struct usb_interface *iface; struct usb_endpoint_descriptor *ep; struct usb_kbd_pdata *data; + int epNum; if (dev->descriptor.bNumConfigurations != 1) return 0; @@ -458,19 +459,21 @@ static int usb_kbd_probe_dev(struct usb_device *dev, unsigned int ifnum) if (iface->desc.bInterfaceProtocol != USB_PROT_HID_KEYBOARD) return 0; - if (iface->desc.bNumEndpoints != 1) + for (epNum = 0; epNum < iface->desc.bNumEndpoints; epNum++) { + ep = &iface->ep_desc[epNum]; + + /* Check if endpoint is interrupt IN endpoint */ + if ((ep->bmAttributes & 3) != 3) + continue; + + if (ep->bEndpointAddress & 0x80) + break; + } + + if (epNum == iface->desc.bNumEndpoints) return 0; - ep = &iface->ep_desc[0]; - - /* Check if endpoint 1 is interrupt endpoint */ - if (!(ep->bEndpointAddress & 0x80)) - return 0; - - if ((ep->bmAttributes & 3) != 3) - return 0; - - debug("USB KBD: found set protocol...\n"); + debug("USB KBD: found interrupt EP: 0x%x\n", ep->bEndpointAddress); data = malloc(sizeof(struct usb_kbd_pdata)); if (!data) { @@ -498,13 +501,15 @@ static int usb_kbd_probe_dev(struct usb_device *dev, unsigned int ifnum) data->last_report = -1; /* We found a USB Keyboard, install it. */ + debug("USB KBD: set boot protocol\n"); usb_set_protocol(dev, iface->desc.bInterfaceNumber, 0); - debug("USB KBD: found set idle...\n"); #if !defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP) && \ !defined(CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE) + debug("USB KBD: set idle interval...\n"); usb_set_idle(dev, iface->desc.bInterfaceNumber, REPEAT_RATE / 4, 0); #else + debug("USB KBD: set idle interval=0...\n"); usb_set_idle(dev, iface->desc.bInterfaceNumber, 0, 0); #endif From 0a7e5e5f103867789328067f87e34b25b26fc3b0 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Wed, 17 Feb 2021 10:17:27 +0100 Subject: [PATCH 13/13] usb: gadget: dwc2_udc_otg: Fix dwc2_gadget_start() and usb_gadget_register_driver() Since commit 8745b9ebccae ("usb: gadget: add super speed support") ums was no more functional on platform which use dwc2_udc_otg driver. This was due to a too restrictive test which checked that the gadget driver speed was either FS or HS. So all gadget driver with max speed set to speed higher than HS (SS in case of composite gadget driver in our case) are not allowed, which is wrong. Update the speed test in usb_gadget_register_driver() and in dwc2_gadget_start() to allow all gadget driver speed equal or higher than FS. Tested on stm32mp157c-ev1 board. Fixes: c791c8431c34 ("usb: dwc2: convert driver to DM_USB_GADGET") Signed-off-by: Patrice Chotard --- drivers/usb/gadget/dwc2_udc_otg.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c index ecac80fc11..2f31814442 100644 --- a/drivers/usb/gadget/dwc2_udc_otg.c +++ b/drivers/usb/gadget/dwc2_udc_otg.c @@ -248,9 +248,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) debug_cond(DEBUG_SETUP != 0, "%s: %s\n", __func__, "no name"); - if (!driver - || (driver->speed != USB_SPEED_FULL - && driver->speed != USB_SPEED_HIGH) + if (!driver || driver->speed < USB_SPEED_FULL || !driver->bind || !driver->disconnect || !driver->setup) return -EINVAL; if (!dev) @@ -320,9 +318,7 @@ static int dwc2_gadget_start(struct usb_gadget *g, debug_cond(DEBUG_SETUP != 0, "%s: %s\n", __func__, "no name"); - if (!driver || - (driver->speed != USB_SPEED_FULL && - driver->speed != USB_SPEED_HIGH) || + if (!driver || driver->speed < USB_SPEED_FULL || !driver->bind || !driver->disconnect || !driver->setup) return -EINVAL;