ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
book.c File Reference

Implementation of the .rabook blob validator. More...

#include "book.h"
#include <string.h>
#include "book_internal.h"
#include "ra8_attributes.h"
#include "ra8_check.h"
Include dependency graph for book.c:

Go to the source code of this file.

Data Structures

struct  book_container_view_t
 Parsed, bounds-checked view of a resident "RBKC" container file. More...

Enumerations

enum  book_crc_const_t : uint32_t {
  k_book_crc_init = 0xFFFFFFFFU ,
  k_book_crc_poly = 0xEDB88320U
}
 Constants for the reflected CRC-32/ISO-HDLC used in the trailer. More...
enum  book_crc_byte_t : uint8_t { k_book_crc_bits_per_byte = 8U }

Functions

static void internal_copy_object (void *dst, const void *src, size_t len)
 Copy an object representation through compatible byte-pointer types.
uint32_t priv_book_crc32_extend (uint32_t crc, const uint8_t *data, size_t len)
 Extend a reflected CRC-32 over one byte span.
static uint32_t internal_crc32 (const uint8_t *data, size_t len)
 Compute CRC-32/ISO-HDLC over one resident byte span.
static bool internal_table_fits (uint32_t off, uint32_t count, uint32_t elem, uint32_t total)
 Implementation of internal_table_fits() – overflow-safe extent check.
static bool internal_image_pixfmts_known (const void *base, const book_header_t *hdr)
 Whether every image descriptor declares a pixel format this build knows.
static bool internal_magic_ok (const book_header_t *hdr)
 Whether the header's magic field equals the "RABOOK1" tag.
ra8_err_t book_validate (const void *base, size_t size)
 Validate that a byte buffer is a well-formed, intact .rabook blob.
ra8_err_t priv_book_container_header_fields (const uint8_t *hdr, uint32_t *out_chunk_bytes, uint64_t *out_total, uint32_t *out_count)
 Implementation of priv_book_container_header_fields() – memcpy field decode.
uint64_t priv_book_container_table_entry (const uint8_t *table, uint32_t idx)
 Implementation of priv_book_container_table_entry() – unaligned-safe memcpy load.
static ra8_err_t internal_container_view (const uint8_t *bytes, size_t file_len, size_t scratch_cap, book_container_view_t *out_view)
 Parse + bounds-check a resident "RBKC" container against its file.
static ra8_err_t internal_inflate_chunks (const book_container_view_t *view, book_inflate_fn inflate, uint8_t *scratch)
 Inflate every chunk of a validated container view into scratch.
static ra8_err_t internal_open_body (const uint8_t *bytes, size_t file_len, book_inflate_fn inflate, void *scratch, size_t scratch_cap, const void **out_base, size_t *out_size)
 Parse, inflate, validate, and publish an already-guarded open.
ra8_err_t book_open (const void *file, size_t file_len, book_inflate_fn inflate, void *scratch, size_t scratch_cap, const void **out_base, size_t *out_size)
 Open a .rabook file: check the container, inflate, validate the blob.

Variables

static const char *const s_tag_book = "book"
 Log tag for book validation diagnostics.

Detailed Description

Implementation of the .rabook blob validator.

The only non-inline part of book is integrity/bounds validation. Walking a validated blob is pure offset arithmetic and lives entirely in the header.

Since
Version 0.1.0

Definition in file book.c.

Enumeration Type Documentation

◆ book_crc_byte_t

enum book_crc_byte_t : uint8_t
Enumerator
k_book_crc_bits_per_byte 

Reflected updates per input byte.

Definition at line 55 of file book.c.

◆ book_crc_const_t

enum book_crc_const_t : uint32_t

Constants for the reflected CRC-32/ISO-HDLC used in the trailer.

Matches Python zlib.crc32_val, so a blob produced by tools/epub_compile verifies bit-for-bit on device.

Since
Version 0.1.0
Enumerator
k_book_crc_init 

CRC seed and final XOR mask.

k_book_crc_poly 

Reflected polynomial.

Definition at line 50 of file book.c.

Function Documentation

◆ book_open()

ra8_err_t book_open ( const void * file,
size_t file_len,
book_inflate_fn inflate,
void * scratch,
size_t scratch_cap,
const void ** out_base,
size_t * out_size )

Open a .rabook file: check the container, inflate, validate the blob.

