|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
Bounded XZ/LZMA2 decode wrapper over the vendored xz-embedded. More...
#include "unarch_xz.h"#include "ra8_attributes.h"#include "ra8_check.h"#include "unarch_xz_pool.h"#include "xz_config.h"Go to the source code of this file.
Data Structures | |
| struct | xz_unwrap_state_t |
| Loop-carried state of one unwrap: cursors, session, and budget. More... | |
Enumerations | |
| enum | xz_wrap_dims_t : uint16_t { k_xz_chunk = 512U , k_xz_out_window = 4096U } |
| Fixed sizes for the unwrap input loop. More... | |
| enum | xz_magic_t : uint8_t { k_xz_magic_b0 = 0xFDU , k_xz_magic_b1 = 0x37U , k_xz_magic_b2 = 0x7AU , k_xz_magic_b3 = 0x58U , k_xz_magic_b4 = 0x5AU , k_xz_magic_b5 = 0x00U } |
| The six XZ stream header magic bytes (FD 37 7A 58 5A 00). More... | |
Functions | |
| bool | unarch_xz_magic (const uint8_t *sig, size_t sig_len) |
Whether sig begins with the XZ stream header magic. | |
| ra8_err_t | unarch_xz_stream_begin (unarch_xz_stream_t *xs, void *scratch, uint32_t scratch_len) |
| Begin a multi-call XZ decode session over a caller scratch. | |
| static ra8_err_t | internal_xz_map_err (enum xz_ret ret) |
| Map an xz-embedded return code onto the wrapper's error space. | |
| ra8_err_t | unarch_xz_stream_run (unarch_xz_stream_t *xs, const uint8_t *in, size_t in_len, size_t *in_used, uint8_t *out, size_t out_cap, size_t *out_used, bool *end) |
| Feed one input chunk through a live session, producing output. | |
| void | unarch_xz_stream_end (unarch_xz_stream_t *xs) |
| End a session: free the decoder and release the allocation pool. | |
| static ra8_err_t | internal_unwrap_reject_null (unarch_read_fn read, const uint8_t *out, const void *scratch, const size_t *out_len) |
| Reject any NULL required argument to unarch_xz_unwrap. | |
| static ra8_err_t | internal_unwrap_pass (xz_unwrap_state_t *st, bool *end) |
| Run one refill + decode pass of the unwrap loop. | |
| ra8_err_t | unarch_xz_unwrap (unarch_read_fn read, void *ctx, uint64_t size, uint8_t *out, size_t out_cap, void *scratch, uint32_t scratch_len, const ra8_decomp_limits_t *limits, size_t *out_len) |
| Decode one whole XZ stream from a read seam into a caller arena. | |
Variables | |
| static const char *const | s_tag_xz = "unarch_xz" |
| Log tag for XZ-wrapper diagnostics. | |
Bounded XZ/LZMA2 decode wrapper over the vendored xz-embedded.
See unarch_xz.h for the contract. The session shape drives the SOUP decoder in XZ_PREALLOC mode: begin installs the caller scratch as the zero-heap allocation arena (unarch_xz_pool.h), reserves k_unarch_xz_state_reserve of it for the decoder state, and hands the remainder to xz-embedded as the maximum LZMA2 dictionary – everything is allocated once at init and a stream declaring a bigger dictionary fails with XZ_MEMLIMIT_ERROR (mapped to k_ra8_err_no_mem) instead of growing. The unwrap shape loops a session over the shared read seam in fixed k_xz_chunk input windows, charging the unified decompression budget every pass so a bomb or stuck stream terminates within policy.
Every decision in this file is a single condition on purpose: the wrapper fronts the most hostile input in the content path, so each bound is tested independently (and carries no compound-decision MC/DC burden).
Definition in file unarch_xz.c.
| enum xz_magic_t : uint8_t |
The six XZ stream header magic bytes (FD 37 7A 58 5A 00).
Values from the .xz file format specification section 2.1.1.1; named per the no-magic-numbers rule.
| Enumerator | |
|---|---|
| k_xz_magic_b0 | Non-ASCII lead-in byte. |
| k_xz_magic_b1 | '7'. |
| k_xz_magic_b2 | 'z'. |
| k_xz_magic_b3 | 'X'. |
| k_xz_magic_b4 | 'Z'. |
| k_xz_magic_b5 | NUL terminator of the magic. |
Definition at line 68 of file unarch_xz.c.
| enum xz_wrap_dims_t : uint16_t |
Fixed sizes for the unwrap input loop.
One k_xz_chunk stack window is refilled from the read seam per decode pass; small enough for the firmware stack budget, large enough that a policy-conformant stream finishes far inside the default iteration budget.
Definition at line 54 of file unarch_xz.c.
|
static |
Run one refill + decode pass of the unwrap loop.
Charges one iteration, refills the input window from the read seam at the current cursor, runs the session, advances both cursors, and charges the produced output against the budget. A zero-byte refill before the stream ended is a truncated backing (fail-closed); a full arena with the stream still open is an undersized arena.
| [in,out] | st | Unwrap state (live session, cursors in range). |
| [out] | end | Receives true when the stream verified and ended. |
| k_ra8_ok | Pass complete; check end. |
| k_ra8_err_no_mem | Arena full with the stream open, or the dictionary over budget. |
| k_ra8_err_validation_failed | Truncated / corrupt / stuck stream. |
| k_ra8_err_not_supported | Unsupported format/check/filter. |
| k_ra8_err_decomp_* | A policy bound was breached. |
Definition at line 307 of file unarch_xz.c.
References xz_unwrap_state_t::budget, xz_unwrap_state_t::chunk, xz_unwrap_state_t::ctx, xz_unwrap_state_t::in_off, k_ra8_err_no_mem, k_ra8_err_validation_failed, k_ra8_ok, k_xz_chunk, k_xz_out_window, xz_unwrap_state_t::out, xz_unwrap_state_t::out_cap, ra8_decomp_budget_charge_iter(), ra8_decomp_budget_charge_output(), xz_unwrap_state_t::read, xz_unwrap_state_t::size, xz_unwrap_state_t::total_out, unarch_xz_stream_run(), and xz_unwrap_state_t::xs.
Referenced by unarch_xz_unwrap().
|
static |
Reject any NULL required argument to unarch_xz_unwrap.
Runs the mandatory null guards so the entry point stays within the function-size budget; scalar validation stays inline there.
| [in] | read | Byte reader over the stream. |
| [in] | out | Destination arena. |
| [in] | scratch | Session scratch. |
| [in] | out_len | Decoded-length out-pointer. |
| k_ra8_ok | Every required argument is non-NULL. |
| k_ra8_err_null_ptr | Some required argument was NULL. |
Definition at line 245 of file unarch_xz.c.
References k_ra8_err_null_ptr, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_log_error, and s_tag_xz.
Referenced by unarch_xz_unwrap().
|
static |
Map an xz-embedded return code onto the wrapper's error space.
The success codes (XZ_OK, XZ_STREAM_END) are handled by the caller before this runs; every remaining code is a bounded failure. XZ_MEMLIMIT_ERROR is the declared-dictionary breach; XZ_FORMAT_ERROR / XZ_OPTIONS_ERROR are non-XZ or unsupported-feature streams; XZ_DATA_ERROR / XZ_BUF_ERROR are corruption, truncation, or a stuck stream. XZ_MEM_ERROR and XZ_UNSUPPORTED_CHECK cannot occur in this build (XZ_PREALLOC allocates only at init; XZ_DEC_ANY_CHECK is off) and fall to the defensive default.
| [in] | ret | xz-embedded return code (a failure code). |
ret. | k_ra8_err_no_mem | Dictionary over the scratch budget. |
| k_ra8_err_not_supported | Not XZ / unsupported check or filter. |
| k_ra8_err_validation_failed | Corrupt, truncated, or stuck stream. |
ret is not XZ_OK / XZ_STREAM_END (caller-handled). Definition at line 146 of file unarch_xz.c.
References k_ra8_err_no_mem, k_ra8_err_not_supported, and k_ra8_err_validation_failed.
Referenced by unarch_xz_stream_run().
|
nodiscard |
Whether sig begins with the XZ stream header magic.
Pure signature probe over the six magic bytes (FD 37 7A 58 5A 00) so open paths can route a wrapped archive without constructing a decoder.
| [in] | sig | Leading archive bytes (may be NULL). |
| [in] | sig_len | Readable length of sig in bytes. |
| true | The six magic bytes match. |
| false | sig is NULL, too short, or not XZ. |
sig holds sig_len readable bytes when non-NULL. sig_len is the true readable length (untrusted values are safe). Definition at line 77 of file unarch_xz.c.
References k_unarch_xz_sig_len, k_xz_magic_b0, k_xz_magic_b1, k_xz_magic_b2, k_xz_magic_b3, k_xz_magic_b4, k_xz_magic_b5, and memeq.
Referenced by comic_open_wrapped(), and internal_open_unwrapped().
|
nodiscard |
Begin a multi-call XZ decode session over a caller scratch.
Installs scratch as the XZ allocation arena and creates an XZ_PREALLOC decoder whose dictionary budget is scratch_len - k_unarch_xz_state_reserve: the dictionary is allocated once at init and never grows, and a stream declaring a larger dictionary is rejected during _run (no growth, no fallback).
| [out] | xs | Session to bind (non-NULL). |
| [in] | scratch | Scratch buffer (non-NULL, 8-byte aligned). |
| [in] | scratch_len | Scratch length, > k_unarch_xz_state_reserve. |
| k_ra8_ok | Session live; feed it via _run. |
| k_ra8_err_null_ptr | xs or scratch was NULL. |
| k_ra8_err_invalid_size | Scratch too small or misaligned. |
| k_ra8_err_busy | Another XZ session is in flight. |
| k_ra8_err_no_mem | Decoder-state allocation failed. |
scratch out-lives the session. xs is dead.Definition at line 96 of file unarch_xz.c.
References unarch_xz_stream_t::dec, k_ra8_err_invalid_size, k_ra8_err_no_mem, k_ra8_ok, k_unarch_xz_state_reserve, unarch_xz_stream_t::live, RA8_CHECK_NULL_PTR, s_tag_xz, unarch_xz_pool_install(), and unarch_xz_pool_reset().
Referenced by unarch_xz_unwrap().
| void unarch_xz_stream_end | ( | unarch_xz_stream_t * | xs | ) |
End a session: free the decoder and release the allocation pool.
Safe on a NULL or never-begun session (teardown paths call it unconditionally). After this the caller's scratch is dead storage again and a new session may begin.
| [in,out] | xs | Session to end (may be NULL). |
xs, when live, owns the installed pool. xs. Definition at line 212 of file unarch_xz.c.
References unarch_xz_stream_t::dec, unarch_xz_stream_t::live, and unarch_xz_pool_reset().
Referenced by unarch_xz_unwrap().
|
nodiscard |
Feed one input chunk through a live session, producing output.
One xz_dec_run pass: consumes up to in_len input bytes and writes up to out_cap output bytes, reporting both counts and whether the stream ended. The caller loops – charging its own ra8_decomp_budget_t per pass – until *end or an error. Returning with zero consumed and zero produced is legal decoder behaviour on tiny buffers; the caller's iteration budget bounds the loop regardless (the decoder itself also reports a stuck stream as a validation failure).
| [in,out] | xs | Live session (non-NULL). |
| [in] | in | Input chunk (non-NULL when in_len > 0). |
| [in] | in_len | Input bytes available. |
| [out] | in_used | Receives input bytes consumed (non-NULL). |
| [out] | out | Output chunk buffer (non-NULL). |
| [in] | out_cap | Output capacity in bytes. |
| [out] | out_used | Receives output bytes produced (non-NULL). |
| [out] | end | Receives true when the stream verified and ended (non-NULL). |
| k_ra8_ok | Pass completed; inspect the counts. |
| k_ra8_err_null_ptr | A required pointer was NULL. |
| k_ra8_err_invalid_state | xs is not live. |
| k_ra8_err_no_mem | Declared dictionary exceeds the session's scratch budget. |
| k_ra8_err_not_supported | Unsupported format/check/filter. |
| k_ra8_err_validation_failed | Corrupt / truncated stream, a failed integrity check, or a stuck stream. |
xs. out holds out_cap writable bytes. Definition at line 168 of file unarch_xz.c.
References unarch_xz_stream_t::dec, internal_xz_map_err(), k_ra8_err_invalid_state, k_ra8_ok, unarch_xz_stream_t::live, RA8_CHECK_NULL_PTR, and s_tag_xz.
Referenced by internal_unwrap_pass().
|
nodiscard |
Decode one whole XZ stream from a read seam into a caller arena.
Runs a full streaming session over [0, size) of the backing: input is fetched in small fixed chunks, each decode pass is charged against limits (iteration budget, output cap, ratio bound), and the stream's integrity check is verified before success. Fail-closed on everything else: truncation, corruption, an unsupported check/filter, a dictionary larger than the scratch budget, output overrun, and trailing bytes after the stream footer.
| [in] | read | Byte reader over the XZ stream (non-NULL). |
| [in] | ctx | Context passed to read. |
| [in] | size | Stream length in bytes (> 0). |
| [out] | out | Destination arena (non-NULL, out_cap bytes). |
| [in] | out_cap | Capacity of out in bytes (> 0). |
| [in] | scratch | Session scratch (non-NULL, 8-byte aligned, > k_unarch_xz_state_reserve bytes). |
| [in] | scratch_len | Scratch length in bytes. |
| [in] | limits | Policy to enforce, or NULL for the default. |
| [out] | out_len | Receives the decoded byte count (non-NULL). |
| k_ra8_ok | Stream decoded and verified. |
| k_ra8_err_null_ptr | A required pointer was NULL. |
| k_ra8_err_invalid_size | size / out_cap is 0, or the scratch is undersized / misaligned. |
| k_ra8_err_invalid_arg | limits has a zero field. |
| k_ra8_err_busy | Another XZ session is in flight. |
| k_ra8_err_no_mem | Decoder-state allocation failed, the declared dictionary exceeds the scratch budget, or out is too small for the stream. |
| k_ra8_err_not_supported | Not an XZ stream, or one using an unsupported check/filter. |
| k_ra8_err_validation_failed | Corrupt / truncated / trailing-byte stream or a failed integrity check. |
| k_ra8_err_decomp_output_cap | Output exceeds the policy cap. |
| k_ra8_err_decomp_ratio | Output breached the ratio bound. |
| k_ra8_err_decomp_iterations | The decode loop budget ran out. |
read serves offsets [0, size) of the stream. Definition at line 351 of file unarch_xz.c.
References xz_unwrap_state_t::budget, xz_unwrap_state_t::ctx, xz_unwrap_state_t::in_off, internal_unwrap_pass(), internal_unwrap_reject_null(), k_ra8_err_invalid_size, k_ra8_err_validation_failed, k_ra8_ok, xz_unwrap_state_t::out, xz_unwrap_state_t::out_cap, ra8_decomp_budget_init(), xz_unwrap_state_t::read, xz_unwrap_state_t::size, xz_unwrap_state_t::total_out, unarch_xz_stream_begin(), unarch_xz_stream_end(), and xz_unwrap_state_t::xs.
Referenced by internal_unwrap().
|
static |
Log tag for XZ-wrapper diagnostics.
Definition at line 37 of file unarch_xz.c.
Referenced by internal_unwrap_reject_null(), unarch_xz_stream_begin(), and unarch_xz_stream_run().