From 5b3a645813e8705d208b632234c95ca62922d2f4 Mon Sep 17 00:00:00 2001 From: Jakob Hasse Date: Thu, 3 Nov 2022 16:59:19 +0100 Subject: [PATCH] feat(esp_system): Partially buildable on Linux now --- .gitlab/ci/host-test.yml | 8 ++ components/esp_system/.build-test-rules.yml | 3 + components/esp_system/CMakeLists.txt | 10 ++ components/esp_system/esp_system.c | 51 -------- .../host_test/test_esp_system/CMakeLists.txt | 9 ++ .../host_test/test_esp_system/README.md | 2 + .../test_esp_system/main/CMakeLists.txt | 3 + .../test_esp_system/main/esp_system_test.c | 120 ++++++++++++++++++ .../test_esp_system/sdkconfig.defaults | 2 + components/esp_system/linker.lf | 2 +- components/esp_system/port/CMakeLists.txt | 3 +- components/esp_system/port/esp_system_chip.c | 60 +++++++++ components/esp_system/port/esp_system_linux.c | 47 +++++++ .../esp_system/port/soc/linux/Kconfig.cpu | 1 + .../esp_system/port/soc/linux/Kconfig.system | 1 + .../esp_system/port/soc/linux/reset_reason.c | 18 +++ .../port/soc/linux/system_internal.c | 17 +++ .../linux/include/freertos/portmacro_idf.h | 6 - tools/cmake/build.cmake | 2 +- 19 files changed, 305 insertions(+), 60 deletions(-) create mode 100644 components/esp_system/host_test/test_esp_system/CMakeLists.txt create mode 100644 components/esp_system/host_test/test_esp_system/README.md create mode 100644 components/esp_system/host_test/test_esp_system/main/CMakeLists.txt create mode 100644 components/esp_system/host_test/test_esp_system/main/esp_system_test.c create mode 100644 components/esp_system/host_test/test_esp_system/sdkconfig.defaults create mode 100644 components/esp_system/port/esp_system_chip.c create mode 100644 components/esp_system/port/esp_system_linux.c create mode 100644 components/esp_system/port/soc/linux/Kconfig.cpu create mode 100644 components/esp_system/port/soc/linux/Kconfig.system create mode 100644 components/esp_system/port/soc/linux/reset_reason.c create mode 100644 components/esp_system/port/soc/linux/system_internal.c diff --git a/.gitlab/ci/host-test.yml b/.gitlab/ci/host-test.yml index e949f1c7b7..93730c3c76 100644 --- a/.gitlab/ci/host-test.yml +++ b/.gitlab/ci/host-test.yml @@ -389,6 +389,14 @@ test_hello_world_linux_compatible_example: - timeout 15 build/hello_world.elf | tee test.txt - grep "Hello world!" test.txt +test_esp_system: + extends: .host_test_template + script: + - cd ${IDF_PATH}/components/esp_system/host_test/test_esp_system/ + - idf.py build + - timeout 5 build/test_esp_system.elf | tee log.txt || true + - grep "6 Tests 0 Failures 0 Ignored" log.txt + test_esp_timer_cxx: extends: .host_test_template script: diff --git a/components/esp_system/.build-test-rules.yml b/components/esp_system/.build-test-rules.yml index b4ddfd4dde..fbafabf15d 100644 --- a/components/esp_system/.build-test-rules.yml +++ b/components/esp_system/.build-test-rules.yml @@ -1,5 +1,8 @@ # Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps +components/esp_system/host_test/esp_system: + enable: + - if: IDF_TARGET == "linux" components/esp_system/test_apps/rtc_8md256: disable: - if: SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256 != 1 diff --git a/components/esp_system/CMakeLists.txt b/components/esp_system/CMakeLists.txt index 25307d36ca..d8f6072f5f 100644 --- a/components/esp_system/CMakeLists.txt +++ b/components/esp_system/CMakeLists.txt @@ -1,5 +1,15 @@ idf_build_get_property(target IDF_TARGET) +# On Linux, we only support a few features, hence this simple component registration +if(${target} STREQUAL "linux") + idf_component_register(SRCS "esp_system.c" + "port/soc/linux/reset_reason.c" + "port/soc/linux/system_internal.c" + "port/esp_system_linux.c" + INCLUDE_DIRS "include") + return() +endif() + set(srcs "esp_err.c") if(CONFIG_IDF_ENV_FPGA) diff --git a/components/esp_system/esp_system.c b/components/esp_system/esp_system.c index d8c473a95e..8001a45d48 100644 --- a/components/esp_system/esp_system.c +++ b/components/esp_system/esp_system.c @@ -6,14 +6,8 @@ #include "esp_system.h" #include "esp_private/system_internal.h" -#include "esp_heap_caps.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "esp_cpu.h" -#include "soc/rtc.h" -#include "esp_private/panic_internal.h" -#include "esp_rom_uart.h" -#include "esp_rom_sys.h" #if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE #if CONFIG_IDF_TARGET_ESP32S2 #include "esp32s2/memprot.h" @@ -28,26 +22,6 @@ static shutdown_handler_t shutdown_handlers[SHUTDOWN_HANDLERS_NO]; -void IRAM_ATTR esp_restart_noos_dig(void) -{ - // make sure all the panic handler output is sent from UART FIFO - if (CONFIG_ESP_CONSOLE_UART_NUM >= 0) { - esp_rom_uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); - } - - // switch to XTAL (otherwise we will keep running from the PLL) - rtc_clk_cpu_freq_set_xtal(); - -#if CONFIG_IDF_TARGET_ESP32 - esp_cpu_unstall(PRO_CPU_NUM); -#endif - // reset the digital part - esp_rom_software_reset_system(); - while (true) { - ; - } -} - esp_err_t esp_register_shutdown_handler(shutdown_handler_t handler) { for (int i = 0; i < SHUTDOWN_HANDLERS_NO; i++) { @@ -109,28 +83,3 @@ void IRAM_ATTR esp_restart(void) } esp_restart_noos(); } - -uint32_t esp_get_free_heap_size( void ) -{ - return heap_caps_get_free_size( MALLOC_CAP_DEFAULT ); -} - -uint32_t esp_get_free_internal_heap_size( void ) -{ - return heap_caps_get_free_size( MALLOC_CAP_8BIT | MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL ); -} - -uint32_t esp_get_minimum_free_heap_size( void ) -{ - return heap_caps_get_minimum_free_size( MALLOC_CAP_DEFAULT ); -} - -const char *esp_get_idf_version(void) -{ - return IDF_VER; -} - -void __attribute__((noreturn)) esp_system_abort(const char *details) -{ - panic_abort(details); -} diff --git a/components/esp_system/host_test/test_esp_system/CMakeLists.txt b/components/esp_system/host_test/test_esp_system/CMakeLists.txt new file mode 100644 index 0000000000..f8c8556e1f --- /dev/null +++ b/components/esp_system/host_test/test_esp_system/CMakeLists.txt @@ -0,0 +1,9 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five 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) +set(COMPONENTS main) +project(test_esp_system) diff --git a/components/esp_system/host_test/test_esp_system/README.md b/components/esp_system/host_test/test_esp_system/README.md new file mode 100644 index 0000000000..37c142df16 --- /dev/null +++ b/components/esp_system/host_test/test_esp_system/README.md @@ -0,0 +1,2 @@ +| Supported Targets | Linux | +| ----------------- | ----- | diff --git a/components/esp_system/host_test/test_esp_system/main/CMakeLists.txt b/components/esp_system/host_test/test_esp_system/main/CMakeLists.txt new file mode 100644 index 0000000000..70b73b9b85 --- /dev/null +++ b/components/esp_system/host_test/test_esp_system/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "esp_system_test.c" + INCLUDE_DIRS "." + PRIV_REQUIRES unity esp_system) diff --git a/components/esp_system/host_test/test_esp_system/main/esp_system_test.c b/components/esp_system/host_test/test_esp_system/main/esp_system_test.c new file mode 100644 index 0000000000..1ea98c7579 --- /dev/null +++ b/components/esp_system/host_test/test_esp_system/main/esp_system_test.c @@ -0,0 +1,120 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "unity.h" + +#include "esp_system.h" + +static jmp_buf env; +static uint32_t token; + +static void jump_back_shutdown_handler(void) +{ + longjmp(env, 1); +} + +static void dummy_shutdown_handler_0(void) { } +static void dummy_shutdown_handler_1(void) { } +static void dummy_shutdown_handler_2(void) { } +static void dummy_shutdown_handler_3(void) { } +static void dummy_shutdown_handler_4(void) { } + +static void action(void) +{ + token++; +} + +static void cleanup(void) +{ + esp_unregister_shutdown_handler(jump_back_shutdown_handler); + esp_unregister_shutdown_handler(dummy_shutdown_handler_0); + esp_unregister_shutdown_handler(dummy_shutdown_handler_1); + esp_unregister_shutdown_handler(dummy_shutdown_handler_2); + esp_unregister_shutdown_handler(dummy_shutdown_handler_3); + esp_unregister_shutdown_handler(dummy_shutdown_handler_4); + esp_unregister_shutdown_handler(action); +} + +void test_reset_reason(void) +{ + TEST_ASSERT_EQUAL(ESP_RST_POWERON, esp_reset_reason()); +} + +void test_unregister_handler_works(void) +{ + token = 0; + // for some reason, the handlers are executed in reverse order of adding handlers, so we always + // register the jumping handler at first to make it execute last + TEST_ASSERT_EQUAL(ESP_OK, esp_register_shutdown_handler(jump_back_shutdown_handler)); + TEST_ASSERT_EQUAL(ESP_OK, esp_register_shutdown_handler(action)); + TEST_ASSERT_EQUAL(ESP_OK, esp_unregister_shutdown_handler(action)); + + if (setjmp(env) == 0) { + esp_restart(); + } + + // fist unregister before any assert to avoid skipping by assert's longjmp + cleanup(); + + TEST_ASSERT_EQUAL(0, token); +} + +void test_register_shutdown_handler_twice_fails(void) +{ + TEST_ASSERT_EQUAL(ESP_OK, esp_register_shutdown_handler(jump_back_shutdown_handler)); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, esp_register_shutdown_handler(jump_back_shutdown_handler)); + + cleanup(); +} + +void test_register_shutdown_handler_works(void) +{ + token = 0; + TEST_ASSERT_EQUAL(esp_register_shutdown_handler(jump_back_shutdown_handler), ESP_OK); + TEST_ASSERT_EQUAL(esp_register_shutdown_handler(action), ESP_OK); + + if (setjmp(env) == 0) { + esp_restart(); + } + + cleanup(); + + TEST_ASSERT_EQUAL(1, token); +} + +void test_register_too_many_shutdown_handler_fails(void) +{ + TEST_ASSERT_EQUAL(ESP_OK, esp_register_shutdown_handler(dummy_shutdown_handler_0)); + TEST_ASSERT_EQUAL(ESP_OK, esp_register_shutdown_handler(dummy_shutdown_handler_1)); + TEST_ASSERT_EQUAL(ESP_OK, esp_register_shutdown_handler(dummy_shutdown_handler_2)); + TEST_ASSERT_EQUAL(ESP_OK, esp_register_shutdown_handler(dummy_shutdown_handler_3)); + TEST_ASSERT_EQUAL(ESP_OK, esp_register_shutdown_handler(dummy_shutdown_handler_4)); + + TEST_ASSERT_EQUAL(esp_register_shutdown_handler(jump_back_shutdown_handler), ESP_ERR_NO_MEM); + + cleanup(); +} + +void test_heap_size_stubs(void) +{ + TEST_ASSERT_EQUAL(47000, esp_get_free_heap_size()); + TEST_ASSERT_EQUAL(47000, esp_get_free_internal_heap_size()); + TEST_ASSERT_EQUAL(47000, esp_get_minimum_free_heap_size()); +} + +void app_main(void) +{ + UNITY_BEGIN(); + RUN_TEST(test_reset_reason); + RUN_TEST(test_unregister_handler_works); + RUN_TEST(test_register_shutdown_handler_twice_fails); + RUN_TEST(test_register_shutdown_handler_works); + RUN_TEST(test_register_too_many_shutdown_handler_fails); + RUN_TEST(test_heap_size_stubs); + UNITY_END(); +} diff --git a/components/esp_system/host_test/test_esp_system/sdkconfig.defaults b/components/esp_system/host_test/test_esp_system/sdkconfig.defaults new file mode 100644 index 0000000000..a3f33f136b --- /dev/null +++ b/components/esp_system/host_test/test_esp_system/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_IDF_TARGET="linux" +CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n diff --git a/components/esp_system/linker.lf b/components/esp_system/linker.lf index 581a886631..775e4ac76a 100644 --- a/components/esp_system/linker.lf +++ b/components/esp_system/linker.lf @@ -7,7 +7,7 @@ entries: panic_arch (noflash) esp_err (noflash) - esp_system:esp_system_abort (noflash) + esp_system_chip:esp_system_abort (noflash) ubsan (noflash) if ESP_CONSOLE_USB_CDC_SUPPORT_ETS_PRINTF: diff --git a/components/esp_system/port/CMakeLists.txt b/components/esp_system/port/CMakeLists.txt index 62d6f15553..b82c9af37b 100644 --- a/components/esp_system/port/CMakeLists.txt +++ b/components/esp_system/port/CMakeLists.txt @@ -6,7 +6,8 @@ endif() target_include_directories(${COMPONENT_LIB} PRIVATE ${INCLUDE_FILES} include/private) -set(srcs "cpu_start.c" "panic_handler.c" "brownout.c") +set(srcs "cpu_start.c" "panic_handler.c" "brownout.c" "esp_system_chip.c") + add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" ${srcs}) target_sources(${COMPONENT_LIB} PRIVATE ${srcs}) diff --git a/components/esp_system/port/esp_system_chip.c b/components/esp_system/port/esp_system_chip.c new file mode 100644 index 0000000000..cca83848fa --- /dev/null +++ b/components/esp_system/port/esp_system_chip.c @@ -0,0 +1,60 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "esp_cpu.h" +#include "soc/rtc.h" +#include "esp_private/panic_internal.h" +#include "esp_private/system_internal.h" +#include "esp_heap_caps.h" +#include "esp_rom_uart.h" +#include "esp_rom_sys.h" +#include "sdkconfig.h" + +void IRAM_ATTR esp_restart_noos_dig(void) +{ + // make sure all the panic handler output is sent from UART FIFO + if (CONFIG_ESP_CONSOLE_UART_NUM >= 0) { + esp_rom_uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); + } + + // switch to XTAL (otherwise we will keep running from the PLL) + rtc_clk_cpu_freq_set_xtal(); + +#if CONFIG_IDF_TARGET_ESP32 + esp_cpu_unstall(PRO_CPU_NUM); +#endif + // reset the digital part + esp_rom_software_reset_system(); + while (true) { + ; + } +} + +uint32_t esp_get_free_heap_size( void ) +{ + return heap_caps_get_free_size( MALLOC_CAP_DEFAULT ); +} + +uint32_t esp_get_free_internal_heap_size( void ) +{ + return heap_caps_get_free_size( MALLOC_CAP_8BIT | MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL ); +} + +uint32_t esp_get_minimum_free_heap_size( void ) +{ + return heap_caps_get_minimum_free_size( MALLOC_CAP_DEFAULT ); +} + +const char *esp_get_idf_version(void) +{ + return IDF_VER; +} + +void __attribute__((noreturn)) esp_system_abort(const char *details) +{ + panic_abort(details); +} diff --git a/components/esp_system/port/esp_system_linux.c b/components/esp_system/port/esp_system_linux.c new file mode 100644 index 0000000000..b2dc4df1b0 --- /dev/null +++ b/components/esp_system/port/esp_system_linux.c @@ -0,0 +1,47 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * All functions presented here are stubs for the POSIX/Linux implementation of FReeRTOS. + * They are meant to allow to compile, but they DO NOT return any meaningful value. + */ + +#include +#include +#include "esp_private/system_internal.h" + +static const uint32_t MAGIC_HEAP_SIZE = 47000; + +// dummy, we should never get here on Linux +void esp_restart_noos_dig(void) +{ + abort(); +} + +uint32_t esp_get_free_heap_size( void ) +{ + return MAGIC_HEAP_SIZE; +} + +uint32_t esp_get_free_internal_heap_size( void ) +{ + return MAGIC_HEAP_SIZE; +} + +uint32_t esp_get_minimum_free_heap_size( void ) +{ + return MAGIC_HEAP_SIZE; +} + +const char *esp_get_idf_version(void) +{ + return IDF_VER; +} + +void __attribute__((noreturn)) esp_system_abort(const char *details) +{ + exit(1); +} diff --git a/components/esp_system/port/soc/linux/Kconfig.cpu b/components/esp_system/port/soc/linux/Kconfig.cpu new file mode 100644 index 0000000000..7f8211d86a --- /dev/null +++ b/components/esp_system/port/soc/linux/Kconfig.cpu @@ -0,0 +1 @@ +# The CPU frequency is never really used, except in some xtensa timer headers, so it's empty for Linux. diff --git a/components/esp_system/port/soc/linux/Kconfig.system b/components/esp_system/port/soc/linux/Kconfig.system new file mode 100644 index 0000000000..73f92833cd --- /dev/null +++ b/components/esp_system/port/soc/linux/Kconfig.system @@ -0,0 +1 @@ +# Original Kconfig has settings related to brownout, rom and cache. All non-existent on Linux. diff --git a/components/esp_system/port/soc/linux/reset_reason.c b/components/esp_system/port/soc/linux/reset_reason.c new file mode 100644 index 0000000000..b9a7c22a75 --- /dev/null +++ b/components/esp_system/port/soc/linux/reset_reason.c @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * All functions presented here are stubs for the POSIX/Linux implementation of FreeRTOS. + * They are meant to allow to compile, but they DO NOT return any meaningful value. + */ + +#include "esp_system.h" + +// On Linux, this is just a meaningful value to make applications build and run +esp_reset_reason_t esp_reset_reason(void) +{ + return ESP_RST_POWERON; +} diff --git a/components/esp_system/port/soc/linux/system_internal.c b/components/esp_system/port/soc/linux/system_internal.c new file mode 100644 index 0000000000..e2e2ea622d --- /dev/null +++ b/components/esp_system/port/soc/linux/system_internal.c @@ -0,0 +1,17 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/* + * "inner" restart function on POSIX/Linux just exits. +*/ +void esp_restart_noos(void) +{ + printf("restart triggered on Linux, hence exiting\n"); + exit(0); // TODO: other exit value? +} diff --git a/components/freertos/FreeRTOS-Kernel/portable/linux/include/freertos/portmacro_idf.h b/components/freertos/FreeRTOS-Kernel/portable/linux/include/freertos/portmacro_idf.h index 60ff5da208..ac86614f07 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/linux/include/freertos/portmacro_idf.h +++ b/components/freertos/FreeRTOS-Kernel/portable/linux/include/freertos/portmacro_idf.h @@ -22,12 +22,6 @@ extern "C" { #endif -// TODO: IDF-5983 From esp_task.h, should later be used from there -// or be refactored in IDF (e.g. move esp_task.h to freertos) -// See also configMINIMAL_STACK_SIZE for more information. -#define CONFIG_ESP_MAIN_TASK_STACK_SIZE ( ( unsigned short ) (0x4000 + 40) / sizeof(portSTACK_TYPE) ) // should be in Kconfig again -#define CONFIG_ESP_MAIN_TASK_AFFINITY 0 - #define ESP_TASK_PRIO_MAX (configMAX_PRIORITIES) #define ESP_TASK_PRIO_MIN (0) #define ESP_TASK_MAIN_PRIO (ESP_TASK_PRIO_MIN + 1) diff --git a/tools/cmake/build.cmake b/tools/cmake/build.cmake index ae17a51563..b1b758f82e 100644 --- a/tools/cmake/build.cmake +++ b/tools/cmake/build.cmake @@ -225,7 +225,7 @@ function(__build_init idf_path) endforeach() if("${target}" STREQUAL "linux") - set(requires_common freertos log esp_rom esp_common linux) + set(requires_common freertos log esp_rom esp_common esp_system linux) idf_build_set_property(__COMPONENT_REQUIRES_COMMON "${requires_common}") else() # Set components required by all other components in the build