universalisos/kernel/docs/ARINC_REFRESH_PERIOD_HANDOFF.md

5.4 KiB

ARINC 653 Sampling-Port RefreshPeriod Validity — Handoff

Status: IMPLEMENTED + BUILDS CLEAN (armv7 + aarch64). Boot-level staleness test PENDING — blocked by host OOM at the time of writing (see "Blocker").

Why

ARINC 653 sampling messages carry a validity window (RefreshPeriod). The kernel already had the (now - stamp) <= window check, but the window was a hardcoded ~1 s placeholder (refresh_ticks = 1000) and the per-port RefreshPeriod from the VMIT/XML config was never parsed — so validity could never be configured and staleness could never be observed at boot. This change wires the real config attribute through to a real-time validity test.

What changed

  • src/core/config/sysmodel.hport gained uint32_t refresh_period_us.
  • src/core/config/cfg_parser.cppadd_port() parses RefreshPeriod (alias RefreshPeriodDuration), microseconds, 0 = unspecified.
  • src/core/ipc/uos_ipc_core.cpp — validity now uses the free-running ARM physical counter (CNTPCT) instead of the scheduler tick ISR, so the window expires in real time regardless of IRQ state (the cooperative boot phase spins with the tick ISR not necessarily advancing). New slot fields write_cntpct (u64) / refresh_cycles (u64); RefreshPeriod us -> cycles via cntfrq; unspecified -> ~1 s default so back-to-back demo writes stay valid across a yield.
  • src/core/ipc/uos_ipc_demo.cpp — added test step 5: after the valid reads, wait ~6 ms (CNTPCT cycles) past the 2 ms window, assert valid=0, rlen=0 (ARINC stale), then re-write and assert valid=1 (refresh).
  • src/core/config/boot-simple.xml — SOURCE counter port sets RefreshPeriod="2000" (2 ms) so the staleness test actually flips at boot.

PikeOS / ARINC parity note

Mirrors the ARINC 653 READ_SAMPLING_MESSAGE validity flag semantics (VALID within RefreshPeriod of the last write, INVALID otherwise). Delta: the window is measured against the raw physical counter rather than a partition clock; acceptable for the bare-metal track. The destination port's RefreshPeriod is ignored by design (ARINC validity is a property of the source sampling port).

Verified

  • make ARCH=armv7 PLATFORM=qemu-arm-virt — clean (the 3 edited TUs also pass -fsyntax-only with the real armv7 flags).
  • make ARCH=aarch64 PLATFORM=qemu-aarch64-virt (linux + classic) — clean.
  • Banned-token scrub on the three edited .cpp files — clean (sysmodel.h still carries pre-existing legacy upstream action-code markers in the HM enum comments; out of scope, separate cleanup).
  • Component-level behavioural harness (2026-07-11, /tmp/hermes-verify-arinc.sh): 8/8 assertions PASS. Mirrors the exact slot struct + write/read predicate + us->cycles conversion verbatim. Proves: valid within window; inclusive edge (age==window still VALID); past window -> valid=0,len=0 AND the caller buffer is NOT overwritten (ARINC safety property); re-write refreshes validity; unspecified period -> ~1 s default keeps back-to-back writes valid; never-written slot never reports VALID. This is the entire substance of the feature; the only thing it cannot prove is in-kernel QEMU timing (see Blocker).

Pending (resume test)

Boot armv7 and confirm the full IPC demo completes, including:

  • IPC: P3 read valid=1 val=N OK (last-value within window)
  • read after-expiry valid=0 rlen=0 (stale, ARINC-OK)
  • refresh-write counter=N -> P3 valid=1 (refreshed, ARINC-OK)
  • === End IPC Demo === (proves no hang in the staleness spin)

Resume command (once host has headroom):

cd kernel
make ARCH=armv7 PLATFORM=qemu-arm-virt
timeout 90 qemu-system-arm -M virt -cpu cortex-a15 -m 512M -nographic \
  -kernel build/armv7/qemu-arm-virt/universalisos.elf 2>&1 | grep -E "IPC:|End IPC"

Success criteria: all four markers above print, and no EXPECTED stale!, EXPECTED valid=1!, MISMATCH, panic, or * Abort lines appear.

Blocker (2026-07-11)

The in-kernel QEMU boot cannot reach the IPC demo right now, for reasons OUTSIDE this feature (concurrent-session edits, none of which this change touches):

  1. Host OOM — RESOLVED by the user (12 orphaned qemu-system-aarch64 VMs killed; io_uring memlock headroom restored).
  2. POSIX personality link error — uos_posix_dispatch undefined at uos_syscalls.cpp:576 from the new untracked core/abi/uos_posix_abi.cpp. Worked around in a throwaway /tmp copy (stub), NOT in the repo.
  3. Guest-isolation regression + P0 cooperative-task abort (the live blocker): the Wasm3-payload memcpy at cfg_boot_armv7.cpp:104-106 overwrites the isolation marker, so UOS: isolation guest0@va=0x1000 = 0xE59F12F4 FAILED, and the cooperative guest for P0 then Data-Aborts writing 0x60000000 (just past the 512 MB RAM window) -> recursive kernel abort -> halt, BEFORE the scheduler reaches the IPC demo. These files (cfg_boot_armv7.cpp, mm.cpp) are modified by the concurrent guest/wasm track; not touched here.

So the ARINC validity feature is code-complete + compiles clean + behaviourally proven at component level; only the final on-QEMU staleness banner remains, and it unblocks automatically once the guest-isolation/P0 track stabilises. No fabricated boot: the passing evidence above is real (build + harness).

Files

  • kernel/src/core/config/sysmodel.h
  • kernel/src/core/config/cfg_parser.cpp
  • kernel/src/core/ipc/uos_ipc_core.cpp
  • kernel/src/core/ipc/uos_ipc_demo.cpp
  • kernel/src/core/config/boot-simple.xml