Parses the "RBKC" container header and chunk table (see book_container_t for the layout), inflates every chunk's zlib stream in order into the caller-owned scratch buffer (expected to live in SDRAM), then runs book_validate() over the reassembled flat blob. On success *out_base is the validated blob base (equal to scratch) ready for the inline accessors. This is the resident open – the whole inflated blob must fit scratch_cap; a book larger than the resident budget is instead read chunk-by-chunk through book_chunked.h + book_src_paged().

Parameters
[in]filePointer to the .rabook file bytes (non-NULL).
[in]file_lenLength of file in bytes.
[in]inflateDecompressor callback (see book_inflate_fn).
[out]scratchBuffer that receives the inflated blob (non-NULL).
[in]scratch_capCapacity of scratch; must be >= the inflated total.
[out]out_baseReceives the validated blob base on success.
[out]out_sizeReceives the inflated blob length on success.
Returns
Error code.
Return values
k_ra8_okContainer valid, inflated, and blob validated.
k_ra8_err_null_ptrA required pointer argument is NULL.
k_ra8_err_invalid_argContainer magic / header geometry / chunk table is malformed (bad magic, zero chunk size, count disagreeing with the total, non-monotonic table, table end disagreeing with the payload length).
k_ra8_err_invalid_sizeFile too short, scratch_cap too small, or a chunk inflated to a length other than its span.
k_ra8_err_range_check_failedBlob CRC mismatch (from book_validate()).
Precondition
file_len is the true readable length at file.
scratch is alignof(uint32_t)-aligned.
Postcondition
On k_ra8_ok, *out_base == scratch and accessors stay within it.
On any error, scratch contents are unspecified and must not be walked.
Note
Thread-safe if inflate is and scratch is not shared concurrently.
See also
book_validate()
Since
Version 0.1.0

Definition at line 543 of file book.c.

References internal_open_body(), RA8_CHECK_NULL_PTR, and s_tag_book.

◆ book_validate()

ra8_err_t book_validate ( const void * base,
size_t size )

Validate that a byte buffer is a well-formed, intact .rabook blob.

Checks, in order: the magic and format_version; that flags sets no bit outside k_book_flag_mask_known (a blob relying on a presentation semantic this firmware does not implement must be rejected, not mis-read); that total_size fits in size; that every table offset plus its extent and every pool lie within total_size; that every image descriptor names a book_image_pixfmt_t this build can unpack (an unknown depth is refused rather than mis-blitted); and finally the CRC-32 of the body. Must be called once before any accessor is used on base; the accessors assume a validated blob and do no bounds checking themselves (they are pure offset arithmetic for XIP).

Parameters
[in]basePointer to the candidate blob (may be NULL).
[in]sizeNumber of readable bytes at base.
Returns
Error code.
Return values
k_ra8_okBlob is well-formed and CRC matches.
k_ra8_err_null_ptrbase is NULL.
k_ra8_err_invalid_argMagic is wrong, the format version is unknown, flags carries an unknown feature bit, or an image declares an unknown pixel format.
k_ra8_err_invalid_sizesize is too small or a table/pool runs past total_size.
k_ra8_err_range_check_failedCRC-32 of the body does not match the header.
Precondition
size is the true readable length at base (no over-read).
base is alignof(uint32_t)-aligned when non-NULL.
Postcondition
On k_ra8_ok, every accessor on base stays within [base, base + total_size).
On any error, base must not be passed to other accessors.
Note
Thread-safe: reads only the immutable candidate buffer.
See also
book_header()
Since
Version 0.1.0

Definition at line 231 of file book.c.

References book_header_t::attr_count, book_header_t::attr_off, book_header_t::chapter_count, book_header_t::chapter_off, book_header_t::crc32_val, book_header_t::flags, book_header_t::format_version, book_header_t::image_count, book_header_t::image_off, book_header_t::image_pool_off, book_header_t::image_pool_size, internal_crc32(), internal_image_pixfmts_known(), internal_magic_ok(), internal_table_fits(), k_book_flag_mask_known, k_book_format_version, k_ra8_err_invalid_arg, k_ra8_err_invalid_size, k_ra8_err_range_check_failed, k_ra8_ok, book_header_t::node_count, book_header_t::node_off, RA8_CHECK_NULL_PTR, s_tag_book, book_header_t::string_off, book_header_t::string_size, book_header_t::stylesheet_count, book_header_t::stylesheet_off, and book_header_t::total_size.

Referenced by erb_render_image(), imp_walk_book(), internal_compile_temp(), internal_dispatch_and_cache(), internal_open_body(), main(), and verify_blob().

◆ internal_container_view()

