diff --git a/boards/native/native_sim/doc/index.rst b/boards/native/native_sim/doc/index.rst index 3f6033884b3..a83d1cd7790 100644 --- a/boards/native/native_sim/doc/index.rst +++ b/boards/native/native_sim/doc/index.rst @@ -702,7 +702,7 @@ host libC (:kconfig:option:`CONFIG_EXTERNAL_LIBC`): Console backend, :ref:`POSIX arch console `, :kconfig:option:`CONFIG_POSIX_ARCH_CONSOLE`, All Display, :ref:`Display SDL `, :kconfig:option:`CONFIG_SDL_DISPLAY`, All Entropy, :ref:`Native posix entropy `, :kconfig:option:`CONFIG_FAKE_ENTROPY_NATIVE_POSIX`, All - EEPROM, EEPROM simulator, :kconfig:option:`CONFIG_EEPROM_SIMULATOR`, Host libC + EEPROM, EEPROM simulator, :kconfig:option:`CONFIG_EEPROM_SIMULATOR`, All EEPROM, EEPROM emulator, :kconfig:option:`CONFIG_EEPROM_EMULATOR`, All Ethernet, :ref:`Eth native_posix `, :kconfig:option:`CONFIG_ETH_NATIVE_POSIX`, All Flash, :ref:`Flash simulator `, :kconfig:option:`CONFIG_FLASH_SIMULATOR`, All diff --git a/drivers/eeprom/CMakeLists.txt b/drivers/eeprom/CMakeLists.txt index 0e2ce2d01d4..4b148e9f1a2 100644 --- a/drivers/eeprom/CMakeLists.txt +++ b/drivers/eeprom/CMakeLists.txt @@ -10,7 +10,14 @@ zephyr_library_sources_ifdef(CONFIG_EEPROM_SHELL eeprom_shell.c) zephyr_library_sources_ifdef(CONFIG_EEPROM_AT2X eeprom_at2x.c) zephyr_library_sources_ifdef(CONFIG_EEPROM_LPC11U6X eeprom_lpc11u6x.c) zephyr_library_sources_ifdef(CONFIG_EEPROM_STM32 eeprom_stm32.c) -zephyr_library_sources_ifdef(CONFIG_EEPROM_SIMULATOR eeprom_simulator.c) +if(CONFIG_EEPROM_SIMULATOR) + zephyr_library_sources(eeprom_simulator.c) + if(CONFIG_NATIVE_LIBRARY) + target_sources(native_simulator INTERFACE eeprom_simulator_native.c) + elseif(CONFIG_ARCH_POSIX) + zephyr_library_sources(eeprom_simulator_native.c) + endif() +endif() zephyr_library_sources_ifdef(CONFIG_EEPROM_EMULATOR eeprom_emulator.c) zephyr_library_sources_ifdef(CONFIG_EEPROM_TMP116 eeprom_tmp116.c) zephyr_library_sources_ifdef(CONFIG_EEPROM_XEC eeprom_mchp_xec.c) diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig index 9b85ffe6dc7..87733d2c2e1 100644 --- a/drivers/eeprom/Kconfig +++ b/drivers/eeprom/Kconfig @@ -104,7 +104,6 @@ config EEPROM_SIMULATOR bool "Simulated EEPROM driver" default y depends on DT_HAS_ZEPHYR_SIM_EEPROM_ENABLED - depends on !(ARCH_POSIX && !EXTERNAL_LIBC) select STATS select STATS_NAMES help diff --git a/drivers/eeprom/eeprom_simulator.c b/drivers/eeprom/eeprom_simulator.c index f6a604bcf6f..a8daf710387 100644 --- a/drivers/eeprom/eeprom_simulator.c +++ b/drivers/eeprom/eeprom_simulator.c @@ -8,18 +8,10 @@ #define DT_DRV_COMPAT zephyr_sim_eeprom #ifdef CONFIG_ARCH_POSIX -#undef _POSIX_C_SOURCE -/* Note: This is used only for interaction with the host C library, and is therefore exempt of - * coding guidelines rule A.4&5 which applies to the embedded code using embedded libraries - */ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include +#include "eeprom_simulator_native.h" #include "cmdline.h" #include "soc.h" -#endif +#endif /* CONFIG_ARCH_POSIX */ #include #include @@ -87,10 +79,13 @@ STATS_NAME(eeprom_sim_thresholds, max_len) STATS_NAME_END(eeprom_sim_thresholds); #ifdef CONFIG_ARCH_POSIX -static uint8_t *mock_eeprom; +static char *mock_eeprom; static int eeprom_fd = -1; static const char *eeprom_file_path; -static const char default_eeprom_file_path[] = "eeprom.bin"; +#define DEFAULT_EEPROM_FILE_PATH "eeprom.bin" +static bool eeprom_erase_at_start; +static bool eeprom_rm_at_exit; +static bool eeprom_in_ram; #else static uint8_t mock_eeprom[DT_INST_PROP(0, size)]; #endif /* CONFIG_ARCH_POSIX */ @@ -218,35 +213,22 @@ static const struct eeprom_sim_config eeprom_sim_config_0 = { static int eeprom_mock_init(const struct device *dev) { - if (eeprom_file_path == NULL) { - eeprom_file_path = default_eeprom_file_path; + int rc; + + ARG_UNUSED(dev); + + if (eeprom_in_ram == false && eeprom_file_path == NULL) { + eeprom_file_path = DEFAULT_EEPROM_FILE_PATH; } - eeprom_fd = open(eeprom_file_path, O_RDWR | O_CREAT, (mode_t)0600); - if (eeprom_fd == -1) { - posix_print_warning("Failed to open eeprom device file " - "%s: %s\n", - eeprom_file_path, strerror(errno)); + rc = eeprom_mock_init_native(eeprom_in_ram, &mock_eeprom, DT_INST_PROP(0, size), &eeprom_fd, + eeprom_file_path, 0xFF, eeprom_erase_at_start); + + if (rc < 0) { return -EIO; + } else { + return 0; } - - if (ftruncate(eeprom_fd, DT_INST_PROP(0, size)) == -1) { - posix_print_warning("Failed to resize eeprom device file " - "%s: %s\n", - eeprom_file_path, strerror(errno)); - return -EIO; - } - - mock_eeprom = mmap(NULL, DT_INST_PROP(0, size), - PROT_WRITE | PROT_READ, MAP_SHARED, eeprom_fd, 0); - if (mock_eeprom == MAP_FAILED) { - posix_print_warning("Failed to mmap eeprom device file " - "%s: %s\n", - eeprom_file_path, strerror(errno)); - return -EIO; - } - - return 0; } #else @@ -269,35 +251,43 @@ static int eeprom_sim_init(const struct device *dev) return eeprom_mock_init(dev); } -DEVICE_DT_INST_DEFINE(0, &eeprom_sim_init, NULL, - NULL, &eeprom_sim_config_0, POST_KERNEL, - CONFIG_EEPROM_INIT_PRIORITY, &eeprom_sim_api); +DEVICE_DT_INST_DEFINE(0, &eeprom_sim_init, NULL, NULL, &eeprom_sim_config_0, POST_KERNEL, + CONFIG_EEPROM_INIT_PRIORITY, &eeprom_sim_api); #ifdef CONFIG_ARCH_POSIX static void eeprom_native_cleanup(void) { - if ((mock_eeprom != MAP_FAILED) && (mock_eeprom != NULL)) { - munmap(mock_eeprom, DT_INST_PROP(0, size)); - } - - if (eeprom_fd != -1) { - close(eeprom_fd); - } + eeprom_mock_cleanup_native(eeprom_in_ram, eeprom_fd, mock_eeprom, DT_INST_PROP(0, size), + eeprom_file_path, eeprom_rm_at_exit); } static void eeprom_native_options(void) { static struct args_struct_t eeprom_options[] = { - { .manual = false, - .is_mandatory = false, - .is_switch = false, - .option = "eeprom", - .name = "path", - .type = 's', - .dest = (void *)&eeprom_file_path, - .call_when_found = NULL, - .descript = "Path to binary file to be used as eeprom" }, + {.option = "eeprom", + .name = "path", + .type = 's', + .dest = (void *)&eeprom_file_path, + .descript = "Path to binary file to be used as EEPROM, by default " + "\"" DEFAULT_EEPROM_FILE_PATH "\""}, + {.is_switch = true, + .option = "eeprom_erase", + .type = 'b', + .dest = (void *)&eeprom_erase_at_start, + .descript = "Erase the EEPROM content at startup"}, + {.is_switch = true, + .option = "eeprom_rm", + .type = 'b', + .dest = (void *)&eeprom_rm_at_exit, + .descript = "Remove the EEPROM file when terminating the execution"}, + {.is_switch = true, + .option = "eeprom_in_ram", + .type = 'b', + .dest = (void *)&eeprom_in_ram, + .descript = "Instead of a file, keep the file content just in RAM. If this is " + "set, eeprom, eeprom_erase & eeprom_rm are ignored, and the EEPROM " + "content is always erased at startup"}, ARG_TABLE_ENDMARKER }; diff --git a/drivers/eeprom/eeprom_simulator_native.c b/drivers/eeprom/eeprom_simulator_native.c new file mode 100644 index 00000000000..52276e03fd1 --- /dev/null +++ b/drivers/eeprom/eeprom_simulator_native.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + * + * Part of EEPROM simulator which interacts with the host OS / Linux + * + * When building for the native simulator, this file is built in the + * native simulator runner/host context, and not in Zephyr/embedded context. + */ + +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Initialize the EEPROM buffer. + * And, if the content is to be kept on disk map it to the buffer to the file. + * + * Returns -1 on failure + * 0 on success + */ +int eeprom_mock_init_native(bool eeprom_in_ram, char **mock_eeprom, unsigned int size, + int *eeprom_fd, const char *eeprom_file_path, unsigned int erase_value, + bool eeprom_erase_at_start) +{ + struct stat f_stat; + int rc; + + if (eeprom_in_ram == true) { + *mock_eeprom = (char *)malloc(size); + if (*mock_eeprom == NULL) { + nsi_print_warning("Could not allocate EEPROM in the process heap %s\n", + strerror(errno)); + return -1; + } + } else { + *eeprom_fd = open(eeprom_file_path, O_RDWR | O_CREAT, (mode_t)0600); + if (*eeprom_fd == -1) { + nsi_print_warning("Failed to open EEPROM device file %s: %s\n", + eeprom_file_path, strerror(errno)); + return -1; + } + + rc = fstat(*eeprom_fd, &f_stat); + if (rc) { + nsi_print_warning("Failed to get status of EEPROM device file %s: %s\n", + eeprom_file_path, strerror(errno)); + return -1; + } + + if (ftruncate(*eeprom_fd, size) == -1) { + nsi_print_warning("Failed to resize EEPROM device file %s: %s\n", + eeprom_file_path, strerror(errno)); + return -1; + } + + *mock_eeprom = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, *eeprom_fd, 0); + if (*mock_eeprom == MAP_FAILED) { + nsi_print_warning("Failed to mmap EEPROM device file %s: %s\n", + eeprom_file_path, strerror(errno)); + return -1; + } + } + + if ((eeprom_erase_at_start == true) || (eeprom_in_ram == true) || (f_stat.st_size == 0)) { + /* Erase the EEPROM by setting all bits to the configured erase value */ + (void)memset(*mock_eeprom, erase_value, size); + } + + return 0; +} + +/* + * If in RAM: Free the mock buffer + * If in disk: unmap the eeprom file from RAM, close the file, and if configured to do so, + * delete the file. + */ +void eeprom_mock_cleanup_native(bool eeprom_in_ram, int eeprom_fd, char *mock_eeprom, + unsigned int size, const char *eeprom_file_path, + bool eeprom_rm_at_exit) +{ + + if (eeprom_in_ram == true) { + if (mock_eeprom != NULL) { + free(mock_eeprom); + } + return; + } + + if ((mock_eeprom != MAP_FAILED) && (mock_eeprom != NULL)) { + munmap(mock_eeprom, size); + } + + if (eeprom_fd != -1) { + close(eeprom_fd); + } + + if ((eeprom_rm_at_exit == true) && (eeprom_file_path != NULL)) { + /* We try to remove the file but do not error out if we can't */ + (void)remove(eeprom_file_path); + } +} diff --git a/drivers/eeprom/eeprom_simulator_native.h b/drivers/eeprom/eeprom_simulator_native.h new file mode 100644 index 00000000000..ecd3071fef7 --- /dev/null +++ b/drivers/eeprom/eeprom_simulator_native.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef DRIVERS_EEPROM_EEPROM_SIMULATOR_NATIVE_H +#define DRIVERS_EEPROM_EEPROM_SIMULATOR_NATIVE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int eeprom_mock_init_native(bool eeprom_in_ram, char **mock_eeprom, unsigned int size, + int *eeprom_fd, const char *eeprom_file_path, unsigned int erase_value, + bool eeprom_erase_at_start); + +void eeprom_mock_cleanup_native(bool eeprom_in_ram, int eeprom_fd, char *mock_eeprom, + unsigned int size, const char *eeprom_file_path, + bool eeprom_rm_at_exit); + +#ifdef __cplusplus +} +#endif + +#endif /* DRIVERS_EEPROM_EEPROM_SIMULATOR_NATIVE_H */