From 62ad5c225866e2942a7e3b0f4818510c9b64dbb8 Mon Sep 17 00:00:00 2001 From: Omar Chebib Date: Fri, 26 Aug 2022 19:40:06 +0800 Subject: [PATCH] Bootloader: retained memory can now be kept after reboot when custom data enabled User's custom data are not taken into account during the CRC calculation anymore. Which means taht the retained mem structure is not systematically erased on each reboot anymore. --- components/bootloader/Kconfig.projbuild | 1 - .../bootloader_support/.build-test-rules.yml | 7 +++++ .../include/esp_image_format.h | 6 ++++ .../src/bootloader_common_loader.c | 17 ++++++++-- .../rtc_custom_section/CMakeLists.txt | 6 ++++ .../test_apps/rtc_custom_section/README.md | 2 ++ .../rtc_custom_section/main/CMakeLists.txt | 2 ++ .../rtc_custom_section/main/test_main.c | 31 +++++++++++++++++++ .../rtc_custom_section/pytest_rtc_mem.py | 14 +++++++++ .../rtc_custom_section/sdkconfig.defaults | 3 ++ 10 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 components/bootloader_support/.build-test-rules.yml create mode 100644 components/bootloader_support/test_apps/rtc_custom_section/CMakeLists.txt create mode 100644 components/bootloader_support/test_apps/rtc_custom_section/README.md create mode 100644 components/bootloader_support/test_apps/rtc_custom_section/main/CMakeLists.txt create mode 100644 components/bootloader_support/test_apps/rtc_custom_section/main/test_main.c create mode 100644 components/bootloader_support/test_apps/rtc_custom_section/pytest_rtc_mem.py create mode 100644 components/bootloader_support/test_apps/rtc_custom_section/sdkconfig.defaults diff --git a/components/bootloader/Kconfig.projbuild b/components/bootloader/Kconfig.projbuild index c9b55a7d77..3bfbb05d8d 100644 --- a/components/bootloader/Kconfig.projbuild +++ b/components/bootloader/Kconfig.projbuild @@ -403,7 +403,6 @@ menu "Bootloader config" 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 diff --git a/components/bootloader_support/.build-test-rules.yml b/components/bootloader_support/.build-test-rules.yml new file mode 100644 index 0000000000..935c7d342e --- /dev/null +++ b/components/bootloader_support/.build-test-rules.yml @@ -0,0 +1,7 @@ +# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps + +components/bootloader_support/test_apps/rtc_custom_section: + disable: + - if: IDF_TARGET == "esp32c2" + temporary: false + reason: esp32c2 does not have RTC memory diff --git a/components/bootloader_support/include/esp_image_format.h b/components/bootloader_support/include/esp_image_format.h index 1db6244253..4c8413befe 100644 --- a/components/bootloader_support/include/esp_image_format.h +++ b/components/bootloader_support/include/esp_image_format.h @@ -53,8 +53,14 @@ typedef struct { uint32_t crc; /*!< Check sum crc32 */ } rtc_retain_mem_t; + +_Static_assert(offsetof(rtc_retain_mem_t, crc) == sizeof(rtc_retain_mem_t) - sizeof(uint32_t), "CRC field must be the last field of rtc_retain_mem_t structure"); + #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"); +/* The custom field must be the penultimate field */ +_Static_assert(offsetof(rtc_retain_mem_t, custom) == sizeof(rtc_retain_mem_t) - sizeof(uint32_t) - CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC_SIZE, + "custom field in rtc_retain_mem_t structure must be the field before the CRC one"); #endif #if defined(CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP) || defined(CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC) diff --git a/components/bootloader_support/src/bootloader_common_loader.c b/components/bootloader_support/src/bootloader_common_loader.c index 34810d7124..53f43bd694 100644 --- a/components/bootloader_support/src/bootloader_common_loader.c +++ b/components/bootloader_support/src/bootloader_common_loader.c @@ -116,6 +116,8 @@ int bootloader_common_select_otadata(const esp_ota_select_entry_t *two_otadata, #define RTC_RETAIN_MEM_ADDR (SOC_RTC_DRAM_HIGH - sizeof(rtc_retain_mem_t)) +_Static_assert(RTC_RETAIN_MEM_ADDR >= SOC_RTC_DRAM_LOW, "rtc_retain_mem_t structure size is bigger than the RTC memory size. Consider reducing RTC reserved memory size."); + rtc_retain_mem_t *const rtc_retain_mem = (rtc_retain_mem_t *)RTC_RETAIN_MEM_ADDR; #ifndef BOOTLOADER_BUILD @@ -128,14 +130,25 @@ rtc_retain_mem_t *const rtc_retain_mem = (rtc_retain_mem_t *)RTC_RETAIN_MEM_ADDR SOC_RESERVE_MEMORY_REGION(RTC_RETAIN_MEM_ADDR, RTC_RETAIN_MEM_ADDR + sizeof(rtc_retain_mem_t), rtc_retain_mem); #endif +static uint32_t rtc_retain_mem_size(void) { +#ifdef CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC + /* A custom memory has been reserved by the user, do not consider this memory into CRC calculation as it may change without + * the have the user updating the CRC. Return the offset of the custom field, which is equivalent to size of the structure + * minus the size of everything after (including) `custom` */ + return offsetof(rtc_retain_mem_t, custom); +#else + return sizeof(rtc_retain_mem_t) - sizeof(rtc_retain_mem->crc); +#endif +} + static bool check_rtc_retain_mem(void) { - return esp_rom_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; + return esp_rom_crc32_le(UINT32_MAX, (uint8_t*)rtc_retain_mem, rtc_retain_mem_size()) == rtc_retain_mem->crc && rtc_retain_mem->crc != UINT32_MAX; } static void update_rtc_retain_mem_crc(void) { - rtc_retain_mem->crc = esp_rom_crc32_le(UINT32_MAX, (uint8_t*)rtc_retain_mem, sizeof(rtc_retain_mem_t) - sizeof(rtc_retain_mem->crc)); + rtc_retain_mem->crc = esp_rom_crc32_le(UINT32_MAX, (uint8_t*)rtc_retain_mem, rtc_retain_mem_size()); } NOINLINE_ATTR void bootloader_common_reset_rtc_retain_mem(void) diff --git a/components/bootloader_support/test_apps/rtc_custom_section/CMakeLists.txt b/components/bootloader_support/test_apps/rtc_custom_section/CMakeLists.txt new file mode 100644 index 0000000000..1950e50346 --- /dev/null +++ b/components/bootloader_support/test_apps/rtc_custom_section/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(test_rtc_custom_section) diff --git a/components/bootloader_support/test_apps/rtc_custom_section/README.md b/components/bootloader_support/test_apps/rtc_custom_section/README.md new file mode 100644 index 0000000000..497a93ba72 --- /dev/null +++ b/components/bootloader_support/test_apps/rtc_custom_section/README.md @@ -0,0 +1,2 @@ +| Supported Targets | ESP32 | ESP32-C3 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | diff --git a/components/bootloader_support/test_apps/rtc_custom_section/main/CMakeLists.txt b/components/bootloader_support/test_apps/rtc_custom_section/main/CMakeLists.txt new file mode 100644 index 0000000000..1df31fac80 --- /dev/null +++ b/components/bootloader_support/test_apps/rtc_custom_section/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "test_main.c" + INCLUDE_DIRS ".") diff --git a/components/bootloader_support/test_apps/rtc_custom_section/main/test_main.c b/components/bootloader_support/test_apps/rtc_custom_section/main/test_main.c new file mode 100644 index 0000000000..116f226a00 --- /dev/null +++ b/components/bootloader_support/test_apps/rtc_custom_section/main/test_main.c @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bootloader_common.h" +#include +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#define TEST_MAGIC_VALUE 0x42987561 + +extern rtc_retain_mem_t* bootloader_common_get_rtc_retain_mem(void); + +void app_main(void) { + rtc_retain_mem_t* mem = bootloader_common_get_rtc_retain_mem(); + uint32_t* _rtc_vars = (uint32_t*) mem->custom; + + if (_rtc_vars[0] != TEST_MAGIC_VALUE) { + /* On the first boot, set the data inside the array */ + _rtc_vars[0] = TEST_MAGIC_VALUE; + } else { + /* Second boot, the data was saved saved, success */ + printf("SUCCESS: data were saved across reboot\n"); + vTaskDelay(10000 / portTICK_PERIOD_MS); + } + + esp_restart(); +} diff --git a/components/bootloader_support/test_apps/rtc_custom_section/pytest_rtc_mem.py b/components/bootloader_support/test_apps/rtc_custom_section/pytest_rtc_mem.py new file mode 100644 index 0000000000..e00fa596ff --- /dev/null +++ b/components/bootloader_support/test_apps/rtc_custom_section/pytest_rtc_mem.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 + +import pytest +from pytest_embedded import Dut + + +@pytest.mark.generic +@pytest.mark.esp32 +@pytest.mark.esp32c3 +@pytest.mark.esp32s2 +@pytest.mark.esp32s3 +def test_rtc_reserved_memory(dut: Dut) -> None: + dut.expect_exact('SUCCESS: data were saved across reboot', timeout=10) diff --git a/components/bootloader_support/test_apps/rtc_custom_section/sdkconfig.defaults b/components/bootloader_support/test_apps/rtc_custom_section/sdkconfig.defaults new file mode 100644 index 0000000000..e10fa74582 --- /dev/null +++ b/components/bootloader_support/test_apps/rtc_custom_section/sdkconfig.defaults @@ -0,0 +1,3 @@ +CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0x10 +CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC=y +CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC_SIZE=0x200