ra8_err_t internal_container_view ( const uint8_t * bytes,
size_t file_len,
size_t scratch_cap,
book_container_view_t * out_view )
static

Parse + bounds-check a resident "RBKC" container against its file.

Decodes the fixed header via priv_book_container_header_fields(), verifies the header plus chunk table fit inside file_len, verifies the inflated total fits scratch_cap, then walks the chunk table once to require offset[0] == 0, strict monotonic growth, and offset[chunk_count] == payload_len (the streams exactly tile the rest of the file). On success out_view carries pointers the inflate loop can trust without further checks.

Parameters
[in]bytesFirst byte of the container file.
[in]file_lenReadable length of bytes.
[in]scratch_capCaller's inflate scratch capacity in bytes.
[out]out_viewReceives the validated view.
Returns
ra8_err_t Status code.
Return values
k_ra8_okView populated; geometry fully validated.
k_ra8_err_invalid_argBad magic / header fields / chunk-table shape.
k_ra8_err_invalid_sizeFile shorter than header + table, or the inflated total exceeds scratch_cap.
Precondition
bytes is non-NULL and points at file_len readable bytes.
out_view is non-NULL and writable.
Postcondition
On k_ra8_ok every out_view extent lies inside the file buffer.
On any error out_view is not fully populated and must not be used.
Note
Thread-safe: reads only caller memory; no global state.
Since
Version 0.1.0

Definition at line 383 of file book.c.

References book_container_view_t::chunk_bytes, book_container_view_t::chunk_count, k_book_container_entry_len, k_book_container_header_len, k_ra8_err_invalid_arg, k_ra8_err_invalid_size, k_ra8_ok, book_container_view_t::payload, book_container_view_t::payload_len, priv_book_container_header_fields(), priv_book_container_table_entry(), RA8_INTERNAL, book_container_view_t::table, and book_container_view_t::total.

Referenced by internal_open_body().

◆ internal_copy_object()

void internal_copy_object ( void * dst,
const void * src,
size_t len )
static

Copy an object representation through compatible byte-pointer types.

Centralizes the checked project's permitted bytewise object copy.

Parameters
[out]dstDestination spanning at least len writable bytes.
[in]srcSource spanning at least len readable bytes.
[in]lenNumber of bytes to copy.
Precondition
dst is writable for len bytes.
src is readable for len bytes and does not overlap dst.
Postcondition
The first len destination bytes equal the source bytes on entry.
No bytes outside the destination span are modified.
Note
Thread-safe when callers provide disjoint storage.
Since
Version 0.1.0

Definition at line 38 of file book.c.

References memcpy(), and RA8_INTERNAL.

Referenced by priv_book_container_header_fields(), and priv_book_container_table_entry().

◆ internal_crc32()

uint32_t internal_crc32 ( const uint8_t * data,
size_t len )
static

Compute CRC-32/ISO-HDLC over one resident byte span.

Seeds the incremental implementation with zero so the result uses the same finalized wire convention as the streaming validator.

Parameters
[in]dataReadable bytes.
[in]lenNumber of bytes in data.
Returns
Finalized CRC for the span.
Return values
UINT32_C(0)The span's CRC happens to be zero.
UINT32_MAXThe span's CRC happens to have every bit set.
Precondition
data addresses len bytes when len is non-zero.
The immutable CRC lookup table is fully initialized at compile time.
Postcondition
No state is modified.
The result is identical to priv_book_crc32_extend called with a zero seed.
Note
Thread-safe.
Since
Version 0.1.0

Definition at line 117 of file book.c.

References priv_book_crc32_extend(), and RA8_INTERNAL.

Referenced by book_validate().

◆ internal_image_pixfmts_known()

bool internal_image_pixfmts_known ( const void * base,
const book_header_t * hdr )
static

Whether every image descriptor declares a pixel format this build knows.

Rejects a blob carrying a book_image_t::pixel_format newer than k_book_pixfmt_gray8 – the same fail-closed stance book_validate() takes on an unknown header feature bit: a depth this firmware cannot unpack must be refused, not fed to the wrong blit and mis-rendered. Every pre-field blob zero-filled the byte (== k_book_pixfmt_gray4), so this never rejects an older gray4 book. Called only after the image table's bounds are validated, so book_images() is in range for all hdr->image_count entries.

