1 /*
2 * Copyright (c) 2023 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT zephyr_sim_flash
8
9 #include <zephyr/device.h>
10 #include <zephyr/devicetree.h>
11 #include <zephyr/linker/devicetree_regions.h>
12 #include <zephyr/drivers/flash.h>
13 #include <zephyr/init.h>
14 #include <zephyr/kernel.h>
15 #include <zephyr/sys/util.h>
16 #include <zephyr/random/rand32.h>
17 #include <zephyr/stats/stats.h>
18 #include <string.h>
19
20 #ifdef CONFIG_ARCH_POSIX
21
22 #include <unistd.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <sys/mman.h>
26 #include <fcntl.h>
27 #include <errno.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30
31 #include "cmdline.h"
32 #include "soc.h"
33
34 #define DEFAULT_FLASH_FILE_PATH "flash.bin"
35
36 #endif /* CONFIG_ARCH_POSIX */
37
38 /* configuration derived from DT */
39 #ifdef CONFIG_ARCH_POSIX
40 #define SOC_NV_FLASH_NODE DT_INST_CHILD(0, flash_0)
41 #else
42 #define SOC_NV_FLASH_NODE DT_INST_CHILD(0, flash_sim_0)
43 #endif /* CONFIG_ARCH_POSIX */
44
45 #define FLASH_SIMULATOR_BASE_OFFSET DT_REG_ADDR(SOC_NV_FLASH_NODE)
46 #define FLASH_SIMULATOR_ERASE_UNIT DT_PROP(SOC_NV_FLASH_NODE, erase_block_size)
47 #define FLASH_SIMULATOR_PROG_UNIT DT_PROP(SOC_NV_FLASH_NODE, write_block_size)
48 #define FLASH_SIMULATOR_FLASH_SIZE DT_REG_SIZE(SOC_NV_FLASH_NODE)
49
50 #define FLASH_SIMULATOR_ERASE_VALUE \
51 DT_PROP(DT_PARENT(SOC_NV_FLASH_NODE), erase_value)
52
53 #define FLASH_SIMULATOR_PAGE_COUNT (FLASH_SIMULATOR_FLASH_SIZE / \
54 FLASH_SIMULATOR_ERASE_UNIT)
55
56 #if (FLASH_SIMULATOR_ERASE_UNIT % FLASH_SIMULATOR_PROG_UNIT)
57 #error "Erase unit must be a multiple of program unit"
58 #endif
59
60 #define MOCK_FLASH(addr) (mock_flash + (addr) - FLASH_SIMULATOR_BASE_OFFSET)
61
62 /* maximum number of pages that can be tracked by the stats module */
63 #define STATS_PAGE_COUNT_THRESHOLD 256
64
65 #define STATS_SECT_EC(N, _) STATS_SECT_ENTRY32(erase_cycles_unit##N)
66 #define STATS_NAME_EC(N, _) STATS_NAME(flash_sim_stats, erase_cycles_unit##N)
67
68 #define STATS_SECT_DIRTYR(N, _) STATS_SECT_ENTRY32(dirty_read_unit##N)
69 #define STATS_NAME_DIRTYR(N, _) STATS_NAME(flash_sim_stats, dirty_read_unit##N)
70
71 #ifdef CONFIG_FLASH_SIMULATOR_STATS
72 /* increment a unit erase cycles counter */
73 #define ERASE_CYCLES_INC(U) \
74 do { \
75 if (U < STATS_PAGE_COUNT_THRESHOLD) { \
76 (*(&flash_sim_stats.erase_cycles_unit0 + (U)) += 1); \
77 } \
78 } while (false)
79
80 #if (CONFIG_FLASH_SIMULATOR_STAT_PAGE_COUNT > STATS_PAGE_COUNT_THRESHOLD)
81 /* Limitation above is caused by used LISTIFY */
82 /* Using FLASH_SIMULATOR_FLASH_PAGE_COUNT allows to avoid terrible */
83 /* error logg at the output and work with the stats module partially */
84 #define FLASH_SIMULATOR_FLASH_PAGE_COUNT STATS_PAGE_COUNT_THRESHOLD
85 #else
86 #define FLASH_SIMULATOR_FLASH_PAGE_COUNT CONFIG_FLASH_SIMULATOR_STAT_PAGE_COUNT
87 #endif
88
89 /* simulator statistics */
90 STATS_SECT_START(flash_sim_stats)
91 STATS_SECT_ENTRY32(bytes_read) /* total bytes read */
92 STATS_SECT_ENTRY32(bytes_written) /* total bytes written */
93 STATS_SECT_ENTRY32(double_writes) /* num. of writes to non-erased units */
94 STATS_SECT_ENTRY32(flash_read_calls) /* calls to flash_read() */
95 STATS_SECT_ENTRY32(flash_read_time_us) /* time spent in flash_read() */
96 STATS_SECT_ENTRY32(flash_write_calls) /* calls to flash_write() */
97 STATS_SECT_ENTRY32(flash_write_time_us) /* time spent in flash_write() */
98 STATS_SECT_ENTRY32(flash_erase_calls) /* calls to flash_erase() */
99 STATS_SECT_ENTRY32(flash_erase_time_us) /* time spent in flash_erase() */
100 /* -- per-unit statistics -- */
101 /* erase cycle count for unit */
102 LISTIFY(FLASH_SIMULATOR_FLASH_PAGE_COUNT, STATS_SECT_EC, ())
103 /* number of read operations on worn out erase units */
104 LISTIFY(FLASH_SIMULATOR_FLASH_PAGE_COUNT, STATS_SECT_DIRTYR, ())
105 STATS_SECT_END;
106
107 STATS_SECT_DECL(flash_sim_stats) flash_sim_stats;
108 STATS_NAME_START(flash_sim_stats)
109 STATS_NAME(flash_sim_stats, bytes_read)
110 STATS_NAME(flash_sim_stats, bytes_written)
111 STATS_NAME(flash_sim_stats, double_writes)
112 STATS_NAME(flash_sim_stats, flash_read_calls)
113 STATS_NAME(flash_sim_stats, flash_read_time_us)
114 STATS_NAME(flash_sim_stats, flash_write_calls)
115 STATS_NAME(flash_sim_stats, flash_write_time_us)
116 STATS_NAME(flash_sim_stats, flash_erase_calls)
117 STATS_NAME(flash_sim_stats, flash_erase_time_us)
118 LISTIFY(FLASH_SIMULATOR_FLASH_PAGE_COUNT, STATS_NAME_EC, ())
119 LISTIFY(FLASH_SIMULATOR_FLASH_PAGE_COUNT, STATS_NAME_DIRTYR, ())
120 STATS_NAME_END(flash_sim_stats);
121
122 /* simulator dynamic thresholds */
123 STATS_SECT_START(flash_sim_thresholds)
124 STATS_SECT_ENTRY32(max_write_calls)
125 STATS_SECT_ENTRY32(max_erase_calls)
126 STATS_SECT_ENTRY32(max_len)
127 STATS_SECT_END;
128
129 STATS_SECT_DECL(flash_sim_thresholds) flash_sim_thresholds;
130 STATS_NAME_START(flash_sim_thresholds)
131 STATS_NAME(flash_sim_thresholds, max_write_calls)
132 STATS_NAME(flash_sim_thresholds, max_erase_calls)
133 STATS_NAME(flash_sim_thresholds, max_len)
134 STATS_NAME_END(flash_sim_thresholds);
135
136 #define FLASH_SIM_STATS_INC(group__, var__) STATS_INC(group__, var__)
137 #define FLASH_SIM_STATS_INCN(group__, var__, n__) STATS_INCN(group__, var__, n__)
138 #define FLASH_SIM_STATS_INIT_AND_REG(group__, size__, name__) \
139 STATS_INIT_AND_REG(group__, size__, name__)
140
141
142 #else
143
144 #define ERASE_CYCLES_INC(U) do {} while (false)
145 #define FLASH_SIM_STATS_INC(group__, var__)
146 #define FLASH_SIM_STATS_INCN(group__, var__, n__)
147 #define FLASH_SIM_STATS_INIT_AND_REG(group__, size__, name__)
148
149 #endif /* CONFIG_FLASH_SIMULATOR_STATS */
150
151
152 #ifdef CONFIG_ARCH_POSIX
153 static uint8_t *mock_flash;
154 static int flash_fd = -1;
155 static const char *flash_file_path;
156 static bool flash_erase_at_start;
157 static bool flash_rm_at_exit;
158 static bool flash_in_ram;
159 #else
160 #if DT_NODE_HAS_PROP(DT_PARENT(SOC_NV_FLASH_NODE), memory_region)
161 #define FLASH_SIMULATOR_MREGION \
162 LINKER_DT_NODE_REGION_NAME( \
163 DT_PHANDLE(DT_PARENT(SOC_NV_FLASH_NODE), memory_region))
164 static uint8_t mock_flash[FLASH_SIMULATOR_FLASH_SIZE] Z_GENERIC_SECTION(FLASH_SIMULATOR_MREGION);
165 #else
166 static uint8_t mock_flash[FLASH_SIMULATOR_FLASH_SIZE];
167 #endif
168 #endif /* CONFIG_ARCH_POSIX */
169
170 static const struct flash_driver_api flash_sim_api;
171
172 static const struct flash_parameters flash_sim_parameters = {
173 .write_block_size = FLASH_SIMULATOR_PROG_UNIT,
174 .erase_value = FLASH_SIMULATOR_ERASE_VALUE
175 };
176
flash_range_is_valid(const struct device * dev,off_t offset,size_t len)177 static int flash_range_is_valid(const struct device *dev, off_t offset,
178 size_t len)
179 {
180 ARG_UNUSED(dev);
181 if ((offset + len > FLASH_SIMULATOR_FLASH_SIZE +
182 FLASH_SIMULATOR_BASE_OFFSET) ||
183 (offset < FLASH_SIMULATOR_BASE_OFFSET)) {
184 return 0;
185 }
186
187 return 1;
188 }
189
flash_sim_read(const struct device * dev,const off_t offset,void * data,const size_t len)190 static int flash_sim_read(const struct device *dev, const off_t offset,
191 void *data,
192 const size_t len)
193 {
194 ARG_UNUSED(dev);
195
196 if (!flash_range_is_valid(dev, offset, len)) {
197 return -EINVAL;
198 }
199
200 if (!IS_ENABLED(CONFIG_FLASH_SIMULATOR_UNALIGNED_READ)) {
201 if ((offset % FLASH_SIMULATOR_PROG_UNIT) ||
202 (len % FLASH_SIMULATOR_PROG_UNIT)) {
203 return -EINVAL;
204 }
205 }
206
207 FLASH_SIM_STATS_INC(flash_sim_stats, flash_read_calls);
208
209 memcpy(data, MOCK_FLASH(offset), len);
210 FLASH_SIM_STATS_INCN(flash_sim_stats, bytes_read, len);
211
212 #ifdef CONFIG_FLASH_SIMULATOR_SIMULATE_TIMING
213 k_busy_wait(CONFIG_FLASH_SIMULATOR_MIN_READ_TIME_US);
214 FLASH_SIM_STATS_INCN(flash_sim_stats, flash_read_time_us,
215 CONFIG_FLASH_SIMULATOR_MIN_READ_TIME_US);
216 #endif
217
218 return 0;
219 }
220
flash_sim_write(const struct device * dev,const off_t offset,const void * data,const size_t len)221 static int flash_sim_write(const struct device *dev, const off_t offset,
222 const void *data, const size_t len)
223 {
224 uint8_t buf[FLASH_SIMULATOR_PROG_UNIT];
225 ARG_UNUSED(dev);
226
227 if (!flash_range_is_valid(dev, offset, len)) {
228 return -EINVAL;
229 }
230
231 if ((offset % FLASH_SIMULATOR_PROG_UNIT) ||
232 (len % FLASH_SIMULATOR_PROG_UNIT)) {
233 return -EINVAL;
234 }
235
236 FLASH_SIM_STATS_INC(flash_sim_stats, flash_write_calls);
237
238 /* check if any unit has been already programmed */
239 memset(buf, FLASH_SIMULATOR_ERASE_VALUE, sizeof(buf));
240 for (uint32_t i = 0; i < len; i += FLASH_SIMULATOR_PROG_UNIT) {
241 if (memcmp(buf, MOCK_FLASH(offset + i), sizeof(buf))) {
242 FLASH_SIM_STATS_INC(flash_sim_stats, double_writes);
243 #if !CONFIG_FLASH_SIMULATOR_DOUBLE_WRITES
244 return -EIO;
245 #endif
246 }
247 }
248
249 #ifdef CONFIG_FLASH_SIMULATOR_STATS
250 bool data_part_ignored = false;
251
252 if (flash_sim_thresholds.max_write_calls != 0) {
253 if (flash_sim_stats.flash_write_calls >
254 flash_sim_thresholds.max_write_calls) {
255 return 0;
256 } else if (flash_sim_stats.flash_write_calls ==
257 flash_sim_thresholds.max_write_calls) {
258 if (flash_sim_thresholds.max_len == 0) {
259 return 0;
260 }
261
262 data_part_ignored = true;
263 }
264 }
265 #endif
266
267 for (uint32_t i = 0; i < len; i++) {
268 #ifdef CONFIG_FLASH_SIMULATOR_STATS
269 if (data_part_ignored) {
270 if (i >= flash_sim_thresholds.max_len) {
271 return 0;
272 }
273 }
274 #endif /* CONFIG_FLASH_SIMULATOR_STATS */
275
276 /* only pull bits to zero */
277 #if FLASH_SIMULATOR_ERASE_VALUE == 0xFF
278 *(MOCK_FLASH(offset + i)) &= *((uint8_t *)data + i);
279 #else
280 *(MOCK_FLASH(offset + i)) = *((uint8_t *)data + i);
281 #endif
282 }
283
284 FLASH_SIM_STATS_INCN(flash_sim_stats, bytes_written, len);
285
286 #ifdef CONFIG_FLASH_SIMULATOR_SIMULATE_TIMING
287 /* wait before returning */
288 k_busy_wait(CONFIG_FLASH_SIMULATOR_MIN_WRITE_TIME_US);
289 FLASH_SIM_STATS_INCN(flash_sim_stats, flash_write_time_us,
290 CONFIG_FLASH_SIMULATOR_MIN_WRITE_TIME_US);
291 #endif
292
293 return 0;
294 }
295
unit_erase(const uint32_t unit)296 static void unit_erase(const uint32_t unit)
297 {
298 const off_t unit_addr = FLASH_SIMULATOR_BASE_OFFSET +
299 (unit * FLASH_SIMULATOR_ERASE_UNIT);
300
301 /* erase the memory unit by setting it to erase value */
302 memset(MOCK_FLASH(unit_addr), FLASH_SIMULATOR_ERASE_VALUE,
303 FLASH_SIMULATOR_ERASE_UNIT);
304 }
305
flash_sim_erase(const struct device * dev,const off_t offset,const size_t len)306 static int flash_sim_erase(const struct device *dev, const off_t offset,
307 const size_t len)
308 {
309 ARG_UNUSED(dev);
310
311 if (!flash_range_is_valid(dev, offset, len)) {
312 return -EINVAL;
313 }
314
315 /* erase operation must be aligned to the erase unit boundary */
316 if ((offset % FLASH_SIMULATOR_ERASE_UNIT) ||
317 (len % FLASH_SIMULATOR_ERASE_UNIT)) {
318 return -EINVAL;
319 }
320
321 FLASH_SIM_STATS_INC(flash_sim_stats, flash_erase_calls);
322
323 #ifdef CONFIG_FLASH_SIMULATOR_STATS
324 if ((flash_sim_thresholds.max_erase_calls != 0) &&
325 (flash_sim_stats.flash_erase_calls >=
326 flash_sim_thresholds.max_erase_calls)){
327 return 0;
328 }
329 #endif
330 /* the first unit to be erased */
331 uint32_t unit_start = (offset - FLASH_SIMULATOR_BASE_OFFSET) /
332 FLASH_SIMULATOR_ERASE_UNIT;
333
334 /* erase as many units as necessary and increase their erase counter */
335 for (uint32_t i = 0; i < len / FLASH_SIMULATOR_ERASE_UNIT; i++) {
336 ERASE_CYCLES_INC(unit_start + i);
337 unit_erase(unit_start + i);
338 }
339
340 #ifdef CONFIG_FLASH_SIMULATOR_SIMULATE_TIMING
341 /* wait before returning */
342 k_busy_wait(CONFIG_FLASH_SIMULATOR_MIN_ERASE_TIME_US);
343 FLASH_SIM_STATS_INCN(flash_sim_stats, flash_erase_time_us,
344 CONFIG_FLASH_SIMULATOR_MIN_ERASE_TIME_US);
345 #endif
346
347 return 0;
348 }
349
350 #ifdef CONFIG_FLASH_PAGE_LAYOUT
351 static const struct flash_pages_layout flash_sim_pages_layout = {
352 .pages_count = FLASH_SIMULATOR_PAGE_COUNT,
353 .pages_size = FLASH_SIMULATOR_ERASE_UNIT,
354 };
355
flash_sim_page_layout(const struct device * dev,const struct flash_pages_layout ** layout,size_t * layout_size)356 static void flash_sim_page_layout(const struct device *dev,
357 const struct flash_pages_layout **layout,
358 size_t *layout_size)
359 {
360 *layout = &flash_sim_pages_layout;
361 *layout_size = 1;
362 }
363 #endif
364
365 static const struct flash_parameters *
flash_sim_get_parameters(const struct device * dev)366 flash_sim_get_parameters(const struct device *dev)
367 {
368 ARG_UNUSED(dev);
369
370 return &flash_sim_parameters;
371 }
372
373 static const struct flash_driver_api flash_sim_api = {
374 .read = flash_sim_read,
375 .write = flash_sim_write,
376 .erase = flash_sim_erase,
377 .get_parameters = flash_sim_get_parameters,
378 #ifdef CONFIG_FLASH_PAGE_LAYOUT
379 .page_layout = flash_sim_page_layout,
380 #endif
381 };
382
383 #ifdef CONFIG_ARCH_POSIX
384
flash_mock_init(const struct device * dev)385 static int flash_mock_init(const struct device *dev)
386 {
387 struct stat f_stat;
388 int rc;
389
390 ARG_UNUSED(dev);
391
392 if (flash_in_ram == true) {
393 mock_flash = (uint8_t *)malloc(FLASH_SIMULATOR_FLASH_SIZE);
394 if (mock_flash == NULL) {
395 posix_print_warning("Could not allocate flash in the process heap %s\n",
396 strerror(errno));
397 return -EIO;
398 }
399 } else {
400
401 if (flash_file_path == NULL) {
402 flash_file_path = DEFAULT_FLASH_FILE_PATH;
403 }
404
405 flash_fd = open(flash_file_path, O_RDWR | O_CREAT, (mode_t)0600);
406 if (flash_fd == -1) {
407 posix_print_warning("Failed to open flash device file "
408 "%s: %s\n",
409 flash_file_path, strerror(errno));
410 return -EIO;
411 }
412
413 rc = fstat(flash_fd, &f_stat);
414 if (rc) {
415 posix_print_warning("Failed to get status of flash device file "
416 "%s: %s\n",
417 flash_file_path, strerror(errno));
418 return -EIO;
419 }
420
421 if (ftruncate(flash_fd, FLASH_SIMULATOR_FLASH_SIZE) == -1) {
422 posix_print_warning("Failed to resize flash device file "
423 "%s: %s\n",
424 flash_file_path, strerror(errno));
425 return -EIO;
426 }
427
428 mock_flash = mmap(NULL, FLASH_SIMULATOR_FLASH_SIZE,
429 PROT_WRITE | PROT_READ, MAP_SHARED, flash_fd, 0);
430 if (mock_flash == MAP_FAILED) {
431 posix_print_warning("Failed to mmap flash device file "
432 "%s: %s\n",
433 flash_file_path, strerror(errno));
434 return -EIO;
435 }
436 }
437
438 if ((flash_erase_at_start == true) || (flash_in_ram == true) || (f_stat.st_size == 0)) {
439 /* Erase the memory unit by pulling all bits to the configured erase value */
440 (void)memset(mock_flash, FLASH_SIMULATOR_ERASE_VALUE,
441 FLASH_SIMULATOR_FLASH_SIZE);
442 }
443
444 return 0;
445 }
446
447 #else
448 #if DT_NODE_HAS_PROP(DT_PARENT(SOC_NV_FLASH_NODE), memory_region)
flash_mock_init(const struct device * dev)449 static int flash_mock_init(const struct device *dev)
450 {
451 ARG_UNUSED(dev);
452 return 0;
453 }
454 #else
flash_mock_init(const struct device * dev)455 static int flash_mock_init(const struct device *dev)
456 {
457 ARG_UNUSED(dev);
458 memset(mock_flash, FLASH_SIMULATOR_ERASE_VALUE, ARRAY_SIZE(mock_flash));
459 return 0;
460 }
461 #endif /* DT_NODE_HAS_PROP(DT_PARENT(SOC_NV_FLASH_NODE), memory_region) */
462 #endif /* CONFIG_ARCH_POSIX */
463
flash_init(const struct device * dev)464 static int flash_init(const struct device *dev)
465 {
466 FLASH_SIM_STATS_INIT_AND_REG(flash_sim_stats, STATS_SIZE_32, "flash_sim_stats");
467 FLASH_SIM_STATS_INIT_AND_REG(flash_sim_thresholds, STATS_SIZE_32,
468 "flash_sim_thresholds");
469 return flash_mock_init(dev);
470 }
471
472 DEVICE_DT_INST_DEFINE(0, flash_init, NULL,
473 NULL, NULL, POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY,
474 &flash_sim_api);
475
476 #ifdef CONFIG_ARCH_POSIX
477
flash_native_posix_cleanup(void)478 static void flash_native_posix_cleanup(void)
479 {
480 if (flash_in_ram == true) {
481 if (mock_flash != NULL) {
482 free(mock_flash);
483 }
484 return;
485 }
486
487 if ((mock_flash != MAP_FAILED) && (mock_flash != NULL)) {
488 munmap(mock_flash, FLASH_SIMULATOR_FLASH_SIZE);
489 }
490
491 if (flash_fd != -1) {
492 close(flash_fd);
493 }
494
495 if ((flash_rm_at_exit == true) && (flash_file_path != NULL)) {
496 /* We try to remove the file but do not error out if we can't */
497 (void) remove(flash_file_path);
498 }
499 }
500
flash_native_posix_options(void)501 static void flash_native_posix_options(void)
502 {
503 static struct args_struct_t flash_options[] = {
504 { .option = "flash",
505 .name = "path",
506 .type = 's',
507 .dest = (void *)&flash_file_path,
508 .descript = "Path to binary file to be used as flash, by default \""
509 DEFAULT_FLASH_FILE_PATH "\""},
510 { .is_switch = true,
511 .option = "flash_erase",
512 .type = 'b',
513 .dest = (void *)&flash_erase_at_start,
514 .descript = "Erase the flash content at startup" },
515 { .is_switch = true,
516 .option = "flash_rm",
517 .type = 'b',
518 .dest = (void *)&flash_rm_at_exit,
519 .descript = "Remove the flash file when terminating the execution" },
520 { .is_switch = true,
521 .option = "flash_in_ram",
522 .type = 'b',
523 .dest = (void *)&flash_in_ram,
524 .descript = "Instead of a file, keep the file content just in RAM. If this is "
525 "set, flash, flash_erase & flash_rm are ignored. The flash content"
526 " is always erased at startup" },
527 ARG_TABLE_ENDMARKER
528 };
529
530 native_add_command_line_opts(flash_options);
531 }
532
533
534 NATIVE_TASK(flash_native_posix_options, PRE_BOOT_1, 1);
535 NATIVE_TASK(flash_native_posix_cleanup, ON_EXIT, 1);
536
537 #endif /* CONFIG_ARCH_POSIX */
538
539 /* Extension to generic flash driver API */
z_impl_flash_simulator_get_memory(const struct device * dev,size_t * mock_size)540 void *z_impl_flash_simulator_get_memory(const struct device *dev,
541 size_t *mock_size)
542 {
543 ARG_UNUSED(dev);
544
545 *mock_size = FLASH_SIMULATOR_FLASH_SIZE;
546 return mock_flash;
547 }
548
549 #ifdef CONFIG_USERSPACE
550
551 #include <zephyr/syscall_handler.h>
552
z_vrfy_flash_simulator_get_memory(const struct device * dev,size_t * mock_size)553 void *z_vrfy_flash_simulator_get_memory(const struct device *dev,
554 size_t *mock_size)
555 {
556 Z_OOPS(Z_SYSCALL_SPECIFIC_DRIVER(dev, K_OBJ_DRIVER_FLASH, &flash_sim_api));
557
558 return z_impl_flash_simulator_get_memory(dev, mock_size);
559 }
560
561 #include <syscalls/flash_simulator_get_memory_mrsh.c>
562
563 #endif /* CONFIG_USERSPACE */
564