Kaynağa Gözat

linux target: add support for building esp_hw_support, soc and hal components for linux target

Marius Vikhammer 3 yıl önce
ebeveyn
işleme
4ddbaa4166

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

@@ -393,6 +393,14 @@ test_heap_linux:
     - echo "*" | timeout 5 build/test_heap.elf | tee log.txt || true
     - grep "4 Tests 0 Failures 0 Ignored" log.txt
 
+test_esp_hw_support_linux:
+  extends: .host_test_template
+  script:
+    - cd ${IDF_PATH}/components/esp_hw_support/host_test/host_test_linux/
+    - idf.py build
+    - echo "*" | timeout 5 build/test_hw_support_linux.elf | tee log.txt || true
+    - grep "2 Tests 0 Failures 0 Ignored" log.txt
+
 test_esp_timer_cxx:
   extends: .host_test_template
   script:

+ 4 - 0
components/esp_hw_support/.build-test-rules.yml

@@ -15,3 +15,7 @@ components/esp_hw_support/test_apps/rtc_clk:
     - if: IDF_TARGET in ["esp32c6"]
       temporary: true
       reason: Unsupported on C6 for now. TODO IDF-5645
+
+components/heap/host_test/host_test_linux:
+  enable:
+    - if: IDF_TARGET == "linux"

+ 8 - 0
components/esp_hw_support/CMakeLists.txt

@@ -1,5 +1,13 @@
 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 "port/linux/esp_random.c"
+                                 "port/linux/chip_info.c"
+                           INCLUDE_DIRS "include")
+    return()
+endif()
+
 set(requires soc)
 # only esp_hw_support/adc_share_hw_ctrl.c requires efuse component
 set(priv_requires efuse spi_flash bootloader_support)

+ 1 - 1
components/esp_hw_support/Kconfig

@@ -33,7 +33,7 @@ menu "Hardware Settings"
             bool
 
             # Insert chip-specific MAC config
-        rsource "./port/$IDF_TARGET/Kconfig.mac"
+        orsource "./port/$IDF_TARGET/Kconfig.mac"
     endmenu
 
     menu "Sleep Config"

+ 9 - 0
components/esp_hw_support/host_test/host_test_linux/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_hw_support_linux)

+ 3 - 0
components/esp_hw_support/host_test/host_test_linux/README.md

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

+ 3 - 0
components/esp_hw_support/host_test/host_test_linux/main/CMakeLists.txt

@@ -0,0 +1,3 @@
+idf_component_register(SRCS "test_hw_support_linux.c"
+                    INCLUDE_DIRS "."
+                    PRIV_REQUIRES unity)

+ 78 - 0
components/esp_hw_support/host_test/host_test_linux/main/test_hw_support_linux.c

@@ -0,0 +1,78 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include <stdio.h>
+#include <string.h>
+#include "unity.h"
+#include "esp_random.h"
+
+/* Note: these are just sanity tests, the implementation of esp_random do not produce cryptographically secure numbers on Linux
+*/
+
+TEST_CASE("call esp_random()", "[random]")
+{
+    const size_t NUM_RANDOM = 128; /* in most cases this is massive overkill */
+
+    uint32_t zeroes = UINT32_MAX;
+    uint32_t ones = 0;
+    for (int i = 0; i < NUM_RANDOM - 1; i++) {
+        uint32_t r = esp_random();
+        ones |= r;
+        zeroes &= ~r;
+    }
+
+    /* assuming a 'white' random distribution, we can expect
+       usually at least one time each bit will be zero and at
+       least one time each will be one. Statistically this
+       can still fail, just *very* unlikely to. */
+    TEST_ASSERT_EQUAL_HEX32(0, zeroes);
+    TEST_ASSERT_EQUAL_HEX32(UINT32_MAX, ones);
+}
+
+TEST_CASE("call esp_fill_random()", "[random]")
+{
+    const size_t NUM_BUF = 200;
+    const size_t BUF_SZ = 16;
+    uint8_t buf[NUM_BUF][BUF_SZ];
+    uint8_t zero_buf[BUF_SZ];
+    uint8_t one_buf[BUF_SZ];
+
+    bzero(buf, sizeof(buf));
+    bzero(one_buf, sizeof(zero_buf));
+    memset(zero_buf, 0xFF, sizeof(one_buf));
+
+    for (int i = 0; i < NUM_BUF; i++) {
+        esp_fill_random(buf[i], BUF_SZ);
+    }
+    /* No two 128-bit buffers should be the same
+       (again, statistically this could happen but it's very unlikely) */
+    for (int i = 0; i < NUM_BUF; i++) {
+        for (int j = 0; j < NUM_BUF; j++) {
+            if (i != j) {
+                TEST_ASSERT_NOT_EQUAL(0, memcmp(buf[i], buf[j], BUF_SZ));
+            }
+        }
+    }
+
+    /* Do the same all bits are zero and one at least once test across the buffers */
+    for (int i = 0; i < NUM_BUF; i++) {
+        for (int x = 0; x < BUF_SZ; x++) {
+            zero_buf[x] &= ~buf[i][x];
+            one_buf[x] |= buf[i][x];
+        }
+    }
+    for (int x = 0; x < BUF_SZ; x++) {
+        TEST_ASSERT_EQUAL_HEX8(0, zero_buf[x]);
+        TEST_ASSERT_EQUAL_HEX8(0xFF, one_buf[x]);
+    }
+}
+
+
+
+void app_main(void)
+{
+    printf("Running heap linux API host test app");
+    unity_run_menu();
+}

