Skip to content

Commit 999b8dd

Browse files
committed
drivers/flash/flash_simulator: Add write and erase callbacks
Add the functionality that allows to register write and erase callbacks. The callbacks can modify the behaviour of this operations. It are meant to be used during testing of the situation when the memory starts to generate errors or the data cannot be trusted anymore. It expands the testing possibility, for a situation when the module is tested that checks the data integrity and and we cannot just jump in between its internal write and read operations to inject an error. Signed-off-by: Radosław Koppel <[email protected]>
1 parent 64a1477 commit 999b8dd

File tree

2 files changed

+171
-9
lines changed

2 files changed

+171
-9
lines changed

drivers/flash/flash_simulator.c

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include <zephyr/stats/stats.h>
1818
#include <string.h>
1919

20+
#include <zephyr/drivers/flash/flash_simulator.h>
21+
2022
#ifdef CONFIG_ARCH_POSIX
2123

2224
#include "flash_simulator_native.h"
@@ -170,6 +172,23 @@ static const struct flash_parameters flash_sim_parameters = {
170172
},
171173
};
172174

175+
#ifdef CONFIG_ARCH_POSIX
176+
static struct flash_simulator_params flash_sim_params = {
177+
#else
178+
static const struct flash_simulator_params flash_sim_params = {
179+
.memory = mock_flash,
180+
#endif
181+
.memory_size = FLASH_SIMULATOR_FLASH_SIZE,
182+
.base_offset = FLASH_SIMULATOR_BASE_OFFSET,
183+
.erase_unit = FLASH_SIMULATOR_ERASE_UNIT,
184+
.prog_unit = FLASH_SIMULATOR_PROG_UNIT,
185+
.explicit_erase = IS_ENABLED(CONFIG_FLASH_SIMULATOR_EXPLICIT_ERASE),
186+
.erase_value = FLASH_SIMULATOR_ERASE_VALUE,
187+
};
188+
189+
static const struct flash_simulator_cb *flash_simulator_cbs;
190+
191+
173192
static int flash_range_is_valid(const struct device *dev, off_t offset,
174193
size_t len)
175194
{
@@ -264,6 +283,13 @@ static int flash_sim_write(const struct device *dev, const off_t offset,
264283
}
265284
#endif
266285

286+
flash_simulator_write_byte_cb_t write_cb = NULL;
287+
const struct flash_simulator_cb *cb = flash_simulator_cbs;
288+
289+
if (cb != NULL) {
290+
write_cb = cb->write_byte;
291+
}
292+
267293
for (uint32_t i = 0; i < len; i++) {
268294
#ifdef CONFIG_FLASH_SIMULATOR_STATS
269295
if (data_part_ignored) {
@@ -273,16 +299,26 @@ static int flash_sim_write(const struct device *dev, const off_t offset,
273299
}
274300
#endif /* CONFIG_FLASH_SIMULATOR_STATS */
275301

276-
/* only pull bits to zero */
302+
uint8_t data_val = *((const uint8_t *)data + i);
303+
277304
#if defined(CONFIG_FLASH_SIMULATOR_EXPLICIT_ERASE)
278305
#if FLASH_SIMULATOR_ERASE_VALUE == 0xFF
279-
*(MOCK_FLASH(offset + i)) &= *((uint8_t *)data + i);
306+
/* only pull bits to zero */
307+
data_val &= *(MOCK_FLASH(offset + i));
280308
#else
281-
*(MOCK_FLASH(offset + i)) |= *((uint8_t *)data + i);
309+
/* only pull bits to one */
310+
data_val |= *(MOCK_FLASH(offset + i));
282311
#endif
283-
#else
284-
*(MOCK_FLASH(offset + i)) = *((uint8_t *)data + i);
285312
#endif
313+
if (write_cb != NULL) {
314+
int ret = write_cb(dev, &flash_sim_params,
315+
offset + i, data_val);
316+
if (ret < 0) {
317+
return ret;
318+
}
319+
data_val = (uint8_t)ret;
320+
}
321+
*(MOCK_FLASH(offset + i)) = data_val;
286322
}
287323

288324
FLASH_SIM_STATS_INCN(flash_sim_stats, bytes_written, len);
@@ -297,20 +333,28 @@ static int flash_sim_write(const struct device *dev, const off_t offset,
297333
return 0;
298334
}
299335

300-
static void unit_erase(const uint32_t unit)
336+
static int unit_erase(const struct device *dev, const uint32_t unit)
301337
{
302338
const off_t unit_addr = unit * FLASH_SIMULATOR_ERASE_UNIT;
339+
flash_simulator_erase_unit_cb_t erase_cb = NULL;
340+
const struct flash_simulator_cb *cb = flash_simulator_cbs;
341+
342+
if (cb != NULL) {
343+
erase_cb = cb->erase_unit;
344+
}
345+
if (erase_cb != NULL) {
346+
return erase_cb(dev, &flash_sim_params, unit_addr);
347+
}
303348

304349
/* erase the memory unit by setting it to erase value */
305350
memset(MOCK_FLASH(unit_addr), FLASH_SIMULATOR_ERASE_VALUE,
306351
FLASH_SIMULATOR_ERASE_UNIT);
352+
return 0;
307353
}
308354

309355
static int flash_sim_erase(const struct device *dev, const off_t offset,
310356
const size_t len)
311357
{
312-
ARG_UNUSED(dev);
313-
314358
if (!flash_range_is_valid(dev, offset, len)) {
315359
return -EINVAL;
316360
}
@@ -335,8 +379,13 @@ static int flash_sim_erase(const struct device *dev, const off_t offset,
335379

336380
/* erase as many units as necessary and increase their erase counter */
337381
for (uint32_t i = 0; i < len / FLASH_SIMULATOR_ERASE_UNIT; i++) {
382+
int ret;
383+
338384
ERASE_CYCLES_INC(unit_start + i);
339-
unit_erase(unit_start + i);
385+
ret = unit_erase(dev, unit_start + i);
386+
if (ret < 0) {
387+
return ret;
388+
}
340389
}
341390

342391
#ifdef CONFIG_FLASH_SIMULATOR_SIMULATE_TIMING
@@ -405,6 +454,7 @@ static int flash_mock_init(const struct device *dev)
405454
rc = flash_mock_init_native(flash_in_ram, &mock_flash, FLASH_SIMULATOR_FLASH_SIZE,
406455
&flash_fd, flash_file_path, FLASH_SIMULATOR_ERASE_VALUE,
407456
flash_erase_at_start);
457+
flash_sim_params.memory = mock_flash;
408458

409459
if (rc < 0) {
410460
return -EIO;
@@ -498,6 +548,13 @@ void *z_impl_flash_simulator_get_memory(const struct device *dev,
498548
return mock_flash;
499549
}
500550

551+
void z_impl_flash_simulator_set_callbacks(const struct device *dev,
552+
const struct flash_simulator_cb *cb)
553+
{
554+
ARG_UNUSED(dev);
555+
flash_simulator_cbs = cb;
556+
}
557+
501558
#ifdef CONFIG_USERSPACE
502559

503560
#include <zephyr/internal/syscall_handler.h>
@@ -510,6 +567,14 @@ void *z_vrfy_flash_simulator_get_memory(const struct device *dev,
510567
return z_impl_flash_simulator_get_memory(dev, mock_size);
511568
}
512569

570+
void z_vrfy_flash_simulator_set_callbacks(const struct device *dev,
571+
const struct flash_simulator_cb *cb)
572+
{
573+
K_OOPS(K_SYSCALL_SPECIFIC_DRIVER(dev, K_OBJ_DRIVER_FLASH, &flash_sim_api));
574+
575+
z_impl_flash_simulator_set_callbacks(dev, cb);
576+
}
577+
513578
#include <zephyr/syscalls/flash_simulator_get_memory_mrsh.c>
514579

515580
#endif /* CONFIG_USERSPACE */

include/zephyr/drivers/flash/flash_simulator.h

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,110 @@
1010
extern "C" {
1111
#endif
1212

13+
#include <zephyr/device.h>
14+
#include <zephyr/types.h>
15+
#include <sys/types.h>
16+
1317
/**
1418
* @file
1519
* @brief Flash simulator specific API.
1620
*
1721
* Extension for flash simulator.
1822
*/
1923

24+
/**
25+
* @brief Flash simulator parameters structure
26+
*
27+
* Auxiliary structure containing flash simulator parameters to be used by callbacks
28+
* that can modify the behavior of the flash simulator driver.
29+
*/
30+
struct flash_simulator_params {
31+
uint8_t *memory; /**< @brief The memory pointer */
32+
size_t memory_size; /**< @brief The total size of the memory */
33+
size_t base_offset; /**< @brief The base offset of the flash simulator */
34+
size_t erase_unit; /**< @brief The erase unit size */
35+
size_t prog_unit; /**< @brief The program unit size */
36+
bool explicit_erase; /**< @brief Whether explicit erase is required */
37+
uint8_t erase_value; /**< @brief The value used to represent erased memory */
38+
};
39+
40+
/**
41+
* @brief Flash simulator write byte callback type
42+
*
43+
* Callback used to overwrite single byte write. The callback gets the requested data
44+
* and offset as the parameter. The offset is the same offset passed to the flash write.
45+
* The callback must return a value to be written at the specified offset or negative value
46+
* in case of error.
47+
*
48+
* @param dev Flash simulator device pointer.
49+
* @param params Flash simulator parameters.
50+
* @param offset Offset within the flash simulator memory.
51+
* @param data Data byte to be written.
52+
* @return Value to be written at the specified offset or negative value in case of error.
53+
*/
54+
typedef int (*flash_simulator_write_byte_cb_t)(const struct device *dev,
55+
const struct flash_simulator_params *params,
56+
off_t offset,
57+
const uint8_t data);
58+
59+
/**
60+
* @brief Flash simulator erase unit callback type
61+
*
62+
* Callback used to overwrite unit erase operation. The callback gets the unit offset
63+
* as the parameter. The offset is the same offset passed to the flash erase. The callback
64+
* must return 0 in case of success or negative value in case of error.
65+
*
66+
* @note If this callback is set, the flash simulator driver will not perform any erase operation
67+
* by itself.
68+
*
69+
* @param dev Flash simulator device pointer.
70+
* @param params Flash simulator parameters.
71+
* @param unit_offset Offset within the flash simulator memory.
72+
* @return 0 in case of success or negative value in case of error.
73+
*/
74+
typedef int (*flash_simulator_erase_unit_cb_t)(const struct device *dev,
75+
const struct flash_simulator_params *params,
76+
off_t unit_offset);
77+
78+
/**
79+
* @brief Flash simulator callbacks structure
80+
*
81+
* Structure containing flash simulator operation callbacks.
82+
*/
83+
struct flash_simulator_cb {
84+
flash_simulator_write_byte_cb_t write_byte; /**< @brief Byte write callback */
85+
flash_simulator_erase_unit_cb_t erase_unit; /**< @brief Unit erase callback */
86+
};
87+
88+
/**
89+
* @brief Get pointer to the flash simulator mock flash memory
90+
*
91+
* This function allows the caller to get the address of the RAM buffer
92+
* in which the flash simulator emulates its flash memory content.
93+
*
94+
* @param[in] params flash simulator parameters.
95+
* @param[in] offset offset within the flash simulator memory.
96+
*
97+
* @retval pointer to the ram buffer at specified offset
98+
*/
99+
static inline uint8_t *flash_simulator_mock_flash(const struct flash_simulator_params *params,
100+
off_t offset)
101+
{
102+
return params->memory + offset;
103+
}
104+
105+
/**
106+
* @brief Set flash simulator callbacks
107+
*
108+
* This function allows the caller to set custom callbacks for byte write and
109+
* unit erase operations performed by the flash simulator.
110+
*
111+
* @param[in] dev flash simulator device pointer.
112+
* @param[in] cb pointer to the structure containing the callbacks.
113+
*/
114+
__syscall void flash_simulator_set_callbacks(const struct device *dev,
115+
const struct flash_simulator_cb *cb);
116+
20117
/**
21118
* @brief Obtain a pointer to the RAM buffer used but by the simulator
22119
*

0 commit comments

Comments
 (0)