ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_rabook_container.c
Go to the documentation of this file.
1
15
17
18#include <stddef.h>
19#include <stdint.h>
20
21#include "book.h"
22#include "ra8_attributes.h"
23#include "ra8_compress.h"
24
34
36typedef enum : uint8_t {
39
52RA8_INTERNAL static void internal_put_u32(uint8_t* out, uint32_t value)
53{
54 for (uint8_t i = 0U; i < (uint8_t)k_rbkc_u32_bytes; i++) {
55 out[i] = (uint8_t)(value >> ((uint32_t)i * (uint32_t)k_rbkc_bits_per_byte));
56 }
57}
58
71RA8_INTERNAL static void internal_put_u64(uint8_t* out, uint64_t value)
72{
73 for (uint8_t i = 0U; i < (uint8_t)k_rbkc_u64_bytes; i++) {
74 const uint32_t shift = (uint32_t)i * (uint32_t)k_rbkc_bits_per_byte;
75 out[i] = (uint8_t)(value >> shift);
76 }
77}
78
99 void* ctx,
100 uint64_t offset,
101 const uint8_t* src,
102 uint32_t len)
103{
104 uint32_t written = 0U;
105 const ra8_err_t err = write_at(ctx, offset, src, len, &written);
106 if (err != k_ra8_ok) {
107 return err;
108 }
109 return (written == len) ? k_ra8_ok : k_ra8_err_invalid_size;
110}
111
132 ra8_rabook_write_at_fn write_at,
134 const uint64_t* out_len,
135 const uint32_t* out_count)
136{
137 if (read == nullptr) {
138 return k_ra8_err_null_ptr;
139 }
140 if (write_at == nullptr) {
141 return k_ra8_err_null_ptr;
142 }
143 if (ws == nullptr) {
144 return k_ra8_err_null_ptr;
145 }
146 if (out_len == nullptr) {
147 return k_ra8_err_null_ptr;
148 }
149 if (out_count == nullptr) {
150 return k_ra8_err_null_ptr;
151 }
152 if (ws->input == nullptr) {
153 return k_ra8_err_null_ptr;
154 }
155 if (ws->compressed == nullptr) {
156 return k_ra8_err_null_ptr;
157 }
158 if (ws->compressor == nullptr) {
159 return k_ra8_err_null_ptr;
160 }
161 if (ws->offsets == nullptr) {
162 return k_ra8_err_null_ptr;
163 }
164 return k_ra8_ok;
165}
166
191 uint32_t flat_len,
192 uint32_t chunk_bytes,
193 ra8_rabook_write_at_fn write_at,
195 const uint64_t* out_len,
196 uint32_t* out_count)
197{
198 const ra8_err_t ptr_err = internal_validate_pointers(read, write_at, ws, out_len, out_count);
199 if (ptr_err != k_ra8_ok) {
200 return ptr_err;
201 }
202 if (flat_len == 0U) {
204 }
205 if (chunk_bytes == 0U) {
207 }
208 if (chunk_bytes > ws->input_cap) {
210 }
211 if (ws->compressor_cap < (uint32_t)k_ra8_compress_scratch_bytes) {
213 }
214 const uint32_t count = ((flat_len - 1U) / chunk_bytes) + 1U;
215 if (count == UINT32_MAX) {
217 }
218 if (ws->offset_cap < (count + 1U)) {
220 }
221 *out_count = count;
222 return k_ra8_ok;
223}
224
246 void* ctx,
247 uint32_t flat_len,
248 uint32_t chunk_bytes,
249 uint32_t count)
250{
251 static const uint8_t rbkc_magic[k_book_container_magic_len] = {'R', 'B', 'K', 'C'};
252 uint8_t header[k_book_container_header_len] = {};
253 for (uint8_t i = 0U; i < (uint8_t)k_book_container_magic_len; i++) {
254 header[i] = rbkc_magic[i];
255 }
256 internal_put_u32(&header[k_rbkc_chunk_bytes_off], chunk_bytes);
257 internal_put_u64(&header[k_rbkc_total_off], (uint64_t)flat_len);
258 internal_put_u32(&header[k_rbkc_count_off], count);
260 ra8_err_t err = internal_write_exact(write_at, ctx, 0U, header, (uint32_t)sizeof(header));
261 if (err != k_ra8_ok) {
262 return err;
263 }
264 const uint8_t zero[k_book_container_entry_len] = {};
265 for (uint32_t i = 0U; i <= count; i++) {
266 const uint64_t at =
267 (uint64_t)k_book_container_header_len + ((uint64_t)i * (uint64_t)k_book_container_entry_len);
268 err = internal_write_exact(write_at, ctx, at, zero, (uint32_t)sizeof(zero));
269 if (err != k_ra8_ok) {
270 return err;
271 }
272 }
273 return k_ra8_ok;
274}
275
300 void* read_ctx,
301 uint32_t flat_len,
302 uint32_t chunk_bytes,
303 ra8_rabook_write_at_fn write_at,
304 void* write_ctx,
306 uint32_t count,
307 uint64_t payload_off)
308{
309 uint32_t flat_off = 0U;
310 uint64_t payload_len = 0U;
311 for (uint32_t i = 0U; i < count; i++) {
312 const uint32_t remaining = flat_len - flat_off;
313 const uint32_t want = (remaining < chunk_bytes) ? remaining : chunk_bytes;
314 uint32_t got = 0U;
315 ra8_err_t err = read(read_ctx, flat_off, ws->input, want, &got);
316 if (err != k_ra8_ok) {
317 return err;
318 }
319 if (got != want) {
321 }
322 uint32_t packed = 0U;
323 err = ra8_compress_zlib(ws->input,
324 want,
325 ws->compressed,
326 ws->compressed_cap,
327 ws->compressor,
328 ws->compressor_cap,
329 &packed);
330 if (err != k_ra8_ok) {
331 return err;
332 }
333 if ((uint64_t)packed > (UINT64_MAX - payload_len)) {
335 }
336 if (payload_len > (UINT64_MAX - payload_off)) {
338 }
339 ws->offsets[i] = payload_len;
340 err =
341 internal_write_exact(write_at, write_ctx, payload_off + payload_len, ws->compressed, packed);
342 if (err != k_ra8_ok) {
343 return err;
344 }
345 payload_len += packed;
346 flat_off += want;
347 }
348 ws->offsets[count] = payload_len;
349 return k_ra8_ok;
350}
351
371 void* ctx,
373 uint32_t count)
374{
375 uint8_t encoded[k_book_container_entry_len];
376 for (uint32_t i = 0U; i <= count; i++) {
377 internal_put_u64(encoded, ws->offsets[i]);
378 const uint64_t at =
379 (uint64_t)k_book_container_header_len + ((uint64_t)i * (uint64_t)k_book_container_entry_len);
380 const ra8_err_t err =
381 internal_write_exact(write_at, ctx, at, encoded, (uint32_t)sizeof(encoded));
382 if (err != k_ra8_ok) {
383 return err;
384 }
385 }
386 return k_ra8_ok;
387}
388
390 void* read_ctx,
391 uint32_t flat_len,
392 uint32_t chunk_bytes,
393 ra8_rabook_write_at_fn write_at,
394 void* write_ctx,
396 uint64_t* out_len)
397{
398 if (out_len != nullptr) {
399 *out_len = 0U;
400 }
401 uint32_t count = 0U;
402 const ra8_err_t valid =
403 internal_validate(read, flat_len, chunk_bytes, write_at, ws, out_len, &count);
404 if (valid != k_ra8_ok) {
405 return valid;
406 }
407 const uint64_t table_bytes = ((uint64_t)count + 1U) * (uint64_t)k_book_container_entry_len;
408 const uint64_t payload_off = (uint64_t)k_book_container_header_len + table_bytes;
409 ra8_err_t err = internal_write_prefix(write_at, write_ctx, flat_len, chunk_bytes, count);
410 if (err == k_ra8_ok) {
411 err = internal_write_chunks(read,
412 read_ctx,
413 flat_len,
414 chunk_bytes,
415 write_at,
416 write_ctx,
417 ws,
418 count,
419 payload_off);
420 }
421 if (err == k_ra8_ok) {
422 err = internal_write_table(write_at, write_ctx, ws, count);
423 }
424 if (err == k_ra8_ok) {
425 if (ws->offsets[count] > (UINT64_MAX - payload_off)) {
427 }
428 *out_len = payload_off + ws->offsets[count];
429 }
430 return err;
431}
Flat, execute-in-place container for a build-time "compiled" e-book.
@ k_book_container_header_len
Fixed header bytes ahead of the chunk table.
Definition book.h:115
@ k_book_container_entry_len
One chunk-table entry (uint64 LE offset).
Definition book.h:116
@ k_book_container_magic_len
Length of the "RBKC" magic.
Definition book.h:114
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
App-domain DEFLATE compress / decompress (zero-heap, firmware-safe).
ra8_err_t ra8_compress_zlib(const uint8_t *src, uint32_t src_len, uint8_t *out, uint32_t out_cap, void *scratch, uint32_t scratch_len, uint32_t *out_len)
Zlib-wrap and DEFLATE-compress one bounded byte range.
@ k_ra8_compress_scratch_bytes
Minimum compress scratch size (one miniz tdefl_compressor).
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ 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
static ra8_err_t internal_validate(ra8_rabook_flat_read_fn read, uint32_t flat_len, uint32_t chunk_bytes, ra8_rabook_write_at_fn write_at, const ra8_rabook_container_workspace_t *ws, const uint64_t *out_len, uint32_t *out_count)
Validate pointers and workspace capacities before output mutation.
rbkc_bits_t
Number of bits shifted per little-endian output byte.
@ k_rbkc_bits_per_byte
Binary bits represented by one output byte.
static ra8_err_t internal_write_prefix(ra8_rabook_write_at_fn write_at, void *ctx, uint32_t flat_len, uint32_t chunk_bytes, uint32_t count)
Write the fixed header and reserve a zero-filled offset table.
static ra8_err_t internal_validate_pointers(ra8_rabook_flat_read_fn read, ra8_rabook_write_at_fn write_at, const ra8_rabook_container_workspace_t *ws, const uint64_t *out_len, const uint32_t *out_count)
Reject a missing callback, result, workspace, or workspace member.
static ra8_err_t internal_write_exact(ra8_rabook_write_at_fn write_at, void *ctx, uint64_t offset, const uint8_t *src, uint32_t len)
Call the destination once and require an exact successful write.
static void internal_put_u64(uint8_t *out, uint64_t value)
Encode one uint64 in little-endian order.
static void internal_put_u32(uint8_t *out, uint32_t value)
Encode one uint32 in little-endian order.
ra8_err_t ra8_rabook_container_write(ra8_rabook_flat_read_fn read, void *read_ctx, uint32_t flat_len, uint32_t chunk_bytes, ra8_rabook_write_at_fn write_at, void *write_ctx, ra8_rabook_container_workspace_t *ws, uint64_t *out_len)
Stream one flat RABOOK1 blob into a chunked RBKC staging object.
static ra8_err_t internal_write_chunks(ra8_rabook_flat_read_fn read, void *read_ctx, uint32_t flat_len, uint32_t chunk_bytes, ra8_rabook_write_at_fn write_at, void *write_ctx, ra8_rabook_container_workspace_t *ws, uint32_t count, uint64_t payload_off)
Read, compress, and append every independent chunk payload.
static ra8_err_t internal_write_table(ra8_rabook_write_at_fn write_at, void *ctx, const ra8_rabook_container_workspace_t *ws, uint32_t count)
Back-fill the little-endian table after all payload streams exist.
rbkc_layout_t
RBKC fixed-field sizes and offsets.
@ k_rbkc_chunk_bytes_off
uint32 chunk size.
@ k_rbkc_count_off
uint32 chunk count.
@ k_rbkc_total_off
uint64 inflated total.
@ k_rbkc_u32_bytes
Little-endian uint32.
@ k_rbkc_u64_bytes
Little-endian uint64.
@ k_rbkc_reserved_off
uint32 reserved zero.
Zero-heap streaming writer for the chunked RBKC .rabook container.
ra8_err_t(* ra8_rabook_write_at_fn)(void *ctx, uint64_t offset, const uint8_t *src, uint32_t requested, uint32_t *out_written)
Write a bounded range at an absolute staging-destination offset.
ra8_err_t(* ra8_rabook_flat_read_fn)(void *ctx, uint32_t offset, uint8_t *dst, uint32_t requested, uint32_t *out_read)
Read a bounded range from the flat RABOOK1 source.
Caller-owned transient storage for one RBKC write.
uint32_t compressor_cap
Writable bytes at compressor.
uint8_t * compressed
One complete zlib stream.
uint64_t * offsets
Payload-relative offset table.
uint32_t offset_cap
Number of uint64 entries at offsets.
uint32_t input_cap
Writable bytes at input.
uint32_t compressed_cap
Writable bytes at compressed.
uint8_t * input
One uncompressed flat chunk.
void * compressor
tdefl_compressor storage, 8-byte aligned.