eeprom sim: Enhance & refactor native part so it works w emb libCs

For the parts of the simulator which are dedicated for the native
platforms (POSIX arch based):
* Refactor the parts that interacts with the host, so it is possible to
  use it also with embedded libCs
* Enhance it with more options to allow:
  * Keeping the content just in RAM
  * Erasing the EEPROM file at exit
  * Clearing the file at boot
* Also show in the command line help the default file name.

As part of this:

* Update the kconfig dependencies, so we allow building it with other
  C libraries in the native targets
* Update the table in the native_sim docs to indicate all C libraries
  are supproted now

Signed-off-by: Alberto Escolar Piedras <alberto.escolar.piedras@nordicsemi.no>
This commit is contained in:
Alberto Escolar Piedras 2024-09-27 10:13:30 +02:00 committed by Alberto Escolar
parent 4da4ee8ece
commit 3ee9b40a5a
6 changed files with 197 additions and 59 deletions

View file

@ -702,7 +702,7 @@ host libC (:kconfig:option:`CONFIG_EXTERNAL_LIBC`):
Console backend, :ref:`POSIX arch console <nsim_back_console>`, :kconfig:option:`CONFIG_POSIX_ARCH_CONSOLE`, All
Display, :ref:`Display SDL <nsim_per_disp_sdl>`, :kconfig:option:`CONFIG_SDL_DISPLAY`, All
Entropy, :ref:`Native posix entropy <nsim_per_entr>`, :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 <nsim_per_ethe>`, :kconfig:option:`CONFIG_ETH_NATIVE_POSIX`, All
Flash, :ref:`Flash simulator <nsim_per_flash_simu>`, :kconfig:option:`CONFIG_FLASH_SIMULATOR`, All

View file

@ -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)

View file

@ -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

View file

@ -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 <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
#include "eeprom_simulator_native.h"
#include "cmdline.h"
#include "soc.h"
#endif
#endif /* CONFIG_ARCH_POSIX */
#include <zephyr/device.h>
#include <zephyr/drivers/eeprom.h>
@ -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,36 +213,23 @@ 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;
}
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;
}
} else {
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,
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",
{.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" },
.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
};

View file

@ -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 <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <nsi_tracing.h>
/*
* 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);
}
}

View file

@ -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 <stdbool.h>
#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 */