1 /*
2 * Block device emulated in RAM
3 *
4 * Copyright (c) 2022, The littlefs authors.
5 * Copyright (c) 2017, Arm Limited. All rights reserved.
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8 #include "bd/lfs_rambd.h"
9
lfs_rambd_createcfg(const struct lfs_config * cfg,const struct lfs_rambd_config * bdcfg)10 int lfs_rambd_createcfg(const struct lfs_config *cfg,
11 const struct lfs_rambd_config *bdcfg) {
12 LFS_RAMBD_TRACE("lfs_rambd_createcfg(%p {.context=%p, "
13 ".read=%p, .prog=%p, .erase=%p, .sync=%p, "
14 ".read_size=%"PRIu32", .prog_size=%"PRIu32", "
15 ".block_size=%"PRIu32", .block_count=%"PRIu32"}, "
16 "%p {.erase_value=%"PRId32", .buffer=%p})",
17 (void*)cfg, cfg->context,
18 (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog,
19 (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
20 cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count,
21 (void*)bdcfg, bdcfg->erase_value, bdcfg->buffer);
22 lfs_rambd_t *bd = cfg->context;
23 bd->cfg = bdcfg;
24
25 // allocate buffer?
26 if (bd->cfg->buffer) {
27 bd->buffer = bd->cfg->buffer;
28 } else {
29 bd->buffer = lfs_malloc(cfg->block_size * cfg->block_count);
30 if (!bd->buffer) {
31 LFS_RAMBD_TRACE("lfs_rambd_createcfg -> %d", LFS_ERR_NOMEM);
32 return LFS_ERR_NOMEM;
33 }
34 }
35
36 // zero for reproducibility?
37 if (bd->cfg->erase_value != -1) {
38 memset(bd->buffer, bd->cfg->erase_value,
39 cfg->block_size * cfg->block_count);
40 } else {
41 memset(bd->buffer, 0, cfg->block_size * cfg->block_count);
42 }
43
44 LFS_RAMBD_TRACE("lfs_rambd_createcfg -> %d", 0);
45 return 0;
46 }
47
lfs_rambd_create(const struct lfs_config * cfg)48 int lfs_rambd_create(const struct lfs_config *cfg) {
49 LFS_RAMBD_TRACE("lfs_rambd_create(%p {.context=%p, "
50 ".read=%p, .prog=%p, .erase=%p, .sync=%p, "
51 ".read_size=%"PRIu32", .prog_size=%"PRIu32", "
52 ".block_size=%"PRIu32", .block_count=%"PRIu32"})",
53 (void*)cfg, cfg->context,
54 (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog,
55 (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
56 cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count);
57 static const struct lfs_rambd_config defaults = {.erase_value=-1};
58 int err = lfs_rambd_createcfg(cfg, &defaults);
59 LFS_RAMBD_TRACE("lfs_rambd_create -> %d", err);
60 return err;
61 }
62
lfs_rambd_destroy(const struct lfs_config * cfg)63 int lfs_rambd_destroy(const struct lfs_config *cfg) {
64 LFS_RAMBD_TRACE("lfs_rambd_destroy(%p)", (void*)cfg);
65 // clean up memory
66 lfs_rambd_t *bd = cfg->context;
67 if (!bd->cfg->buffer) {
68 lfs_free(bd->buffer);
69 }
70 LFS_RAMBD_TRACE("lfs_rambd_destroy -> %d", 0);
71 return 0;
72 }
73
lfs_rambd_read(const struct lfs_config * cfg,lfs_block_t block,lfs_off_t off,void * buffer,lfs_size_t size)74 int lfs_rambd_read(const struct lfs_config *cfg, lfs_block_t block,
75 lfs_off_t off, void *buffer, lfs_size_t size) {
76 LFS_RAMBD_TRACE("lfs_rambd_read(%p, "
77 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
78 (void*)cfg, block, off, buffer, size);
79 lfs_rambd_t *bd = cfg->context;
80
81 // check if read is valid
82 LFS_ASSERT(off % cfg->read_size == 0);
83 LFS_ASSERT(size % cfg->read_size == 0);
84 LFS_ASSERT(block < cfg->block_count);
85
86 // read data
87 memcpy(buffer, &bd->buffer[block*cfg->block_size + off], size);
88
89 LFS_RAMBD_TRACE("lfs_rambd_read -> %d", 0);
90 return 0;
91 }
92
lfs_rambd_prog(const struct lfs_config * cfg,lfs_block_t block,lfs_off_t off,const void * buffer,lfs_size_t size)93 int lfs_rambd_prog(const struct lfs_config *cfg, lfs_block_t block,
94 lfs_off_t off, const void *buffer, lfs_size_t size) {
95 LFS_RAMBD_TRACE("lfs_rambd_prog(%p, "
96 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
97 (void*)cfg, block, off, buffer, size);
98 lfs_rambd_t *bd = cfg->context;
99
100 // check if write is valid
101 LFS_ASSERT(off % cfg->prog_size == 0);
102 LFS_ASSERT(size % cfg->prog_size == 0);
103 LFS_ASSERT(block < cfg->block_count);
104
105 // check that data was erased? only needed for testing
106 if (bd->cfg->erase_value != -1) {
107 for (lfs_off_t i = 0; i < size; i++) {
108 LFS_ASSERT(bd->buffer[block*cfg->block_size + off + i] ==
109 bd->cfg->erase_value);
110 }
111 }
112
113 // program data
114 memcpy(&bd->buffer[block*cfg->block_size + off], buffer, size);
115
116 LFS_RAMBD_TRACE("lfs_rambd_prog -> %d", 0);
117 return 0;
118 }
119
lfs_rambd_erase(const struct lfs_config * cfg,lfs_block_t block)120 int lfs_rambd_erase(const struct lfs_config *cfg, lfs_block_t block) {
121 LFS_RAMBD_TRACE("lfs_rambd_erase(%p, 0x%"PRIx32")", (void*)cfg, block);
122 lfs_rambd_t *bd = cfg->context;
123
124 // check if erase is valid
125 LFS_ASSERT(block < cfg->block_count);
126
127 // erase, only needed for testing
128 if (bd->cfg->erase_value != -1) {
129 memset(&bd->buffer[block*cfg->block_size],
130 bd->cfg->erase_value, cfg->block_size);
131 }
132
133 LFS_RAMBD_TRACE("lfs_rambd_erase -> %d", 0);
134 return 0;
135 }
136
lfs_rambd_sync(const struct lfs_config * cfg)137 int lfs_rambd_sync(const struct lfs_config *cfg) {
138 LFS_RAMBD_TRACE("lfs_rambd_sync(%p)", (void*)cfg);
139 // sync does nothing because we aren't backed by anything real
140 (void)cfg;
141 LFS_RAMBD_TRACE("lfs_rambd_sync -> %d", 0);
142 return 0;
143 }
144