Merge branch 'feature/deep_sleep_fast_wake' into 'master'

bootloader: Reduce the time spent in image validation when waking from deep sleep

See merge request espressif/esp-idf!5140
This commit is contained in:
Angus Gratton 2019-08-28 08:54:28 +08:00
commit a21ca2270a
17 changed files with 393 additions and 79 deletions

View file

@ -219,6 +219,53 @@ menu "Bootloader config"
It allow to test anti-rollback implemention without permanent write eFuse bits. It allow to test anti-rollback implemention without permanent write eFuse bits.
In partition table should be exist this partition `emul_efuse, data, 5, , 0x2000`. In partition table should be exist this partition `emul_efuse, data, 5, , 0x2000`.
config BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP
bool "Skip image validation when exiting deep sleep"
depends on (SECURE_BOOT_ENABLED && SECURE_BOOT_INSECURE) || !SECURE_BOOT_ENABLED
default n
help
This option disables the normal validation of an image coming out of
deep sleep (checksums, SHA256, and signature). This is a trade-off
between wakeup performance from deep sleep, and image integrity checks.
Only enable this if you know what you are doing. It should not be used
in conjunction with using deep_sleep() entry and changing the active OTA
partition as this would skip the validation upon first load of the new
OTA partition.
config BOOTLOADER_RESERVE_RTC_SIZE
hex
default 0x10 if BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP || BOOTLOADER_CUSTOM_RESERVE_RTC
default 0
help
Reserve RTC FAST memory for Skip image validation. This option in bytes.
This option reserves an area in the RTC FAST memory (access only PRO_CPU).
Used to save the addresses of the selected application.
When a wakeup occurs (from Deep sleep), the bootloader retrieves it and
loads the application without validation.
config BOOTLOADER_CUSTOM_RESERVE_RTC
bool "Reserve RTC FAST memory for custom purposes"
default n
help
This option allows the customer to place data in the RTC FAST memory,
this area remains valid when rebooted, except for power loss.
This memory is located at a fixed address and is available
for both the bootloader and the application.
(The application and bootoloader must be compiled with the same option).
The RTC FAST memory has access only through PRO_CPU.
config BOOTLOADER_CUSTOM_RESERVE_RTC_SIZE
hex "Size in bytes for custom purposes"
range 0 0x10
default 0
depends on BOOTLOADER_CUSTOM_RESERVE_RTC
help
This option reserves in RTC FAST memory the area for custom purposes.
If you want to create your own bootloader and save more information
in this area of memory, you can increase it. It must be a multiple of 4 bytes.
This area (rtc_retain_mem_t) is reserved and has access from the bootloader and an application.
endmenu # Bootloader endmenu # Bootloader

View file

@ -41,6 +41,14 @@ void __attribute__((noreturn)) call_start_cpu0(void)
bootloader_reset(); bootloader_reset();
} }
#ifdef CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP
// If this boot is a wake up from the deep sleep then go to the short way,
// try to load the application which worked before deep sleep.
// It skips a lot of checks due to it was done before (while first boot).
bootloader_utility_load_boot_image_from_deep_sleep();
// If it is not successful try to load an application as usual.
#endif
// 2. Select the number of boot partition // 2. Select the number of boot partition
bootloader_state_t bs = { 0 }; bootloader_state_t bs = { 0 };
int boot_index = select_partition_number(&bs); int boot_index = select_partition_number(&bs);

View file

