ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
book_chunked_validate.c
Go to the documentation of this file.
1
15#include <string.h>
16
17#include "book_chunked.h"
18#include "ra8_attributes.h"
19
21typedef struct {
23 uint8_t* chunk;
24 uint32_t loaded_idx;
25 uint32_t loaded_len;
26 bool loaded;
28
33
56static bool
57internal_spans_overlap(const void* a, uint64_t a_len, const void* b, uint64_t b_len, bool* invalid)
58{
59 uintptr_t a_begin = 0U;
60 uintptr_t b_begin = 0U;
61 static_assert(sizeof(a_begin) == sizeof(a), "uintptr_t must preserve pointer representation");
62 static_assert(sizeof(b_begin) == sizeof(b), "uintptr_t must preserve pointer representation");
63 (void)memcpy((void*)&a_begin, (const void*)&a, sizeof(a_begin));
64 (void)memcpy((void*)&b_begin, (const void*)&b, sizeof(b_begin));
65 *invalid = true;
66 if (a_len > (uint64_t)UINTPTR_MAX) {
67 return false;
68 }
69 if (b_len > (uint64_t)UINTPTR_MAX) {
70 return false;
71 }
72 if (a_begin > (UINTPTR_MAX - (uintptr_t)a_len)) {
73 return false;
74 }
75 if (b_begin > (UINTPTR_MAX - (uintptr_t)b_len)) {
76 return false;
77 }
78 *invalid = false;
79 const uintptr_t a_end = a_begin + (uintptr_t)a_len;
80 const uintptr_t b_end = b_begin + (uintptr_t)b_len;
81 if (a_begin >= b_end) {
82 return false;
83 }
84 return b_begin < a_end;
85}
86
107{
108 if (rd->file_read == nullptr) {
110 }
111 if (rd->inflate_cb == nullptr) {
113 }
114 if (rd->table == nullptr) {
116 }
117 if (rd->staging == nullptr) {
119 }
120 if (rd->chunk_bytes == 0U) {
122 }
123 if (rd->chunk_count == 0U) {
125 }
126 if (rd->inflated_total == 0U) {
128 }
129 if (rd->staging_cap == 0U) {
131 }
132 return k_ra8_ok;
133}
134
159{
160 const uint64_t expected_count =
161 (rd->inflated_total / (uint64_t)rd->chunk_bytes) +
162 (((rd->inflated_total % (uint64_t)rd->chunk_bytes) != 0U) ? 1U : 0U);
163 const uint64_t table_entries = (uint64_t)rd->chunk_count + 1U;
164 if (expected_count > (uint64_t)UINT32_MAX) {
166 }
167 if ((uint64_t)rd->chunk_count != expected_count) {
169 }
170 if (table_entries > (uint64_t)rd->table_cap_entries) {
172 }
173 if (rd->table[0] != 0U) {
175 }
176 for (uint32_t i = 0U; i < rd->chunk_count; ++i) {
177 if (rd->table[i + 1U] <= rd->table[i]) {
179 }
180 if ((rd->table[i + 1U] - rd->table[i]) > (uint64_t)rd->staging_cap) {
182 }
183 }
184 if (rd->table[rd->chunk_count] > (UINT64_MAX - rd->payload_off)) {
186 }
187 return k_ra8_ok;
188}
189
208{
210 if (fields != k_ra8_ok) {
211 return fields;
212 }
214}
215
240 const uint8_t* chunk,
241 uint32_t chunk_cap,
242 const uint8_t* scratch,
243 uint32_t scratch_cap,
244 const book_header_t* out_header)
245{
246 const uint64_t table_len = (uint64_t)rd->table_cap_entries * sizeof(rd->table[0]);
247 const void* bases[k_chunk_validate_span_count] = {rd, chunk, scratch, rd->staging, rd->table};
248 const uint64_t lens[k_chunk_validate_span_count] = {sizeof(*rd),
249 chunk_cap,
250 scratch_cap,
251 rd->staging_cap,
252 table_len};
253 for (uint8_t i = 0U; i < k_chunk_validate_span_count; ++i) {
254 if (bases[i] != nullptr) {
255 if (lens[i] == 0U) {
256 continue;
257 }
258 bool invalid = false;
259 if (internal_spans_overlap(out_header, sizeof(*out_header), bases[i], lens[i], &invalid)) {
260 return true;
261 }
262 if (invalid) {
263 return true;
264 }
265 }
266 }
267 return false;
268}
269
291 const uint8_t* chunk,
292 uint32_t chunk_len,
293 const uint8_t* scratch,
294 uint32_t scratch_cap)
295{
296 const uint64_t table_len = ((uint64_t)rd->chunk_count + 1U) * sizeof(rd->table[0]);
297 const void* bases[k_chunk_validate_span_count] = {rd, chunk, scratch, rd->staging, rd->table};
298 const uint64_t lens[k_chunk_validate_span_count] = {sizeof(*rd),
299 chunk_len,
300 scratch_cap,
301 rd->staging_cap,
302 table_len};
303 for (uint8_t i = 0U; i < k_chunk_validate_span_count; ++i) {
304 for (uint8_t j = (uint8_t)(i + 1U); j < k_chunk_validate_span_count; ++j) {
305 bool invalid = false;
306 if (internal_spans_overlap(bases[i], lens[i], bases[j], lens[j], &invalid)) {
308 }
309 if (invalid) {
311 }
312 }
313 }
314 return k_ra8_ok;
315}
316
335{
336 if (ctx->loaded && (ctx->loaded_idx == idx)) {
337 return k_ra8_ok;
338 }
339 const uint64_t offset = (uint64_t)idx * (uint64_t)ctx->rd->chunk_bytes;
340 uint64_t remain = ctx->rd->inflated_total - offset;
341 uint32_t span = ctx->rd->chunk_bytes;
342 if (remain < (uint64_t)span) {
343 span = (uint32_t)remain;
344 }
345 const ra8_err_t err = book_chunked_read(ctx->rd, offset, ctx->chunk, span);
346 if (err == k_ra8_ok) {
347 ctx->loaded = true;
348 ctx->loaded_idx = idx;
349 ctx->loaded_len = span;
350 }
351 return err;
352}
353
374static ra8_err_t internal_chunk_flat_read(void* opaque, uint64_t offset, uint8_t* dst, uint32_t len)
375{
376 chunk_validate_t* ctx = (chunk_validate_t*)opaque;
377 uint64_t cursor = offset;
378 // mcdc-deactivated: internal_chunk_flat_read range guard; this callback is reachable only from book_validate_stream_strict, whose priv_book_stream_read applies the identical `(off > source_size) || (len > source_size - off)` test against the same rd->inflated_total before invoking it, so neither condition can be true here -- it is a defensive duplicate of an upstream bound.
379 if ((cursor > ctx->rd->inflated_total) || ((uint64_t)len > (ctx->rd->inflated_total - cursor))) {
381 }
382 uint32_t copied = 0U;
383 while (copied < len) {
384 const uint32_t idx = (uint32_t)(cursor / (uint64_t)ctx->rd->chunk_bytes);
385 ra8_err_t err = internal_load_chunk(ctx, idx);
386 if (err != k_ra8_ok) {
387 return err;
388 }
389 const uint32_t in_chunk = (uint32_t)(cursor % (uint64_t)ctx->rd->chunk_bytes);
390 uint32_t span = ctx->loaded_len - in_chunk;
391 if (span > (len - copied)) {
392 span = len - copied;
393 }
394 (void)memmove(&dst[copied], &ctx->chunk[in_chunk], span);
395 copied += span;
396 cursor += span;
397 }
398 return k_ra8_ok;
399}
400
402 uint8_t* chunk,
403 uint32_t chunk_cap,
404 uint8_t* scratch,
405 uint32_t scratch_cap,
406 book_header_t* out_header)
407{
408 if (out_header == nullptr) {
409 return k_ra8_err_null_ptr;
410 }
411 if (rd == nullptr) {
412 *out_header = (book_header_t){};
413 return k_ra8_err_null_ptr;
414 }
415 if (internal_output_is_aliased(rd, chunk, chunk_cap, scratch, scratch_cap, out_header)) {
417 }
418 *out_header = (book_header_t){};
419 if ((chunk == nullptr) || (scratch == nullptr)) {
420 return k_ra8_err_null_ptr;
421 }
422 if ((chunk_cap == 0U) || (scratch_cap == 0U)) {
424 }
426 if (err != k_ra8_ok) {
427 return err;
428 }
429 if (chunk_cap < rd->chunk_bytes) {
431 }
432 err = internal_validate_workspaces(rd, chunk, rd->chunk_bytes, scratch, scratch_cap);
433 if (err != k_ra8_ok) {
434 return err;
435 }
436 chunk_validate_t ctx = {
437 .rd = rd,
438 .chunk = chunk,
439 .loaded_idx = 0U,
440 .loaded_len = 0U,
441 .loaded = false,
442 };
443 book_header_t validated = {};
445 &ctx,
446 rd->inflated_total,
447 scratch,
448 scratch_cap,
449 &validated);
450 if (err == k_ra8_ok) {
451 *out_header = validated;
452 }
453 return err;
454}
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.
static bool internal_spans_overlap(const void *a, uint64_t a_len, const void *b, uint64_t b_len, bool *invalid)
Decide whether two non-empty caller-memory spans overlap.
ra8_err_t book_chunked_validate_strict(book_chunked_t *rd, uint8_t *chunk, uint32_t chunk_cap, uint8_t *scratch, uint32_t scratch_cap, book_header_t *out_header)
Strictly validate the complete flat blob behind an open RBKC reader.
static ra8_err_t internal_validate_workspaces(const book_chunked_t *rd, const uint8_t *chunk, uint32_t chunk_len, const uint8_t *scratch, uint32_t scratch_cap)
Require strict-validation workspaces to be pairwise disjoint.
static ra8_err_t internal_validate_reader_fields(const book_chunked_t *rd)
Require every reader callback and geometry field to be present.
static ra8_err_t internal_validate_reader(const book_chunked_t *rd)
Revalidate the open-reader invariants needed by strict validation.
static ra8_err_t internal_load_chunk(chunk_validate_t *ctx, uint32_t idx)
Inflate one requested chunk into the caller cache when not resident.
chunk_validate_constant_t
Fixed span count used by strict alias validation.
@ k_chunk_validate_span_count
Reader, chunk, scratch, staging, and table.
static ra8_err_t internal_validate_reader_table(const book_chunked_t *rd)
Revalidate the derived chunk count and the offset table's shape.
static ra8_err_t internal_chunk_flat_read(void *opaque, uint64_t offset, uint8_t *dst, uint32_t len)
Serve an exact arbitrary flat-blob read through the one-chunk cache.
static bool internal_output_is_aliased(const book_chunked_t *rd, const uint8_t *chunk, uint32_t chunk_cap, const uint8_t *scratch, uint32_t scratch_cap, const book_header_t *out_header)
Reject output aliases before the output is zeroed or published.
ra8_err_t book_validate_stream_strict(book_stream_read_fn read, void *read_ctx, uint64_t source_size, uint8_t *scratch, uint32_t scratch_cap, book_header_t *out_header)
Strictly validate one callback-backed RABOOK1 flat blob.
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ k_ra8_err_out_of_range
Sensor or peripheral output out of valid range.
Definition ra8_err.h:337
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_invalid_state
Module in wrong state for requested operation.
Definition ra8_err.h:161
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_null_ptr
Pointer was NULL where a valid pointer was required.
Definition ra8_err.h:478
@ 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 * memmove(void *dst, const void *src, size_t n)
Copy memory area between potentially overlapping regions.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
One open chunked .rabook file: parsed geometry + caller storage.
uint64_t inflated_total
Served flat-blob length.
ra8_vsource_read_fn file_read
Container byte reader.
uint8_t * staging
Compressed-byte staging.
book_inflate_fn inflate_cb
zlib decompressor.
const uint64_t * table
Chunk offsets.
uint32_t chunk_count
Chunk count.
uint32_t table_cap_entries
Table entry capacity.
uint32_t chunk_bytes
Inflated bytes per chunk.
uint64_t payload_off
First stream file offset.
uint32_t staging_cap
Staging byte capacity.
Fixed 100-byte prologue describing every table and pool in the blob.
Definition book.h:246
Cached inflated-chunk view used by arbitrary flat-source reads.
uint32_t loaded_idx
Cached chunk index.
bool loaded
Whether the cache contains data.
book_chunked_t * rd
Open compressed reader.
uint8_t * chunk
Caller-owned inflated chunk.
uint32_t loaded_len
Exact cached inflated byte span.