ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_cache_store.c
Go to the documentation of this file.
1
21
22#include "ra8_cache_store.h"
23
24#include <stdint.h>
25#include <string.h>
26
27#include "lx_api.h"
29#include "ra8_check.h"
30#include "ra8_err.h"
31
33static const char* const s_tag = "ra8_cache_store";
34
40typedef enum : uint32_t {
41 k_ra8_cs_max_run = 0xFFFFU,
43
44/* ------------------------------------------------------------------------- */
45/* Allocation + append helpers */
46/* ------------------------------------------------------------------------- */
47
62{
63 if (store == nullptr) {
64 return 0U;
65 }
66 if (store->index == nullptr) {
67 return 0U;
68 }
69 uint16_t used = 0U;
70 for (uint16_t i = 0U; i < store->index_cap; i++) {
71 if ((store->index[i].flags & (uint8_t)k_ra8_cache_store_flag_in_use) != 0U) {
72 used++;
73 }
74 }
75 return used;
76}
77
94RA8_INTERNAL static bool
95internal_run_free(const ra8_cache_store_t* store, uint32_t start, uint32_t count)
96{
97 if (store == nullptr) {
98 return false;
99 }
100 if (store->index == nullptr) {
101 return false;
102 }
103 uint32_t end = start + count;
104 for (uint16_t i = 0U; i < store->index_cap; i++) {
105 const ra8_cache_store_entry_t* e = &store->index[i];
106 if ((e->flags & (uint8_t)k_ra8_cache_store_flag_in_use) == 0U) {
107 continue;
108 }
109 uint32_t es = e->start_sector;
110 uint32_t ee = es + e->sector_count;
111 if (start < ee) {
112 if (es < end) {
113 return false;
114 }
115 }
116 }
117 return true;
118}
119
139internal_alloc_run(const ra8_cache_store_t* store, uint32_t count, uint32_t* out_start)
140{
141 RA8_CHECK_NULL_PTR(store, s_tag, "store");
142 RA8_CHECK_NULL_PTR(out_start, s_tag, "out_start");
143 if (count == 0U) {
145 }
146 for (uint32_t start = store->log_start; (start + count) <= store->logical_sectors; start++) {
147 if (internal_run_free(store, start, count)) {
148 *out_start = start;
149 return k_ra8_ok;
150 }
151 }
152 return k_ra8_err_no_mem;
153}
154
177 uint32_t start,
178 uint32_t seq,
179 uint32_t key,
180 const uint8_t* data,
181 uint32_t len,
182 uint16_t count)
183{
184 RA8_CHECK_NULL_PTR(store, s_tag, "store");
185 RA8_CHECK_NULL_PTR(data, s_tag, "data");
186 uint16_t data_sectors = (uint16_t)(count - 1U);
187 uint32_t off = 0U;
188 const uint32_t sec_sz = (uint32_t)k_ra8_cache_store_sector_bytes;
189 for (uint16_t i = 0U; i < data_sectors; i++) {
190 uint32_t remain = len - off;
191 uint32_t chunk = (remain < sec_sz) ? remain : sec_sz;
192 (void)memset(store->staging, 0, (size_t)sec_sz);
193 (void)memcpy(store->staging, &data[off], (size_t)chunk);
195 priv_cache_store_sector_write(store, start + 1U + (uint32_t)i, store->staging),
196 s_tag,
197 "payload");
198 off += chunk;
199 }
200 ra8_cs_entry_hdr_t h = {.magic = (uint32_t)k_ra8_cs_entry_magic,
201 .seq = seq,
202 .key = key,
203 .byte_len = len,
204 .start_sector = start,
205 .sector_count = count,
206 .flags = 0U,
207 .hdr_crc = 0U};
208 h.hdr_crc = priv_cache_store_crc32((const uint8_t*)&h, (uint32_t)(sizeof(h) - sizeof(h.hdr_crc)));
209 (void)memset(store->staging, 0, (size_t)sec_sz);
210 (void)memcpy(store->staging, &h, sizeof(h));
211 return priv_cache_store_sector_write(store, start, store->staging);
212}
213
232{
233 RA8_CHECK_NULL_PTR(store, s_tag, "store");
234 RA8_VALIDATE_INIT(store->inited, s_tag, "store");
235 if (store->flash_state == (uint8_t)k_ra8_cs_dirty) {
236 return k_ra8_ok;
237 }
239 s_tag,
240 "mark dirty");
241 store->flash_state = (uint8_t)k_ra8_cs_dirty;
242 return k_ra8_ok;
243}
244
262{
263 RA8_CHECK_NULL_PTR(store, s_tag, "store");
264 RA8_VALIDATE_INIT(store->inited, s_tag, "store");
265 RA8_RETURN_ON_ERROR(internal_mark_dirty(store), s_tag, "pre-dirty");
266 uint32_t count = 0U;
267 RA8_RETURN_ON_ERROR(priv_cache_store_dir_save(store, &count), s_tag, "dir save");
269 s_tag,
270 "clean super");
271 store->flash_state = (uint8_t)k_ra8_cs_clean;
272 return k_ra8_ok;
273}
274
300 uint32_t key,
301 const uint8_t* data,
302 uint32_t len,
303 uint32_t* out_count)
304{
305 RA8_CHECK_NULL_PTR(store, s_tag, "store");
306 RA8_CHECK_NULL_PTR(data, s_tag, "data");
307 RA8_VALIDATE_INIT(store->inited, s_tag, "store");
308 if (len == 0U) {
310 }
311 if (priv_cache_store_index_find(store, key) >= 0) {
312 return k_ra8_err_exists;
313 }
314 if (internal_index_used(store) >= store->index_cap) {
315 return k_ra8_err_no_mem;
316 }
317 const uint32_t sec_sz = (uint32_t)k_ra8_cache_store_sector_bytes;
318 uint32_t count = 1U + ((len + (sec_sz - 1U)) / sec_sz);
319 if (count > (uint32_t)k_ra8_cs_max_run) {
321 }
322 if ((store->live_sectors + count) > store->data_capacity) {
323 return k_ra8_err_no_mem;
324 }
325 *out_count = count;
326 return k_ra8_ok;
327}
328
351 uint32_t data_start,
352 uint64_t byte_pos,
353 uint8_t* dst,
354 uint32_t max,
355 uint32_t* out_copied)
356{
357 RA8_CHECK_NULL_PTR(store, s_tag, "store");
358 RA8_CHECK_NULL_PTR(dst, s_tag, "dst");
359 const uint32_t sec_sz = (uint32_t)k_ra8_cache_store_sector_bytes;
360 uint32_t sector = data_start + (uint32_t)(byte_pos / sec_sz);
361 uint32_t soff = (uint32_t)(byte_pos % sec_sz);
362 uint32_t space = sec_sz - soff;
363 uint32_t chunk = (max < space) ? max : space;
364 RA8_RETURN_ON_ERROR(priv_cache_store_sector_read(store, sector, store->staging), s_tag, "read");
365 (void)memcpy(dst, &store->staging[soff], (size_t)chunk);
366 *out_copied = chunk;
367 return k_ra8_ok;
368}
369
390internal_release_run(ra8_cache_store_t* store, uint32_t start, uint16_t count)
391{
392 RA8_CHECK_NULL_PTR(store, s_tag, "store");
393 RA8_VALIDATE_INIT(store->inited, s_tag, "store");
394 for (uint16_t i = 0U; i < count; i++) {
395 RA8_RETURN_ON_ERROR(priv_cache_store_sector_release(store, start + (uint32_t)i),
396 s_tag,
397 "release");
398 }
399 return k_ra8_ok;
400}
401
402/* ------------------------------------------------------------------------- */
403/* Public API */
404/* ------------------------------------------------------------------------- */
405
407ra8_cache_store_put(ra8_cache_store_t* store, uint32_t key, const uint8_t* data, uint32_t len)
408{
409 uint32_t count = 0U;
410 RA8_RETURN_ON_ERROR(internal_put_check(store, key, data, len, &count), s_tag, "check");
412 uint32_t start = 0U;
413 RA8_RETURN_ON_ERROR(internal_alloc_run(store, count, &start), s_tag, "alloc");
415 internal_write_entry(store, start, store->next_seq, key, data, len, (uint16_t)count),
416 s_tag,
417 "write");
418 (void)priv_cache_store_index_add(store, key, start, (uint16_t)count, len, false);
419 store->live_sectors += count;
420 store->next_seq += 1U;
421 return k_ra8_ok;
422}
423
425 uint32_t key,
426 ra8_cache_store_reader_t* out_reader)
427{
428 RA8_CHECK_NULL_PTR(store, s_tag, "store");
429 RA8_CHECK_NULL_PTR(out_reader, s_tag, "out_reader");
430 RA8_VALIDATE_INIT(store->inited, s_tag, "store");
431 int32_t slot = priv_cache_store_index_find(store, key);
432 if (slot < 0) {
433 return k_ra8_err_not_found;
434 }
435 const ra8_cache_store_entry_t* e = &store->index[slot];
436 *out_reader = (ra8_cache_store_reader_t){.store = store,
437 .data_start = e->start_sector + 1U,
438 .data_sectors = (uint32_t)e->sector_count - 1U,
439 .byte_len = e->byte_len};
440 return k_ra8_ok;
441}
442
465 uint32_t data_start,
466 uint32_t data_sectors,
467 uint64_t offset,
468 uint8_t* buf,
469 uint32_t len)
470{
471 RA8_CHECK_NULL_PTR(store, s_tag, "store");
472 RA8_CHECK_NULL_PTR(buf, s_tag, "buf");
473 uint32_t done = 0U;
474 uint32_t max_iter = data_sectors + 1U;
475 for (uint32_t g = 0U; g <= max_iter; g++) {
476 if (done >= len) {
477 break;
478 }
479 uint32_t copied = 0U;
481 internal_read_at(store, data_start, offset + (uint64_t)done, &buf[done], len - done, &copied),
482 s_tag,
483 "at");
484 done += copied;
485 }
486 return k_ra8_ok;
487}
488
489ra8_err_t ra8_cache_store_read(void* ctx, uint64_t offset, uint8_t* buf, uint32_t len)
490{
491 RA8_CHECK_NULL_PTR(ctx, s_tag, "ctx");
492 RA8_CHECK_NULL_PTR(buf, s_tag, "buf");
494 const ra8_cache_store_t* store = r->store;
495 RA8_CHECK_NULL_PTR(store, s_tag, "reader store");
496 if ((offset + (uint64_t)len) > (uint64_t)r->byte_len) {
498 }
499 return internal_read_stream(store, r->data_start, r->data_sectors, offset, buf, len);
500}
501
503{
504 RA8_CHECK_NULL_PTR(store, s_tag, "store");
505 RA8_VALIDATE_INIT(store->inited, s_tag, "store");
506 int32_t slot = priv_cache_store_index_find(store, key);
507 if (slot < 0) {
508 return k_ra8_err_not_found;
509 }
510 ra8_cache_store_entry_t* e = &store->index[slot];
511 if ((e->flags & (uint8_t)k_ra8_cache_store_flag_pinned) != 0U) {
512 return k_ra8_err_busy;
513 }
516 s_tag,
517 "release");
518 store->live_sectors -= e->sector_count;
520 return k_ra8_ok;
521}
522
524{
525 RA8_CHECK_NULL_PTR(store, s_tag, "store");
526 RA8_VALIDATE_INIT(store->inited, s_tag, "store");
527 int32_t slot = priv_cache_store_index_find(store, key);
528 if (slot < 0) {
529 return k_ra8_err_not_found;
530 }
532 ra8_cache_store_entry_t* e = &store->index[slot];
533 if (pin) {
535 } else {
536 e->flags &= (uint8_t)~(uint8_t)k_ra8_cache_store_flag_pinned;
537 }
538 return k_ra8_ok;
539}
540
542{
543 RA8_CHECK_NULL_PTR(store, s_tag, "store");
544 RA8_VALIDATE_INIT(store->inited, s_tag, "store");
545 return internal_checkpoint(store);
546}
547
549{
550 RA8_CHECK_NULL_PTR(store, s_tag, "store");
551 RA8_VALIDATE_INIT(store->inited, s_tag, "store");
552 RA8_RETURN_ON_ERROR(internal_checkpoint(store), s_tag, "checkpoint");
553 (void)lx_nor_flash_close(store->flash);
554 store->inited = false;
555 return k_ra8_ok;
556}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
ra8_board_eth_pin_t pin
Pin.
static ra8_err_t internal_read_stream(const ra8_cache_store_t *store, uint32_t data_start, uint32_t data_sectors, uint64_t offset, uint8_t *buf, uint32_t len)
Stream len payload bytes at offset, sector by sector, into buf.
static ra8_err_t internal_write_entry(ra8_cache_store_t *store, uint32_t start, uint32_t seq, uint32_t key, const uint8_t *data, uint32_t len, uint16_t count)
Write one entry: payload sectors first, then the header (atomic commit).
static ra8_err_t internal_alloc_run(const ra8_cache_store_t *store, uint32_t count, uint32_t *out_start)
First-fit a free contiguous run of count sectors in the log region.
ra8_err_t ra8_cache_store_close(ra8_cache_store_t *store)
Checkpoint, set the clean-shutdown marker, and close the store.
ra8_cs_rt_const_t
Runtime sizing limits.
@ k_ra8_cs_max_run
Max run length (fits ra8_cs_entry_hdr_t sector_count).
ra8_err_t ra8_cache_store_sync(ra8_cache_store_t *store)
Checkpoint the index to flash (directory + clean marker not set).
static ra8_err_t internal_read_at(const ra8_cache_store_t *store, uint32_t data_start, uint64_t byte_pos, uint8_t *dst, uint32_t max, uint32_t *out_copied)
Copy the payload slice that starts at byte_pos, within one sector.
static ra8_err_t internal_mark_dirty(ra8_cache_store_t *store)
Stamp a dirty superblock before mutating (unless already dirty).
static uint16_t internal_index_used(const ra8_cache_store_t *store)
Count the in-use index slots.
static ra8_err_t internal_checkpoint(ra8_cache_store_t *store)
Save the directory + a clean superblock (the checkpoint commit).
ra8_err_t ra8_cache_store_pin(ra8_cache_store_t *store, uint32_t key, bool pin)
Pin or unpin an entry (pinned entries are never evicted).
static ra8_err_t internal_release_run(ra8_cache_store_t *store, uint32_t start, uint16_t count)
Release every logical sector of a run back to the free pool.
ra8_err_t ra8_cache_store_read(void *ctx, uint64_t offset, uint8_t *buf, uint32_t len)
ra8_vsource_read_fn-shaped random read over an open entry.
ra8_err_t ra8_cache_store_get(const ra8_cache_store_t *store, uint32_t key, ra8_cache_store_reader_t *out_reader)
Open a sealed entry for random reads through ra8_cache_store_read.
ra8_err_t ra8_cache_store_put(ra8_cache_store_t *store, uint32_t key, const uint8_t *data, uint32_t len)
Seal a new entry once: append data under key, atomically.
static ra8_err_t internal_put_check(const ra8_cache_store_t *store, uint32_t key, const uint8_t *data, uint32_t len, uint32_t *out_count)
Validate a put request and compute its run length.
static bool internal_run_free(const ra8_cache_store_t *store, uint32_t start, uint32_t count)
True when [start, start+count) overlaps no in-use entry's run.
ra8_err_t ra8_cache_store_evict(ra8_cache_store_t *store, uint32_t key)
Drop an entry and reclaim its sectors (no write-back).
Persistent key(CRC32)->blob cache for compiled .rabook containers,built on the vendored,...
@ k_ra8_cache_store_flag_pinned
Never-evict (open book / metadata).
@ k_ra8_cache_store_flag_in_use
Slot holds a live entry.
@ k_ra8_cache_store_sector_bytes
LevelX logical-sector size (bytes).
Internal on-media format + cross-TU helpers for ra8_cache_store (#201).
uint32_t priv_cache_store_crc32(const uint8_t *data, uint32_t len)
Fold a byte block into a CRC-32/ISO-HDLC value (seeded + finalised).
@ k_ra8_cs_entry_magic
Entry-header tag 'R','C','S','E'.
int32_t priv_cache_store_index_add(ra8_cache_store_t *store, uint32_t key, uint32_t start_sector, uint16_t sector_count, uint32_t byte_len, bool pinned)
Claim a free index slot and populate it for key.
@ k_ra8_cs_dirty
Session open or crashed -> mount must replay the log.
@ k_ra8_cs_clean
Clean shutdown -> the checkpoint directory is valid.
ra8_err_t priv_cache_store_dir_save(ra8_cache_store_t *store, uint32_t *out_entry_count)
Serialize the live index into the on-flash checkpoint directory.
ra8_err_t priv_cache_store_sector_read(const ra8_cache_store_t *store, uint32_t sector, uint8_t *out512)
Read one LevelX logical sector into the store staging buffer region.
int32_t priv_cache_store_index_find(const ra8_cache_store_t *store, uint32_t key)
Find the index slot holding key.
ra8_err_t priv_cache_store_super_write(ra8_cache_store_t *store, uint32_t clean)
Write the superblock (sector 0) with the given clean marker.
ra8_err_t priv_cache_store_sector_write(ra8_cache_store_t *store, uint32_t sector, const uint8_t *in512)
Write one LevelX logical sector from a one-sector source buffer.
ra8_err_t priv_cache_store_sector_release(ra8_cache_store_t *store, uint32_t sector)
Release a LevelX logical sector back to the free pool.
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_RETURN_ON_ERROR(err, tag, message)
Early return on error, propagating the code upward.
Definition ra8_check.h:184
#define RA8_VALIDATE_INIT(initialized, tag, message)
Precondition: module must be initialized.
Definition ra8_check.h:334
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_err_no_mem
Static buffer exhausted (no dynamic memory on this project).
Definition ra8_err.h:142
@ k_ra8_err_busy
Resource busy – blocking operation cannot proceed.
Definition ra8_err.h:195
@ k_ra8_err_out_of_range
Sensor or peripheral output out of valid range.
Definition ra8_err.h:337
@ k_ra8_err_exists
Item already exists – cannot create again.
Definition ra8_err.h:216
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_not_found
Requested item not found (lookup / search missed).
Definition ra8_err.h:173
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
One RAM index slot: key -> {header sector, run length, payload len}.
uint32_t byte_len
Payload length in bytes.
uint32_t start_sector
Logical sector of the entry header.
uint8_t flags
ra8_cache_store_flag_t bit set.
uint16_t sector_count
Run length (header + payload sectors).
Handle to an open entry that streams through ra8_cache_store_read.
uint32_t byte_len
Payload length (== vsource size).
const ra8_cache_store_t * store
Parent store (flash + staging).
uint32_t data_start
First payload logical sector.
uint32_t data_sectors
Payload sector count.
Caller-owned store handle.
bool inited
True between init and close.
uint32_t data_capacity
Overprovisioned live-sector budget.
uint32_t log_start
First append-log sector.
uint32_t live_sectors
Sectors currently held by live entries.
uint8_t * staging
Caller-owned >=1-sector scratch.
ra8_cache_store_entry_t * index
Caller-owned index slot array.
uint16_t index_cap
Number of index slots.
uint32_t next_seq
Monotonic append sequence number.
struct LX_NOR_FLASH_STRUCT * flash
LevelX control block (borrowed).
uint8_t flash_state
RAM shadow of sector 0 (dirty/clean).
uint32_t logical_sectors
Usable LevelX logical-sector span.
On-flash entry header at a run's first logical sector.
uint32_t hdr_crc
CRC-32 over the six fields above.