ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
sweep_block_backends.c
Go to the documentation of this file.
1
17#include <string.h>
18#include <time.h>
19
20#include "book_chunked.h"
21#include "miniz.h"
22#include "ra8_err.h"
24
25typedef enum : uint32_t {
29
30static_assert(sizeof(tdefl_compressor) <= (size_t)k_cbs_cache_bytes,
31 "tdefl overlay must fit the semantic cache backing");
32static_assert(alignof(max_align_t) >= alignof(tdefl_compressor),
33 "composition cache alignment must satisfy tdefl");
34
35typedef struct {
37 uint64_t offset;
38 bool failed;
40
41typedef struct {
43 tinfl_decompressor* inflater;
44 uint8_t* input;
45 uint32_t input_capacity;
46 uint32_t chunk_bytes;
47 uint32_t chunk_count;
48 uint64_t total_bytes;
49 uint64_t payload_offset;
50 uint64_t source_bytes;
52
54uint64_t priv_now_ns(void)
55{
56 struct timespec ts = {};
57 (void)clock_gettime(CLOCK_MONOTONIC, &ts);
58 return ((uint64_t)ts.tv_sec * (uint64_t)k_cbs_ns_per_s) + (uint64_t)ts.tv_nsec;
59}
60
62ra8_err_t priv_meter_read(void* ctx, uint64_t offset, uint8_t* buffer, uint32_t length)
63{
64 cbs_meter_t* meter = (cbs_meter_t*)ctx;
65 if ((meter == nullptr) || (meter->inner == nullptr)) {
66 return k_ra8_err_null_ptr;
67 }
68 meter->calls++;
69 meter->bytes += length;
70 return meter->inner(meter->inner_ctx, offset, buffer, length);
71}
72
95 ra8_vsource_read_fn payload_read,
96 void* payload_ctx,
97 uint32_t blob_bytes,
98 uint32_t block_bytes,
99 cb_sweep_config_t* config)
100{
101 (void)block_bytes;
102 (void)config;
103 if ((be == nullptr) || (payload_read == nullptr) || (payload_ctx == nullptr) ||
104 (blob_bytes == 0U)) {
105 return 1;
106 }
107 be->read = payload_read;
108 be->read_ctx = payload_ctx;
109 be->backing_bytes = blob_bytes;
110 be->src_bytes = nullptr;
111 return 0;
112}
113
128{
129 if (be != nullptr) {
130 be->read = nullptr;
131 be->read_ctx = nullptr;
132 be->src_bytes = nullptr;
133 }
134}
135
152static void
153internal_rbkc_header(uint8_t* output, uint32_t block_bytes, uint64_t total, uint32_t count)
154{
155 size_t position = 0U;
156 memcpy(&output[position], "RBKC", sizeof("RBKC") - 1U);
157 position += sizeof("RBKC") - 1U;
158 memcpy(&output[position], &block_bytes, sizeof(block_bytes));
159 position += sizeof(block_bytes);
160 memcpy(&output[position], &total, sizeof(total));
161 position += sizeof(total);
162 memcpy(&output[position], &count, sizeof(count));
163 position += sizeof(count);
164 const uint32_t reserved = 0U;
165 memcpy(&output[position], &reserved, sizeof(reserved));
166}
167
186static mz_bool internal_pack_write(const void* data, int length, void* user)
187{
188 cbs_pack_sink_t* sink = (cbs_pack_sink_t*)user;
189 if ((sink == nullptr) || (data == nullptr) || (length < 0) || sink->failed) {
190 return MZ_FALSE;
191 }
192 const cb_io_status_t status =
193 sink->scratch->write(sink->scratch->ctx, sink->offset, (void*)data, (size_t)length);
194 if (status != k_cb_io_ok) {
195 sink->failed = true;
196 return MZ_FALSE;
197 }
198 sink->offset += (uint64_t)length;
199 return MZ_TRUE;
200}
201
225static int internal_rbkc_pack_chunk(tdefl_compressor* compressor,
226 cbs_pack_sink_t* sink,
227 ra8_vsource_read_fn payload_read,
228 void* payload_ctx,
229 uint8_t* input,
230 uint32_t input_capacity,
231 uint32_t offset,
232 uint32_t length)
233{
234 const mz_uint flags = tdefl_create_comp_flags_from_zip_params(MZ_BEST_COMPRESSION,
236 MZ_DEFAULT_STRATEGY);
237 if (tdefl_init(compressor, internal_pack_write, sink, (int)flags) != TDEFL_STATUS_OKAY) {
238 return 1;
239 }
240 uint32_t complete = 0U;
241 while (complete < length) {
242 uint32_t span = length - complete;
243 if (span > input_capacity) {
244 span = input_capacity;
245 }
246 if (payload_read(payload_ctx, (uint64_t)offset + complete, input, span) != k_ra8_ok ||
247 tdefl_compress_buffer(compressor, input, span, TDEFL_NO_FLUSH) < TDEFL_STATUS_OKAY) {
248 return 1;
249 }
250 complete += span;
251 }
252 const tdefl_status status = tdefl_compress_buffer(compressor, nullptr, 0U, TDEFL_FINISH);
253 return ((status == TDEFL_STATUS_DONE) && !sink->failed) ? 0 : 1;
254}
255
280 void* payload_ctx,
281 uint32_t blob_bytes,
282 uint32_t block_bytes,
283 cb_sweep_config_t* config,
284 uint8_t* input,
285 uint32_t input_capacity,
286 uint64_t* output_length)
287{
288 if ((sizeof(tdefl_compressor) > config->cache_capacity) ||
289 (((uintptr_t)config->cache_backing % alignof(tdefl_compressor)) != 0U)) {
290 config->workspace_required = sizeof(tdefl_compressor);
291 return 1;
292 }
293 const uint32_t count = (blob_bytes + block_bytes - 1U) / block_bytes;
294 const uint64_t table_bytes = ((uint64_t)count + 1U) * k_book_container_entry_len;
295 const uint64_t payload_offset = (uint64_t)k_book_container_header_len + table_bytes;
296 uint8_t header[k_book_container_header_len] = {};
297 internal_rbkc_header(header, block_bytes, blob_bytes, count);
298 if (config->scratch->write(config->scratch->ctx, 0U, header, sizeof(header)) != k_cb_io_ok) {
299 return 1;
300 }
301 uint64_t relative = 0U;
302 if (config->scratch->write(config->scratch->ctx,
304 &relative,
305 sizeof(relative)) != k_cb_io_ok) {
306 return 1;
307 }
308 tdefl_compressor* compressor = (tdefl_compressor*)config->cache_backing;
309 cbs_pack_sink_t sink = {.scratch = config->scratch, .offset = payload_offset};
310 for (uint32_t chunk = 0U; chunk < count; ++chunk) {
311 const uint32_t offset = chunk * block_bytes;
312 uint32_t length = blob_bytes - offset;
313 if (length > block_bytes) {
314 length = block_bytes;
315 }
316 if (internal_rbkc_pack_chunk(compressor,
317 &sink,
318 payload_read,
319 payload_ctx,
320 input,
321 input_capacity,
322 offset,
323 length) != 0) {
324 return 1;
325 }
326 relative = sink.offset - payload_offset;
327 const uint64_t table_offset =
328 (uint64_t)k_book_container_header_len + (((uint64_t)chunk + 1U) * k_book_container_entry_len);
329 if (config->scratch->write(config->scratch->ctx, table_offset, &relative, sizeof(relative)) !=
330 k_cb_io_ok) {
331 return 1;
332 }
333 }
334 *output_length = sink.offset;
335 config->scratch->size = sink.offset;
336 memset(config->cache_backing, 0, config->cache_capacity);
337 return 0;
338}
339
359static ra8_err_t
360internal_rbkc_offsets(cbs_rbkc_t* rb, uint32_t chunk, uint64_t* begin, uint64_t* end)
361{
362 const uint64_t table_offset =
363 (uint64_t)k_book_container_header_len + ((uint64_t)chunk * k_book_container_entry_len);
364 if ((rb->scratch->read(rb->scratch->ctx, table_offset, begin, sizeof(*begin)) != k_cb_io_ok) ||
365 (rb->scratch->read(rb->scratch->ctx,
366 table_offset + k_book_container_entry_len,
367 end,
368 sizeof(*end)) != k_cb_io_ok) ||
369 (*end < *begin) || ((rb->payload_offset + *end) > rb->scratch->size)) {
371 }
372 return k_ra8_ok;
373}
374
396 uint64_t begin,
397 uint64_t end,
398 uint8_t* output,
399 uint32_t output_length)
400{
401 tinfl_init(rb->inflater);
402 uint64_t source = begin;
403 uint32_t produced = 0U;
404 tinfl_status status = TINFL_STATUS_NEEDS_MORE_INPUT;
405 while (status != TINFL_STATUS_DONE) {
406 uint32_t input_length = (uint32_t)(end - source);
407 if (input_length > rb->input_capacity) {
408 input_length = rb->input_capacity;
409 }
410 if ((input_length == 0U) || (rb->scratch->read(rb->scratch->ctx,
411 rb->payload_offset + source,
412 rb->input,
413 input_length) != k_cb_io_ok)) {
415 }
416 rb->source_bytes += input_length;
417 size_t consumed = input_length;
418 size_t available = output_length - produced;
419 const mz_uint32 flags =
420 (mz_uint32)(TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF |
421 (((source + input_length) < end) ? TINFL_FLAG_HAS_MORE_INPUT : 0U));
422 status = tinfl_decompress(rb->inflater,
423 rb->input,
424 &consumed,
425 output,
426 &output[produced],
427 &available,
428 flags);
429 source += consumed;
430 produced += (uint32_t)available;
431 if ((status < TINFL_STATUS_DONE) || (consumed == 0U)) {
433 }
434 }
435 return ((source == end) && (produced == output_length)) ? k_ra8_ok : k_ra8_err_invalid_size;
436}
437
459static ra8_err_t internal_rbkc_read(void* ctx, uint64_t offset, uint8_t* buffer, uint32_t length)
460{
461 cbs_rbkc_t* rb = (cbs_rbkc_t*)ctx;
462 if ((rb == nullptr) || (buffer == nullptr)) {
463 return k_ra8_err_null_ptr;
464 }
465 if ((offset >= rb->total_bytes) || ((offset % rb->chunk_bytes) != 0U)) {
467 }
468 const uint32_t chunk = (uint32_t)(offset / rb->chunk_bytes);
469 uint32_t expected = (uint32_t)(rb->total_bytes - offset);
470 if (expected > rb->chunk_bytes) {
471 expected = rb->chunk_bytes;
472 }
473 if ((chunk >= rb->chunk_count) || (length != expected)) {
475 }
476 uint64_t begin = 0U;
477 uint64_t end = 0U;
478 const ra8_err_t status = internal_rbkc_offsets(rb, chunk, &begin, &end);
479 return (status == k_ra8_ok) ? internal_rbkc_inflate(rb, begin, end, buffer, length) : status;
480}
481
499static void* internal_setup_take(cb_sweep_config_t* config, size_t bytes)
500{
501 const size_t alignment = alignof(max_align_t);
502 const size_t span = (bytes + alignment - 1U) & ~(alignment - 1U);
503 if ((config->workspace_used > config->workspace_capacity) ||
504 (span > (config->workspace_capacity - config->workspace_used))) {
505 config->workspace_required = config->workspace_used + span;
506 return nullptr;
507 }
508 void* result = &config->workspace[config->workspace_used];
509 config->workspace_used += span;
510 config->workspace_required = config->workspace_used;
511 return result;
512}
513
536 ra8_vsource_read_fn payload_read,
537 void* payload_ctx,
538 uint32_t blob_bytes,
539 uint32_t block_bytes,
540 cb_sweep_config_t* config)
541{
542 if ((be == nullptr) || (payload_read == nullptr) || (config == nullptr) ||
543 (config->scratch == nullptr) || (block_bytes == 0U)) {
544 return 1;
545 }
546 uint8_t* input = (uint8_t*)internal_setup_take(config, k_cbs_codec_input_bytes);
547 uint64_t file_length = 0U;
548 if ((input == nullptr) || (internal_rbkc_pack(payload_read,
549 payload_ctx,
550 blob_bytes,
551 block_bytes,
552 config,
553 input,
554 (uint32_t)k_cbs_codec_input_bytes,
555 &file_length) != 0)) {
556 return 1;
557 }
558 config->workspace_used = config->workspace_floor;
559 cbs_rbkc_t* rb = (cbs_rbkc_t*)internal_setup_take(config, sizeof(cbs_rbkc_t));
560 tinfl_decompressor* inflater =
561 (tinfl_decompressor*)internal_setup_take(config, sizeof(tinfl_decompressor));
562 input = (uint8_t*)internal_setup_take(config, k_cbs_codec_input_bytes);
563 if ((rb == nullptr) || (inflater == nullptr) || (input == nullptr)) {
564 return 1;
565 }
566 const uint32_t count = (blob_bytes + block_bytes - 1U) / block_bytes;
567 *rb = (cbs_rbkc_t){.scratch = config->scratch,
568 .inflater = inflater,
569 .input = input,
570 .input_capacity = k_cbs_codec_input_bytes,
571 .chunk_bytes = block_bytes,
572 .chunk_count = count,
573 .total_bytes = blob_bytes,
574 .payload_offset = (uint64_t)k_book_container_header_len +
575 (((uint64_t)count + 1U) * k_book_container_entry_len)};
576 be->read = internal_rbkc_read;
577 be->read_ctx = rb;
578 be->backing_bytes = file_length;
579 be->src_bytes = &rb->source_bytes;
580 return 0;
581}
582
584 {.name = "mem", .setup = internal_mem_setup, .teardown = internal_backend_teardown},
585 {.name = "rbkc-z9", .setup = internal_rbkc_setup, .teardown = internal_backend_teardown},
586};
587
589cbs_backend_t* priv_backends(uint32_t* out_count)
590{
591 if (out_count != nullptr) {
592 *out_count = (uint32_t)(sizeof(s_cbs_backends) / sizeof(s_cbs_backends[0]));
593 }
594 return s_cbs_backends;
595}
@ 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
Demand-paged chunk reader for the "RBKC" .rabook container.
cb_io_status_t
Status returned by tool-local injected I/O callbacks.
@ k_cb_io_ok
Operation completed.
#define RA8_PRIV
Module-private helper: shared across TUs but only inside one library.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Error Code Definitions for ra8-firmware.
@ 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_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 * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
ra8_err_t(* ra8_vsource_read_fn)(void *ctx, uint64_t offset, uint8_t *buf, uint32_t len)
Read len bytes at offset from a paged object's backing.
Definition ra8_vsource.h:79
Injected bounded random-access scratch transaction.
void * ctx
Caller-owned binding.
uint64_t size
Logical bytes written.
cb_scratch_io_fn write
Complete write-at callback.
cb_scratch_io_fn read
Complete read-at callback.
Caller-owned bindings for the block sweep.
Definition sweep_block.h:51
size_t cache_capacity
Supplied cache bytes.
Definition sweep_block.h:53
size_t workspace_floor
Persistent payload-index prefix.
Definition sweep_block.h:58
size_t workspace_capacity
Supplied workspace bytes.
Definition sweep_block.h:56
uint8_t * workspace
Small metadata/codec-input workspace.
Definition sweep_block.h:55
cb_scratch_t * scratch
Host-composed streamed RBKC transaction.
Definition sweep_block.h:60
size_t workspace_used
Current phase workspace usage.
Definition sweep_block.h:59
uint8_t * cache_backing
Exactly the measured resident-cache budget.
Definition sweep_block.h:52
size_t workspace_required
Exact latest requirement.
Definition sweep_block.h:57
One byte-addressed backing store the sweep reads through – the backend DIP seam the #208 hardware leg...
Counting shim around an ra8_vsource_read_fn.
uint64_t bytes
Bytes served through the shim.
uint64_t calls
Read calls forwarded so far.
void * inner_ctx
Context for inner.
ra8_vsource_read_fn inner
Wrapped reader.
cb_scratch_t * scratch
Destination transaction.
uint64_t offset
Next destination byte.
bool failed
Sticky publication failure.
uint64_t total_bytes
Logical payload extent.
cb_scratch_t * scratch
Container source transaction.
uint32_t chunk_count
Container chunk count.
uint32_t chunk_bytes
Logical bytes per chunk.
tinfl_decompressor * inflater
Caller-owned inflate state.
uint8_t * input
Compressed-input staging.
uint64_t payload_offset
First compressed payload byte.
uint64_t source_bytes
Complete container extent.
uint32_t input_capacity
Input staging extent.
RA8_PRIV uint64_t priv_now_ns(void)
Monotonic wall-clock in nanoseconds.
static RA8_INTERNAL int internal_rbkc_setup(cbs_backend_t *be, ra8_vsource_read_fn payload_read, void *payload_ctx, uint32_t blob_bytes, uint32_t block_bytes, cb_sweep_config_t *config)
Construct and bind the streamed RBKC-z9 benchmark backend.
static RA8_INTERNAL ra8_err_t internal_rbkc_inflate(cbs_rbkc_t *rb, uint64_t begin, uint64_t end, uint8_t *output, uint32_t output_length)
Inflate one exact RBKC chunk from scratch into caller storage.
static RA8_INTERNAL mz_bool internal_pack_write(const void *data, int length, void *user)
Append one compressor fragment to the injected scratch transaction.
RA8_PRIV ra8_err_t priv_meter_read(void *ctx, uint64_t offset, uint8_t *buffer, uint32_t length)
ra8_vsource_read_fn forwarding through a cbs_meter_t.
static cbs_backend_t s_cbs_backends[]
static RA8_INTERNAL ra8_err_t internal_rbkc_read(void *ctx, uint64_t offset, uint8_t *buffer, uint32_t length)
Serve one aligned logical chunk through the RBKC backend seam.
static RA8_INTERNAL int internal_rbkc_pack_chunk(tdefl_compressor *compressor, cbs_pack_sink_t *sink, ra8_vsource_read_fn payload_read, void *payload_ctx, uint8_t *input, uint32_t input_capacity, uint32_t offset, uint32_t length)
Compress one logical payload chunk into the scratch stream.
static RA8_INTERNAL void internal_backend_teardown(cbs_backend_t *be)
Clear the borrowed runtime bindings of one backend.
cbs_codec_limit_t
@ k_cbs_codec_window_bits
Zlib window size as log2(bytes).
@ k_cbs_codec_input_bytes
Streamed codec transfer grain.
static RA8_INTERNAL int internal_mem_setup(cbs_backend_t *be, ra8_vsource_read_fn payload_read, void *payload_ctx, uint32_t blob_bytes, uint32_t block_bytes, cb_sweep_config_t *config)
Bind the deterministic payload directly as an uncompressed backend.
RA8_PRIV cbs_backend_t * priv_backends(uint32_t *out_count)
Expose the registered sweep backends (the seam the HW leg extends).
static RA8_INTERNAL void internal_rbkc_header(uint8_t *output, uint32_t block_bytes, uint64_t total, uint32_t count)
Encode the fixed RBKC container header into caller storage.
static RA8_INTERNAL ra8_err_t internal_rbkc_offsets(cbs_rbkc_t *rb, uint32_t chunk, uint64_t *begin, uint64_t *end)
Read and validate one compressed chunk's relative offset pair.
static RA8_INTERNAL void * internal_setup_take(cb_sweep_config_t *config, size_t bytes)
Take one aligned setup region from the shared small workspace.
static RA8_INTERNAL int internal_rbkc_pack(ra8_vsource_read_fn payload_read, void *payload_ctx, uint32_t blob_bytes, uint32_t block_bytes, cb_sweep_config_t *config, uint8_t *input, uint32_t input_capacity, uint64_t *output_length)
Stream an RBKC container into the injected scratch transaction.
Module-private seams shared by the #208 sweep translation units.
@ k_cbs_cache_bytes
1 MiB resident cache budget (constant).
@ k_cbs_ns_per_s
Nanoseconds per second.