ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
sh_paged.c
Go to the documentation of this file.
1
31#include <string.h>
32
33#include "book_chunked.h"
34#include "ra8_check.h"
35#include "ra8_vmem.h"
36#include "ra8_vsource.h"
37#include "sh_app.h"
38
55typedef enum : uint32_t {
56 k_shp_frame_bytes = 64U * 1024U,
60 k_shp_staging_bytes = 72U * 1024U,
62
64[[gnu::section(".sdram_data"),
65 gnu::aligned(8)]] static uint8_t s_shp_frames[k_shp_frame_count * k_shp_frame_bytes];
66
68[[gnu::section(".sdram_data"), gnu::aligned(8)]] static uint8_t s_shp_staging[k_shp_staging_bytes];
69
72
75
78
81
84
87
90
93
98typedef struct {
99 const uint8_t* data;
100 uint64_t len;
102
105
107static const char* const s_shp_tag = "sh_paged";
108
110/* cppcheck-suppress constParameterCallback -- ra8_vsource_read_fn fixes this callback's context type as void*. */
111static ra8_err_t sh_paged_mram_read(void* ctx, uint64_t offset, uint8_t* buf, uint32_t len)
112{
113 RA8_CHECK_NULL_PTR(ctx, s_shp_tag, "mram: null ctx");
114 RA8_CHECK_NULL_PTR(buf, s_shp_tag, "mram: null buf");
115 const sh_paged_mram_t* m = (const sh_paged_mram_t*)ctx;
116 if ((offset + (uint64_t)len) > m->len) {
118 }
119 (void)memcpy(buf, &m->data[offset], (size_t)len);
120 return k_ra8_ok;
121}
122
124static bool sh_paged_extent_ok(uint32_t off, uint32_t count, uint32_t elem, uint32_t total)
125{
126 const uint64_t end = (uint64_t)off + ((uint64_t)count * (uint64_t)elem);
127 if (off > total) {
128 return false;
129 }
130 return end <= (uint64_t)total;
131}
132
146static bool sh_paged_hdr_ok(const book_header_t* hdr, uint64_t inflated_total)
147{
148 const char k_magic[8] = {'R', 'A', 'B', 'O', 'O', 'K', '1', '\0'};
149 if (memcmp(hdr->magic, k_magic, sizeof k_magic) != 0) {
150 return false;
151 }
152 if (hdr->format_version != (uint32_t)k_book_format_version) {
153 return false;
154 }
155 if ((uint64_t)hdr->total_size != inflated_total) {
156 return false;
157 }
158 if (hdr->total_size < (uint32_t)sizeof(book_header_t)) {
159 return false;
160 }
161 const struct {
162 uint32_t off;
163 uint32_t count;
164 uint32_t elem;
165 } k_ext[] = {
166 {hdr->chapter_off, hdr->chapter_count, (uint32_t)sizeof(book_chapter_t)},
167 {hdr->node_off, hdr->node_count, (uint32_t)sizeof(book_node_t)},
168 {hdr->attr_off, hdr->attr_count, (uint32_t)sizeof(book_attr_t)},
169 {hdr->stylesheet_off, hdr->stylesheet_count, (uint32_t)sizeof(book_stylesheet_t)},
170 {hdr->image_off, hdr->image_count, (uint32_t)sizeof(book_image_t)},
171 {hdr->string_off, hdr->string_size, 1U},
172 {hdr->image_pool_off, hdr->image_pool_size, 1U},
173 };
174 for (size_t i = 0U; i < (sizeof(k_ext) / sizeof(k_ext[0])); ++i) {
175 if (!sh_paged_extent_ok(k_ext[i].off, k_ext[i].count, k_ext[i].elem, hdr->total_size)) {
176 return false;
177 }
178 }
179 return true;
180}
181
183static bool sh_paged_bind(void)
184{
186 return false;
187 }
188 uint32_t oid = 0U;
191 &s_shp_rd,
192 0U,
193 s_shp_rd.inflated_total,
194 &oid) != k_ra8_ok) {
195 return false;
196 }
197 const ra8_vmem_cfg_t cfg = {
198 .frame_mem = s_shp_frames,
199 .frame_bytes = (uint32_t)k_shp_frame_bytes,
200 .frame_count = (uint32_t)k_shp_frame_count,
201 .meta = s_shp_meta,
202 .keys = s_shp_keys,
203 .buckets = s_shp_buckets,
204 .bucket_count = (uint32_t)k_shp_bucket_count,
205 .loader = ra8_vsource_loader,
206 .loader_ctx = &s_shp_vs,
207 };
208 s_shp_vm = (ra8_vmem_t){};
209 if (ra8_vmem_init(&s_shp_vm, &cfg) != k_ra8_ok) {
210 return false;
211 }
212 /* Binding reads the 100-byte header through the cache (faults chunk 0 in). */
213 if (book_src_paged(&g_sh.book_src,
214 &s_shp_vm,
215 oid,
216 (uint32_t)k_shp_frame_bytes,
217 (uint32_t)s_shp_rd.inflated_total) != k_ra8_ok) {
218 return false;
219 }
220 return sh_paged_hdr_ok(&g_sh.book_src.hdr, s_shp_rd.inflated_total);
221}
222
223bool sh_paged_open(ra8_vsource_read_fn file_read, void* file_ctx, uint64_t file_len)
224{
225 /* Unbind any previous source, but do NOT sh_paged_close() here: the caller
226 * has already torn the old book down (sh_book_open), and a full close would
227 * wipe the MRAM context / close the SD file that @p file_read is about to
228 * read from. The failure paths below do close, releasing the SD backing. */
229 g_sh.book_src = (book_src_t){};
231 if ((file_read == nullptr) || (file_len == 0U)) {
233 return false;
234 }
236 file_read,
237 file_ctx,
238 file_len,
241 (uint32_t)k_shp_table_entries,
243 (uint32_t)k_shp_staging_bytes) != k_ra8_ok) {
245 return false;
246 }
247 /* One chunk == one cache frame: the read callback's contract. A container
248 * compiled with a different --chunk-bytes cannot be paged through this
249 * cache, so reject it here instead of failing obscurely per read. */
250 if (s_shp_rd.chunk_bytes != (uint32_t)k_shp_frame_bytes) {
252 return false;
253 }
254 /* book_src_t carries a uint32 size; the table budget already caps books
255 * at 64 MiB, so this guard is belt-and-braces against a lying header. */
256 if (s_shp_rd.inflated_total > (uint64_t)UINT32_MAX) {
258 return false;
259 }
260 if (!sh_paged_bind()) {
262 return false;
263 }
264 return true;
265}
266
267bool sh_paged_open_mram(const uint8_t* blob, uint32_t blob_len)
268{
269 if (blob == nullptr) {
270 return false;
271 }
272 if (blob_len == 0U) {
273 return false;
274 }
275 s_shp_mram = (sh_paged_mram_t){.data = blob, .len = (uint64_t)blob_len};
276 return sh_paged_open(sh_paged_mram_read, &s_shp_mram, (uint64_t)blob_len);
277}
278
280{
281 g_sh.book_src = (book_src_t){};
284 sh_sd_book_close(); /* release the held SD file handle, if any */
285}
@ k_book_format_version
Current .rabook layout revision.
Definition book.h:86
Demand-paged chunk reader for the "RBKC" .rabook container.
ra8_err_t book_chunked_read(void *ctx, uint64_t offset, uint8_t *buf, uint32_t len)
Serve one chunk-aligned read of the inflated flat blob.
ra8_err_t book_chunked_open(book_chunked_t *rd, ra8_vsource_read_fn file_read, void *file_ctx, uint64_t file_len, book_inflate_fn inflate, uint64_t *table_buf, uint32_t table_cap_entries, uint8_t *staging, uint32_t staging_cap)
Open a chunked .rabook container for demand-paged chunk reads.
ra8_err_t book_src_paged(book_src_t *out, ra8_vmem_t *vm, uint32_t object_id, uint32_t frame_bytes, uint32_t size)
Bind a paged book source over an ra8_vmem cache + ra8_vsource object.
Definition book_paged.c:61
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
@ k_ra8_err_out_of_range
Sensor or peripheral output out of valid range.
Definition ra8_err.h:337
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
int memcmp(const void *a, const void *b, size_t n)
Compare bytes in two memory areas.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
Byte-range page cache with SLRU eviction (Layer 2, #147).
ra8_err_t ra8_vmem_init(ra8_vmem_t *vm, const ra8_vmem_cfg_t *cfg)
Initialise a page cache over caller-supplied storage.
Definition ra8_vmem.c:131
ra8_keycache_cell_t ra8_vmem_frame_t
Per-frame cache metadata (one caller-owned array entry per frame).
Definition ra8_vmem.h:122
Virtual-memory object sources – the page-cache storage seam (Layer 1, #147).
ra8_err_t ra8_vsource_loader(void *ctx, uint32_t object_id, uint64_t offset, uint8_t *frame, uint32_t frame_bytes)
Fill a page frame from an object – the ra8_vmem_loader_fn adapter.
Definition ra8_vsource.c:84
ra8_err_t ra8_vsource_add_paged(ra8_vsource_t *vs, ra8_vsource_read_fn read, void *ctx, uint64_t base, uint64_t size, uint32_t *out_id)
Register a storage-paged object; returns its object_id.
Definition ra8_vsource.c:42
ra8_err_t(* ra8_vsource_read_fn)(void *ctx, uint64_t offset, uint8_t *buf, uint32_t len)
Read len bytes at offset from a paged object's backing.
Definition ra8_vsource.h:79
ra8_err_t ra8_vsource_init(ra8_vsource_t *vs, ra8_vsource_obj_t *objs, uint32_t cap)
Initialise an empty source registry over a caller-owned object array.
Definition ra8_vsource.c:29
Shared contract for the ereader_shelf multi-screen e-reader.
ra8_err_t sh_inflate(const void *src, size_t src_len, void *dst, size_t dst_cap, size_t *out_len)
Heap-free zlib inflater matching book_inflate_fn (miniz; main.c).
Definition main.c:160
void sh_sd_book_close(void)
Close the held SD book file (idempotent).
Definition sh_sd.c:225
sh_state_t g_sh
The single whole-app state instance (defined in main.c).
Definition main.c:64
static ra8_vmem_key_t s_shp_keys[k_shp_frame_count]
Per-frame cache key storage (parallel to the frame pool).
Definition sh_paged.c:77
static ra8_err_t sh_paged_mram_read(void *ctx, uint64_t offset, uint8_t *buf, uint32_t len)
ra8_vsource_read_fn over a memory-mapped (MRAM) container blob.
Definition sh_paged.c:111
bool sh_paged_open(ra8_vsource_read_fn file_read, void *file_ctx, uint64_t file_len)
Open a chunked .rabook container as the demand-paged book source.
Definition sh_paged.c:223
sh_paged_dim_t
Paged-stack buffer budgets.
Definition sh_paged.c:55
@ k_shp_staging_bytes
>= compressBound(chunk) for zlib and miniz.
Definition sh_paged.c:60
@ k_shp_table_entries
chunk_count+1 budget: 64 MiB inflated cap.
Definition sh_paged.c:59
@ k_shp_frame_count
384 x 64 KiB = 24 MiB SDRAM frame pool.
Definition sh_paged.c:57
@ k_shp_bucket_count
Cache hash buckets (~1.3x frames, pow2).
Definition sh_paged.c:58
@ k_shp_frame_bytes
ra8_vmem frame size == container chunk_bytes.
Definition sh_paged.c:56
bool sh_paged_open_mram(const uint8_t *blob, uint32_t blob_len)
Open a memory-mapped (baked MRAM) RBKC container as the paged source.
Definition sh_paged.c:267
static ra8_vmem_t s_shp_vm
The page cache the bound book_src_t reads through.
Definition sh_paged.c:92
static uint8_t s_shp_staging[k_shp_staging_bytes]
SDRAM staging buffer for one compressed chunk's zlib stream.
Definition sh_paged.c:68
static const char *const s_shp_tag
Log tag for paged-open diagnostics.
Definition sh_paged.c:107
static bool sh_paged_extent_ok(uint32_t off, uint32_t count, uint32_t elem, uint32_t total)
Does the header extent [off, off + count*elem) fit inside total?
Definition sh_paged.c:124
static bool sh_paged_hdr_ok(const book_header_t *hdr, uint64_t inflated_total)
Validate the paged source's header copy (no whole-blob CRC).
Definition sh_paged.c:146
static uint64_t s_shp_table[k_shp_table_entries]
Resident chunk table (chunk_count + 1 stream offsets).
Definition sh_paged.c:71
static ra8_vsource_obj_t s_shp_obj
Single-slot object registry: object 0 is the open book.
Definition sh_paged.c:86
static bool sh_paged_bind(void)
Register the bound chunk reader, init the cache, bind g_sh.book_src.
Definition sh_paged.c:183
static ra8_vsource_t s_shp_vs
Source registry fronting s_shp_obj.
Definition sh_paged.c:89
static book_chunked_t s_shp_rd
The open book's chunk reader (unbound when no rabook is open).
Definition sh_paged.c:83
static int32_t s_shp_buckets[k_shp_bucket_count]
Cache hash-bucket heads.
Definition sh_paged.c:80
static ra8_vmem_frame_t s_shp_meta[k_shp_frame_count]
Per-frame cache metadata (parallel to the frame pool).
Definition sh_paged.c:74
static sh_paged_mram_t s_shp_mram
Backing context while an MRAM (baked) book is open.
Definition sh_paged.c:104
static uint8_t s_shp_frames[k_shp_frame_count *k_shp_frame_bytes]
SDRAM page-frame pool (the old inflate-scratch budget, repurposed).
Definition sh_paged.c:65
void sh_paged_close(void)
Unbind the paged book source and release its SD backing (idempotent).
Definition sh_paged.c:279
One name="value" attribute on an element.
Definition book.h:317
One spine document (a renderable chapter) plus its TOC label.
Definition book.h:280
One open chunked .rabook file: parsed geometry + caller storage.
Fixed 100-byte prologue describing every table and pool in the blob.
Definition book.h:246
uint32_t format_version
book_version_t of this blob.
Definition book.h:248
uint32_t image_off
Offset to the image table.
Definition book.h:265
uint32_t image_pool_size
Image-pool length in bytes.
Definition book.h:269
uint32_t attr_count
Number of attribute records.
Definition book.h:260
uint32_t node_count
Number of DOM nodes.
Definition book.h:258
uint32_t chapter_count
Number of spine chapters.
Definition book.h:256
uint32_t image_count
Number of image descriptors.
Definition book.h:264
uint32_t string_off
Offset to the string pool.
Definition book.h:266
uint32_t attr_off
Offset to the attribute table.
Definition book.h:261
uint32_t node_off
Offset to the node table.
Definition book.h:259
uint32_t string_size
String-pool length in bytes.
Definition book.h:267
uint32_t stylesheet_off
Offset to the stylesheet table.
Definition book.h:263
char magic[8]
Always "RABOOK1" (7 chars + NUL).
Definition book.h:247
uint32_t chapter_off
Offset to the chapter table.
Definition book.h:257
uint32_t stylesheet_count
Number of preserved stylesheets.
Definition book.h:262
uint32_t image_pool_off
Offset to the image pool.
Definition book.h:268
uint32_t total_size
Total blob length in bytes.
Definition book.h:249
Descriptor for one transcoded image in the image pool.
Definition book.h:354
One DOM node.
Definition book.h:299
A book data source: resident (zero-copy) or paged (demand-fetched).
Definition book_paged.h:69
A preserved CSS stylesheet and the chapter it scopes to.
Definition book.h:332
Caller-supplied storage + loader for ra8_vmem_init.
Definition ra8_vmem.h:151
The (object_id, frame-aligned offset) key the page cache hashes on.
Definition ra8_vmem.h:136
Page-cache state (caller-owned; treat as private).
Definition ra8_vmem.h:179
One registered object's backing (paged or XIP).
Definition ra8_vsource.h:90
Object-source registry (caller-owned; treat as private).
Memory-mapped container backing (baked books).
Definition sh_paged.c:98
const uint8_t * data
First container byte (MRAM, memory-mapped).
Definition sh_paged.c:99
uint64_t len
Container length in bytes.
Definition sh_paged.c:100