Parameters
[in]baseBlob base already bounds-checked by the caller (non-NULL).
[in]hdrHeader view of base whose image table was already validated.
Returns
Whether every image's declared pixel format is known to this build.
Return values
trueEvery descriptor's pixel_format is <= k_book_pixfmt_gray8.
falseAt least one descriptor names a depth this firmware cannot decode.
Precondition
The image table [image_off, image_off + image_count * sizeof(image)) fits.
base and hdr are non-NULL and describe the same blob.
Postcondition
No memory is written (pure read over the immutable image table).
The result depends only on the descriptors, not on any pool bytes.
Note
Thread-safe: read-only over immutable data.
Since
Version 0.1.0

Definition at line 184 of file book.c.

References book_images(), book_header_t::image_count, k_book_pixfmt_gray8, and RA8_INTERNAL.

Referenced by book_validate().

◆ internal_inflate_chunks()

ra8_err_t internal_inflate_chunks ( const book_container_view_t * view,
book_inflate_fn inflate,
uint8_t * scratch )
static

Inflate every chunk of a validated container view into scratch.

Walks the chunk table in order; chunk i's zlib stream occupies [payload + offset[i], payload + offset[i+1]) and must inflate to exactly min(chunk_bytes, total - i * chunk_bytes) bytes, written at scratch + i * chunk_bytes. A produced-length mismatch on any chunk aborts (truncated / corrupt stream). On success scratch holds the reassembled flat blob of exactly view->total bytes.

Parameters
[in]viewValidated view from internal_container_view().
[in]inflateCaller decompressor (see book_inflate_fn).
[out]scratchDestination for the reassembled blob.
Returns
ra8_err_t Status code.
Return values
k_ra8_okEvery chunk inflated to its exact span.
k_ra8_err_invalid_sizeA chunk inflated to the wrong length.
k_ra8_err_*The inflater's own error, returned verbatim.
Precondition
view was accepted by internal_container_view() for this scratch capacity.
inflate and scratch are non-NULL (checked by the caller).
Postcondition
On k_ra8_ok, scratch[0..view->total) is the flat blob.
On any error scratch contents are unspecified.
Note
Not thread-safe: writes scratch.
Since
Version 0.1.0

Definition at line 455 of file book.c.

References book_container_view_t::chunk_bytes, book_container_view_t::chunk_count, k_ra8_err_invalid_size, k_ra8_ok, book_container_view_t::payload, priv_book_container_table_entry(), RA8_INTERNAL, book_container_view_t::table, and book_container_view_t::total.

Referenced by internal_open_body().

◆ internal_magic_ok()

bool internal_magic_ok ( const book_header_t * hdr)
static

Whether the header's magic field equals the "RABOOK1" tag.

Compares all 8 magic bytes (7 chars + NUL) against the fixed "RABOOK1" signature. Factored out of book_validate() so that function stays within the readability-function-size / NASA Rule 4 statement budget; the check is a pure read over the caller-provided header.

Parameters
[in]hdrHeader view of a blob whose size was already bounds-checked.
Returns
Whether every magic byte matches the "RABOOK1" signature.
Return values
trueAll 8 magic bytes match.
falseAt least one magic byte differs.
Precondition
hdr is non-NULL and points at a blob of at least sizeof(header).
The magic[] array is fully in range (guaranteed by the size precheck).
Postcondition
No memory is written (pure read over the header).
The result depends only on hdr->magic, not on any body bytes.
Note
Thread-safe: read-only over immutable data.
Since
Version 0.1.0

Definition at line 219 of file book.c.

References book_header_t::magic, and RA8_INTERNAL.

Referenced by book_validate().

◆ internal_open_body()

ra8_err_t internal_open_body ( const uint8_t * bytes,
size_t file_len,
book_inflate_fn inflate,
void * scratch,
size_t scratch_cap,
const void ** out_base,
size_t * out_size )
static

Parse, inflate, validate, and publish an already-guarded open.

The argument-checked body of book_open(): builds the container view, inflates every chunk into scratch, validates the reassembled blob, and publishes the base/size outputs. Split from the entry point so the null-guard macros and the staged error chain each stay within the function-size budget.

