Skip to content

Commit e084bd4

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 e084bd4

File tree

3 files changed

+195
-11
lines changed

3 files changed

+195
-11
lines changed

drivers/flash/Kconfig.simulator

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ menuconfig FLASH_SIMULATOR
1414

1515
if FLASH_SIMULATOR
1616

17+
config FLASH_SIMULATOR_CALLBACKS
18+
bool "Provide callback mechanism"
19+
help
20+
If selected the flash_simulator_set_callbacks is implemented allowing
21+
to change write and erase functions behavior.
22+
This option is meant to be used with tests when checking module reaction
23+
to different write/erase errors in the memory.
24+
1725
config FLASH_SIMULATOR_UNALIGNED_READ
1826
bool "Allow read access to be unaligned"
1927
default y

drivers/flash/flash_simulator.c

Lines changed: 90 additions & 11 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,26 @@ static const struct flash_parameters flash_sim_parameters = {
170172
},
171173
};
172174

175+
176+
#ifdef CONFIG_FLASH_SIMULATOR_CALLBACKS
177+
#ifdef CONFIG_ARCH_POSIX
178+
static struct flash_simulator_params flash_sim_params = {
179+
#else
180+
static const struct flash_simulator_params flash_sim_params = {
181+
.memory = mock_flash,
182+
#endif
183+
.memory_size = FLASH_SIMULATOR_FLASH_SIZE,
184+
.base_offset = FLASH_SIMULATOR_BASE_OFFSET,
185+
.erase_unit = FLASH_SIMULATOR_ERASE_UNIT,
186+
.prog_unit = FLASH_SIMULATOR_PROG_UNIT,
187+
.explicit_erase = IS_ENABLED(CONFIG_FLASH_SIMULATOR_EXPLICIT_ERASE),
188+
.erase_value = FLASH_SIMULATOR_ERASE_VALUE,
189+
};
190+
191+
static const struct flash_simulator_cb *flash_simulator_cbs;
192+
#endif /* CONFIG_FLASH_SIMULATOR_CALLBACKS */
193+
194+
173195
static int flash_range_is_valid(const struct device *dev, off_t offset,
174196
size_t len)
175197
{
@@ -231,7 +253,7 @@ static int flash_sim_write(const struct device *dev, const off_t offset,
231253

232254
FLASH_SIM_STATS_INC(flash_sim_stats, flash_write_calls);
233255

234-
#if defined(CONFIG_FLASH_SIMULATOR_EXPLICIT_ERASE)
256+
#ifdef CONFIG_FLASH_SIMULATOR_EXPLICIT_ERASE
235257
/* check if any unit has been already programmed */
236258
memset(buf, FLASH_SIMULATOR_ERASE_VALUE, sizeof(buf));
237259
#else
@@ -264,6 +286,15 @@ static int flash_sim_write(const struct device *dev, const off_t offset,
264286
}
265287
#endif
266288

289+
#ifdef CONFIG_FLASH_SIMULATOR_CALLBACKS
290+
flash_simulator_write_byte_cb_t write_cb = NULL;
291+
const struct flash_simulator_cb *cb = flash_simulator_cbs;
292+
293+
if (cb != NULL) {
294+
write_cb = cb->write_byte;
295+
}
296+
#endif /* CONFIG_FLASH_SIMULATOR_CALLBACKS */
297+
267298
for (uint32_t i = 0; i < len; i++) {
268299
#ifdef CONFIG_FLASH_SIMULATOR_STATS
269300
if (data_part_ignored) {
@@ -273,16 +304,28 @@ static int flash_sim_write(const struct device *dev, const off_t offset,
273304
}
274305
#endif /* CONFIG_FLASH_SIMULATOR_STATS */
275306

276-
/* only pull bits to zero */
277-
#if defined(CONFIG_FLASH_SIMULATOR_EXPLICIT_ERASE)
307+
uint8_t data_val = *((const uint8_t *)data + i);
308+
309+
#ifdef CONFIG_FLASH_SIMULATOR_EXPLICIT_ERASE
278310
#if FLASH_SIMULATOR_ERASE_VALUE == 0xFF
279-
*(MOCK_FLASH(offset + i)) &= *((uint8_t *)data + i);
311+
/* only pull bits to zero */
312+
data_val &= *(MOCK_FLASH(offset + i));
280313
#else
281-
*(MOCK_FLASH(offset + i)) |= *((uint8_t *)data + i);
314+
/* only pull bits to one */
315+
data_val |= *(MOCK_FLASH(offset + i));
282316
#endif
283-
#else
284-
*(MOCK_FLASH(offset + i)) = *((uint8_t *)data + i);
285317
#endif
318+
#ifdef CONFIG_FLASH_SIMULATOR_CALLBACKS
319+
if (write_cb != NULL) {
320+
int ret = write_cb(dev, &flash_sim_params,
321+
offset + i, data_val);
322+
if (ret < 0) {
323+
return ret;
324+
}
325+
data_val = (uint8_t)ret;
326+
}
327+
#endif /* CONFIG_FLASH_SIMULATOR_CALLBACKS */
328+
*(MOCK_FLASH(offset + i)) = data_val;
286329
}
287330

288331
FLASH_SIM_STATS_INCN(flash_sim_stats, bytes_written, len);
@@ -297,20 +340,31 @@ static int flash_sim_write(const struct device *dev, const off_t offset,
297340
return 0;
298341
}
299342

300-
static void unit_erase(const uint32_t unit)
343+
static int unit_erase(const struct device *dev, const uint32_t unit)
301344
{
302345
const off_t unit_addr = unit * FLASH_SIMULATOR_ERASE_UNIT;
303346

347+
#ifdef CONFIG_FLASH_SIMULATOR_CALLBACKS
348+
flash_simulator_erase_unit_cb_t erase_cb = NULL;
349+
const struct flash_simulator_cb *cb = flash_simulator_cbs;
350+
351+
if (cb != NULL) {
352+
erase_cb = cb->erase_unit;
353+
}
354+
if (erase_cb != NULL) {
355+
return erase_cb(dev, &flash_sim_params, unit_addr);
356+
}
357+
#endif /* CONFIG_FLASH_SIMULATOR_CALLBACKS */
358+
304359
/* erase the memory unit by setting it to erase value */
305360
memset(MOCK_FLASH(unit_addr), FLASH_SIMULATOR_ERASE_VALUE,
306361
FLASH_SIMULATOR_ERASE_UNIT);
362+
return 0;
307363
}
308364

309365
static int flash_sim_erase(const struct device *dev, const off_t offset,
310366
const size_t len)
311367
{
312-
ARG_UNUSED(dev);
313-
314368
if (!flash_range_is_valid(dev, offset, len)) {
315369
return -EINVAL;
316370
}
@@ -335,8 +389,13 @@ static int flash_sim_erase(const struct device *dev, const off_t offset,
335389

336390
/* erase as many units as necessary and increase their erase counter */
337391
for (uint32_t i = 0; i < len / FLASH_SIMULATOR_ERASE_UNIT; i++) {
392+
int ret;
393+
338394
ERASE_CYCLES_INC(unit_start + i);
339-
unit_erase(unit_start + i);
395+
ret = unit_erase(dev, unit_start + i);
396+
if (ret < 0) {
397+
return ret;
398+
}
340399
}
341400

342401
#ifdef CONFIG_FLASH_SIMULATOR_SIMULATE_TIMING
@@ -405,6 +464,9 @@ static int flash_mock_init(const struct device *dev)
405464
rc = flash_mock_init_native(flash_in_ram, &mock_flash, FLASH_SIMULATOR_FLASH_SIZE,
406465
&flash_fd, flash_file_path, FLASH_SIMULATOR_ERASE_VALUE,
407466
flash_erase_at_start);
467+
#ifdef CONFIG_FLASH_SIMULATOR_CALLBACKS
468+
flash_sim_params.memory = mock_flash;
469+
#endif
408470

409471
if (rc < 0) {
410472
return -EIO;
@@ -498,6 +560,15 @@ void *z_impl_flash_simulator_get_memory(const struct device *dev,
498560
return mock_flash;
499561
}
500562

563+
#ifdef CONFIG_FLASH_SIMULATOR_CALLBACKS
564+
void z_impl_flash_simulator_set_callbacks(const struct device *dev,
565+
const struct flash_simulator_cb *cb)
566+
{
567+
ARG_UNUSED(dev);
568+
flash_simulator_cbs = cb;
569+
}
570+
#endif /* CONFIG_FLASH_SIMULATOR_CALLBACKS */
571+
501572
#ifdef CONFIG_USERSPACE
502573

503574
#include <zephyr/internal/syscall_handler.h>
@@ -510,6 +581,14 @@ void *z_vrfy_flash_simulator_get_memory(const struct device *dev,
510581
return z_impl_flash_simulator_get_memory(dev, mock_size);
511582
}
512583

584+
void z_vrfy_flash_simulator_set_callbacks(const struct device *dev,
585+
const struct flash_simulator_cb *cb)
586+
{
587+
K_OOPS(K_SYSCALL_SPECIFIC_DRIVER(dev, K_OBJ_DRIVER_FLASH, &flash_sim_api));
588+
589+
z_impl_flash_simulator_set_callbacks(dev, cb);
590+
}
591+
513592
#include <zephyr/syscalls/flash_simulator_get_memory_mrsh.c>
514593

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