Procházet zdrojové kódy

Merge branch 'feature/esp_system_linux' into 'master'

esp_system partially buildable on Linux

Closes IDF-5983

See merge request espressif/esp-idf!21055
Jakob Hasse před 3 roky
rodič
revize
c381fee319

+ 8 - 0
.gitlab/ci/host-test.yml

@@ -370,6 +370,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:

+ 3 - 0
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

+ 10 - 0
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)

+ 0 - 51
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);
-}

+ 9 - 0
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)

+ 2 - 0
components/esp_system/host_test/test_esp_system/README.md

@@ -0,0 +1,2 @@
+| Supported Targets | Linux |
+| ----------------- | ----- |

+ 3 - 0
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)

+ 120 - 0
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 <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#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();
+}

+ 2 - 0
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

+ 1 - 1
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:

+ 2 - 1
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})

+ 60 - 0
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 <stdint.h>
+#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);
+}

+ 47 - 0
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 <stdlib.h>
+#include <stdint.h>
+#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);
+}

+ 1 - 0
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.

+ 1 - 0
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.

+ 18 - 0
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;
+}

+ 17 - 0
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 <stdio.h>
+#include <stdlib.h>
+
+/*
+ * "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?
+}

+ 0 - 6
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)

+ 1 - 1
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