Skip to content

Commit afb05bc

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 afb05bc

File tree

2 files changed

+166
-9
lines changed

2 files changed

+166
-9
lines changed

drivers/flash/flash_simulator.c

Lines changed: 69 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,19 @@ static const struct flash_parameters flash_sim_parameters = {
170172
},
171173
};
172174

175+
static const struct flash_simulator_params flash_sim_params = {
176+
.memory = &mock_flash,
177+
.memory_size = FLASH_SIMULATOR_FLASH_SIZE,
178+
.base_offset = FLASH_SIMULATOR_BASE_OFFSET,
179+
.erase_unit = FLASH_SIMULATOR_ERASE_UNIT,
180+
.prog_unit = FLASH_SIMULATOR_PROG_UNIT,
181+
.explicit_erase = IS_ENABLED(CONFIG_FLASH_SIMULATOR_EXPLICIT_ERASE),
182+
.erase_value = FLASH_SIMULATOR_ERASE_VALUE,
183+
};
184+
185+
static const struct flash_simulator_cb *flash_simulator_cbs;
186+
187+
173188
static int flash_range_is_valid(const struct device *dev, off_t offset,
174189
size_t len)
175190
{
@@ -264,6 +279,13 @@ static int flash_sim_write(const struct device *dev, const off_t offset,
264279
}
265280
#endif
266281

282+
flash_simulator_write_byte_cb_t write_cb = NULL;
283+
const struct flash_simulator_cb *cb = flash_simulator_cbs;
284+
285+
if (cb != NULL) {
286+
write_cb = cb->write_byte;
287+
}
288+
267289
for (uint32_t i = 0; i < len; i++) {
268290
#ifdef CONFIG_FLASH_SIMULATOR_STATS
269291
if (data_part_ignored) {
@@ -273,16 +295,26 @@ static int flash_sim_write(const struct device *dev, const off_t offset,
273295
}
274296
#endif /* CONFIG_FLASH_SIMULATOR_STATS */
275297

276-
/* only pull bits to zero */
298+
uint8_t data_val = *((uint8_t *)data + i);
299+
277300
#if defined(CONFIG_FLASH_SIMULATOR_EXPLICIT_ERASE)
278301
#if FLASH_SIMULATOR_ERASE_VALUE == 0xFF
279-
*(MOCK_FLASH(offset + i)) &= *((uint8_t *)data + i);
302+
/* only pull bits to zero */
303+
data_val &= *(MOCK_FLASH(offset + i));
280304
#else
281-
*(MOCK_FLASH(offset + i)) |= *((uint8_t *)data + i);
305+
/* only pull bits to one */
306+
data_val |= *(MOCK_FLASH(offset + i));
282307
#endif
283-
#else
284-
*(MOCK_FLASH(offset + i)) = *((uint8_t *)data + i);
285308
#endif
309+
if (write_cb != NULL) {
310+
int ret = write_cb(dev, &flash_sim_params,
311+
offset + i, data_val);
312+
if (ret < 0) {
313+
return ret;
314+
}
315+
data_val = (uint8_t)ret;
316+
}
317+
*(MOCK_FLASH(offset + i)) = data_val;
286318
}
287319

288320
FLASH_SIM_STATS_INCN(flash_sim_stats, bytes_written, len);
@@ -297,20 +329,28 @@ static int flash_sim_write(const struct device *dev, const off_t offset,
297329
return 0;
298330
}
299331

300-
static void unit_erase(const uint32_t unit)
332+
static int unit_erase(const struct device *dev, const uint32_t unit)
301333
{
302334
const off_t unit_addr = unit * FLASH_SIMULATOR_ERASE_UNIT;
335+
flash_simulator_erase_unit_cb_t erase_cb = NULL;
336+
const struct flash_simulator_cb *cb = flash_simulator_cbs;
337+
338+
if (cb != NULL) {
339+
erase_cb = cb->erase_unit;
340+
}
341+
if (erase_cb != NULL) {
342+
return erase_cb(dev, &flash_sim_params, unit_addr);
343+
}
303344

304345
/* erase the memory unit by setting it to erase value */
305346
memset(MOCK_FLASH(unit_addr), FLASH_SIMULATOR_ERASE_VALUE,
306347
FLASH_SIMULATOR_ERASE_UNIT);
348+
return 0;
307349
}
308350

309351
static int flash_sim_erase(const struct device *dev, const off_t offset,
310352
const size_t len)
311353
{
312-
ARG_UNUSED(dev);
313-
314354
if (!flash_range_is_valid(dev, offset, len)) {
315355
return -EINVAL;
316356
}
@@ -335,8 +375,13 @@ static int flash_sim_erase(const struct device *dev, const off_t offset,
335375

336376
/* erase as many units as necessary and increase their erase counter */
337377
for (uint32_t i = 0; i < len / FLASH_SIMULATOR_ERASE_UNIT; i++) {
378+
int ret;
379+
338380
ERASE_CYCLES_INC(unit_start + i);
339-
unit_erase(unit_start + i);
381+
ret = unit_erase(dev, unit_start + i);
382+
if (ret < 0) {
383+
return ret;
384+
}
340385
}
341386

342387
#ifdef CONFIG_FLASH_SIMULATOR_SIMULATE_TIMING
@@ -498,6 +543,13 @@ void *z_impl_flash_simulator_get_memory(const struct device *dev,
498543
return mock_flash;
499544
}
500545

546+
void z_impl_flash_simulator_set_callbacks(const struct device *dev,
547+
const struct flash_simulator_cb *cb)
548+
{
549+
ARG_UNUSED(dev);
550+
flash_simulator_cbs = cb;
551+
}
552+
501553
#ifdef CONFIG_USERSPACE
502554

503555
#include <zephyr/internal/syscall_handler.h>
@@ -510,6 +562,14 @@ void *z_vrfy_flash_simulator_get_memory(const struct device *dev,
510562
return z_impl_flash_simulator_get_memory(dev, mock_size);
511563
}
512564

565+
void z_vrfy_flash_simulator_set_callbacks(const struct device *dev,
566+
const struct flash_simulator_cb *cb)
567+
{
568+
K_OOPS(K_SYSCALL_SPECIFIC_DRIVER(dev, K_OBJ_DRIVER_FLASH, &flash_sim_api));
569+
570+
z_impl_flash_simulator_set_callbacks(dev, cb);
571+
}
572+
513573
#include <zephyr/syscalls/flash_simulator_get_memory_mrsh.c>
514574

515575
#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)