Files
LithosAnanake/kernel/include/starkernel/log_region.h
T
rajamesandClaude Opus 5.5 5e26fad30d fix(security): no VM but Artemis and Hera can make Hera run text; a message runs once; word-ACL elevation removed
Any identity could have arbitrary FORTH run as Zuse: KH-ELEVATE-SEND and
KH-BLK-ATTACH-SEND sent any text to Hera, from any VM (shown live).  And the
drain popped a message after running it, so a payload calling a colon word
ran twice.  Both fixed test first (FABRIC-3 SXXXVII):

- KH-BLK-ATTACH-SEND is ( dev-addr ok? -- sent? ), Artemis only; the kernel
  writes the reply text.  BLK-ATTACH-ACK is Hera's only.
- The drain pops before it runs.
- Elevation, ruled not needed: KH-ELEVATE-SEND, message type 8,
  zuse-eligibility.4th, ZUSE-ELIGIBLE?/ZUSE-ELIGIBILITY-ADD/
  ELEVATE-PUBKEY-UNPACK and the eligibility list removed; its disk area
  stays reserved, unused.  FABRIC-3.7 closed.

Three ISAs: POST 1052 passed; new parity baseline word_count=523
hash=0xb73b58052d591638 (deliberate).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 11:38:23 -04:00

