mirror of
https://github.com/littlefs-project/littlefs.git
synced 2025-12-01 12:20:02 +00:00
Useful for emulating much larger disks in a file (or in RAM). kiwibd doesn't have all the features of emubd, but this allows it to prioritize disk size and speed for benchmarking. kiwibd still keeps some features useful for benchmarking/emulation: - Optional erase value emulation, including nor-masking - Read/prog/erase trackers for measuring bd operations - Read/prog/erase sleeps for slowing down the simulation to a human viewable speed
132 lines
4.3 KiB
C
132 lines
4.3 KiB
C
/*
|
|
* Block device emulated in RAM
|
|
*
|
|
* Copyright (c) 2022, The littlefs authors.
|
|
* Copyright (c) 2017, Arm Limited. All rights reserved.
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
#include "bd/lfs3_rambd.h"
|
|
|
|
int lfs3_rambd_createcfg(const struct lfs3_cfg *cfg,
|
|
const struct lfs3_rambd_cfg *bdcfg) {
|
|
LFS3_RAMBD_TRACE("lfs3_rambd_createcfg(%p {.context=%p, "
|
|
".read=%p, .prog=%p, .erase=%p, .sync=%p, "
|
|
".read_size=%"PRIu32", .prog_size=%"PRIu32", "
|
|
".block_size=%"PRIu32", .block_count=%"PRIu32"}, "
|
|
"%p {.buffer=%p})",
|
|
(void*)cfg, cfg->context,
|
|
(void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog,
|
|
(void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
|
|
cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count,
|
|
(void*)bdcfg, bdcfg->buffer);
|
|
lfs3_rambd_t *bd = cfg->context;
|
|
bd->cfg = bdcfg;
|
|
|
|
// allocate buffer?
|
|
if (bd->cfg->buffer) {
|
|
bd->mem = bd->cfg->buffer;
|
|
} else {
|
|
bd->mem = lfs3_malloc(cfg->block_size * cfg->block_count);
|
|
if (!bd->mem) {
|
|
LFS3_RAMBD_TRACE("lfs3_rambd_createcfg -> %d", LFS3_ERR_NOMEM);
|
|
return LFS3_ERR_NOMEM;
|
|
}
|
|
}
|
|
|
|
// zero for reproducibility
|
|
memset(bd->mem, 0, cfg->block_size * cfg->block_count);
|
|
|
|
LFS3_RAMBD_TRACE("lfs3_rambd_createcfg -> %d", 0);
|
|
return 0;
|
|
}
|
|
|
|
int lfs3_rambd_create(const struct lfs3_cfg *cfg) {
|
|
LFS3_RAMBD_TRACE("lfs3_rambd_create(%p {.context=%p, "
|
|
".read=%p, .prog=%p, .erase=%p, .sync=%p, "
|
|
".read_size=%"PRIu32", .prog_size=%"PRIu32", "
|
|
".block_size=%"PRIu32", .block_count=%"PRIu32"})",
|
|
(void*)cfg, cfg->context,
|
|
(void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog,
|
|
(void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
|
|
cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count);
|
|
static const struct lfs3_rambd_cfg defaults = {0};
|
|
int err = lfs3_rambd_createcfg(cfg, &defaults);
|
|
LFS3_RAMBD_TRACE("lfs3_rambd_create -> %d", err);
|
|
return err;
|
|
}
|
|
|
|
int lfs3_rambd_destroy(const struct lfs3_cfg *cfg) {
|
|
LFS3_RAMBD_TRACE("lfs3_rambd_destroy(%p)", (void*)cfg);
|
|
// clean up memory
|
|
lfs3_rambd_t *bd = cfg->context;
|
|
if (!bd->cfg->buffer) {
|
|
lfs3_free(bd->mem);
|
|
}
|
|
LFS3_RAMBD_TRACE("lfs3_rambd_destroy -> %d", 0);
|
|
return 0;
|
|
}
|
|
|
|
int lfs3_rambd_read(const struct lfs3_cfg *cfg, lfs3_block_t block,
|
|
lfs3_off_t off, void *buffer, lfs3_size_t size) {
|
|
LFS3_RAMBD_TRACE("lfs3_rambd_read(%p, "
|
|
"0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
|
|
(void*)cfg, block, off, buffer, size);
|
|
lfs3_rambd_t *bd = cfg->context;
|
|
|
|
// check if read is valid
|
|
LFS3_ASSERT(block < cfg->block_count);
|
|
LFS3_ASSERT(off % cfg->read_size == 0);
|
|
LFS3_ASSERT(size % cfg->read_size == 0);
|
|
LFS3_ASSERT(off+size <= cfg->block_size);
|
|
|
|
// read data
|
|
memcpy(buffer, &bd->mem[block*cfg->block_size + off], size);
|
|
|
|
LFS3_RAMBD_TRACE("lfs3_rambd_read -> %d", 0);
|
|
return 0;
|
|
}
|
|
|
|
int lfs3_rambd_prog(const struct lfs3_cfg *cfg, lfs3_block_t block,
|
|
lfs3_off_t off, const void *buffer, lfs3_size_t size) {
|
|
LFS3_RAMBD_TRACE("lfs3_rambd_prog(%p, "
|
|
"0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
|
|
(void*)cfg, block, off, buffer, size);
|
|
lfs3_rambd_t *bd = cfg->context;
|
|
|
|
// check if write is valid
|
|
LFS3_ASSERT(block < cfg->block_count);
|
|
LFS3_ASSERT(off % cfg->prog_size == 0);
|
|
LFS3_ASSERT(size % cfg->prog_size == 0);
|
|
LFS3_ASSERT(off+size <= cfg->block_size);
|
|
|
|
// program data
|
|
memcpy(&bd->mem[block*cfg->block_size + off], buffer, size);
|
|
|
|
LFS3_RAMBD_TRACE("lfs3_rambd_prog -> %d", 0);
|
|
return 0;
|
|
}
|
|
|
|
int lfs3_rambd_erase(const struct lfs3_cfg *cfg, lfs3_block_t block) {
|
|
LFS3_RAMBD_TRACE("lfs3_rambd_erase(%p, 0x%"PRIx32" (%"PRIu32"))",
|
|
(void*)cfg, block, cfg->block_size);
|
|
|
|
// check if erase is valid
|
|
LFS3_ASSERT(block < cfg->block_count);
|
|
|
|
// erase is a noop
|
|
(void)block;
|
|
|
|
LFS3_RAMBD_TRACE("lfs3_rambd_erase -> %d", 0);
|
|
return 0;
|
|
}
|
|
|
|
int lfs3_rambd_sync(const struct lfs3_cfg *cfg) {
|
|
LFS3_RAMBD_TRACE("lfs3_rambd_sync(%p)", (void*)cfg);
|
|
|
|
// sync is a noop
|
|
(void)cfg;
|
|
|
|
LFS3_RAMBD_TRACE("lfs3_rambd_sync -> %d", 0);
|
|
return 0;
|
|
}
|