From c543aac91ed54dc93c4cd5a46756648c3ca1169b Mon Sep 17 00:00:00 2001 From: KonstantinKondrashov Date: Fri, 5 Jul 2019 18:18:58 +0800 Subject: [PATCH] bootloader: API for the fast wakeup and custom using RTC mem Added "Reserve RTC FAST memory for custom purposes" option. Added a boot counter. --- components/bootloader/Kconfig.projbuild | 24 ++++++- .../subproject/main/bootloader_start.c | 8 +++ .../include/bootloader_common.h | 62 ++++++++++++++++++ .../include/esp_image_format.h | 28 +++++++++ .../include_bootloader/bootloader_utility.h | 10 +++ .../src/bootloader_common.c | 63 +++++++++++++++++++ .../src/bootloader_utility.c | 2 +- components/esp32/ld/esp32.ld | 4 +- 8 files changed, 198 insertions(+), 3 deletions(-) diff --git a/components/bootloader/Kconfig.projbuild b/components/bootloader/Kconfig.projbuild index ba08b7238..2d4a05091 100644 --- a/components/bootloader/Kconfig.projbuild +++ b/components/bootloader/Kconfig.projbuild @@ -235,7 +235,7 @@ menu "Bootloader config" config BOOTLOADER_RESERVE_RTC_SIZE hex - default 0x10 if BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP + 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. @@ -244,6 +244,28 @@ menu "Bootloader config" 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 diff --git a/components/bootloader/subproject/main/bootloader_start.c b/components/bootloader/subproject/main/bootloader_start.c index e9bd32d88..f93fa5694 100644 --- a/components/bootloader/subproject/main/bootloader_start.c +++ b/components/bootloader/subproject/main/bootloader_start.c @@ -41,6 +41,14 @@ void __attribute__((noreturn)) call_start_cpu0(void) 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 bootloader_state_t bs = { 0 }; int boot_index = select_partition_number(&bs); diff --git a/components/bootloader_support/include/bootloader_common.h b/components/bootloader_support/include/bootloader_common.h index 4b887f55f..1058b20cc 100644 --- a/components/bootloader_support/include/bootloader_common.h +++ b/components/bootloader_support/include/bootloader_common.h @@ -146,6 +146,68 @@ esp_err_t bootloader_common_get_partition_description(const esp_partition_pos_t */ 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 } #endif diff --git a/components/bootloader_support/include/esp_image_format.h b/components/bootloader_support/include/esp_image_format.h index 09d4bda3d..4e656a17b 100644 --- a/components/bootloader_support/include/esp_image_format.h +++ b/components/bootloader_support/include/esp_image_format.h @@ -51,6 +51,34 @@ typedef enum { #endif } 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. * diff --git a/components/bootloader_support/include_bootloader/bootloader_utility.h b/components/bootloader_support/include_bootloader/bootloader_utility.h index 84d0cb48f..4f31f5acb 100644 --- a/components/bootloader_support/include_bootloader/bootloader_utility.h +++ b/components/bootloader_support/include_bootloader/bootloader_utility.h @@ -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); +#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 diff --git a/components/bootloader_support/src/bootloader_common.c b/components/bootloader_support/src/bootloader_common.c index a10fb2f2a..acc7644ea 100644 --- a/components/bootloader_support/src/bootloader_common.c +++ b/components/bootloader_support/src/bootloader_common.c @@ -270,3 +270,66 @@ void bootloader_common_vddsdio_configure(void) } #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 \ No newline at end of file diff --git a/components/bootloader_support/src/bootloader_utility.c b/components/bootloader_support/src/bootloader_utility.c index 7d5f67ac7..b9d76ed9b 100644 --- a/components/bootloader_support/src/bootloader_utility.c +++ b/components/bootloader_support/src/bootloader_utility.c @@ -417,7 +417,7 @@ static void set_actual_ota_seq(const bootloader_state_t *bs, int index) update_anti_rollback(&bs->ota[index]); #endif } -#if defined( CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP ) +#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 diff --git a/components/esp32/ld/esp32.ld b/components/esp32/ld/esp32.ld index 514b9ebd8..a52b56f90 100644 --- a/components/esp32/ld/esp32.ld +++ b/components/esp32/ld/esp32.ld @@ -21,7 +21,9 @@ #define CONFIG_BT_RESERVE_DRAM 0 #endif -#if defined(CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP) +#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