From 46f3f0b3c74d320d9033a21b13d77969ec65d85d Mon Sep 17 00:00:00 2001 From: Djordje Nedic Date: Fri, 20 Sep 2024 01:35:52 +0200 Subject: [PATCH] feat: Add support for Secure Download Mode This adds support for connecting in secure download mode, a special mode in which the commands accepted by the boot ROM are limited to a safe subset. Closes https://github.com/espressif/esp-serial-flasher/issues/110 --- include/esp_loader.h | 34 +++++++++++++++++++++++++++- src/esp_loader.c | 53 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 78 insertions(+), 9 deletions(-) diff --git a/include/esp_loader.h b/include/esp_loader.h index 04839e5..a8a29b0 100644 --- a/include/esp_loader.h +++ b/include/esp_loader.h @@ -154,6 +154,30 @@ target_chip_t esp_loader_get_target(void); */ esp_loader_error_t esp_loader_connect_with_stub(esp_loader_connect_args_t *connect_args); +#ifdef SERIAL_FLASHER_INTERFACE_UART +/** + * @brief Connects to the target running in secure download mode + * + * Secure download mode is a special mode in which the commands accepted by the boot ROM + * are limited to a safe subset. It is enabled by burning an efuse on the target. + * Read more about it here: + * https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/kconfig.html#config-secure-uart-rom-dl-mode + * + * @param connect_args[in] Timing parameters to be used for connecting to target. + * @param flash_size Flash size of the target chip. + * @param target_chip Target chip. Used for the ESP32 and ESP8266, which do not support the + * GET_SECURITY_INFO command required to identify the target in secure + * download mode. Leave as ESP_UNKNOWN_CHIP for autodetection of newer chips. + * + * @return + * - ESP_LOADER_SUCCESS Success + * - ESP_LOADER_ERROR_TIMEOUT Timeout + * - ESP_LOADER_ERROR_INVALID_RESPONSE Internal error + */ +esp_loader_error_t esp_loader_connect_secure_download_mode(esp_loader_connect_args_t *connect_args, + uint32_t flash_size, target_chip_t target_chip); +#endif /* SERIAL_FLASHER_INTERFACE_UART */ + /** * @brief Initiates flash operation * @@ -209,6 +233,7 @@ esp_loader_error_t esp_loader_flash_finish(bool reboot); * @return * - ESP_LOADER_SUCCESS Success * - ESP_LOADER_ERROR_UNSUPPORTED_CHIP The target flash chip is not known + * - ESP_LOADER_ERROR_UNSUPPORTED_FUNC The target chip is running in secure download mode */ esp_loader_error_t esp_loader_flash_detect_size(uint32_t *flash_size); @@ -262,6 +287,7 @@ esp_loader_error_t esp_loader_get_security_info(esp_loader_target_security_info_ * - ESP_LOADER_SUCCESS Success * - ESP_LOADER_ERROR_TIMEOUT Timeout * - ESP_LOADER_ERROR_INVALID_RESPONSE Internal error + * - ESP_LOADER_ERROR_UNSUPPORTED_FUNC The target is running in secure download mode */ esp_loader_error_t esp_loader_mem_start(uint32_t offset, uint32_t size, uint32_t block_size); @@ -280,6 +306,7 @@ esp_loader_error_t esp_loader_mem_start(uint32_t offset, uint32_t size, uint32_t * - ESP_LOADER_SUCCESS Success * - ESP_LOADER_ERROR_TIMEOUT Timeout * - ESP_LOADER_ERROR_INVALID_RESPONSE Internal error + * - ESP_LOADER_ERROR_UNSUPPORTED_FUNC The target is running in secure download mode */ esp_loader_error_t esp_loader_mem_write(const void *payload, uint32_t size); @@ -294,6 +321,7 @@ esp_loader_error_t esp_loader_mem_write(const void *payload, uint32_t size); * - ESP_LOADER_SUCCESS Success * - ESP_LOADER_ERROR_TIMEOUT Timeout * - ESP_LOADER_ERROR_INVALID_RESPONSE Internal error + * - ESP_LOADER_ERROR_UNSUPPORTED_FUNC The target is running in secure download mode */ esp_loader_error_t esp_loader_mem_finish(uint32_t entrypoint); @@ -307,6 +335,7 @@ esp_loader_error_t esp_loader_mem_finish(uint32_t entrypoint); * - ESP_LOADER_SUCCESS Success * - ESP_LOADER_ERROR_TIMEOUT Timeout * - ESP_LOADER_ERROR_INVALID_RESPONSE Internal error + * - ESP_LOADER_ERROR_UNSUPPORTED_FUNC The target is running in secure download mode */ esp_loader_error_t esp_loader_read_mac(uint8_t *mac); @@ -320,6 +349,7 @@ esp_loader_error_t esp_loader_read_mac(uint8_t *mac); * - ESP_LOADER_SUCCESS Success * - ESP_LOADER_ERROR_TIMEOUT Timeout * - ESP_LOADER_ERROR_INVALID_RESPONSE Internal error + * - ESP_LOADER_ERROR_UNSUPPORTED_FUNC The target is running in secure download mode */ esp_loader_error_t esp_loader_write_register(uint32_t address, uint32_t reg_value); @@ -333,6 +363,7 @@ esp_loader_error_t esp_loader_write_register(uint32_t address, uint32_t reg_valu * - ESP_LOADER_SUCCESS Success * - ESP_LOADER_ERROR_TIMEOUT Timeout * - ESP_LOADER_ERROR_INVALID_RESPONSE Internal error + * - ESP_LOADER_ERROR_UNSUPPORTED_FUNC The target is running in secure download mode */ esp_loader_error_t esp_loader_read_register(uint32_t address, uint32_t *reg_value); @@ -348,7 +379,8 @@ esp_loader_error_t esp_loader_read_register(uint32_t address, uint32_t *reg_valu * - ESP_LOADER_SUCCESS Success * - ESP_LOADER_ERROR_TIMEOUT Timeout * - ESP_LOADER_ERROR_INVALID_RESPONSE Internal error - * - ESP_LOADER_ERROR_UNSUPPORTED_FUNC Unsupported on the target + * - ESP_LOADER_ERROR_UNSUPPORTED_FUNC Either the target is running in secure download + * mode or the stub is running on the target. */ esp_loader_error_t esp_loader_change_transmission_rate(uint32_t transmission_rate); diff --git a/src/esp_loader.c b/src/esp_loader.c index 1c253c3..e4afec2 100644 --- a/src/esp_loader.c +++ b/src/esp_loader.c @@ -32,6 +32,7 @@ typedef enum { static const target_registers_t *s_reg = NULL; static target_chip_t s_target = ESP_UNKNOWN_CHIP; +static uint32_t s_target_flash_size = 0; #if MD5_ENABLED @@ -75,6 +76,8 @@ esp_loader_error_t esp_loader_connect(esp_loader_connect_args_t *connect_args) RETURN_ON_ERROR(loader_detect_chip(&s_target, &s_reg)); #if (defined SERIAL_FLASHER_INTERFACE_UART) || (defined SERIAL_FLASHER_INTERFACE_USB) + s_target_flash_size = 0; + if (s_target == ESP8266_CHIP) { return loader_flash_begin_cmd(0, 0, 0, 0, s_target); } else { @@ -84,6 +87,7 @@ esp_loader_error_t esp_loader_connect(esp_loader_connect_args_t *connect_args) return loader_spi_attach_cmd(spi_config); } #endif /* SERIAL_FLASHER_INTERFACE_UART || SERIAL_FLASHER_INTERFACE_USB */ + return ESP_LOADER_SUCCESS; } @@ -97,6 +101,8 @@ static uint32_t s_flash_write_size = 0; esp_loader_error_t esp_loader_connect_with_stub(esp_loader_connect_args_t *connect_args) { + s_target_flash_size = 0; + loader_port_enter_bootloader(); RETURN_ON_ERROR(loader_initialize_conn(connect_args)); @@ -108,6 +114,34 @@ esp_loader_error_t esp_loader_connect_with_stub(esp_loader_connect_args_t *conne return ESP_LOADER_SUCCESS; } +#ifdef SERIAL_FLASHER_INTERFACE_UART +esp_loader_error_t esp_loader_connect_secure_download_mode(esp_loader_connect_args_t *connect_args, + const uint32_t flash_size, const target_chip_t target_chip) +{ + s_target_flash_size = flash_size; + s_target = target_chip; + + loader_port_enter_bootloader(); + + RETURN_ON_ERROR(loader_initialize_conn(connect_args)); + + if (s_target == ESP_UNKNOWN_CHIP) { + RETURN_ON_ERROR(loader_detect_chip(&s_target, &s_reg)); + } + + if (s_target == ESP8266_CHIP) { + return loader_flash_begin_cmd(0, 0, 0, 0, s_target); + } else { + uint32_t spi_config; + RETURN_ON_ERROR( loader_read_spi_config(s_target, &spi_config) ); + loader_port_start_timer(DEFAULT_TIMEOUT); + return loader_spi_attach_cmd(spi_config); + } + + return ESP_LOADER_SUCCESS; +} +#endif /* SERIAL_FLASHER_INTERFACE_UART */ + static esp_loader_error_t spi_set_data_lengths(size_t mosi_bits, size_t miso_bits) { if (mosi_bits > 0) { @@ -280,15 +314,18 @@ esp_loader_error_t esp_loader_flash_start(uint32_t offset, uint32_t image_size, { s_flash_write_size = block_size; - uint32_t flash_size = 0; - if (esp_loader_flash_detect_size(&flash_size) == ESP_LOADER_SUCCESS) { - if (image_size + offset > flash_size) { - return ESP_LOADER_ERROR_IMAGE_SIZE; + /* Flash size will be known in advance if we're in secure download mode or we already read it*/ + if (s_target_flash_size == 0) { + if (esp_loader_flash_detect_size(&s_target_flash_size) == ESP_LOADER_SUCCESS) { + loader_port_start_timer(DEFAULT_TIMEOUT); + RETURN_ON_ERROR(loader_spi_parameters(s_target_flash_size)); + } else { + loader_port_debug_print("Flash size detection failed, falling back to default"); } - loader_port_start_timer(DEFAULT_TIMEOUT); - RETURN_ON_ERROR( loader_spi_parameters(flash_size) ); - } else { - loader_port_debug_print("Flash size detection failed, falling back to default"); + } + + if (image_size + offset > s_target_flash_size) { + return ESP_LOADER_ERROR_IMAGE_SIZE; } #if MD5_ENABLED