diff --git a/.gitlab/ci/host-test.yml b/.gitlab/ci/host-test.yml index f666dd07182..287386c56b3 100644 --- a/.gitlab/ci/host-test.yml +++ b/.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: diff --git a/components/esp_hw_support/.build-test-rules.yml b/components/esp_hw_support/.build-test-rules.yml index 0de7028cab1..9f131e0743d 100644 --- a/components/esp_hw_support/.build-test-rules.yml +++ b/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" diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index 6eb8cb86566..7a0ac71c502 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/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) diff --git a/components/esp_hw_support/Kconfig b/components/esp_hw_support/Kconfig index 7d022f50c58..9d5306d4f89 100644 --- a/components/esp_hw_support/Kconfig +++ b/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" diff --git a/components/esp_hw_support/host_test/host_test_linux/CMakeLists.txt b/components/esp_hw_support/host_test/host_test_linux/CMakeLists.txt new file mode 100644 index 00000000000..6cdacc8bfa9 --- /dev/null +++ b/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) diff --git a/components/esp_hw_support/host_test/host_test_linux/README.md b/components/esp_hw_support/host_test/host_test_linux/README.md new file mode 100644 index 00000000000..ab0780283aa --- /dev/null +++ b/components/esp_hw_support/host_test/host_test_linux/README.md @@ -0,0 +1,3 @@ +| Supported Targets | Linux | +| ----------------- | ----- | + diff --git a/components/esp_hw_support/host_test/host_test_linux/main/CMakeLists.txt b/components/esp_hw_support/host_test/host_test_linux/main/CMakeLists.txt new file mode 100644 index 00000000000..892d36db2d5 --- /dev/null +++ b/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) diff --git a/components/esp_hw_support/host_test/host_test_linux/main/test_hw_support_linux.c b/components/esp_hw_support/host_test/host_test_linux/main/test_hw_support_linux.c new file mode 100644 index 00000000000..d581b3532b4 --- /dev/null +++ b/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 +#include +#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(); +} diff --git a/components/esp_hw_support/host_test/host_test_linux/sdkconfig.defaults b/components/esp_hw_support/host_test/host_test_linux/sdkconfig.defaults new file mode 100644 index 00000000000..9b39f10b99e --- /dev/null +++ b/components/esp_hw_support/host_test/host_test_linux/sdkconfig.defaults @@ -0,0 +1 @@ +CONFIG_IDF_TARGET="linux" diff --git a/components/esp_hw_support/include/esp_chip_info.h b/components/esp_hw_support/include/esp_chip_info.h index 3e976af880d..5f56c561685 100644 --- a/components/esp_hw_support/include/esp_chip_info.h +++ b/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 */ diff --git a/components/esp_hw_support/port/linux/chip_info.c b/components/esp_hw_support/port/linux/chip_info.c new file mode 100644 index 00000000000..684886ccc47 --- /dev/null +++ b/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 +#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; +} diff --git a/components/esp_hw_support/port/linux/esp_random.c b/components/esp_hw_support/port/linux/esp_random.c new file mode 100644 index 00000000000..38118269059 --- /dev/null +++ b/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 +#include +#include +#include +#include +#include + +#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; + } +} diff --git a/components/hal/CMakeLists.txt b/components/hal/CMakeLists.txt index 9c28dfbab4c..bb638925e57 100644 --- a/components/hal/CMakeLists.txt +++ b/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" diff --git a/components/soc/CMakeLists.txt b/components/soc/CMakeLists.txt index 9dacce53357..45cb7ed9b4b 100644 --- a/components/soc/CMakeLists.txt +++ b/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() diff --git a/components/soc/linux/CMakeLists.txt b/components/soc/linux/CMakeLists.txt new file mode 100644 index 00000000000..47e3727b8c1 --- /dev/null +++ b/components/soc/linux/CMakeLists.txt @@ -0,0 +1 @@ +target_include_directories(${COMPONENT_LIB} INTERFACE . include) diff --git a/components/soc/linux/include/soc/soc_caps.h b/components/soc/linux/include/soc/soc_caps.h new file mode 100644 index 00000000000..899a604ce05 --- /dev/null +++ b/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 diff --git a/tools/cmake/build.cmake b/tools/cmake/build.cmake index a46aa63f7d4..1224cc75105 100644 --- a/tools/cmake/build.cmake +++ b/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 diff --git a/tools/mocks/driver/CMakeLists.txt b/tools/mocks/driver/CMakeLists.txt index 218f7deb18c..1d81a73d761 100644 --- a/tools/mocks/driver/CMakeLists.txt +++ b/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) diff --git a/tools/mocks/soc/include/soc/soc_caps.h b/tools/mocks/soc/include/soc/soc_caps.h deleted file mode 100644 index 5d60ac48f55..00000000000 --- a/tools/mocks/soc/include/soc/soc_caps.h +++ /dev/null @@ -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) diff --git a/tools/test_apps/linux_compatible/hello_world_linux_compatible/main/CMakeLists.txt b/tools/test_apps/linux_compatible/hello_world_linux_compatible/main/CMakeLists.txt index 392c049cbff..07686dc8e11 100644 --- a/tools/test_apps/linux_compatible/hello_world_linux_compatible/main/CMakeLists.txt +++ b/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") diff --git a/tools/test_apps/linux_compatible/hello_world_linux_compatible/main/hello_world_main.c b/tools/test_apps/linux_compatible/hello_world_linux_compatible/main/hello_world_main.c index 988ea320fc7..d8696bba6e1 100644 --- a/tools/test_apps/linux_compatible/hello_world_linux_compatible/main/hello_world_main.c +++ b/tools/test_apps/linux_compatible/hello_world_linux_compatible/main/hello_world_main.c @@ -5,20 +5,45 @@ */ #include -#include +#include #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(); }