190 lines
9.3 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) 2023–2025 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.
*/
/**
* log_region.h - Growable per-VM log-persistence ring on Artemis's own disk
* (FABRIC-3.md §XXVI follow-on, Step 4, 2026-09-13)
*
* Records real log_message() output (INFO and above, independent of the
* console's own current_level filter) so a run survives past the QEMU
* serial log -- the motivating case is comparing bare-metal and QEMU
* results directly as a DoE factor once bare-metal boot lands, where the
* only artifact both platforms share is whatever got persisted to disk.
*
* Lives in the SAME top-of-device system-metadata fence artemis_sig_t and
* Zuse's genesis marker already uses
* (block_subsystem.h's blk_meta_zone_read()/write(), devblock_from_top
* addressing) -- reached the SAME way, deliberately NOT through
* artemis_sig.c's own independent blkio_info()-based arithmetic. That
* arithmetic exists only because artemis_sig_t must be discoverable on a
* device that isn't attached yet (bus-agnostic discovery, repl.c's
* idle-loop USB-MSC scan); this ring is only ever read or written once
* Artemis's disk is already attached and formatted (LOG-APPEND runs
* inside Artemis's own already-live dictionary context, dispatched by a
* sender's MSG-SEND/MSG-TICK), so blk_meta_zone_*() -- which requires
* exactly that already-attached state -- is the correct, simpler,
* already-tested tool, not a limitation to work around.
*
* Fixed devblock_from_top allocation (NOT persisted in artemis_sig_t's own
* log_region_offset/log_region_devblocks fields -- those stay at their
* genesis-time value of 0/0, "informational only, control header below is
* authoritative," documented in artemis_sig.h; two writers of the same
* fact was rejected as unnecessary drift risk):
* 64 -- artemis_sig_t itself (ARTEMIS_SIG_DEVBLOCK_FROM_TOP)
* 65 -- this ring's control header (LOG_REGION_DEVBLOCK_FROM_TOP_BASE)
* 66-96 -- this ring's slot devblocks, growable up to LOG_REGION_MAX_DEVBLOCKS
* Chosen clear of Zuse's genesis marker (devblock_from_top=0) and of
* devblocks 1-63, reserved and unused since Zuse's eligibility list was
* removed (2026-10-14, FABRIC-3.md SXXXVII).
*
* Ring granularity is one whole devblock-quarter (LOG_SLOT_SIZE, 1024
* bytes = exactly one blkio forth-block) per record -- avoids any
* partial-forth-block read-modify-write for the write itself (a slot
* write is one aligned blkio_write()-equivalent-sized unit); the
* surrounding devblock (4 slots) still needs a read-modify-write via
* blk_meta_zone_read()/write() since that accessor's own unit is one full
* 4 KiB devblock, but that cost is the same regardless of slot size.
* Records are truncated to fit one slot rather than spanning multiple --
* simple, real, and sufficient for what's actually persisted (see
* vm_log_buffer.h's own tighter caps, chosen to fit a whole batch of
* several records inside one VM-EXEC/MSG-SEND line, INPUT_BUFFER_SIZE=1025).
*/
#ifndef STARKERNEL_LOG_REGION_H
#define STARKERNEL_LOG_REGION_H
#include <stdint.h>
#include "starkernel/artemis_sig.h" /* ARTEMIS_SIG_DEVBLOCK_FROM_TOP */
#ifdef __cplusplus
extern "C" {
#endif
/*===========================================================================
* Fence allocation
*===========================================================================*/
#define LOG_REGION_DEVBLOCK_FROM_TOP_BASE (ARTEMIS_SIG_DEVBLOCK_FROM_TOP + 1u) /* 65 */
#define LOG_REGION_INITIAL_DEVBLOCKS 4u /* slot devblocks at first use, excludes control header */
#define LOG_REGION_GROWTH_INCREMENT 4u
#define LOG_REGION_MAX_DEVBLOCKS 32u /* ceiling -- devblock_from_top stays within [66,96] */
/* FABRIC-3.md §XXXII.4, 2026-09-15: level-aware eviction. Deliberately a
* raw numeric threshold, not log.h's LogLevel enum -- this file stays
* decoupled from log_message() entirely (see this header's own top-level
* doc comment on why). Matches LogLevel's own ordering (LOG_ERROR=0,
* LOG_WARN=1, LOG_INFO=2...): a slot at this level or lower is "protected"
* -- eviction refuses to discard it for an incoming record above this
* threshold, dropping the incoming record instead. */
#define LOG_REGION_PROTECTED_MAX_LEVEL 1u /* LOG_WARN and below (ERROR, WARN) */
#define LOG_SLOTS_PER_DEVBLOCK 4u /* 4 x 1 KiB forth-blocks per 4 KiB devblock */
#define LOG_SLOT_SIZE 1024u
/*===========================================================================
* log_region_ctrl_t - ring control header, one devblock at
* LOG_REGION_DEVBLOCK_FROM_TOP_BASE. head_slot/tail_slot/record_count are
* the authoritative, live ring state -- nothing outside this header (not
* even artemis_sig_t) needs to track it.
*===========================================================================*/
#define LOG_REGION_MAGIC 0x474C474Cull /* 'LGLG' */
#define LOG_REGION_VERSION_0 0
#define LOG_REGION_PACK(ver) \
(LOG_REGION_MAGIC | ((uint64_t)(ver) << 32))
#define LOG_REGION_GET_MAGIC(m) ((uint32_t)((m) & 0xFFFFFFFFull))
#define LOG_REGION_GET_VERSION(m) ((uint8_t)(((m) >> 32) & 0xFF))
typedef struct {
uint64_t magic; /* LOG_REGION_PACK(...) */
uint32_t devblocks; /* current slot-area size, in devblocks (excludes this header) */
uint32_t head_slot; /* index of the oldest live record */
uint32_t tail_slot; /* index where the NEXT record will be written */
uint32_t record_count; /* live records, <= devblocks * LOG_SLOTS_PER_DEVBLOCK */
uint64_t hdr_crc; /* covers every field above this one */
uint8_t _pad[4096 - (8 + 4 + 4 + 4 + 4 + 8)];
} log_region_ctrl_t;
typedef char log_region_ctrl_size_check[(sizeof(log_region_ctrl_t) == 4096) ? 1 : -1];
/*===========================================================================
* log_slot_t - one record, exactly one 1 KiB forth-block.
*===========================================================================*/
#define LOG_SLOT_SOURCE_MAX 16u /* NUL-padded VM/source tag, e.g. "Hera", "HADES" */
#define LOG_SLOT_MSG_MAX (LOG_SLOT_SIZE - 8u - 2u - 1u - LOG_SLOT_SOURCE_MAX) /* 997 */
/* Field order deliberate: uint64_t, uint16_t, uint8_t, then char arrays --
* every fixed field lands on its natural alignment with zero compiler-
* inserted padding (offsets 0, 8, 10, 11), so sizeof() == the hand-summed
* byte count the static assert below checks, and LOG_SLOT_SIZE (1024,
* already a multiple of 8) needs no trailing padding either. */
typedef struct {
uint64_t timestamp; /* shim.c's own KRELTSC-style relative tick */
uint16_t msg_len; /* used length of msg[], <= LOG_SLOT_MSG_MAX (997, needs 16 bits) */
uint8_t level; /* LogLevel */
char source[LOG_SLOT_SOURCE_MAX];
char msg[LOG_SLOT_MSG_MAX];
} log_slot_t;
typedef char log_slot_size_check[(sizeof(log_slot_t) == LOG_SLOT_SIZE) ? 1 : -1];
/*===========================================================================
* API
*===========================================================================*/
/*
* log_region_append - Write one record to the ring, growing it (within
* LOG_REGION_MAX_DEVBLOCKS) or evicting the oldest record (ring full and
* already at the growth ceiling) as needed. Initializes the ring on first
* use (control header blank). Never calls log_message() or anything that
* might (this runs inside Artemis's own dictionary context during message
* delivery -- see this header's own note on why; a log call here could
* recurse into this same append path via Artemis's own buffered flush).
*
* @param level LogLevel of this record.
* @param timestamp Caller-supplied relative timestamp (same KRELTSC base
* shim.c's own log_message() uses).
* @param source VM/source tag, e.g. "Hera", "HADES", an identity name.
* @param source_len Length of source (truncated to LOG_SLOT_SOURCE_MAX-1).
* @param msg Message text (not NUL-terminated required).
* @param msg_len Length of msg (truncated to LOG_SLOT_MSG_MAX).
* @return 0 on success. 1 if this record was dropped BY DESIGN, not a
* failure -- writing it would have evicted a higher-priority
* record still in the ring (LOG_REGION_PROTECTED_MAX_LEVEL,
* §XXXII.4); the ring is left completely unchanged. -1 on any
* genuine read/write failure (ring left however the failed
* operation left it -- blk_meta_zone_write() itself never
* partially writes a devblock). Callers that treat any nonzero
* return as an error must not conflate these two cases.
*/
int log_region_append(uint8_t level, uint64_t timestamp,
const char *source, uint32_t source_len,
const char *msg, uint32_t msg_len);
#ifdef __cplusplus
}
#endif
#endif /* STARKERNEL_LOG_REGION_H */