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