+ 1 - 0
components/esp_hw_support/host_test/host_test_linux/sdkconfig.defaults

@@ -0,0 +1 @@
+CONFIG_IDF_TARGET="linux"

+ 1 - 0
components/esp_hw_support/include/esp_chip_info.h

@@ -27,6 +27,7 @@ typedef enum {
     CHIP_ESP32H4 = 6, //!< ESP32-H4
     CHIP_ESP32C2 = 12, //!< ESP32-C2
     CHIP_ESP32C6 = 13, //!< ESP32-C6
+    CHIP_POSIX_LINUX = 999, //!< The code is running on POSIX/Linux simulator
 } esp_chip_model_t;
 
 /* Chip feature flags, used in esp_chip_info_t */

+ 20 - 0
components/esp_hw_support/port/linux/chip_info.c

@@ -0,0 +1,20 @@
+/*
+ * SPDX-FileCopyrightText: 2013-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <string.h>
+#include "esp_chip_info.h"
+
+void esp_chip_info(esp_chip_info_t *out_info)
+{
+    memset(out_info, 0, sizeof(*out_info));
+
+    out_info->model = CHIP_POSIX_LINUX;
+
+    // TODO: May need to adjust once networking becomes available on POSIX/Linux
+    out_info->features = 0;
+    out_info->revision = 0;
+    out_info->cores = 1;
+}

+ 40 - 0
components/esp_hw_support/port/linux/esp_random.c

@@ -0,0 +1,40 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include <stdlib.h>
+#include <time.h>
+#include <stdint.h>
+#include <assert.h>
+#include <string.h>
+#include <sys/param.h>
+
+#include "esp_log.h"
+
+static const char* TAG = "esp-random";
+
+static void __attribute__((constructor)) esp_random_init()
+{
+    srand(time(NULL));
+    ESP_LOGW(TAG, "esp_random do not provide a cryptographically secure numbers on Linux, and should never be used for anything security related");
+}
+
+uint32_t esp_random(void)
+{
+    /* Adding INT32_MAX to shift the results such that after conversion to uint32_t we still get 32 bits of random data */
+    return (rand() + INT32_MAX);
+}
+
+void esp_fill_random(void *buf, size_t len)
+{
+    assert(buf != NULL);
+    uint8_t *buf_bytes = (uint8_t *)buf;
+    while (len > 0) {
+        uint32_t word = esp_random();
+        uint32_t to_copy = MIN(sizeof(word), len);
+        memcpy(buf_bytes, &word, to_copy);
+        buf_bytes += to_copy;
+        len -= to_copy;
+    }
+}

+ 6 - 0
components/hal/CMakeLists.txt

@@ -1,5 +1,11 @@
 idf_build_get_property(target IDF_TARGET)
 
