Files
LithosAnanake/include/starkernel/timer.h
T
Robert Allan JamesandClaude Sonnet 5 3699be964d starkernel: converge the tick path and wire the adaptive heartbeat (item 0.8)
Introduces src/starkernel/heartbeat.c as the shared top/bottom-half
implementation of heartbeat_init/tick/service/ticks/trust/state, replacing
the per-architecture duplicates in amd64/riscv64/aarch64 timer.c. Each
arch's timer.c now contributes only heartbeat_read_counter() (rdtsc /
rdtime / CNTPCT_EL0). Per the GAP-A1 ruling the top half stays counter+
latch only; heartbeat_service() (called every REPL idle iteration,
unconditionally per FABRIC.md's fidelity note) does the window/variance/
trust work outside interrupt context. vm_tick()'s call sites are
unchanged -- the engine still runs on the virtual tick.

Per FABRIC.md §26 (ruled 2026-08-03): wires Loop #7's execution-derived
stable/volatile signal into the physical re-arm period. vm_runtime.c's
existing Loop #7 site now calls heartbeat_set_adaptive_period_ns() with
tick_target_ns ratio-rescaled onto a 10ms kernel base (not the hosted
10us HEARTBEAT_TICK_NS -- see §26.3 for the scale mismatch). Each
architecture's re-arm function (apic_timer_rearm() on amd64/aarch64,
riscv64_timer_rearm()) now converts heartbeat_next_period_ns() to its
own raw counter units instead of a fixed constant; amd64 gained a
rearm function it didn't previously need, since periodic-mode auto-reload
never required one before this item.

Verified: all three architectures build with no new warnings and boot
cleanly to ok> with dict_hash=0x3d4e1daf289da94f, unchanged from the
pre-change baseline -- no regression. Verified NOT achieved: live re-arm
period variation under load. A temporary diagnostic (added and reverted)
confirmed Loop #7 never actually fired during a live QEMU session -- a
synthetic word-execution loop drove ~6,500 executions, past the 1000-tick
inference frequency, without tripping vm_tick_inference_engine()'s
pre-existing !vm->rolling_window.is_warm gate. That gate predates this
item and was not investigated -- out of scope. FABRIC.md's Done-when is
amended to record this honestly rather than claim it.

