ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
rabook_import_compiler.c
Go to the documentation of this file.
1
12
14
15#include <stddef.h>
16#include <stdint.h>
17
18#include "book.h"
19#include "epub.h"
20#include "ra8_attributes.h"
21#include "ra8_check.h"
22#include "ra8_err.h"
23#include "ra8_fs.h"
24#include "ra8_rabook_pipeline.h"
25#include "ra8_vmem.h"
26#include "ra8_vmem_stream.h"
27#include "ra8_vsource.h"
28
30static const char* const s_tag = "rabook_import_compiler";
31
49
76internal_source_read(void* ctx, uint64_t offset, uint8_t* buf, uint32_t len)
77{
78 RA8_CHECK_NULL_PTR(ctx, s_tag, "source_read: ctx");
79 RA8_CHECK_NULL_PTR(buf, s_tag, "source_read: buf");
80 if (offset > (uint64_t)UINT32_MAX) {
81 return k_ra8_err_out_of_range; /* GCOVR_EXCL_LINE -- ra8_fs_size is 32-bit, so offsets fit */
82 }
83 ra8_fs_file_t* file = (ra8_fs_file_t*)ctx;
84 ra8_err_t err = ra8_fs_seek(file, (uint32_t)offset);
85 if (err != k_ra8_ok) {
86 return err; /* GCOVR_EXCL_LINE -- seek clamps to size and cannot fail on a live handle */
87 }
88 uint32_t got = 0U;
89 err = ra8_fs_read(file, buf, len, &got);
90 if (err != k_ra8_ok) {
91 return err; /* corrupt FAT chain / backend fault mid-stream */
92 }
93 if (got != len) {
94 return k_ra8_err_hw_error; /* GCOVR_EXCL_LINE -- ra8_vsource_loader clamps len to o->size */
95 }
96 return k_ra8_ok;
97}
98
124{
125 RA8_CHECK_NULL_PTR(ctx->cache, s_tag, "cache");
126 RA8_CHECK_NULL_PTR(ss->file, s_tag, "file");
127 ra8_err_t err = ra8_vsource_init(&ss->vsrc, &ss->obj, 1U);
128 if (err != k_ra8_ok) {
129 return err; /* GCOVR_EXCL_LINE -- registry storage is the frame's own struct, never NULL/zero */
130 }
131 uint32_t oid = 0U;
132 err = ra8_vsource_add_paged(&ss->vsrc, internal_source_read, ss->file, 0U, (uint64_t)size, &oid);
133 if (err != k_ra8_ok) {
134 return err;
135 }
136 const ra8_vmem_cfg_t cfg = {
137 .frame_mem = ctx->cache_frames,
138 .frame_bytes = ctx->cache_frame_bytes,
139 .frame_count = ctx->cache_frame_count,
140 .meta = ctx->cache_meta,
141 .keys = ctx->cache_keys,
142 .buckets = ctx->cache_buckets,
143 .bucket_count = ctx->cache_bucket_count,
144 .loader = ra8_vsource_loader,
145 .loader_ctx = &ss->vsrc,
146 };
147 *ctx->cache = (ra8_vmem_t){};
148 err = ra8_vmem_init(ctx->cache, &cfg);
149 if (err != k_ra8_ok) {
150 return err; /* a NULL / zero-sized cookie cache dimension */
151 }
152 return ra8_vmem_stream_init(&ss->st, ctx->cache, oid, (uint64_t)size);
153}
154
179 ra8_fs_mount_t* mount,
180 const char* epub_path,
181 import_stream_t* ss)
182{
183 RA8_CHECK_NULL_PTR(ctx->epub, s_tag, "epub");
184 RA8_CHECK_NULL_PTR(ss, s_tag, "stream state");
185 ra8_err_t err = ra8_fs_open(mount, epub_path, k_ra8_fs_mode_read, &ss->file);
186 if (err != k_ra8_ok) {
187 return err;
188 }
189 /* ra8_fs_size cannot fail on the handle ra8_fs_open just returned (in_use
190 * set, both out-params non-NULL); on any future contract change `size`
191 * stays 0 and internal_cache_bind rejects it as invalid_size. */
192 uint64_t size64 = 0U;
193 (void)ra8_fs_size(ss->file, &size64);
194 /* Import sources are sized in 32 bits; an over-4-GiB source is clamped to
195 * the reject path (0 -> invalid_size in the bind below). */
196 const uint32_t size = (size64 <= (uint64_t)UINT32_MAX) ? (uint32_t)size64 : 0U;
197 err = internal_cache_bind(ctx, ss, size);
198 if (err == k_ra8_ok) {
199 const epub_stream_media_t media = {
200 .read = ra8_vmem_stream_read,
201 .ctx = &ss->st,
202 .size = (uint64_t)size,
203 };
204 err = epub_open_streamed(&media, epub_path, ctx->epub);
205 }
206 if (err != k_ra8_ok) {
207 (void)ra8_fs_close(ss->file);
208 ss->file = nullptr;
209 }
210 return err;
211}
212
214 ra8_fs_mount_t* mount,
215 const char* epub_path,
216 const char* out_path)
217{
218 RA8_CHECK_NULL_PTR(compile_ctx, s_tag, "compile_ctx");
219 RA8_CHECK_NULL_PTR(mount, s_tag, "mount");
220 RA8_CHECK_NULL_PTR(epub_path, s_tag, "epub_path");
221 RA8_CHECK_NULL_PTR(out_path, s_tag, "out_path");
222
223 /* The cookie's epub/cache fields are validated by the stream-open helpers and
224 * the bufs/scr by `rabook_compile_from_epub`, so a NULL cookie field still
225 * yields k_ra8_err_null_ptr without restating those guards here. */
226 const rabook_import_compiler_ctx_t* ctx = (const rabook_import_compiler_ctx_t*)compile_ctx;
227
228 /* The book streams through `ss` for the whole compile, so it lives in this
229 * frame, spanning open -> compile -> close. */
230 import_stream_t ss = {};
231 ra8_err_t err = internal_stream_open(ctx, mount, epub_path, &ss);
232 if (err != k_ra8_ok) {
233 return err;
234 }
235
236 err = rabook_compile_from_epub(ctx->epub, ctx->bufs, ctx->scr, mount, out_path);
237 ra8_err_t cerr = epub_close(ctx->epub);
238 (void)ra8_fs_close(ss.file); /* always release the source handle */
239 if (err != k_ra8_ok) {
240 return err;
241 }
242 return cerr;
243}
244
272 const char* path,
273 uint8_t* buf,
274 uint32_t cap,
275 uint32_t* out_len)
276{
277 ra8_fs_file_t* file = nullptr;
278 ra8_err_t err = ra8_fs_open(mount, path, k_ra8_fs_mode_read, &file);
279 if (err != k_ra8_ok) {
280 return err;
281 }
282 /* ra8_fs_size cannot fail on a just-opened handle; a lying 0 simply reads 0
283 * bytes below and the dispatch rejects the empty source. */
284 uint64_t size64 = 0U;
285 (void)ra8_fs_size(file, &size64);
286 const uint32_t size = (size64 <= (uint64_t)UINT32_MAX) ? (uint32_t)size64 : UINT32_MAX;
287 if (size > cap) {
288 /* Transport overflow: the source cannot fit the cross-core buffer. Report
289 * no_mem (an offload-failure class) so the streamed in-core fallback --
290 * which has no size ceiling (#230) -- can still import the book. */
291 (void)ra8_fs_close(file);
292 return k_ra8_err_no_mem;
293 }
294 err = ra8_fs_read(file, buf, cap, out_len);
295 ra8_err_t cerr = ra8_fs_close(file);
296 if (err != k_ra8_ok) {
297 return err;
298 }
299 return cerr;
300}
301
325 uint32_t epub_len,
326 ra8_fs_mount_t* mount,
327 const char* out_path)
328{
329 uint32_t blob_len = 0U;
330 ra8_err_t err = ctx->dispatch(ctx->dispatch_ctx,
331 ctx->epub_load_buf,
332 epub_len,
333 ctx->blob_buf,
334 ctx->blob_cap,
335 &blob_len);
336 if (err != k_ra8_ok) {
337 return err;
338 }
339 /* Validate the worker-produced blob before caching -- a cross-core transfer
340 * slip or a worker fault could yield a structurally-broken blob. */
341 err = book_validate(ctx->blob_buf, (size_t)blob_len);
342 if (err != k_ra8_ok) {
343 return err;
344 }
345 return ra8_fs_write_file(mount, out_path, ctx->blob_buf, blob_len);
346}
347
373{
374 return (err == k_ra8_err_hw_error) || (err == k_ra8_err_no_mem);
375}
376
402 ra8_err_t err,
403 ra8_fs_mount_t* mount,
404 const char* epub_path,
405 const char* out_path)
406{
408 return err;
409 }
410 if (ctx->fallback == nullptr) {
411 return err;
412 }
413 ra8_log_warn(s_tag, "M33 offload failed; compiling in-core instead");
414 return rabook_import_compile_adapter(ctx->fallback, mount, epub_path, out_path);
415}
416
438 uint32_t epub_len,
439 ra8_fs_mount_t* mount,
440 const char* epub_path,
441 const char* out_path)
442{
443 ra8_err_t err = internal_dispatch_and_cache(ctx, epub_len, mount, out_path);
444 if (err == k_ra8_ok) {
445 return k_ra8_ok;
446 }
447 return internal_fallback_or_propagate(ctx, err, mount, epub_path, out_path);
448}
449
451 ra8_fs_mount_t* mount,
452 const char* epub_path,
453 const char* out_path)
454{
455 RA8_CHECK_NULL_PTR(compile_ctx, s_tag, "compile_ctx");
456 RA8_CHECK_NULL_PTR(mount, s_tag, "mount");
457 RA8_CHECK_NULL_PTR(epub_path, s_tag, "epub_path");
458 RA8_CHECK_NULL_PTR(out_path, s_tag, "out_path");
459
461 RA8_CHECK_NULL_PTR(ctx->dispatch, s_tag, "dispatch");
462
463 /* ctx->epub_load_buf / ctx->blob_buf are caller-owned per the cookie invariant
464 * and reached through ra8_fs_read / the dispatch, so a NULL there is a caller
465 * bug -- matching how the in-core adapter leans on its downstream guards. */
466
467 /* Read the source .epub off the mount (the M85 owns the FS), then offload. A
468 * read-stage transport overflow (source larger than the load buffer, #230)
469 * is an offload failure like any other: the streamed in-core fallback still
470 * imports the book. */
471 uint32_t epub_len = 0U;
472 ra8_err_t err =
473 internal_read_whole_file(mount, epub_path, ctx->epub_load_buf, ctx->epub_load_cap, &epub_len);
474 if (err != k_ra8_ok) {
475 return internal_fallback_or_propagate(ctx, err, mount, epub_path, out_path);
476 }
477 return internal_offload_or_fallback(ctx, epub_len, mount, epub_path, out_path);
478}
Flat, execute-in-place container for a build-time "compiled" e-book.
ra8_err_t book_validate(const void *base, size_t size)
Validate that a byte buffer is a well-formed, intact .rabook blob.
Definition book.c:231
static cb_io_status_t internal_source_read(void *ctx, uint64_t offset, uint8_t *dst, size_t capacity, size_t *out_read)
Read a bounded fragment from a snapshotted host source.
EPUB (.epub) reader and chapter iterator for ra8-firmware.
ra8_err_t epub_close(epub_book_t *book)
Close a previously opened EPUB book.
Definition epub_open.c:507
ra8_err_t epub_open_streamed(const epub_stream_media_t *media, const char *path, epub_book_t *out_book)
Open an EPUB book from a seekable stream, with no whole-file residency (#151).
Definition epub_open.c:455
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
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
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_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
@ k_ra8_err_hw_error
Generic hardware fault detected (error flag set, fault interrupt).
Definition ra8_err.h:310
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
Minimal FAT12/FAT16/FAT32 filesystem adapter (read + write).
ra8_err_t ra8_fs_size(const ra8_fs_file_t *file, uint64_t *out_bytes)
Report the file's size in bytes (64-bit on exFAT, #676).
ra8_err_t ra8_fs_read(ra8_fs_file_t *file, uint8_t *buf, uint32_t max_len, uint32_t *got_len)
Read up to max_len bytes; advance the cluster chain on cluster crossings.
ra8_err_t ra8_fs_open(ra8_fs_mount_t *handle, const char *path, ra8_fs_mode_t mode, ra8_fs_file_t **out_file)
Open or create a file by path, 8.3 or long.
ra8_err_t ra8_fs_close(ra8_fs_file_t *file)
Close an open file, stamping its final modification time.
ra8_err_t ra8_fs_seek(ra8_fs_file_t *file, uint64_t offset_bytes)
Move the file offset to offset_bytes (clamped to size).
ra8_err_t ra8_fs_write_file(ra8_fs_mount_t *handle, const char *path, const uint8_t *data, uint32_t len)
Create a whole file in one call (provisioning helper).
@ k_ra8_fs_mode_read
Read-only, must exist.
#define ra8_log_warn(tag, message)
RA8 log warn.
Definition ra8_log.h:347
End-to-end EPUB -> RABOOK1 compile pipeline (#149).
ra8_err_t rabook_compile_from_epub(epub_book_t *epub, const ra8_rabook_buffers_t *buffers, const ra8_rabook_pipeline_scratch_t *scratch, ra8_fs_mount_t *mount, const char *out_path)
Compile an open EPUB into a RABOOK1 blob written to out_path on the SD filesystem.
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
Read a page-cached object as a seekable byte stream (Layer 2 helper, #147/#151).
ra8_err_t ra8_vmem_stream_init(ra8_vmem_stream_t *st, ra8_vmem_t *vm, uint32_t object_id, uint64_t size)
Bind a page-cached paged object to the byte-stream reader.
size_t ra8_vmem_stream_read(void *ctx, uint64_t offset, void *buf, size_t len)
Read len bytes at absolute offset through the page cache.
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_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
ra8_err_t rabook_import_compile_adapter_m33(void *compile_ctx, ra8_fs_mount_t *mount, const char *epub_path, const char *out_path)
Import-seam adapter that offloads the compile to the Cortex-M33 (#149).
static ra8_err_t internal_source_read(void *ctx, uint64_t offset, uint8_t *buf, uint32_t len)
ra8_vsource_read_fn over the open source file: seek + full read.
ra8_err_t rabook_import_compile_adapter(void *compile_ctx, ra8_fs_mount_t *mount, const char *epub_path, const char *out_path)
Import-seam adapter: stream a .epub off mount and compile it.
static ra8_err_t internal_cache_bind(const rabook_import_compiler_ctx_t *ctx, import_stream_t *ss, uint32_t size)
Rebuild the cookie's page cache over the open source file.
static ra8_err_t internal_offload_or_fallback(const rabook_import_compiler_m33_ctx_t *ctx, uint32_t epub_len, ra8_fs_mount_t *mount, const char *epub_path, const char *out_path)
Run the M33 offload, retrying in-core when the offload itself failed.
static ra8_err_t internal_read_whole_file(ra8_fs_mount_t *mount, const char *path, uint8_t *buf, uint32_t cap, uint32_t *out_len)
Read a whole file off mount into buf, closing it on every path.
static ra8_err_t internal_fallback_or_propagate(const rabook_import_compiler_m33_ctx_t *ctx, ra8_err_t err, ra8_fs_mount_t *mount, const char *epub_path, const char *out_path)
Retry a failed offload in-core, or propagate the offload error.
static bool internal_is_dispatch_failure(ra8_err_t err)
Classify an offload result: does err warrant an in-core retry?
static ra8_err_t internal_stream_open(const rabook_import_compiler_ctx_t *ctx, ra8_fs_mount_t *mount, const char *epub_path, import_stream_t *ss)
Open the source .epub as a cache-fronted stream (no residency).
static ra8_err_t internal_dispatch_and_cache(const rabook_import_compiler_m33_ctx_t *ctx, uint32_t epub_len, ra8_fs_mount_t *mount, const char *out_path)
Dispatch the staged compile to the secondary core, validate, cache it.
Production adapter binding the import seam to the real compiler (#151).
Seekable EPUB media descriptor – opens with no whole-file residency (#151).
Definition epub.h:232
Per-compile streaming state living in the adapter's stack frame.
ra8_vsource_t vsrc
Source registry the cache's loader reads through.
ra8_fs_file_t * file
Open source .epub (owned until the compile ends).
ra8_vsource_obj_t obj
The registry's single object slot.
ra8_vmem_stream_t st
Byte-stream binding handed to the EPUB reader.
Open-file state.
Cached parse of one mounted FAT volume.
Caller-supplied storage + loader for ra8_vmem_init.
Definition ra8_vmem.h:151
Binds one page-cached object to the byte-stream read adapter.
uint64_t size
Object length in bytes.
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).
Cookie carrying the storage rabook_import_compile_adapter needs.
epub_book_t * epub
Caller-owned open-book storage.
ra8_vmem_t * cache
Page cache re-initialised per compile.
ra8_vmem_key_t * cache_keys
Per-frame key-storage array.
const ra8_rabook_buffers_t * bufs
RABOOK1 builder arenas.
uint32_t cache_frame_bytes
Bytes per cache frame (e.g.
uint32_t cache_frame_count
Frames in the pool (the RAM budget).
int32_t * cache_buckets
Cache hash-bucket heads.
uint8_t * cache_frames
Frame pool backing the cache.
uint32_t cache_bucket_count
Number of hash buckets (>= 1).
ra8_vmem_frame_t * cache_meta
Per-frame metadata array.
const ra8_rabook_pipeline_scratch_t * scr
XHTML + image decode scratch.
Cookie for rabook_import_compile_adapter_m33 (the M33-offload binding).
uint32_t blob_cap
Capacity of blob_buf in bytes.
uint8_t * blob_buf
Buffer the dispatched RABOOK1 blob lands in.
ra8_dual_core_compile_dispatch_fn dispatch
Cross-core compile seam (non-NULL).
uint8_t * epub_load_buf
Buffer the source .epub is read into.
void * dispatch_ctx
Cookie forwarded to dispatch.
rabook_import_compiler_ctx_t * fallback
In-core retry cookie used if the offload fails; NULL = offload-only.
uint32_t epub_load_cap
Capacity of epub_load_buf in bytes.