Skip to content

Commit

Permalink
Merge branch 'feature/linux_esp_hw_support' into 'master'
Browse files Browse the repository at this point in the history
linux target: add support for building esp_hw_support, soc and hal components for linux target

See merge request espressif/esp-idf!21502
  • Loading branch information
0xjakob committed Dec 12, 2022
2 parents c4c904c + 4ddbaa4 commit b36c0e8
Show file tree
Hide file tree
Showing 21 changed files with 250 additions and 21 deletions.
8 changes: 8 additions & 0 deletions .gitlab/ci/host-test.yml
Expand Up @@ -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:
Expand Down
4 changes: 4 additions & 0 deletions components/esp_hw_support/.build-test-rules.yml
Expand Up @@ -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 changes: 8 additions & 0 deletions 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)
Expand Down
2 changes: 1 addition & 1 deletion components/esp_hw_support/Kconfig
Expand Up @@ -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"
Expand Down
@@ -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 changes: 3 additions & 0 deletions components/esp_hw_support/host_test/host_test_linux/README.md
@@ -0,0 +1,3 @@
| Supported Targets | Linux |
| ----------------- | ----- |

@@ -0,0 +1,3 @@
idf_component_register(SRCS "test_hw_support_linux.c"
INCLUDE_DIRS "."
PRIV_REQUIRES unity)
@@ -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();
}
@@ -0,0 +1 @@
CONFIG_IDF_TARGET="linux"
1 change: 1 addition & 0 deletions components/esp_hw_support/include/esp_chip_info.h
Expand Up @@ -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 */
Expand Down
20 changes: 20 additions & 0 deletions 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 changes: 40 additions & 0 deletions 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 changes: 6 additions & 0 deletions 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"
Expand Down
15 changes: 12 additions & 3 deletions 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 change: 1 addition & 0 deletions components/soc/linux/CMakeLists.txt
@@ -0,0 +1 @@
target_include_directories(${COMPONENT_LIB} INTERFACE . include)
25 changes: 25 additions & 0 deletions 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
2 changes: 1 addition & 1 deletion tools/cmake/build.cmake
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion tools/mocks/driver/CMakeLists.txt
Expand Up @@ -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}
Expand All @@ -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)
11 changes: 0 additions & 11 deletions tools/mocks/soc/include/soc/soc_caps.h

This file was deleted.

@@ -1,4 +1,2 @@
idf_component_register(SRCS "hello_world_main.c"
INCLUDE_DIRS "")

target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
Expand Up @@ -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();
}

0 comments on commit b36c0e8

Please sign in to comment.