@ -146,6 +146,68 @@ esp_err_t bootloader_common_get_partition_description(const esp_partition_pos_t
*/ */
void bootloader_common_vddsdio_configure(void); void bootloader_common_vddsdio_configure(void);
#if defined( CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP ) || defined( CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC )
/**
* @brief Returns partition from rtc_retain_mem
*
* Uses to get the partition of application which was worked before to go to the deep sleep.
* This partition was stored in rtc_retain_mem.
* Note: This function operates the RTC FAST memory which available only for PRO_CPU.
* Make sure that this function is used only PRO_CPU.
*
* @return partition: If rtc_retain_mem is valid.
* - NULL: If it is not valid.
*/
esp_partition_pos_t* bootloader_common_get_rtc_retain_mem_partition(void);
/**
* @brief Update the partition and reboot_counter in rtc_retain_mem.
*
* This function saves the partition of application for fast booting from the deep sleep.
* An algorithm uses this partition to avoid reading the otadata and does not validate an image.
* Note: This function operates the RTC FAST memory which available only for PRO_CPU.
* Make sure that this function is used only PRO_CPU.
*
* @param[in] partition App partition description. Can be NULL, in this case rtc_retain_mem.partition is not updated.
* @param[in] reboot_counter If true then update reboot_counter.
*
*/
void bootloader_common_update_rtc_retain_mem(esp_partition_pos_t* partition, bool reboot_counter);
/**
* @brief Reset entire rtc_retain_mem.
*
* Note: This function operates the RTC FAST memory which available only for PRO_CPU.
* Make sure that this function is used only PRO_CPU.
*/
void bootloader_common_reset_rtc_retain_mem(void);
/**
* @brief Returns reboot_counter from rtc_retain_mem
*
* The reboot_counter counts the number of reboots. Reset only when power is off.
* The very first launch of the application will be from 1.
* Overflow is not possible, it will stop at the value UINT16_MAX.
* Note: This function operates the RTC FAST memory which available only for PRO_CPU.
* Make sure that this function is used only PRO_CPU.
*
* @return reboot_counter: 1..65535
* - 0: If rtc_retain_mem is not valid.
*/
uint16_t bootloader_common_get_rtc_retain_mem_reboot_counter(void);
/**
* @brief Returns rtc_retain_mem
*
* Note: This function operates the RTC FAST memory which available only for PRO_CPU.
* Make sure that this function is used only PRO_CPU.
*
* @return rtc_retain_mem
*/
rtc_retain_mem_t* bootloader_common_get_rtc_retain_mem(void);
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -42,15 +42,43 @@ typedef struct {
uint8_t image_digest[32]; /* appended SHA-256 digest */ uint8_t image_digest[32]; /* appended SHA-256 digest */
} esp_image_metadata_t; } esp_image_metadata_t;
/* Mode selection for esp_image_load() */
typedef enum { typedef enum {
ESP_IMAGE_VERIFY, /* Verify image contents, load metadata. Print errors. */ ESP_IMAGE_VERIFY, /* Verify image contents, not load to memory, load metadata. Print errors. */
ESP_IMAGE_VERIFY_SILENT, /* Verify image contents, load metadata. Don't print errors. */ ESP_IMAGE_VERIFY_SILENT, /* Verify image contents, not load to memory, load metadata. Don't print errors. */
#ifdef BOOTLOADER_BUILD #ifdef BOOTLOADER_BUILD
ESP_IMAGE_LOAD, /* Verify image contents, load to memory. Print errors. */ ESP_IMAGE_LOAD, /* Verify image contents, load to memory, load metadata. Print errors. */
ESP_IMAGE_LOAD_NO_VALIDATE, /* Not verify image contents, load to memory, load metadata. Print errors. */
#endif #endif
} esp_image_load_mode_t; } esp_image_load_mode_t;
typedef struct {
esp_partition_pos_t partition; /*!< Partition of application which worked before goes to the deep sleep. */
uint16_t reboot_counter; /*!< Reboot counter. Reset only when power is off. */
uint16_t reserve; /*!< Reserve */
#ifdef CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC
uint8_t custom[CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC_SIZE]; /*!< Reserve for custom propose */
#endif
uint32_t crc; /*!< Check sum crc32 */
} rtc_retain_mem_t;
#ifdef CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC
_Static_assert(CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC_SIZE % 4 == 0, "CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC_SIZE must be a multiple of 4 bytes");
#endif
#if defined(CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP) || defined(CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC)
_Static_assert(CONFIG_BOOTLOADER_RESERVE_RTC_SIZE % 4 == 0, "CONFIG_BOOTLOADER_RESERVE_RTC_SIZE must be a multiple of 4 bytes");
#endif
#ifdef CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC
#define ESP_BOOTLOADER_RESERVE_RTC (CONFIG_BOOTLOADER_RESERVE_RTC_SIZE + CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC_SIZE)
#elif defined(CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP)
#define ESP_BOOTLOADER_RESERVE_RTC (CONFIG_BOOTLOADER_RESERVE_RTC_SIZE)
#endif
#if defined(CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP) || defined(CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC)
_Static_assert(sizeof(rtc_retain_mem_t) <= ESP_BOOTLOADER_RESERVE_RTC, "Reserved RTC area must exceed size of rtc_retain_mem_t");
#endif
/** /**
* @brief Verify and (optionally, in bootloader mode) load an app image. * @brief Verify and (optionally, in bootloader mode) load an app image.
* *
@ -134,6 +162,24 @@ esp_err_t esp_image_verify(esp_image_load_mode_t mode, const esp_partition_pos_t
*/ */
esp_err_t bootloader_load_image(const esp_partition_pos_t *part, esp_image_metadata_t *data); esp_err_t bootloader_load_image(const esp_partition_pos_t *part, esp_image_metadata_t *data);
/**
* @brief Load an app image without verification (available only in space of bootloader).
*
* If encryption is enabled, data will be transparently decrypted.
*
* @param part Partition to load the app from.
* @param[inout] data Pointer to the image metadata structure which is be filled in by this function.
* 'start_addr' member should be set (to the start address of the image.)
* Other fields will all be initialised by this function.
*
* @return
* - ESP_OK if verify or load was successful
* - ESP_ERR_IMAGE_FLASH_FAIL if a SPI flash error occurs
* - ESP_ERR_IMAGE_INVALID if the image appears invalid.
* - ESP_ERR_INVALID_ARG if the partition or data pointers are invalid.
*/
esp_err_t bootloader_load_image_no_verify(const esp_partition_pos_t *part, esp_image_metadata_t *data);
/** /**
* @brief Verify the bootloader image. * @brief Verify the bootloader image.
* *

View file

@ -54,6 +54,16 @@ int bootloader_utility_get_selected_boot_partition(const bootloader_state_t *bs)
*/ */
__attribute__((noreturn)) void bootloader_utility_load_boot_image(const bootloader_state_t *bs, int start_index); __attribute__((noreturn)) void bootloader_utility_load_boot_image(const bootloader_state_t *bs, int start_index);
#ifdef CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP
/**
* @brief Load that application which was worked before we go to the deep sleep.
*
* Checks the reboot reason if it is the deep sleep and has a valid partition in the RTC memory
* then try to load the application which was worked before we go to the deep sleep.
*
*/
void bootloader_utility_load_boot_image_from_deep_sleep(void);
#endif
/** /**
* @brief Software reset the ESP32 * @brief Software reset the ESP32

View file

@ -270,3 +270,66 @@ void bootloader_common_vddsdio_configure(void)
} }
#endif // CONFIG_BOOTLOADER_VDDSDIO_BOOST #endif // CONFIG_BOOTLOADER_VDDSDIO_BOOST
} }
#if defined( CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP ) || defined( CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC )
rtc_retain_mem_t *const rtc_retain_mem = (rtc_retain_mem_t *)(SOC_RTC_DRAM_HIGH - sizeof(rtc_retain_mem_t));
static bool check_rtc_retain_mem(void)
{
return crc32_le(UINT32_MAX, (uint8_t*)rtc_retain_mem, sizeof(rtc_retain_mem_t) - sizeof(rtc_retain_mem->crc)) == rtc_retain_mem->crc && rtc_retain_mem->crc != UINT32_MAX;
}
static void update_rtc_retain_mem_crc(void)
{
rtc_retain_mem->crc = crc32_le(UINT32_MAX, (uint8_t*)rtc_retain_mem, sizeof(rtc_retain_mem_t) - sizeof(rtc_retain_mem->crc));
}
void bootloader_common_reset_rtc_retain_mem(void)
{
memset(rtc_retain_mem, 0, sizeof(rtc_retain_mem_t));
}
uint16_t bootloader_common_get_rtc_retain_mem_reboot_counter(void)
{
if (check_rtc_retain_mem()) {
return rtc_retain_mem->reboot_counter;
}
return 0;
}
esp_partition_pos_t* bootloader_common_get_rtc_retain_mem_partition(void)
{
if (check_rtc_retain_mem()) {
return &rtc_retain_mem->partition;
}
return NULL;
}
void bootloader_common_update_rtc_retain_mem(esp_partition_pos_t* partition, bool reboot_counter)
{
if (reboot_counter) {
if (!check_rtc_retain_mem()) {
bootloader_common_reset_rtc_retain_mem();
}
if (++rtc_retain_mem->reboot_counter == 0) {
// do not allow to overflow. Stop it.
--rtc_retain_mem->reboot_counter;
}
}
if (partition != NULL) {
rtc_retain_mem->partition.offset = partition->offset;
rtc_retain_mem->partition.size = partition->size;
}
update_rtc_retain_mem_crc();
}
rtc_retain_mem_t* bootloader_common_get_rtc_retain_mem(void)
{
return rtc_retain_mem;
}
#endif

View file

@ -28,6 +28,7 @@
#include "esp32/rom/uart.h" #include "esp32/rom/uart.h"
#include "esp32/rom/gpio.h" #include "esp32/rom/gpio.h"
#include "esp32/rom/secure_boot.h" #include "esp32/rom/secure_boot.h"
#include "esp32/rom/rtc.h"
#include "soc/soc.h" #include "soc/soc.h"
#include "soc/cpu.h" #include "soc/cpu.h"
@ -416,8 +417,31 @@ static void set_actual_ota_seq(const bootloader_state_t *bs, int index)
update_anti_rollback(&bs->ota[index]); update_anti_rollback(&bs->ota[index]);
#endif #endif
} }
#if defined( CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP ) || defined( CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC )
esp_partition_pos_t partition = index_to_partition(bs, index);
bootloader_common_update_rtc_retain_mem(&partition, true);
#endif
} }
#ifdef CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP
void bootloader_utility_load_boot_image_from_deep_sleep(void)
{
if (rtc_get_reset_reason(0) == DEEPSLEEP_RESET) {
esp_partition_pos_t* partition = bootloader_common_get_rtc_retain_mem_partition();
if (partition != NULL) {
esp_image_metadata_t image_data;
if (bootloader_load_image_no_verify(partition, &image_data) == ESP_OK) {
ESP_LOGI(TAG, "Fast booting app from partition at offset 0x%x", partition->offset);
bootloader_common_update_rtc_retain_mem(NULL, true);
load_image(&image_data);
}
}
ESP_LOGE(TAG, "Fast booting is not successful");
ESP_LOGI(TAG, "Try to load an app as usual with all validations");
}
}
#endif
#define TRY_LOG_FORMAT "Trying partition index %d offs 0x%x size 0x%x" #define TRY_LOG_FORMAT "Trying partition index %d offs 0x%x size 0x%x"
void bootloader_utility_load_boot_image(const bootloader_state_t *bs, int start_index) void bootloader_utility_load_boot_image(const bootloader_state_t *bs, int start_index)

View file

@ -97,14 +97,17 @@ static esp_err_t __attribute__((unused)) verify_simple_hash(bootloader_sha256_ha
static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data) static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data)
{ {
#ifdef BOOTLOADER_BUILD #ifdef BOOTLOADER_BUILD
bool do_load = (mode == ESP_IMAGE_LOAD); bool do_load = (mode == ESP_IMAGE_LOAD) || (mode == ESP_IMAGE_LOAD_NO_VALIDATE);
bool do_verify = (mode == ESP_IMAGE_LOAD) || (mode == ESP_IMAGE_VERIFY) || (mode == ESP_IMAGE_VERIFY_SILENT);
#else #else
bool do_load = false; // Can't load the image in app mode bool do_load = false; // Can't load the image in app mode
bool do_verify = true; // In app mode is avalible only verify mode
#endif #endif
bool silent = (mode == ESP_IMAGE_VERIFY_SILENT); bool silent = (mode == ESP_IMAGE_VERIFY_SILENT);
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
// checksum the image a word at a time. This shaves 30-40ms per MB of image size // checksum the image a word at a time. This shaves 30-40ms per MB of image size
uint32_t checksum_word = ESP_ROM_CHECKSUM_INITIAL; uint32_t checksum_word = ESP_ROM_CHECKSUM_INITIAL;
uint32_t *checksum = NULL;
bootloader_sha256_handle_t sha_handle = NULL; bootloader_sha256_handle_t sha_handle = NULL;
if (data == NULL || part == NULL) { if (data == NULL || part == NULL) {
@ -125,41 +128,45 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
goto err; goto err;
} }
// Calculate SHA-256 of image if secure boot is on, or if image has a hash appended if (do_verify) {
checksum = &checksum_word;
// Calculate SHA-256 of image if secure boot is on, or if image has a hash appended
#ifdef SECURE_BOOT_CHECK_SIGNATURE #ifdef SECURE_BOOT_CHECK_SIGNATURE
if (1) { if (1) {
#else #else
if (data->image.hash_appended) { if (data->image.hash_appended) {
#endif #endif
sha_handle = bootloader_sha256_start(); sha_handle = bootloader_sha256_start();
if (sha_handle == NULL) { if (sha_handle == NULL) {
return ESP_ERR_NO_MEM; return ESP_ERR_NO_MEM;
}
bootloader_sha256_data(sha_handle, &data->image, sizeof(esp_image_header_t));
} }
bootloader_sha256_data(sha_handle, &data->image, sizeof(esp_image_header_t));
}
ESP_LOGD(TAG, "image header: 0x%02x 0x%02x 0x%02x 0x%02x %08x", ESP_LOGD(TAG, "image header: 0x%02x 0x%02x 0x%02x 0x%02x %08x",
data->image.magic, data->image.magic,
data->image.segment_count, data->image.segment_count,
data->image.spi_mode, data->image.spi_mode,
data->image.spi_size, data->image.spi_size,
data->image.entry_addr); data->image.entry_addr);
err = verify_image_header(data->start_addr, &data->image, silent); err = verify_image_header(data->start_addr, &data->image, silent);
if (err != ESP_OK) { if (err != ESP_OK) {
goto err; goto err;
} }
if (data->image.segment_count > ESP_IMAGE_MAX_SEGMENTS) { if (data->image.segment_count > ESP_IMAGE_MAX_SEGMENTS) {
FAIL_LOAD("image at 0x%x segment count %d exceeds max %d", FAIL_LOAD("image at 0x%x segment count %d exceeds max %d",
data->start_addr, data->image.segment_count, ESP_IMAGE_MAX_SEGMENTS); data->start_addr, data->image.segment_count, ESP_IMAGE_MAX_SEGMENTS);
} }
} // if (do_verify)
uint32_t next_addr = data->start_addr + sizeof(esp_image_header_t); uint32_t next_addr = data->start_addr + sizeof(esp_image_header_t);
for(int i = 0; i < data->image.segment_count; i++) { for(int i = 0; i < data->image.segment_count; i++) {
esp_image_segment_header_t *header = &data->segments[i]; esp_image_segment_header_t *header = &data->segments[i];
ESP_LOGV(TAG, "loading segment header %d at offset 0x%x", i, next_addr); ESP_LOGV(TAG, "loading segment header %d at offset 0x%x", i, next_addr);
err = process_segment(i, next_addr, header, silent, do_load, sha_handle, &checksum_word); err = process_segment(i, next_addr, header, silent, do_load, sha_handle, checksum);
if (err != ESP_OK) { if (err != ESP_OK) {
goto err; goto err;
} }
@ -168,64 +175,67 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
next_addr += header->data_len; next_addr += header->data_len;
} }
// Segments all loaded, verify length if (do_verify) {
uint32_t end_addr = next_addr; // Segments all loaded, verify length
if (end_addr < data->start_addr) { uint32_t end_addr = next_addr;
FAIL_LOAD("image offset has wrapped"); if (end_addr < data->start_addr) {
} FAIL_LOAD("image offset has wrapped");
data->image_len = end_addr - data->start_addr;
ESP_LOGV(TAG, "image start 0x%08x end of last section 0x%08x", data->start_addr, end_addr);
if (!esp_cpu_in_ocd_debug_mode()) {
err = verify_checksum(sha_handle, checksum_word, data);
if (err != ESP_OK) {
goto err;
} }
}
if (data->image_len > part->size) {
FAIL_LOAD("Image length %d doesn't fit in partition length %d", data->image_len, part->size);
}
bool is_bootloader = (data->start_addr == ESP_BOOTLOADER_OFFSET); data->image_len = end_addr - data->start_addr;
/* For secure boot, we don't verify signature on bootloaders. ESP_LOGV(TAG, "image start 0x%08x end of last section 0x%08x", data->start_addr, end_addr);
if (NULL != checksum && !esp_cpu_in_ocd_debug_mode()) {
err = verify_checksum(sha_handle, checksum_word, data);
if (err != ESP_OK) {
goto err;
}
}
For non-secure boot, we don't verify any SHA-256 hash appended to the bootloader because esptool.py may have if (data->image_len > part->size) {
rewritten the header - rely on esptool.py having verified the bootloader at flashing time, instead. FAIL_LOAD("Image length %d doesn't fit in partition length %d", data->image_len, part->size);
*/ }
if (!is_bootloader) {
bool is_bootloader = (data->start_addr == ESP_BOOTLOADER_OFFSET);
/* For secure boot, we don't verify signature on bootloaders.
For non-secure boot, we don't verify any SHA-256 hash appended to the bootloader because esptool.py may have
rewritten the header - rely on esptool.py having verified the bootloader at flashing time, instead.
*/
if (!is_bootloader) {
#ifdef SECURE_BOOT_CHECK_SIGNATURE #ifdef SECURE_BOOT_CHECK_SIGNATURE
// secure boot images have a signature appended // secure boot images have a signature appended
err = verify_secure_boot_signature(sha_handle, data); err = verify_secure_boot_signature(sha_handle, data);
#else #else
// No secure boot, but SHA-256 can be appended for basic corruption detection // No secure boot, but SHA-256 can be appended for basic corruption detection
if (sha_handle != NULL && !esp_cpu_in_ocd_debug_mode()) { if (sha_handle != NULL && !esp_cpu_in_ocd_debug_mode()) {
err = verify_simple_hash(sha_handle, data); err = verify_simple_hash(sha_handle, data);
} }
#endif // SECURE_BOOT_CHECK_SIGNATURE #endif // SECURE_BOOT_CHECK_SIGNATURE
} else { // is_bootloader } else { // is_bootloader
// bootloader may still have a sha256 digest handle open // bootloader may still have a sha256 digest handle open
if (sha_handle != NULL) { if (sha_handle != NULL) {
bootloader_sha256_finish(sha_handle, NULL); bootloader_sha256_finish(sha_handle, NULL);
}
} }
}
if (data->image.hash_appended) { if (data->image.hash_appended) {
const void *hash = bootloader_mmap(data->start_addr + data->image_len - HASH_LEN, HASH_LEN); const void *hash = bootloader_mmap(data->start_addr + data->image_len - HASH_LEN, HASH_LEN);
if (hash == NULL) { if (hash == NULL) {
err = ESP_FAIL; err = ESP_FAIL;
goto err; goto err;
}
memcpy(data->image_digest, hash, HASH_LEN);
bootloader_munmap(hash);
} }
memcpy(data->image_digest, hash, HASH_LEN); sha_handle = NULL;
bootloader_munmap(hash); } // if (do_verify)
}
sha_handle = NULL;
if (err != ESP_OK) { if (err != ESP_OK) {
goto err; goto err;
} }
#ifdef BOOTLOADER_BUILD #ifdef BOOTLOADER_BUILD
if (do_load) { // Need to deobfuscate RAM if (do_load && ram_obfs_value[0] != 0 && ram_obfs_value[1] != 0) { // Need to deobfuscate RAM
for (int i = 0; i < data->image.segment_count; i++) { for (int i = 0; i < data->image.segment_count; i++) {
uint32_t load_addr = data->segments[i].load_addr; uint32_t load_addr = data->segments[i].load_addr;
if (should_load(load_addr)) { if (should_load(load_addr)) {
@ -263,6 +273,15 @@ esp_err_t bootloader_load_image(const esp_partition_pos_t *part, esp_image_metad
#endif #endif
} }
esp_err_t bootloader_load_image_no_verify(const esp_partition_pos_t *part, esp_image_metadata_t *data)
{
#ifdef BOOTLOADER_BUILD
return image_load(ESP_IMAGE_LOAD_NO_VALIDATE, part, data);
#else
return ESP_FAIL;
#endif
}
esp_err_t esp_image_verify(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data) esp_err_t esp_image_verify(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data)
{ {
return image_load(mode, part, data); return image_load(mode, part, data);
@ -396,6 +415,13 @@ err:
static esp_err_t process_segment_data(intptr_t load_addr, uint32_t data_addr, uint32_t data_len, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum) static esp_err_t process_segment_data(intptr_t load_addr, uint32_t data_addr, uint32_t data_len, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum)
{ {
// If we are not loading, and the checksum is empty, skip processing this
// segment for data
if(!do_load && checksum == NULL) {
ESP_LOGD(TAG, "skipping checksum for segment");
return ESP_OK;
}
const uint32_t *data = (const uint32_t *)bootloader_mmap(data_addr, data_len); const uint32_t *data = (const uint32_t *)bootloader_mmap(data_addr, data_len);
if(!data) { if(!data) {
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed",
@ -403,6 +429,12 @@ static esp_err_t process_segment_data(intptr_t load_addr, uint32_t data_addr, ui
return ESP_FAIL; return ESP_FAIL;
} }
if (checksum == NULL && sha_handle == NULL) {
memcpy((void *)load_addr, data, data_len);
bootloader_munmap(data);
return ESP_OK;
}
#ifdef BOOTLOADER_BUILD #ifdef BOOTLOADER_BUILD
// Set up the obfuscation value to use for loading // Set up the obfuscation value to use for loading
while (ram_obfs_value[0] == 0 || ram_obfs_value[1] == 0) { while (ram_obfs_value[0] == 0 || ram_obfs_value[1] == 0) {
@ -416,7 +448,9 @@ static esp_err_t process_segment_data(intptr_t load_addr, uint32_t data_addr, ui
for (int i = 0; i < data_len; i += 4) { for (int i = 0; i < data_len; i += 4) {
int w_i = i/4; // Word index int w_i = i/4; // Word index
uint32_t w = src[w_i]; uint32_t w = src[w_i];
*checksum ^= w; if (checksum != NULL) {
*checksum ^= w;
}
#ifdef BOOTLOADER_BUILD #ifdef BOOTLOADER_BUILD
if (do_load) { if (do_load) {
dest[w_i] = w ^ ((w_i & 1) ? ram_obfs_value[0] : ram_obfs_value[1]); dest[w_i] = w ^ ((w_i & 1) ? ram_obfs_value[0] : ram_obfs_value[1]);
@ -494,15 +528,15 @@ static bool should_load(uint32_t load_addr)
if (!load_rtc_memory) { if (!load_rtc_memory) {
if (load_addr >= SOC_RTC_IRAM_LOW && load_addr < SOC_RTC_IRAM_HIGH) { if (load_addr >= SOC_RTC_IRAM_LOW && load_addr < SOC_RTC_IRAM_HIGH) {
ESP_LOGD(TAG, "Skipping RTC fast memory segment at 0x%08x\n", load_addr); ESP_LOGD(TAG, "Skipping RTC fast memory segment at 0x%08x", load_addr);
return false; return false;
} }
if (load_addr >= SOC_RTC_DRAM_LOW && load_addr < SOC_RTC_DRAM_HIGH) { if (load_addr >= SOC_RTC_DRAM_LOW && load_addr < SOC_RTC_DRAM_HIGH) {
ESP_LOGD(TAG, "Skipping RTC fast memory segment at 0x%08x\n", load_addr); ESP_LOGD(TAG, "Skipping RTC fast memory segment at 0x%08x", load_addr);
return false; return false;
} }
if (load_addr >= SOC_RTC_DATA_LOW && load_addr < SOC_RTC_DATA_HIGH) { if (load_addr >= SOC_RTC_DATA_LOW && load_addr < SOC_RTC_DATA_HIGH) {
ESP_LOGD(TAG, "Skipping RTC slow memory segment at 0x%08x\n", load_addr); ESP_LOGD(TAG, "Skipping RTC slow memory segment at 0x%08x", load_addr);
return false; return false;
} }
} }

View file

@ -21,6 +21,14 @@
#define CONFIG_BT_RESERVE_DRAM 0 #define CONFIG_BT_RESERVE_DRAM 0
#endif #endif
#ifdef CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC
#define ESP_BOOTLOADER_RESERVE_RTC (CONFIG_BOOTLOADER_RESERVE_RTC_SIZE + CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC_SIZE)
#elif defined(CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP)
#define ESP_BOOTLOADER_RESERVE_RTC (CONFIG_BOOTLOADER_RESERVE_RTC_SIZE)
#else
#define ESP_BOOTLOADER_RESERVE_RTC 0
#endif
#if defined(CONFIG_ESP32_USE_FIXED_STATIC_RAM_SIZE) #if defined(CONFIG_ESP32_USE_FIXED_STATIC_RAM_SIZE)
ASSERT((CONFIG_ESP32_FIXED_STATIC_RAM_SIZE <= 0x2c200), ASSERT((CONFIG_ESP32_FIXED_STATIC_RAM_SIZE <= 0x2c200),
@ -74,7 +82,7 @@ MEMORY
rtc_iram_seg(RWX) : org = 0x400C0000, len = 0x2000 rtc_iram_seg(RWX) : org = 0x400C0000, len = 0x2000
/* RTC fast memory (same block as above), viewed from data bus */ /* RTC fast memory (same block as above), viewed from data bus */
rtc_data_seg(RW) : org = 0x3ff80000, len = 0x2000 rtc_data_seg(RW) : org = 0x3ff80000, len = 0x2000 - ESP_BOOTLOADER_RESERVE_RTC
/* RTC slow memory (data accessible). Persists over deep sleep. /* RTC slow memory (data accessible). Persists over deep sleep.

View file

@ -55,6 +55,10 @@ After the GPIO input is deactivated and the device reboots, the normally configu
:ref:`CONFIG_BOOTLOADER_HOLD_TIME_GPIO` - this is hold time of GPIO for reset/test mode (by default 5 seconds). The GPIO must be held low continuously for this period of time after reset before a factory reset or test partition boot (as applicable) is performed. :ref:`CONFIG_BOOTLOADER_HOLD_TIME_GPIO` - this is hold time of GPIO for reset/test mode (by default 5 seconds). The GPIO must be held low continuously for this period of time after reset before a factory reset or test partition boot (as applicable) is performed.
Fast boot from Deep Sleep
-------------------------
The bootloader has the :ref:`CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP` option which allows to reduce the wake-up time (useful to reduce consumption). This option is available when the :ref:`CONFIG_SECURE_BOOT_ENABLED` option is disabled. Reduction of time is achieved due to the lack of image verification. During the first boot, the bootloader stores the address of the application being launched in the RTC FAST memory. And during the awakening, this address is used for booting without any checks, thus fast loading is achieved.
Customer bootloader Customer bootloader
--------------------- ---------------------
The current bootloader implementation allows the customer to override it. To do this, you must copy the folder `/esp-idf/components/bootloader` and then edit `/your_project/components/bootloader/subproject/main/bootloader_main.c`. The current bootloader implementation allows the customer to override it. To do this, you must copy the folder `/esp-idf/components/bootloader` and then edit `/your_project/components/bootloader/subproject/main/bootloader_main.c`.

View file

@ -88,4 +88,4 @@ For example, the equivalent example in ``rtc_wake_stub_counter.c``::
The second way is a better option if you need to use strings, or write other more complex code. The second way is a better option if you need to use strings, or write other more complex code.
To reduce wake-up time use the `CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP` Kconfig option, see more information in :doc:`Fast boot from Deep Sleep <bootloader>`.

View file

@ -9,3 +9,4 @@ The following wake up sources are configured:
- Touch: wake up the chip if any of the touch pads are pressed (GPIO32, GPIO33) - Touch: wake up the chip if any of the touch pads are pressed (GPIO32, GPIO33)
- ULP: wake up when the chip temperature changes by more than ~5 degrees Celsius (this value hasn't been characterized exactly yet). - ULP: wake up when the chip temperature changes by more than ~5 degrees Celsius (this value hasn't been characterized exactly yet).
In this example, the `CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP` Kconfig option is used, which allows you to reduce the boot time of the bootloader during waking up from deep sleep. The bootloader stores in rtc memory the address of a running partition and uses it when it wakes up. This example allows you to skip all image checks and speed up the boot.

View file

@ -4,3 +4,4 @@ CONFIG_ESP32_ULP_COPROC_ENABLED=y
CONFIG_ESP32_ULP_COPROC_RESERVE_MEM=512 CONFIG_ESP32_ULP_COPROC_RESERVE_MEM=512
CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y
CONFIG_ESP32_RTC_CLK_SRC_INT_RC=y CONFIG_ESP32_RTC_CLK_SRC_INT_RC=y
CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y

View file

@ -12,6 +12,8 @@ Upon wakeup, the main program saves total edge count into NVS and returns to dee
In this example the input signal is connected to GPIO0. Note that this pin was chosen because most development boards have a button connected to it, so the pulses to be counted can be generated by pressing the button. For real world applications this is not a good choice of a pin, because GPIO0 also acts as a bootstrapping pin. To change the pin number, check the ESP32 Chip Pin List document and adjust `gpio_num` and `ulp_io_number` variables in main.c. In this example the input signal is connected to GPIO0. Note that this pin was chosen because most development boards have a button connected to it, so the pulses to be counted can be generated by pressing the button. For real world applications this is not a good choice of a pin, because GPIO0 also acts as a bootstrapping pin. To change the pin number, check the ESP32 Chip Pin List document and adjust `gpio_num` and `ulp_io_number` variables in main.c.
In this example, the `CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP` Kconfig option is used, which allows you to reduce the boot time of the bootloader during waking up from deep sleep. The bootloader stores in rtc memory the address of a running partition and uses it when it wakes up. This example allows you to skip all image checks and speed up the boot.
## Example output ## Example output
``` ```

View file

@ -6,3 +6,4 @@ CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y
CONFIG_BOOTLOADER_LOG_LEVEL=2 CONFIG_BOOTLOADER_LOG_LEVEL=2
CONFIG_LOG_DEFAULT_LEVEL_WARN=y CONFIG_LOG_DEFAULT_LEVEL_WARN=y
CONFIG_LOG_DEFAULT_LEVEL=2 CONFIG_LOG_DEFAULT_LEVEL=2
CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y

View file

@ -16,6 +16,8 @@ Measurement frequency, Hz | Average current, uA
50 | 20 50 | 20
100 | 37 100 | 37
In this example, the `CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP` Kconfig option is used, which allows you to reduce the boot time of the bootloader during waking up from deep sleep. The bootloader stores in rtc memory the address of a running partition and uses it when it wakes up. This example allows you to skip all image checks and speed up the boot.
## Example output ## Example output
Below is the output from this example. Below is the output from this example.

View file

@ -6,3 +6,4 @@ CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y
CONFIG_BOOTLOADER_LOG_LEVEL=2 CONFIG_BOOTLOADER_LOG_LEVEL=2
CONFIG_LOG_DEFAULT_LEVEL_WARN=y CONFIG_LOG_DEFAULT_LEVEL_WARN=y
CONFIG_LOG_DEFAULT_LEVEL=2 CONFIG_LOG_DEFAULT_LEVEL=2
CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y