+# On Linux, there is currently no HAL, hence this simple component registration
+if(${target} STREQUAL "linux")
+    idf_component_register()
+    return()
+endif()
+
 set(srcs "mpu_hal.c"
          "efuse_hal.c"
          "${target}/efuse_hal.c"

+ 12 - 3
components/soc/CMakeLists.txt

@@ -1,9 +1,18 @@
-idf_component_register(SRCS "lldesc.c"
-                            "dport_access_common.c"
+idf_build_get_property(target IDF_TARGET)
+
+# On Linux the soc component is a simple wrapper, without much functionality
+if(NOT ${target} STREQUAL "linux")
+     set(srcs "lldesc.c"
+              "dport_access_common.c")
+endif()
+
+idf_component_register(SRCS ${srcs}
                        INCLUDE_DIRS include
                        LDFRAGMENTS "linker.lf")
 
 idf_build_get_property(target IDF_TARGET)
 add_subdirectory(${target})
 
-target_linker_script(${COMPONENT_LIB} INTERFACE "${target}/ld/${target}.peripherals.ld")
+if(NOT CONFIG_IDF_TARGET_LINUX)
+     target_linker_script(${COMPONENT_LIB} INTERFACE "${target}/ld/${target}.peripherals.ld")
+endif()

+ 1 - 0
components/soc/linux/CMakeLists.txt

@@ -0,0 +1 @@
+target_include_directories(${COMPONENT_LIB} INTERFACE . include)

+ 25 - 0
components/soc/linux/include/soc/soc_caps.h

@@ -0,0 +1,25 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+// The long term plan is to have a single soc_caps.h for each peripheral.
+// During the refactoring and multichip support development process, we
+// seperate these information into periph_caps.h for each peripheral and
+// include them here.
+
+/*
+ * These defines are parsed and imported as kconfig variables via the script
+ * `tools/gen_soc_caps_kconfig/gen_soc_caps_kconfig.py`
+ *
+ * If this file is changed the script will automatically run the script
+ * and generate the kconfig variables as part of the pre-commit hooks.
+ *
+ * It can also be ran manually with `./tools/gen_soc_caps_kconfig/gen_soc_caps_kconfig.py 'components/soc/esp32c3/include/soc/'`
+ *
+ * For more information see `tools/gen_soc_caps_kconfig/README.md`
+ *
+*/
+
+#pragma once

+ 1 - 1
tools/cmake/build.cmake

@@ -226,7 +226,7 @@ function(__build_init idf_path)
     endforeach()
 
     if("${target}" STREQUAL "linux")
-        set(requires_common freertos heap log esp_rom esp_common esp_system linux)
+        set(requires_common freertos esp_hw_support heap log soc hal 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

+ 2 - 1
tools/mocks/driver/CMakeLists.txt

@@ -10,7 +10,6 @@ set(include_dirs
     "${original_driver_dir}/include"
     "${original_driver_dir}/include/driver"
     "${CMAKE_CURRENT_SOURCE_DIR}/../hal/include"
-    "${CMAKE_CURRENT_SOURCE_DIR}/../soc/include" # for I2C SOC caps
     "${CMAKE_CURRENT_SOURCE_DIR}/../esp_hw_support/include")
 
 idf_component_mock(INCLUDE_DIRS ${include_dirs}
@@ -20,3 +19,5 @@ idf_component_mock(INCLUDE_DIRS ${include_dirs}
     ${original_driver_dir}/include/driver/spi_common.h
     ${original_driver_dir}/include/driver/i2c.h
     ${original_driver_dir}/include/driver/gpio.h)
+
+target_compile_definitions(${COMPONENT_LIB} PUBLIC SOC_I2C_NUM=2)

+ 0 - 11
tools/mocks/soc/include/soc/soc_caps.h

@@ -1,11 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-
-/**
- * NOTE: this is not the original header file from the soc component. It is a stripped-down copy to support mocking.
- */
-
-#define SOC_I2C_NUM             (2)

+ 0 - 2
tools/test_apps/linux_compatible/hello_world_linux_compatible/main/CMakeLists.txt

@@ -1,4 +1,2 @@
 idf_component_register(SRCS "hello_world_main.c"
                     INCLUDE_DIRS "")
-
-target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

+ 27 - 2
tools/test_apps/linux_compatible/hello_world_linux_compatible/main/hello_world_main.c

@@ -5,20 +5,45 @@
  */
 
 #include <stdio.h>
-#include <stdlib.h>
+#include <inttypes.h>
 #include "sdkconfig.h"
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
+#include "esp_chip_info.h"
+#include "esp_system.h"
 
 void app_main(void)
 {
     printf("Hello world!\n");
 
+    /* Print chip information */
+    esp_chip_info_t chip_info;
+    uint32_t flash_size;
+    esp_chip_info(&chip_info);
+    printf("This is %s chip with %d CPU core(s), WiFi%s%s%s, ",
+           CONFIG_IDF_TARGET,
+           chip_info.cores,
+           (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
+           (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "",
+           (chip_info.features & CHIP_FEATURE_IEEE802154) ? ", 802.15.4 (Zigbee/Thread)" : "");
+
+    unsigned major_rev = chip_info.revision / 100;
+    unsigned minor_rev = chip_info.revision % 100;
+    printf("silicon revision v%d.%d, ", major_rev, minor_rev);
+
+    /* get_flash_size API not available on Linux*/
+    flash_size = UINT32_MAX;
+
+    printf("%" PRIu32 "MB %s flash\n", flash_size / (uint32_t)(1024 * 1024),
+           (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
+
+    printf("Minimum free heap size: %" PRIu32 " bytes\n", esp_get_minimum_free_heap_size());
+
     for (int i = 10; i >= 0; i--) {
         printf("Restarting in %d seconds...\n", i);
         vTaskDelay(1000 / portTICK_PERIOD_MS);
     }
     printf("Restarting now.\n");
     fflush(stdout);
-    exit(0);
+    esp_restart();
 }