diff options
Diffstat (limited to 'drivers/fastboot')
-rw-r--r-- | drivers/fastboot/Kconfig | 9 | ||||
-rw-r--r-- | drivers/fastboot/fb_command.c | 68 | ||||
-rw-r--r-- | drivers/fastboot/fb_mmc.c | 210 |
3 files changed, 199 insertions, 88 deletions
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/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c index 50532acb84..8e74e50e91 100644 --- a/drivers/fastboot/fb_mmc.c +++ b/drivers/fastboot/fb_mmc.c @@ -28,30 +28,9 @@ 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, 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,13 +64,65 @@ 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; } +static int do_get_part_info(struct blk_desc **dev_desc, const char *name, + struct disk_partition *info) +{ + int ret; + + /* 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]; + 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 = do_get_part_info(dev_desc, aliased_part_name, + info); + } + return ret; +} + /** * fb_mmc_blk_write() - Write/erase MMC in chunks of FASTBOOT_MAX_BLK_WRITE * @@ -424,28 +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 mmcpart; + 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, &mmcpart) < 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; } /** @@ -461,24 +513,20 @@ 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) { - 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 @@ -490,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)) { @@ -513,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", @@ -535,23 +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, &mmcpart) == 0) { - if (blk_dselect_hwpart(dev_desc, mmcpart)) { - pr_err("Failed to select hwpart\n"); - fastboot_fail("Failed to select hwpart", 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); + 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; @@ -593,30 +642,20 @@ 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"); - 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 @@ -624,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 @@ -632,17 +675,8 @@ 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); - 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); + 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; |