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_create(const struct lfs_config * cfg,const struct lfs_rambd_config * bdcfg)10 int lfs_rambd_create(const struct lfs_config *cfg,
11         const struct lfs_rambd_config *bdcfg) {
12     LFS_RAMBD_TRACE("lfs_rambd_create(%p {.context=%p, "
13                 ".read=%p, .prog=%p, .erase=%p, .sync=%p}, "
14                 "%p {.read_size=%"PRIu32", .prog_size=%"PRIu32", "
15                 ".erase_size=%"PRIu32", .erase_count=%"PRIu32", "
16                 ".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             (void*)bdcfg,
21             bdcfg->read_size, bdcfg->prog_size, bdcfg->erase_size,
22             bdcfg->erase_count, bdcfg->buffer);
23     lfs_rambd_t *bd = cfg->context;
24     bd->cfg = bdcfg;
25 
26     // allocate buffer?
27     if (bd->cfg->buffer) {
28         bd->buffer = bd->cfg->buffer;
29     } else {
30         bd->buffer = lfs_malloc(bd->cfg->erase_size * bd->cfg->erase_count);
31         if (!bd->buffer) {
32             LFS_RAMBD_TRACE("lfs_rambd_create -> %d", LFS_ERR_NOMEM);
33             return LFS_ERR_NOMEM;
34         }
35     }
36 
37     // zero for reproducibility
38     memset(bd->buffer, 0, bd->cfg->erase_size * bd->cfg->erase_count);
39 
40     LFS_RAMBD_TRACE("lfs_rambd_create -> %d", 0);
41     return 0;
42 }
43 
lfs_rambd_destroy(const struct lfs_config * cfg)44 int lfs_rambd_destroy(const struct lfs_config *cfg) {
45     LFS_RAMBD_TRACE("lfs_rambd_destroy(%p)", (void*)cfg);
46     // clean up memory
47     lfs_rambd_t *bd = cfg->context;
48     if (!bd->cfg->buffer) {
49         lfs_free(bd->buffer);
50     }
51     LFS_RAMBD_TRACE("lfs_rambd_destroy -> %d", 0);
52     return 0;
53 }
54 
lfs_rambd_read(const struct lfs_config * cfg,lfs_block_t block,lfs_off_t off,void * buffer,lfs_size_t size)55 int lfs_rambd_read(const struct lfs_config *cfg, lfs_block_t block,
56         lfs_off_t off, void *buffer, lfs_size_t size) {
57     LFS_RAMBD_TRACE("lfs_rambd_read(%p, "
58                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
59             (void*)cfg, block, off, buffer, size);
60     lfs_rambd_t *bd = cfg->context;
61 
62     // check if read is valid
63     LFS_ASSERT(block < bd->cfg->erase_count);
64     LFS_ASSERT(off  % bd->cfg->read_size == 0);
65     LFS_ASSERT(size % bd->cfg->read_size == 0);
66     LFS_ASSERT(off+size <= bd->cfg->erase_size);
67 
68     // read data
69     memcpy(buffer, &bd->buffer[block*bd->cfg->erase_size + off], size);
70 
71     LFS_RAMBD_TRACE("lfs_rambd_read -> %d", 0);
72     return 0;
73 }
74 
lfs_rambd_prog(const struct lfs_config * cfg,lfs_block_t block,lfs_off_t off,const void * buffer,lfs_size_t size)75 int lfs_rambd_prog(const struct lfs_config *cfg, lfs_block_t block,
76         lfs_off_t off, const void *buffer, lfs_size_t size) {
77     LFS_RAMBD_TRACE("lfs_rambd_prog(%p, "
78                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
79             (void*)cfg, block, off, buffer, size);
80     lfs_rambd_t *bd = cfg->context;
81 
82     // check if write is valid
83     LFS_ASSERT(block < bd->cfg->erase_count);
84     LFS_ASSERT(off  % bd->cfg->prog_size == 0);
85     LFS_ASSERT(size % bd->cfg->prog_size == 0);
86     LFS_ASSERT(off+size <= bd->cfg->erase_size);
87 
88     // program data
89     memcpy(&bd->buffer[block*bd->cfg->erase_size + off], buffer, size);
90 
91     LFS_RAMBD_TRACE("lfs_rambd_prog -> %d", 0);
92     return 0;
93 }
94 
lfs_rambd_erase(const struct lfs_config * cfg,lfs_block_t block)95 int lfs_rambd_erase(const struct lfs_config *cfg, lfs_block_t block) {
96     LFS_RAMBD_TRACE("lfs_rambd_erase(%p, 0x%"PRIx32" (%"PRIu32"))",
97             (void*)cfg, block, ((lfs_rambd_t*)cfg->context)->cfg->erase_size);
98     lfs_rambd_t *bd = cfg->context;
99 
100     // check if erase is valid
101     LFS_ASSERT(block < bd->cfg->erase_count);
102 
103     // erase is a noop
104     (void)block;
105 
106     LFS_RAMBD_TRACE("lfs_rambd_erase -> %d", 0);
107     return 0;
108 }
109 
lfs_rambd_sync(const struct lfs_config * cfg)110 int lfs_rambd_sync(const struct lfs_config *cfg) {
111     LFS_RAMBD_TRACE("lfs_rambd_sync(%p)", (void*)cfg);
112 
113     // sync is a noop
114     (void)cfg;
115 
116     LFS_RAMBD_TRACE("lfs_rambd_sync -> %d", 0);
117     return 0;
118 }
119