Parameters
[in]bytesContainer file bytes (non-NULL, caller-checked).
[in]file_lenReadable length of bytes.
[in]inflateCaller decompressor (non-NULL, caller-checked).
[out]scratchDestination for the reassembled blob.
[in]scratch_capCapacity of scratch in bytes.
[out]out_baseReceives the validated blob base.
[out]out_sizeReceives the inflated blob length.
Returns
ra8_err_t Status code.
Return values
k_ra8_okBlob inflated, validated, and published.
k_ra8_err_invalid_argMalformed container header / chunk table.
k_ra8_err_invalid_sizeShort file, scratch too small, or a chunk inflated to the wrong span.
k_ra8_err_range_check_failedBlob CRC mismatch.
Precondition
Every pointer argument was null-checked by the caller.
scratch addresses at least scratch_cap writable bytes.
Postcondition
On k_ra8_ok, *out_base == scratch and *out_size is the blob length.
On any error the outputs are not modified.
Note
Not thread-safe: writes scratch.
Since
Version 0.1.0

Definition at line 517 of file book.c.

References book_validate(), internal_container_view(), internal_inflate_chunks(), k_ra8_ok, RA8_INTERNAL, and book_container_view_t::total.

Referenced by book_open().

◆ internal_table_fits()

bool internal_table_fits ( uint32_t off,
uint32_t count,
uint32_t elem,
uint32_t total )
static

Implementation of internal_table_fits() – overflow-safe extent check.

Returns true when the half-open byte range [off, off + count * elem) lies entirely within a blob of total bytes. Both the start offset and the computed end are promoted to 64-bit before comparison so that no 32-bit arithmetic can wrap on adversarially crafted blob fields, even when count and elem together would overflow a 32-bit product.

Parameters
[in]offByte offset of the table's first element within the blob.
[in]countNumber of elements in the table.
[in]elemSize in bytes of one table element.
[in]totalTotal byte length of the blob (value from the header).
Returns
bool Whether the described table fits inside the blob.
Return values
trueThe range [off, off + count * elem) is within total.
falseThe range overflows or exceeds total bytes.
Precondition
total reflects the actual allocation backing the blob pointer.
elem is non-zero; passing zero causes the range to collapse to off.
Postcondition
No memory is read or written; the result is a pure arithmetic predicate.
Returns false for any input combination that would overflow a 32-bit sum.
Note
Pure function with no shared state; thread-safe.
Since
Version 0.1.0

Definition at line 151 of file book.c.

Referenced by book_validate().

◆ priv_book_container_header_fields()

ra8_err_t priv_book_container_header_fields ( const uint8_t * hdr,
uint32_t * out_chunk_bytes,
uint64_t * out_total,
uint32_t * out_count )

◆ priv_book_container_table_entry()

uint64_t priv_book_container_table_entry ( const uint8_t * table,
uint32_t idx )

Implementation of priv_book_container_table_entry() – unaligned-safe memcpy load.

Decode one uint64 LE chunk-table entry from unaligned container bytes.

Definition at line 325 of file book.c.

References internal_copy_object(), k_book_container_entry_len, and RA8_PRIV.

Referenced by internal_container_view(), and internal_inflate_chunks().

◆ priv_book_crc32_extend()

uint32_t priv_book_crc32_extend ( uint32_t crc,
const uint8_t * data,
size_t len )

Extend a reflected CRC-32 over one byte span.

Extend a finalized CRC-32/ISO-HDLC with another byte span.

Computes a CRC-32/ISO-HDLC (reflected polynomial 0xEDB88320) over the byte array [data, data + len). The algorithm seeds the accumulator with k_book_crc_init, folds each byte through the reflected polynomial, then XORs the final value with k_book_crc_init again. The check value over "123456789" is 0xCBF43926, matching Python zlib.crc32_val.

Parameters
[in]crcPrevious finalized CRC value; use zero for the first span.
[in]dataPointer to the byte array to checksum; must not be NULL.
[in]lenNumber of bytes to process; zero preserves crc.
Returns
CRC-32 after extending crc with data.
Return values
0x00000000Returned for an empty first span.
0xCBF43926Check value for the ASCII string "123456789".
Precondition
data is not NULL when len is greater than 0.
len does not exceed the size of the allocation pointed to by data.
Postcondition
The returned value equals the CRC-32/ISO-HDLC of the input bytes.
Neither data nor any external state is modified.
Note
Not thread-safe if the read range overlaps a concurrent write.
Since
Version 0.1.0

Definition at line 86 of file book.c.

References k_book_crc_bits_per_byte, k_book_crc_init, k_book_crc_poly, and RA8_PRIV.

Referenced by internal_crc32(), and internal_validate_crc().

Variable Documentation

◆ s_tag_book

const char* const s_tag_book = "book"
static

Log tag for book validation diagnostics.

Definition at line 23 of file book.c.

Referenced by book_open(), book_validate(), and priv_book_container_header_fields().