diff --git a/drivers/fastboot/fb_command.c b/drivers/fastboot/fb_command.c index 200f9910c5666af794c3a3156ac97aaae15df417..a5fdfa20da3b3ff7a17384d479d1d5f76eccd025 100644 --- a/drivers/fastboot/fb_command.c +++ b/drivers/fastboot/fb_command.c @@ -86,6 +86,15 @@ static const struct { .dispatch = oem_format, }, #endif + /* Add command to lock/unlock emmc bootloader block access */ + [FASTBOOT_COMMAND_LOCK_CRITICAL] = { + .command = "flashing lock_critical", + .dispatch = fastboot_lock_critical + }, + [FASTBOOT_COMMAND_UNLOCK_CRITICAL] = { + .command = "flashing unlock_critical", + .dispatch = fastboot_unlock_critical + }, }; /** diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c index 4c1c7fd2cd8d08d1c90817beadb2341827d4cb24..4e0c37be2eb8309a127eb783ad8e75e1317a8177 100644 --- a/drivers/fastboot/fb_mmc.c +++ b/drivers/fastboot/fb_mmc.c @@ -29,6 +29,27 @@ static int part_get_info_by_name_or_alias(struct blk_desc *dev_desc, { int ret; + /** check if the MMC is configured for boot partition r/w. + * If so, then we aren't reading the partition table, it's not + * stored in the boot partition only the bootloader is and + * instead we are in raw block programming mode of the HW + * bootpartition, most likely to program the bootloader. If we + * try to read the partition from emmc while the emmc HW boot + * partition is activit, it'll just fail. Not a big deal, but + * the failure is a timeout in SDHC, so it takes a couple + * seconds to fail. Checking for that here prevents the query + * and saves the 2 seconds failure. + * See eMMCC spec for partition configuration registers (CSD + * Byte 179) + */ + struct mmc *mmc = find_mmc_device(CONFIG_FASTBOOT_FLASH_MMC_DEV); + + if (mmc && (EXT_CSD_EXTRACT_PARTITION_ACCESS(mmc->part_config))) { + /* no partition table available in the boot partitions */ + printf("accessing boot partition, skipping partition table\n"); + return -1; + } + ret = part_get_info_by_name(dev_desc, name, info); if (ret < 0) { /* strlen("fastboot_partition_alias_") + 32(part_name) + 1 */ @@ -123,7 +144,7 @@ static void write_raw_image(struct blk_desc *dev_desc, disk_partition_t *info, return; } - printf("........ wrote " LBAFU " bytes to '%s'\n", blkcnt * info->blksz, + printf(".. wrote " LBAFU " bytes to '%s'\n", blkcnt * info->blksz, part_name); fastboot_okay(NULL, response); } @@ -395,8 +416,27 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer, #endif 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); + /* Check if a valid block address was passed in, and if so, + * write to a * block * This allows writing raw blocks via + * fastboot flash <block> <binary> + * Note: simple_strtol returns 0 on error so we can't write + * to block 0 + */ + unsigned int start_addr = simple_strtol(cmd, NULL, 0); + disk_partition_t info; + + if (!start_addr) { + pr_err("partition or address invalid : '%s'\n", cmd); + fastboot_fail("partition or addr invalid", response); + return; + } + info.blksz = dev_desc->blksz; + info.start = start_addr; + info.size = dev_desc->lba; + printf("writing raw image at block %lu (0x%lx), size %ld\n", + info.start, info.start, info.size); + write_raw_image(dev_desc, &info, cmd, download_buffer, + download_bytes, response); return; } @@ -486,3 +526,70 @@ void fastboot_mmc_erase(const char *cmd, char *response) blks_size * info.blksz, cmd); fastboot_okay(NULL, response); } + +/** + * fastboot_lock_critical() - Disable writing to special + * partitions like eMMC bootloader See eMMC spec for more + * details + * + * @cmd_parameter: Pointer to command parameter + * @response: Pointer to fastboot response buffer + */ +void fastboot_lock_critical(char *cmd_parameter, char *response) +{ + u8 ack = 1; + u8 part_num = 1; + u8 access = 0; + int ret = -1; + struct mmc *mmc = find_mmc_device(CONFIG_FASTBOOT_FLASH_MMC_DEV); + + if (!mmc) { + printf("no mmc device at slot\n"); + fastboot_fail("no mmc device at slot", response); + return; + } + + ret = mmc_set_part_conf(mmc, ack, part_num, access); + if (ret) { + printf("failed to disable bootloader block access\n"); + fastboot_fail("failed to disable bootloader block access", + response); + return; + } + fastboot_okay(NULL, response); +} + +/** + * unlock_critical() - Enable writing to eMMC bootloader + * partition by setting r/w to boot partition enable bits of + * CSD byte 179. See eMMC specification + * + * @cmd_parameter: Pointer to command parameter + * @response: Pointer to fastboot response buffer + */ +void fastboot_unlock_critical(char *cmd_parameter, char *response) +{ +#define BOOT_ACK_EN 1 +#define BOOT_PART_ACCESS CONFIG_SYS_MMC_ENV_PART + u8 ack = BOOT_ACK_EN; + u8 part_num = CONFIG_SYS_MMC_ENV_PART; + u8 access = BOOT_PART_ACCESS; + int ret = -1; + struct mmc *mmc = find_mmc_device(CONFIG_FASTBOOT_FLASH_MMC_DEV); + + if (!mmc) { + printf("no mmc device at slot\n"); + fastboot_fail("no mmc device at slot", response); + return; + } + + ret = mmc_set_part_conf(mmc, ack, part_num, access); + if (ret) { + printf("failed to enable bootloader block access\n"); + fastboot_fail("failed to enable bootloader block access", + response); + return; + } + + fastboot_okay(NULL, response); +} diff --git a/include/fastboot.h b/include/fastboot.h index 1933b1d98e3bb9a03832f37b5efb616cb6ec952b..60cb79fa9ff857aa1e015155d325ffa908e00c90 100644 --- a/include/fastboot.h +++ b/include/fastboot.h @@ -36,7 +36,8 @@ enum { #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT) FASTBOOT_COMMAND_OEM_FORMAT, #endif - + FASTBOOT_COMMAND_LOCK_CRITICAL, + FASTBOOT_COMMAND_UNLOCK_CRITICAL, FASTBOOT_COMMAND_COUNT }; diff --git a/include/fb_mmc.h b/include/fb_mmc.h index fd5db9eac8753b8e526036a65bb610d162ea4780..b51dae77b59f86b35929404e94e78b9b214169ca 100644 --- a/include/fb_mmc.h +++ b/include/fb_mmc.h @@ -34,4 +34,20 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer, * @response: Pointer to fastboot response buffer */ void fastboot_mmc_erase(const char *cmd, char *response); + +/** + * fastboot_lock_critical() - Disable writing to eMMC bootloader partition + * + * @cmd_parameter: Pointer to command parameter + * @response: Pointer to fastboot response buffer + */ +void fastboot_lock_critical(char *cmd_parameter, char *response); + +/** + * fastboot_unlock_critical() - Enable writing to eMMC bootloader partition + * + * @cmd_parameter: Pointer to command parameter + * @response: Pointer to fastboot response buffer + */ +void fastboot_unlock_critical(char *cmd_parameter, char *response); #endif