==> include/mesh/rt/view.h <==1/* @ajax/mesh-rt-view: a bounds-checked byte window of the mailbox (a program's view, or
2 * part of one), and the fault record a bad access leaves.
3 *
4 * Offsets are bytes from the window's start; u32/f32 accessors want 4-aligned
5 * offsets, u64 8-aligned. An out-of-range access reads 0 or drops the write
6 * and records FAULT_VIEW_BOUNDS | off << 8 in the caller's P_FAULT (meshd then
7 * fails the program loudly). Ported from alpha-rust-mesh
8 * crates/mesh-rt/src/ctx.rs (View, fault). */
9#ifndef MESH_RT_VIEW_H
10#define MESH_RT_VIEW_H
11
12#include <stdbool.h>
13#include <stdint.h>
14
15#include "mesh/abi/control_block.h"
16#include "mesh/abi/fault.h"
17#include "mesh/rt/prim.h"
18
19/* Records the first fault of a program (later ones keep the first). */
20MESH_RT_INLINE void mesh_rt_fault(uint8_t *ctl, uint32_t code) {
21 if (mesh_rt_ld_relaxed(ctl + MESH_P_FAULT) == 0) mesh_rt_st_relaxed(ctl + MESH_P_FAULT, code);
22}
23
24typedef struct {
25 uint8_t *base;
26 uint32_t len;
27 /* The caller's control block, where a bounds fault is recorded. */
28 uint8_t *ctl;
29} mesh_view;
30
31MESH_RT_INLINE bool mesh_view_ok(const mesh_view *v, uint32_t off, uint32_t n) {
32 bool fine = (uint64_t)off + n <= v->len;
33 if (!fine) mesh_rt_fault(v->ctl, MESH_FAULT_VIEW_BOUNDS | off << 8);
34 return fine;
35}
36MESH_RT_INLINE uint32_t mesh_view_len(mesh_view v) { return v.len; }
37MESH_RT_INLINE bool mesh_view_is_empty(mesh_view v) { return v.len == 0; }
38/* The raw base pointer (unchecked access, e.g. bulk loops). */
39MESH_RT_INLINE uint8_t *mesh_view_ptr(mesh_view v) { return v.base; }
40MESH_RT_INLINE uint32_t mesh_view_u32(mesh_view v, uint32_t off) { return mesh_view_ok(&v, off, 4) ? mesh_rt_rd(v.base + off) : 0; }
41MESH_RT_INLINE float mesh_view_f32(mesh_view v, uint32_t off) { return mesh_f32_from_bits(mesh_view_u32(v, off)); }
42MESH_RT_INLINE uint64_t mesh_view_u64(mesh_view v, uint32_t off) { return mesh_view_ok(&v, off, 8) ? mesh_rt_rd64(v.base + off) : 0; }
43MESH_RT_INLINE uint8_t mesh_view_u8(mesh_view v, uint32_t off) {
44 return mesh_view_ok(&v, off, 1) ? *(const volatile uint8_t *)(v.base + off) : 0;
45}
46MESH_RT_INLINE void mesh_view_set_u32(mesh_view v, uint32_t off, uint32_t x) { if (mesh_view_ok(&v, off, 4)) mesh_rt_wr(v.base + off, x); }
47MESH_RT_INLINE void mesh_view_set_f32(mesh_view v, uint32_t off, float x) { mesh_view_set_u32(v, off, mesh_f32_bits(x)); }
48MESH_RT_INLINE void mesh_view_set_u64(mesh_view v, uint32_t off, uint64_t x) { if (mesh_view_ok(&v, off, 8)) mesh_rt_wr64(v.base + off, x); }
49MESH_RT_INLINE void mesh_view_set_u8(mesh_view v, uint32_t off, uint8_t x) { if (mesh_view_ok(&v, off, 1)) mesh_rt_wrb(v.base + off, x); }
50/* A sub-window [off, off + len): false (and a fault) when out of range. */
51MESH_RT_INLINE bool mesh_view_sub(mesh_view v, uint32_t off, uint32_t len, mesh_view *out) {
52 if (!mesh_view_ok(&v, off, len)) return false;
53 *out = (mesh_view){v.base + off, len, v.ctl};
54 return true;
55}
56
57#endif