Punch list §25 item 0.8 complete (per amended, weaker acceptance -- see
the item's own annotation).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-04 00:01:48 -04:00

220 lines
8.0 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
StarForth — Steady-State Virtual Machine Runtime
Copyright (c) 20232025 Robert A. James
All rights reserved.
This file is part of the StarForth project.
Licensed under the StarForth License, Version 1.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
https://github.com/star.4th@proton.me/StarForth/LICENSE.txt
This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
express or implied, including but not limited to the warranties of
merchantability, fitness for a particular purpose, and noninfringement.
See the License for the specific language governing permissions and
limitations under the License.
StarForth — Steady-State Virtual Machine Runtime
Copyright (c) 20232025 Robert A. James
All rights reserved.
This file is part of the StarForth project.
Licensed under the StarForth License, Version 1.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
https://github.com/star.4th@proton.me/StarForth/LICENSE.txt
This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
express or implied, including but not limited to the warranties of
merchantability, fitness for a particular purpose, and noninfringement.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* timer.h - Timer and Heartbeat Interface
*
* M5 Time Model:
* - TIME-TICKS (Q64.0): Monotonic heartbeat counter, never decreases
* - TIME-TRUST (Q48.16): Continuous confidence metric [0.0, 1.0]
* - No discrete modes (NONE/REL/ABS are legacy, being phased out)
* - Trust is a measurement, never gates execution
*/
#ifndef STARKERNEL_TIMER_H
#define STARKERNEL_TIMER_H
#include <stdint.h>
#include "uefi.h"
#include "q48_16.h"
/* ============================================================================
* M5 Time Model (New)
* ============================================================================ */
/* TIME-TRUST: Continuous confidence metric in Q48.16 format */
typedef q48_16_t time_trust_t;
/* Rolling window size for timestamp variance computation */
#define TIME_WINDOW_SIZE 64
/* TIME-TRUST thresholds in Q48.16 (for diagnostics, NOT for gating) */
#define TIME_TRUST_HIGH Q48_ONE /* 1.0 = full confidence */
#define TIME_TRUST_LOW (Q48_ONE >> 2) /* 0.25 = low confidence */
/*
* Rolling window of timestamp deltas for variance computation.
* Each entry is (actual_tsc_delta - expected_tsc_delta) in TSC ticks.
*/
typedef struct time_window {
int64_t deltas[TIME_WINDOW_SIZE]; /* Signed: can be early or late */
uint32_t pos; /* Current write position */
uint32_t count; /* Number of valid samples (up to SIZE) */
} TimeWindow;
/*
* M5 Heartbeat State: Holds all time-related metrics.
* Updated every heartbeat tick by the ISR.
*/
typedef struct time_trust_state {
/* Core counters */
uint64_t ticks; /* TIME-TICKS: monotonic heartbeat count */
uint64_t last_tsc; /* TSC at last heartbeat */
uint64_t expected_delta; /* Expected TSC ticks per heartbeat */
/* Rolling window for variance */
TimeWindow window;
/* Derived metrics (Q48.16) */
q48_16_t variance; /* Variance of deltas */
q48_16_t trust; /* TIME-TRUST: derived from variance */
/* Statistics */
uint64_t total_samples; /* Lifetime sample count */
} TimeTrustState;
/* ============================================================================
* Legacy M4 Interface (To Be Phased Out)
* ============================================================================ */
/*
* Timer trust levels (LEGACY - discrete modes violate M5 spec):
* - NONE: no usable time base
* - RELATIVE: monotonic-ish, not for claims
* - ABSOLUTE: invariant + calibrated
*/
typedef enum timer_trust_level {
TIMER_TRUST_NONE = 0,
TIMER_TRUST_RELATIVE = 1,
TIMER_TRUST_ABSOLUTE = 2
} timer_trust_level_t;
/*
* Timer calibration record for logging / DoE traceability.
* Keep it minimal and serial-friendly.
*/
typedef struct timer_calibration_record {
uint64_t hpet_hz; /* HPET frequency derived from period_fs (if available) */
uint64_t tsc_hz_mean; /* Locked TSC Hz (final) */
uint64_t pit_hz_mean; /* PIT-based estimate (if used) */
uint64_t cv_hpet_ppm; /* HPET window CV in ppm (bare metal convergence) */
uint64_t cv_pit_ppm; /* PIT window CV in ppm (bare metal convergence) */
uint64_t diff_ppm; /* HPET vs PIT mean diff in ppm (bare metal convergence) */
uint32_t windows_used; /* number of windows consumed to converge */
uint8_t converged; /* 1 if converged/locked, 0 otherwise */
uint8_t vm_mode; /* 1 if hypervisor policy path used */
uint8_t trust; /* timer_trust_level_t (NONE/RELATIVE/ABSOLUTE) */
uint8_t reserved[1];
} timer_calibration_record_t;
/* Legacy API (still works, wraps M5 internals) */
int timer_init(BootInfo *boot_info);
uint64_t timer_tsc_hz(void);
uint64_t timer_now_ns(void);
int timer_check_drift_now(void);
const timer_calibration_record_t *timer_calibration_record(void);
/* ============================================================================
* M5 Heartbeat API (New)
* ============================================================================ */
/*
* Initialize the heartbeat subsystem.
* Called after timer_init(), before enabling APIC timer.
*/
void heartbeat_init(uint64_t tsc_hz, uint64_t tick_hz);
/**
* Top half. Called directly from each architecture's ISR (punch-list item
* 0.8) -- one call site per architecture, unchanged from before this item.
* Does exactly three things: reads the raw counter via
* @c heartbeat_read_counter(), increments TIME-TICKS, and latches the
* sample for @c heartbeat_service() to pick up. No window math, no
* variance, no loops -- this must stay cheap enough for interrupt context.
*/
void heartbeat_tick(void);
/**
* Bottom half (punch-list item 0.8). Services one pending sample if
* @c heartbeat_tick() has latched one since the last call: computes the
* inter-tick deviation, updates the rolling window, and (architecture
* permitting -- see @c heartbeat.c) recomputes variance and TIME-TRUST.
* Never runs in interrupt context. Call from the mainline, as frequently
* as convenient -- a stale/skipped service call degrades the window's
* fidelity but affects nothing else, since TIME-TRUST is diagnostic only
* and never gates execution.
*/
void heartbeat_service(void);
/**
* Read the raw hardware counter this architecture's heartbeat is paced
* against -- the same clock @c timer_now_ns() and calibration already use
* internally (rdtsc on amd64, the `time` CSR on riscv64, CNTPCT_EL0 on
* aarch64), not a separate/different source. Implemented once per
* architecture in that architecture's timer.c; consumed only by
* @c heartbeat_tick() in the shared heartbeat.c.
*/
uint64_t heartbeat_read_counter(void);
/**
* Get current TIME-TICKS (monotonic heartbeat count).
*/
uint64_t heartbeat_ticks(void);
/**
* Get current TIME-TRUST (Q48.16 confidence metric).
*/
time_trust_t heartbeat_trust(void);
/**
* Get pointer to full heartbeat state (for diagnostics).
*/
const TimeTrustState *heartbeat_state(void);
/**
* Set the adaptive re-arm period, in nanoseconds (punch-list item 0.8,
* FABRIC.md §26). Called from the mainline execution path only (Loop #7's
* site in vm_runtime.c) -- never from interrupt context. Clamped to
* [1/4x, 4x] of the kernel's base period internally; a caller need not
* pre-clamp.
*/
void heartbeat_set_adaptive_period_ns(uint64_t ns);
/**
* Read the period the next hardware re-arm should use. Called from
* interrupt context by each architecture's re-arm function in place of a
* fixed constant.
*/
uint64_t heartbeat_next_period_ns(void);
#endif /* STARKERNEL_TIMER_H */