docs: reorganise -- current reference gathered, finished work archived, superseded and dead ideas marked as such

docs/CLAUDE.md Phase 2, 2026-10-14.  All moves by git mv; every archived
file carries a header saying what it is, why, and where to look instead.

- docs/reference/ (new): roadmap and versioning policy, M7.1, word-ACL
  design, kernel args, hosted acceptance test, dictionary, primitives,
  ontology, L8 table -- previously spread over docs/, docs/lithosananke/
  and docs/03-architecture/.
- docs/working/archive/historical/: finished work (session plan, test-gap
  audit, birthing plan, fix write-ups, the January architecture draft).
- docs/working/archive/superseded/: the Hermes-VM Tripod docs and July
  Hermes designs (-> FABRIC-3.5/3.6), the StarForth roadmap, every working
  doc already flagged superseded or obsolete.
- docs/working/archive/dead/: the hal_* target contract (never adopted),
  L4Re, metrics-and-knobs.
- Papers and proposals into docs/working/papers/.
- References rewritten across the repo (not logs/, not docs/patent/);
  CLAUDE.md's documentation section rewritten.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-14 16:03:56 -04:00
co-authored by Claude Opus 5.5
parent 1a4b163861
commit 7aed588f78
116 changed files with 305 additions and 175 deletions
@@ -0,0 +1,981 @@
> **HISTORICAL (docs triage 2026-10-14).** Draft 0.1 of the system vision ("everything is a VM, everything is a capsule"), 2026-01-27; the design that was built is recorded in the FABRIC documents.
> Instead: docs/fabric/ (FABRIC-3.5.md for the Tripod and kernel-Hermes, FABRIC-3.md for bare metal). Moved here from `docs/lithosananke/SYSTEM_ARCHITECTURE.md`.
# LithosAnanke System Architecture
**Version**: 0.1 (Draft)
**Date**: 2026-01-27
**Status**: Architectural Design
---
## 1. EXECUTIVE SUMMARY
LithosAnanke is a microkernel-style operating system where all system services run as isolated Virtual Machines (VMs) communicating exclusively through message passing. User identity is tied to physical media (thumbdrives), with cryptographically signed capability grants enforced at VM birth.
**Core Principles:**
- Everything is a VM, everything is a capsule
- All communication through messaging backbone (no exceptions)
- All storage through block I/O VM (no exceptions)
- Physical possession = authentication
- Cryptographic signing = capability enforcement
- One admin key, no recovery, no backdoors
---
## 2. VM HIERARCHY
### 2.1 Overview
```
┌─────────────────────────────────────────────────────────────────┐
│ Mama VM │
│ (births and deaths ONLY) │
└─────────────────────────────────────────────────────────────────┘
│
┌─────────────────┼─────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────────┐ ┌───────────────┐ ┌───────────────────┐
│ Messaging VM │ │ Block I/O VM │ │ User Session │
│ (all comms) │ │ (all storage)│ │ VMs... │
└───────────────────┘ └───────────────┘ └───────────────────┘
```
### 2.2 Mama VM
**Role:** Root VM, births and deaths other VMs. Nothing else.
**Responsibilities:**
- Execute Mama init capsule at boot
- Birth system VMs (Messaging, Block I/O)
- Birth user session VMs on thumbdrive insertion
- Death user session VMs on thumbdrive removal
- Maintain VM registry
**Does NOT do:**
- Message routing (Messaging VM does this)
- Block I/O (Block I/O VM does this)
- User interaction (User VMs do this)
**Capsule:** `mama-init.4th` with flag `CAPSULE_FLAG_MAMA_INIT`
### 2.3 Messaging Backbone VM
**Role:** All inter-VM communication routes through this VM. No exceptions.
**Responsibilities:**
- Route messages between VMs
- Enforce message-level ACLs
- Queue messages for sleeping/busy VMs
- Handle hardware interrupts (keyboard, USB events)
- Notify Mama of hardware events (thumbdrive insertion)
**Capabilities Required:**
- `CAP_ROUTE_MESSAGES` - Can route between any VMs
- `CAP_HARDWARE_IRQ` - Can receive hardware interrupts
- `CAP_VM_ENUMERATE` - Can query VM registry
**Capsule:** `messaging.4th` with flag `CAPSULE_FLAG_PRODUCTION`
### 2.4 Block I/O VM
**Role:** All storage access routes through this VM. No exceptions.
**Responsibilities:**
- Physical block I/O to all storage devices
- Map user virtual blocks to physical blocks
- Enforce block-level ACLs
- Manage Block Allocation Maps (BAM)
- Handle storage device hotplug
**Capabilities Required:**
- `CAP_BLOCK_PHYSICAL` - Direct hardware access to storage
- `CAP_BLOCK_MAP` - Can create/modify block mappings
- `CAP_ACL_ENFORCE` - Can check ACLs on block operations
**Capsule:** `block-io.4th` with flag `CAPSULE_FLAG_PRODUCTION`
### 2.5 User Session VMs
**Role:** Isolated user environment with REPL.
**Created when:** User inserts authenticated thumbdrive
**Destroyed when:** Thumbdrive removed or user executes BYE
**Each user session gets:**
- Own VM instance
- Own heap (memory arena)
- Own RAM blocks (0-2047)
- Own disk blocks mapped to thumbdrive (2048+)
- Capabilities as granted by signed capability block
**Capsule:** `user-shell.4th` or user-specified custom capsule
---
## 3. BLOCK SUBSYSTEM ARCHITECTURE
### 3.1 User's Logical View (Deterministic)
Every user sees the identical logical layout:
```
┌─────────────────────────────────────────────────────────────┐
│ Blocks 0-2047: RAM Drive │
│ - Fast, volatile working space │
│ - 2 MB total (2048 × 1024 bytes) │
│ - Cleared on session end │
├─────────────────────────────────────────────────────────────┤
│ Blocks 2048+: Physical Storage (Thumbdrive) │
│ - Persistent across sessions │
│ - User's "home" blocks │
│ - Block 2048 typically contains startup script │
└─────────────────────────────────────────────────────────────┘
```
**Guarantees:**
- Blocks 0-2047 are ALWAYS RAM (fast, volatile)
- Blocks 2048+ are ALWAYS physical storage (persistent)
- This layout is identical for every user on every machine
- User FORTH code is portable (same logical addresses everywhere)
### 3.2 Physical Storage Layout (Thumbdrive)
```
┌─────────────────────────────────────────────────────────────┐
│ Devblock 0: Volume Header (4 KiB) │
│ - Magic, version, geometry │
│ - BAM location pointers │
│ - Reserved range definitions │
├─────────────────────────────────────────────────────────────┤
│ Devblocks 1..B: Physical BAM │
│ - 1 bit per 1 KiB block │
│ - Tracks allocated/free status │
├─────────────────────────────────────────────────────────────┤
│ Devblocks B+1..X: System Region │
│ - NOT VISIBLE to user (no logical block maps here) │
│ - Identity sector (fingerprint source data) │
│ - Signed capability grants │
│ - ACL tables (variable size, chained blocks) │
│ - Audit log (grows over time) │
│ - Startup block pointer │
├─────────────────────────────────────────────────────────────┤
│ Devblocks X+1..end: User Block Region │
│ - Mapped to user's logical blocks 2048+ │
│ - User's FORTH code, data, definitions │
│ - Fully under user control (within ACL limits) │
└─────────────────────────────────────────────────────────────┘
```
### 3.3 Virtual BAM
Each user session has a **Virtual BAM** that maps only their accessible blocks:
```
User's Virtual BAM Physical Reality
───────────────── ─────────────────
Block 0 ─────────────────► RAM buffer[0]
Block 1 ─────────────────► RAM buffer[1]
...
Block 2047 ─────────────────► RAM buffer[2047]
Block 2048 ─────────────────► Thumbdrive devblock X+1
Block 2049 ─────────────────► Thumbdrive devblock X+2
...
```
**Key property:** System region devblocks have NO entry in the virtual BAM. From the user's FORTH perspective, they don't exist. No block number maps to them.
### 3.4 Block I/O Flow
User VM requests a block read:
```
User VM Messaging VM Block I/O VM
│ │ │
│ ─── MSG(READ,2048) ───► │ │
│ │ ─── MSG(READ) ─────► │
│ │ │
│ │ ├─ Check ACL
│ │ ├─ Map virtual→physical
│ │ ├─ Physical I/O
│ │ │
│ │ ◄─── MSG(DATA) ───── │
│ ◄─── MSG(DATA) ──────── │ │
│ │ │
```
**No direct hardware access** from user VMs. All I/O is mediated.
### 3.5 System Region Uses
The system region (invisible to user) stores variable-size metadata:
| Data | Size | Notes |
|------|------|-------|
| Identity sector | ~256 bytes | Source data for fingerprint |
| Fingerprint | 32-64 bytes | SHA-256 or SHA-512 hash |
| Capability grants | Variable | Signed by admin |
| ACL tables | Variable | Block-level permissions |
| Group memberships | Variable | For shared access |
| Audit log | Grows | Tracks significant events |
| Startup pointer | 8 bytes | Which block to LOAD at init |
| Custom metadata | Variable | Application-specific |
**Variable-size data** uses block chaining (existing `prev_block`, `next_block` fields in `blk_meta_t`).
---
## 4. USER IDENTITY MODEL
### 4.1 Physical Capability Model
**Identity IS the thumbdrive.** No passwords, no usernames.
```
┌─────────────────────────────────────────────────────────────┐
│ User's Thumbdrive │
├─────────────────────────────────────────────────────────────┤
│ Contains: │
│ - Identity data → SHA fingerprint │
│ - Signed capability grants │
│ - User's blocks (code, data) │
│ - Startup configuration │
├─────────────────────────────────────────────────────────────┤
│ Properties: │
│ - Fully portable (works on any LithosAnanke system) │
│ - Self-contained (no central user database) │
│ - Physical possession = authentication │
└─────────────────────────────────────────────────────────────┘
```
### 4.2 Fingerprint Generation
The SHA fingerprint uniquely identifies the user:
```
Fingerprint = SHA-256(identity_sector_data)
```
**Identity sector contents** (stored in system region):
- UUID (random, generated at user creation)
- Creation timestamp
- Optional: hardware serial numbers, user metadata
**The fingerprint:**
- Is computed by the kernel at thumbdrive insertion
- Is matched against the signed capability grant
- Cannot be forged (would need admin signature)
### 4.3 Session Lifecycle
```
┌─────────────────────────────────────────────────────────────┐
│ 1. THUMBDRIVE INSERTION │
├─────────────────────────────────────────────────────────────┤
│ • Hardware interrupt → Messaging VM │
│ • Messaging VM notifies Mama │
│ • Block I/O VM reads system region │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 2. IDENTITY VERIFICATION │
├─────────────────────────────────────────────────────────────┤
│ • Compute SHA fingerprint from identity sector │
│ • Read signed capability grant from system region │
│ • Verify signature against fused admin public key │
│ • If invalid: reject, log attempt, stop │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 3. VM BIRTH │
├─────────────────────────────────────────────────────────────┤
│ • Mama selects base capsule (user-shell or custom) │
│ • Mama births new VM │
│ • VM allocated: heap, RAM blocks (0-2047) │
│ • Disk blocks (2048+) mapped to thumbdrive │
│ • Capabilities granted: capsule ∩ signed_grant │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 4. INITIALIZATION │
├─────────────────────────────────────────────────────────────┤
│ • Base capsule executes (defines PERSONALITY) │
│ • User's startup block LOADed (e.g., 2048 LOAD) │
│ • Custom words, aliases, preferences applied │
│ • REPL ready for user input │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 5. ACTIVE SESSION │
├─────────────────────────────────────────────────────────────┤
│ • User interacts via REPL │
│ • All I/O through Block I/O VM │
│ • All comms through Messaging VM │
│ • ACLs enforced on every operation │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 6. SESSION END (thumbdrive removal OR BYE) │
├─────────────────────────────────────────────────────────────┤
│ • Hardware interrupt (removal) or explicit BYE │
│ • Messaging VM notifies Mama │
│ • Mama deaths the user VM │
│ • RAM blocks freed │
│ • Heap freed │
│ • Block mappings removed │
│ • Session over, no trace remains │
└─────────────────────────────────────────────────────────────┘
```
### 4.4 User Startup Customization
Users can customize their environment like `.bashrc`:
```forth
\ Block 2048 - User's startup script (example)
\ Load my personal library
2049 LOAD
\ Define aliases
: LS DIR ;
: PWD BLK@ . ;
\ Set preferences
DECIMAL
64 BASE-DEFAULT !
\ Greeting
." Welcome back, Captain!" CR
```
**Constraints:**
- Startup runs AFTER base capsule
- Can define words, load blocks, set variables
- CANNOT exceed capability grants
- CANNOT access blocks outside mapped range
- CANNOT send unauthorized messages
---
## 5. SECURITY MODEL
### 5.1 Root of Trust: Admin Fusing
**One-time, irreversible provisioning:**
```
┌─────────────────────────────────────────────────────────────┐
│ PROVISIONING MODE (First Boot Only) │
├─────────────────────────────────────────────────────────────┤
│ 1. System detects unprovisioned state │
│ 2. Generate Ed25519 keypair │
│ • Private key: 32 bytes │
│ • Public key: 32 bytes │
│ 3. FUSE public key to system │
│ • Written to NVRAM/secure storage │
│ • Cannot be changed after this │
│ 4. Create admin thumbdrive │
│ • Private key stored in system region │
│ • Root capability grant (all permissions) │
│ • Self-signed (bootstrap) │
│ 5. Exit provisioning mode FOREVER │
│ • Provisioning flag set │
│ • Cannot re-enter this mode │
└─────────────────────────────────────────────────────────────┘
```
**After fusing:**
- Public key is immutable (fused to system)
- Private key exists ONLY on admin thumbdrive
- No copies, no backups, no recovery mechanism
- Lose admin thumbdrive = cannot provision new users
### 5.2 Admin Thumbdrive
**The single point of administrative authority:**
```
Admin Thumbdrive (System Region)
├── Admin identity sector
├── Root capability grant (self-signed at provisioning)
├── Private signing key (Ed25519)
└── Admin blocks (tools, scripts)
Admin Capabilities:
├── CAP_SIGN_GRANTS - Can sign capability grants
├── CAP_CREATE_USERS - Can provision new thumbdrives
├── CAP_REVOKE_USERS - Can revoke capabilities
├── CAP_SYSTEM_CONFIG - Can modify system settings
├── CAP_ALL_BLOCKS - Can access any block
└── CAP_* - All capabilities
```
**Admin can:**
- Create new user thumbdrives
- Sign capability grants
- Revoke user capabilities (by not re-signing)
- Access any user's blocks (for recovery, audit)
- Modify system configuration
**Admin CANNOT:**
- Create another admin (no delegation)
- Recover lost admin thumbdrive
- Change the fused public key
### 5.3 Capability Grant Structure
```
┌─────────────────────────────────────────────────────────────┐
│ Capability Grant Block │
├─────────────────────────────────────────────────────────────┤
│ Header: │
│ Magic: "CPGR" (0x43504752) │
│ Version: 1 │
│ Grant ID: unique identifier │
│ Created: timestamp │
│ Expires: timestamp (0 = never) │
├─────────────────────────────────────────────────────────────┤
│ Identity: │
│ Fingerprint: SHA-256 (32 bytes) │
│ Must match computed fingerprint at auth time │
├─────────────────────────────────────────────────────────────┤
│ Capabilities (bitmap + parameters): │
│ CAP_BLOCK_READ - Can read blocks │
│ CAP_BLOCK_WRITE - Can write blocks │
│ CAP_BLOCK_RANGE - Allowed block range (start, end) │
│ CAP_MSG_SEND - Can send messages │
│ CAP_MSG_RECEIVE - Can receive messages │
│ CAP_MSG_TARGETS - Allowed message targets (VM list) │
│ CAP_CAPSULE_LOAD - Can request capsule loading │
│ CAP_CUSTOM_CAPSULE - Can use custom init capsule │
│ CAP_GROUP_MEMBER - Group membership list │
│ CAP_RESOURCE_QUOTA - CPU, memory, block limits │
├─────────────────────────────────────────────────────────────┤
│ Signature: │
│ Ed25519 signature over all above fields │
│ Signed by admin private key │
│ 64 bytes │
└─────────────────────────────────────────────────────────────┘
```
### 5.4 Capability Verification Flow
```
Thumbdrive inserted
│
▼
┌───────────────────────────────────────┐
│ 1. Read identity sector │
│ 2. Compute fingerprint = SHA-256(id) │
└───────────────────────────────────────┘
│
▼
┌───────────────────────────────────────┐
│ 3. Read capability grant block │
│ 4. Extract grant.fingerprint │
│ 5. Compare: computed == grant.fp? │
│ NO → Reject (identity mismatch) │
└───────────────────────────────────────┘
│ YES
▼
┌───────────────────────────────────────┐
│ 6. Extract grant.signature │
│ 7. Verify: Ed25519_verify( │
│ fused_public_key, │
│ grant_data, │
│ signature) │
│ FAIL → Reject (tampered/forged) │
└───────────────────────────────────────┘
│ PASS
▼
┌───────────────────────────────────────┐
│ 8. Check expiry timestamp │
│ EXPIRED → Reject │
└───────────────────────────────────────┘
│ VALID
▼
┌───────────────────────────────────────┐
│ 9. Grant capabilities to new VM │
│ effective_caps = grant.caps │
└───────────────────────────────────────┘
```
### 5.5 Capability Enforcement Points
**At VM Birth:**
- Capabilities extracted from signed grant
- Stored in VM registry entry
- Cannot be modified after birth
**At Message Send:**
- Messaging VM checks: Does sender have CAP_MSG_SEND?
- Messaging VM checks: Is target in CAP_MSG_TARGETS?
- Reject if not authorized
**At Block Access:**
- Block I/O VM checks: Does requestor have CAP_BLOCK_READ/WRITE?
- Block I/O VM checks: Is block in CAP_BLOCK_RANGE?
- Reject if not authorized
**At Capsule Load:**
- Mama checks: Does requestor have CAP_CAPSULE_LOAD?
- Mama checks: Does requestor have CAP_CUSTOM_CAPSULE (if custom)?
- Reject if not authorized
### 5.6 Effective Capabilities
Final capabilities are the intersection:
```
effective_caps = capsule.declared ∩ grant.allowed ∩ system.policy
```
**capsule.declared:** What the init capsule requests
**grant.allowed:** What the signed grant permits
**system.policy:** System-wide limits (optional)
A user cannot gain capabilities not in their signed grant, even if the capsule requests them.
### 5.7 Revocation
**Capability revocation works by:**
1. Admin creates new grant with reduced capabilities
2. Admin re-signs the grant
3. New grant replaces old on thumbdrive
4. Next session uses new (reduced) capabilities
**Immediate revocation:**
- Admin can maintain a revocation list
- Checked at session start
- Fingerprint on revocation list = reject
**No online revocation checking** - this is a standalone system. Revocation requires physical access to update the thumbdrive or revocation list.
### 5.8 Attack Surface Analysis
**Attacks PREVENTED:**
| Attack | Prevention |
|--------|------------|
| Password guessing | No passwords exist |
| Credential theft | Must steal physical device |
| Privilege escalation | Capabilities signed, immutable |
| Block range escape | Virtual BAM has no mapping |
| Direct hardware access | All I/O through service VMs |
| Message spoofing | Source VM verified by Messaging VM |
| Capability forging | Ed25519 signature required |
| Admin impersonation | Admin private key on single device |
| Recovery mode exploit | No recovery mode exists |
| Backup compromise | No backups exist |
**Attacks NOT PREVENTED:**
| Attack | Notes |
|--------|-------|
| Physical theft of thumbdrive | Physical security is user's responsibility |
| Physical theft of admin drive | Total compromise, must reflash |
| Cold boot attack | RAM contents may be recoverable |
| Evil maid (hardware tampering) | Outside scope, requires secure boot |
| Side channel timing | Not addressed in current design |
### 5.9 Security Boundaries
```
┌─────────────────────────────────────────────────────────────┐
│ KERNEL SPACE │
│ • Mama VM │
│ • VM scheduler │
│ • Fused public key │
│ • Hardware abstraction │
└─────────────────────────────────────────────────────────────┘
│
│ Capsule-defined boundary
▼
┌─────────────────────────────────────────────────────────────┐
│ PRIVILEGED VM SPACE │
│ • Messaging VM (CAP_ROUTE_MESSAGES) │
│ • Block I/O VM (CAP_BLOCK_PHYSICAL) │
└─────────────────────────────────────────────────────────────┘
│
│ Capability-checked boundary
▼
┌─────────────────────────────────────────────────────────────┐
│ USER VM SPACE │
│ • User session VMs │
│ • Constrained by signed capability grants │
│ • Cannot access other user's blocks │
│ • Cannot send unauthorized messages │
└─────────────────────────────────────────────────────────────┘
```
---
## 6. MESSAGING BACKBONE
### 6.1 Message Structure
```
┌─────────────────────────────────────────────────────────────┐
│ Message Header │
├─────────────────────────────────────────────────────────────┤
│ msg_id: uint64 Unique message identifier │
│ source_vm: uint32 Sender VM ID │
│ target_vm: uint32 Recipient VM ID │
│ msg_type: uint16 Message type code │
│ flags: uint16 Delivery flags │
│ payload_len: uint32 Payload size in bytes │
│ timestamp: uint64 Send timestamp (monotonic) │
├─────────────────────────────────────────────────────────────┤
│ Message Payload │
│ (variable length, message-type specific) │
└─────────────────────────────────────────────────────────────┘
```
### 6.2 Message Types
**System Messages:**
- `MSG_VM_BIRTH` - Mama→Messaging: new VM created
- `MSG_VM_DEATH` - Mama→Messaging: VM terminated
- `MSG_HARDWARE_EVENT` - Messaging→Mama: USB insert/remove
**Block I/O Messages:**
- `MSG_BLOCK_READ` - Request block read
- `MSG_BLOCK_WRITE` - Request block write
- `MSG_BLOCK_DATA` - Block data response
- `MSG_BLOCK_ACK` - Write acknowledgment
- `MSG_BLOCK_ERROR` - I/O error response
**User Messages:**
- `MSG_USER_DEFINED` - Application-specific messages
### 6.3 Message Routing
```
┌─────────────────────────────────────────────────────────────┐
│ Messaging VM │
├─────────────────────────────────────────────────────────────┤
│ Inbound Queue ──► │ Route │ ──► Per-VM Outbound Queues │
│ │ │ ├── Mama Queue │
│ │ │ ├── Block I/O Queue │
│ │ │ ├── User VM 1 Queue │
│ │ │ ├── User VM 2 Queue │
│ │ │ └── ... │
├─────────────────────────────────────────────────────────────┤
│ Routing Logic: │
│ 1. Verify source VM exists and is alive │
│ 2. Check source has CAP_MSG_SEND │
│ 3. Check target is in source's CAP_MSG_TARGETS │
│ 4. Enqueue to target's outbound queue │
│ 5. Wake target VM if sleeping │
└─────────────────────────────────────────────────────────────┘
```
### 6.4 Synchronous vs Asynchronous
**Asynchronous (default):**
- Sender posts message and continues
- Message queued for recipient
- Response comes as separate message
**Synchronous (CALL pattern):**
- Sender posts message and blocks
- Waits for response message
- Useful for RPC-style operations (e.g., block read)
---
## 7. BOOT SEQUENCE
### 7.1 Full Boot Flow
```
┌─────────────────────────────────────────────────────────────┐
│ PHASE 0: Hardware Initialization │
├─────────────────────────────────────────────────────────────┤
│ • UEFI boot │
│ • Memory map from firmware │
│ • Jump to kernel entry │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ PHASE 1: Kernel Initialization │
├─────────────────────────────────────────────────────────────┤
│ • Console init (serial UART) │
│ • PMM init (physical memory manager) │
│ • VMM init (virtual memory manager) │
│ • Heap init (kernel malloc) │
│ • IDT init (interrupt descriptor table) │
│ • APIC init (interrupt controller) │
│ • Timer init (APIC timer, TSC calibration) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ PHASE 2: Provisioning Check │
├─────────────────────────────────────────────────────────────┤
│ • Check provisioning flag in NVRAM │
│ • If NOT provisioned: enter provisioning mode │
│ └── Generate keypair, fuse, create admin drive, exit │
│ • If provisioned: load fused public key, continue │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ PHASE 3: Mama VM Creation │
├─────────────────────────────────────────────────────────────┤
│ • Allocate Mama heap │
│ • Create Mama VM (VM ID 0) │
│ • Load mama-init capsule │
│ • Execute Mama init │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ PHASE 4: System VM Birth │
├─────────────────────────────────────────────────────────────┤
│ • Mama births Messaging VM from messaging.4th capsule │
│ • Mama births Block I/O VM from block-io.4th capsule │
│ • System services now running │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ PHASE 5: Device Enumeration │
├─────────────────────────────────────────────────────────────┤
│ • USB controller initialization │
│ • Storage device discovery │
│ • Messaging VM registers for hardware events │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ PHASE 6: Ready for Users │
├─────────────────────────────────────────────────────────────┤
│ • System idle, waiting for thumbdrive insertion │
│ • Console shows: "Insert thumbdrive to login" │
│ • Or admin thumbdrive for administration │
└─────────────────────────────────────────────────────────────┘
```
### 7.2 Capsule Boot Order
```
Capsule Directory (in kernel or on system storage)
├── mama-init.4th ← Loaded first, by kernel
├── messaging.4th ← Birthed by Mama, second
├── block-io.4th ← Birthed by Mama, third
├── user-shell.4th ← Birthed on user login
└── (other capsules) ← As needed
```
---
## 8. IMPLEMENTATION PRIORITIES
Based on dependencies:
### 8.1 Critical Path
```
1. USB Driver (XHCI)
└── Need to detect thumbdrives
2. Block I/O Kernel Port
└── Need to read thumbdrive system region
3. SHA-256 in Kernel
└── Need to compute fingerprints
4. Ed25519 in Kernel
└── Need to verify signatures
5. Messaging Backbone VM
└── Need for all inter-VM communication
6. Block I/O VM
└── Need for all storage access
7. Capability Enforcement
└── Need to check grants at every operation
8. User Session VM
└── Finally can have interactive users
```
### 8.2 Estimated Complexity
| Component | LOC Estimate | Complexity |
|-----------|--------------|------------|
| XHCI driver | ~2500 | High |
| USB mass storage | ~800 | Medium |
| Block subsystem port | ~500 | Medium (reuse existing) |
| SHA-256 | ~400 | Low (well-known algorithm) |
| Ed25519 | ~600 | Medium (or use library) |
| Capability grant parser | ~300 | Low |
| Messaging VM | ~1000 | Medium |
| Block I/O VM | ~800 | Medium |
| Capability enforcement | ~500 | Medium |
| User session management | ~600 | Medium |
| Admin provisioning | ~400 | Medium |
**Total: ~8,400 LOC** for core security infrastructure
---
## 9. DATA STRUCTURES SUMMARY
### 9.1 VM Registry Entry (Extended)
```c
typedef struct {
uint32_t vm_id; // Unique VM identifier
uint32_t state; // VMState enum
uint64_t birth_capsule_id; // Which capsule birthed this
uint64_t birth_timestamp_ns; // When born
uint64_t birth_dict_hash; // Dictionary hash at birth
// Security fields (new)
uint8_t fingerprint[32]; // SHA-256 of user identity
uint64_t capability_bitmap; // Granted capabilities
uint32_t block_range_start; // First allowed block
uint32_t block_range_end; // Last allowed block
uint32_t msg_target_count; // Number of allowed targets
uint32_t msg_targets[16]; // Allowed message target VMs
// Resource tracking
uint64_t heap_base; // VM's heap start
uint64_t heap_size; // VM's heap size
uint64_t ram_blocks_base; // RAM block allocation
uint32_t flags;
uint32_t reserved;
} VMRegistryEntry;
```
### 9.2 Capability Bitmap
```c
// Capability flags
#define CAP_BLOCK_READ (1ULL << 0) // Can read blocks
#define CAP_BLOCK_WRITE (1ULL << 1) // Can write blocks
#define CAP_MSG_SEND (1ULL << 2) // Can send messages
#define CAP_MSG_RECEIVE (1ULL << 3) // Can receive messages
#define CAP_CAPSULE_LOAD (1ULL << 4) // Can request capsule load
#define CAP_CUSTOM_CAPSULE (1ULL << 5) // Can use custom capsule
#define CAP_SIGN_GRANTS (1ULL << 6) // Can sign capability grants (admin)
#define CAP_CREATE_USERS (1ULL << 7) // Can provision users (admin)
#define CAP_REVOKE_USERS (1ULL << 8) // Can revoke capabilities (admin)
#define CAP_SYSTEM_CONFIG (1ULL << 9) // Can modify system config (admin)
#define CAP_ALL_BLOCKS (1ULL << 10) // Can access any block (admin)
#define CAP_HARDWARE_IRQ (1ULL << 11) // Can receive hardware interrupts
#define CAP_ROUTE_MESSAGES (1ULL << 12) // Can route messages (messaging VM)
#define CAP_BLOCK_PHYSICAL (1ULL << 13) // Direct hardware I/O (block VM)
#define CAP_VM_ENUMERATE (1ULL << 14) // Can query VM registry
#define CAP_BLOCK_MAP (1ULL << 15) // Can create block mappings
#define CAP_ACL_ENFORCE (1ULL << 16) // Can enforce ACLs
// Convenience
#define CAP_USER_DEFAULT (CAP_BLOCK_READ | CAP_BLOCK_WRITE | \
CAP_MSG_SEND | CAP_MSG_RECEIVE)
#define CAP_ADMIN_ALL (0xFFFFFFFFFFFFFFFFULL)
```
### 9.3 Signed Capability Grant (On-disk)
```c
typedef struct __attribute__((packed)) {
// Header (16 bytes)
uint32_t magic; // "CPGR" = 0x43504752
uint16_t version; // Grant format version
uint16_t flags; // Grant flags
uint64_t grant_id; // Unique grant identifier
// Timestamps (16 bytes)
uint64_t created_ns; // Creation timestamp
uint64_t expires_ns; // Expiry (0 = never)
// Identity (32 bytes)
uint8_t fingerprint[32]; // SHA-256 that must match
// Capabilities (32 bytes)
uint64_t capability_bitmap; // Granted capabilities
uint32_t block_range_start; // First allowed block (logical)
uint32_t block_range_end; // Last allowed block (logical)
uint32_t msg_target_count; // Number of target VMs
uint32_t msg_targets[4]; // Allowed targets (expandable)
// Quotas (16 bytes)
uint32_t max_heap_mb; // Maximum heap size
uint32_t max_ram_blocks; // Maximum RAM blocks
uint32_t max_disk_blocks; // Maximum disk blocks
uint32_t reserved;
// Signature (64 bytes)
uint8_t signature[64]; // Ed25519 signature
} CapabilityGrant; // Total: 176 bytes
```
---
## 10. GLOSSARY
| Term | Definition |
|------|------------|
| **Mama VM** | Root VM that births and deaths all other VMs |
| **Baby VM** | Any VM birthed by Mama |
| **Capsule** | Immutable init block sequence defining VM personality |
| **PERSONALITY** | VM's immutable identity after birth (from capsule) |
| **DOMAIN** | Mama's construction space (never visible to babies) |
| **Fingerprint** | SHA-256 hash of identity sector, identifies user |
| **Capability Grant** | Signed document specifying user's permissions |
| **Fused Key** | Admin public key permanently written at provisioning |
| **Virtual BAM** | Per-user block allocation map (subset view) |
| **System Region** | Thumbdrive area invisible to user (metadata, ACLs) |
| **Admin Thumbdrive** | Single device with signing authority |
---
## 11. OPEN QUESTIONS
1. **Multiple simultaneous users?** Can multiple thumbdrives be inserted at once, with multiple concurrent sessions?
2. **Shared blocks between users?** Can users share specific blocks with each other? (Would require group capabilities)
3. **Network authentication?** Future extension for remote login?
4. **Audit log rotation?** System region audit log grows forever - need rotation policy?
5. **Capability delegation?** Can a user grant subset of their capabilities to another? (Currently: no)
6. **Time-limited sessions?** Automatic logout after idle timeout?
---
## 12. REVISION HISTORY
| Version | Date | Changes |
|---------|------|---------|
| 0.1 | 2026-01-27 | Initial architecture draft |
---
**Document Status:** Draft - Pending Review
**Authors:** Claude (AI Assistant), Robert A. James
**Next Steps:**
1. Review and refine security model
2. Prototype USB detection
3. Implement Ed25519/SHA-256 in kernel
4. Design message format in detail
5. Implement Block I/O VM capsule
@@ -0,0 +1,228 @@
> **HISTORICAL (docs triage 2026-10-14).** A test-coverage audit of StarForth v3.0.3 / LithosAnanke v1.0.8, 2026-06-03; POST has grown since (1052 tests).
> Instead: v3/src/test_runner/ and the POST line of any current boot. Moved here from `docs/TEST_GAPS.md`.
# StarForth Dictionary Test Coverage — Gap Audit
**Branch:** `lithosananke` | **StarForth v3.0.3 / LithosAnanke v1.0.8**
**Audited:** 2026-06-03
---
## Summary
| Metric | Count |
|--------|-------|
| Total registered words | ~230 |
| Words with at least one test | ~115 |
| Words with **no** test | ~115 |
| Test files | 20 |
| Untested word categories | 5 (editor, inference, log, physics-diag, q48) |
Coverage is solid for the foundational FORTH-79 core but has critical holes
in control-flow completeness, format output, memory ops, and the S" word
just added in v3.0.3.
---
## Priority 1 — FORTH-79 Core: Missing Critical Words
These are standard FORTH-79 words used in virtually all real programs.
Missing tests here are compliance failures.
| Word(s) | Source file | Why critical |
|---------|-------------|--------------|
| `1+` `1-` `2+` `2-` `2*` `2/` | arithmetic_words.c | Shorthand increment/shift ops; used in almost every program. Arithmetic test only covers `/MOD` variants, not these. |
| `I` `J` | control_words.c | Loop index access. Every `DO...LOOP` that reads the index uses `I`; nested loops need `J`. No test at all. |
| `EXIT` | control_words.c | Return from word mid-execution. Essential for early-return patterns. No test. |
| `LEAVE` | control_words.c | Early exit from `DO...LOOP`. No test. |
| `UNLOOP` | control_words.c | Required to clean the return stack before `EXIT` inside a loop. Omitting it is a stack-corruption bug; no test exercises this. |
| `AGAIN` | control_words.c | `BEGIN...AGAIN` infinite loop. Common pattern, completely untested. |
| `CASE` `OF` `ENDOF` `ENDCASE` | control_words.c | Full `CASE` structure. Entire construct untested. |
| `+!` `-!` | memory_words.c | Modify-in-place. The single most common memory idiom in FORTH after `@` and `!`. No test. |
| `FILL` `MOVE` `ERASE` | memory_words.c | Bulk memory primitives. Used by string ops, block subsystem, array initialisation. No test. |
| `2!` | memory_words.c | Store double/address pair. `2@` is tested; its store partner is not. |
---
## Priority 2 — S" (New in v3.0.3) — Urgent
`S"` was added as a proper IMMEDIATE primitive in this release. It has zero
test coverage. Regression risk is high since the implementation is new.
| Word(s) | Source file | Gap |
|---------|-------------|-----|
| `S"` | string_words.c | No test for interpret-mode push (c-addr u), compile-mode inline (`(s")` runtime), or use inside a `:` definition. |
| `(s")` | string_words.c | Internal runtime for compiled `S"`. Exercised only by compiled `S"` — needs a compile-mode test. |
| `BL` | string_words.c | Space-character constant. Trivial but untested; often paired with `S"`. |
| `SOURCE` `>IN` | string_words.c | Input stream state. `SOURCE` returns ( c-addr u ); `>IN` is the offset. Both untested. |
---
## Priority 3 — Format / Output Words
`format_words.c` has 19 registered words. Only `.` and `BASE`/`DECIMAL` are
touched (from io_words_test.c). The pictured numeric output group is
completely dark.
| Word(s) | Source file | Gap |
|---------|-------------|-----|
| `HEX` `OCTAL` | format_words.c | Base switching. Used constantly in systems work. No test. |
| `.S` | format_words.c | Print entire stack without consuming it. Core debugging primitive. No test. |
| `?` | format_words.c | Print cell at address (` @ . `). Heavily used. No test. |
| `.R` `U.` `U.R` | format_words.c | Right-justified and unsigned output. No test. |
| `D.` `D.R` | format_words.c | Double-number output. No test. |
| `<#` `#` `#S` `#>` `HOLD` `SIGN` | format_words.c | Pictured numeric output group. Entire 6-word subsystem untested. |
| `DUMP` | format_words.c | Memory hex dump. No test. |
---
## Priority 4 — Logical / Comparison Gaps
logical_words_test.c covers the common cases but misses several FORTH-79 words.
| Word(s) | Source file | Gap |
|---------|-------------|-----|
| `0<>` | logical_words.c | Not-equal-to-zero. Symmetric counterpart to `0=`. No test. |
| `U<` `U>` | logical_words.c | Unsigned comparison. Critical for address arithmetic and char comparisons. No test. |
| `WITHIN` | logical_words.c | Range test. No test. |
| `TRUE` `FALSE` | logical_words.c | Boolean constants. Untested (though they're trivially `0` and `-1`). |
---
## Priority 5 — Stack Word Gaps
stack_words_test.c covers DUP DROP SWAP OVER ROT DEPTH PICK ROLL.
Two standard words missing:
| Word(s) | Source file | Gap |
|---------|-------------|-----|
| `?DUP` | stack_words.c | Conditional dup (dup only if non-zero). Common idiom. No test. |
| `-ROT` | stack_words.c | Reverse rotate. Tested implicitly via `ROT` but never directly. |
---
## Priority 6 — Double Number Gaps
double_words_test.c is thorough but misses:
| Word(s) | Source file | Gap |
|---------|-------------|-----|
| `S>D` | double_words.c | Convert single to double. The entry point for all `D`-word arithmetic. No test. |
| `D2*` `D2/` | double_words.c | Double arithmetic shifts. No test. |
| `2>R` `2R>` `2R@` | double_words.c | Double-number return stack. No test. |
---
## Priority 7 — Mixed Arithmetic Gap
| Word(s) | Source file | Gap |
|---------|-------------|-----|
| `M-` | mixed_arithmetic_words.c | `M+` and `M*` are tested; `M-` is not. |
---
## Priority 8 — Compilation / Meta Words
These are used to build user-defined IMMEDIATE words and to manipulate the
dictionary at compile time. None are tested.
| Word(s) | Source file | Gap |
|---------|-------------|-----|
| `COMPILE` `[COMPILE]` | defining_words.c | Used to force compilation of words inside IMMEDIATE definitions. No test. |
| `[']` | string_words.c | Compile-time version of `'` (tick). Returns XT of next word at compile time. No test. |
| `LIT` | defining_words.c | Internal compile-time literal push. No test. |
| `STATE` | defining_words.c / dictionary_manipulation_words.c | Dual-registered. Compile/interpret switch. No test. |
| `ALIGN` | dictionary_words.c | Align `HERE` to cell boundary. No test. |
| `'` (TICK) | dictionary_manipulation_words.c | Fetch execution token of named word. Core of `[']` and `EXECUTE`. No test. |
| `LITERAL` `[LITERAL]` | string_words.c | Compile a literal at runtime / inside definitions. Partially touched in io test but no dedicated test. |
---
## Priority 9 — Dictionary Traversal Words
These enable introspection of the dictionary structure. No tests at all.
| Word(s) | Source file | Gap |
|---------|-------------|-----|
| `>NAME` `NAME>` | dictionary_manipulation_words.c | Convert between CFA and NFA. No test. |
| `>LINK` `LINK>` | dictionary_manipulation_words.c | Navigate dictionary linked list. No test. |
| `CFA` `NFA` `LFA` `PFA` | dictionary_manipulation_words.c | Classic field-access words. No test. |
| `TRAVERSE` | dictionary_manipulation_words.c | Walk dictionary chain. No test. |
| `INTERPRET` | dictionary_manipulation_words.c | The outer interpreter. No test. |
---
## Priority 10 — System Words
| Word(s) | Source file | Gap |
|---------|-------------|-----|
| `ABORT"` `(ABORT")` | system_words.c | Conditional abort with message. Used in error handling. No test. |
| `WORDS` `VLIST` | system_words.c | Dictionary listing. No test. |
| `SEE` | system_words.c | Decompiler. No test. |
| `COLD` `WARM` | system_words.c | System restart/reinit. No test (understandably risky to test directly). |
| `QUIT` | system_words.c | Outer interpreter restart. No test. |
---
## Priority 11 — Block Word Gap
| Word(s) | Source file | Gap |
|---------|-------------|-----|
| `-->` | block_words.c | Chain-load next block. Used in multi-block definitions. No test. |
---
## Priority 12 — Lifecycle / Capsule Words
Capsule-BIRTH/KILL/PAUSE/RESUME/USE have partial coverage from mama_forth tests
but direct functional tests are missing.
| Word(s) | Source file | Gap |
|---------|-------------|-----|
| `KILL` `PAUSE` `RESUME` | lifecycle_words_hosted.c | Capsule lifecycle management. No direct test. |
| `USE` | lifecycle_words_hosted.c | Switch active VM. No test. |
---
## Priority 13 — Entire Untested Categories
These word groups have **zero test coverage**. Lower urgency than gaps above
because they are StarForth-specific extensions (not FORTH-79 compliance),
but they should be ticketed.
| Category | Source file | Word count | Notes |
|----------|-------------|------------|-------|
| Q48 fixed-point | q48_words.c | 21 | POST unit tests exist for the C layer but no FORTH-word tests |
| Inference | inference_words.c | 19 | Physics adaptive engine; complex to test deterministically |
| Log words | log_words.c | 7 | LOG-ERROR … LOG-LEVEL@; simple but untested |
| Physics diagnostics | physics_diagnostic_words.c | 4 | PHYSICS-WORD-METRICS etc. |
| Physics freeze | physics_freeze_words.c | 9 | FREEZE-WORD, HEAT@, etc. |
| Physics benchmark | physics_benchmark_words.c | 6 | BENCH-DICT-LOOKUP etc. |
| Physics pipelining diag | physics_pipelining_diagnostic_words.c | 6 | PIPELINING-SHOW-STATS etc. |
| Editor | editor_words.c | 4 | L, S, SHOW, EDIT — block editor; very low priority |
---
## Work Order (suggested sequence)
```
1. [ ] P1a arithmetic_words_test.c — add 1+ 1- 2+ 2- 2* 2/
2. [ ] P1b control_words_test.c — add I J EXIT LEAVE UNLOOP AGAIN
3. [ ] P1c control_words_test.c — add CASE OF ENDOF ENDCASE
4. [ ] P1d memory_words_test.c — add +! -! 2! FILL MOVE ERASE
5. [ ] P2 string_words_test.c — add S" (s") BL SOURCE >IN
6. [ ] P3a format_words_test.c — new file: HEX OCTAL .S ? .R U. U.R D. D.R
7. [ ] P3b format_words_test.c — add <# # #S #> HOLD SIGN DUMP
8. [ ] P4 logical_words_test.c — add 0<> U< U> WITHIN TRUE FALSE
9. [ ] P5 stack_words_test.c — add ?DUP -ROT
10.[ ] P6 double_words_test.c — add S>D D2* D2/ 2>R 2R> 2R@
11.[ ] P7 mixed_arithmetic_words_test.c — add M-
12.[ ] P8a defining_words_tests.c — add COMPILE [COMPILE] LIT STATE
13.[ ] P8b dictionary_manipulation_words_test.c — add ' ['] ALIGN LITERAL
14.[ ] P9 dictionary_manipulation_words_test.c — add >NAME NAME> CFA NFA LFA PFA TRAVERSE INTERPRET
15.[ ] P10 system_words_test.c — new file: ABORT" WORDS VLIST SEE
16.[ ] P11 block_words_test.c — add -->
17.[ ] P12 lifecycle capsule tests — add KILL PAUSE RESUME USE
18.[ ] P13a q48_words_test.c — new file: all 21 Q48 FORTH words
19.[ ] P13b log_words_test.c — new file: LOG-ERROR … LOG-LEVEL@
20.[ ] P13c physics words tests — new files as needed
```
@@ -0,0 +1,218 @@
> **HISTORICAL (docs triage 2026-10-14).** A session hand-off plan from 2026-06-10, on the pre-split `lithosananke` branch; every item in it is long done or overtaken.
> Instead: .claude/CLAUDE.md and docs/fabric/FABRIC-3.md for current status. Moved here from `docs/NEXT_SESSION.md`.
# Next Session Plan
Generated at end of session `cdcb1844` (2026-06-10).
Branch at close: `lithosananke` (merged and pushed; all three arches boot to `ok>`)
---
## What Was Accomplished This Session
- Fixed SysV ABI stack alignment bug in `kernel_entry.S` (`sub rax, 8`)
- Removed redundant kmalloc stack switch from `kernel_main.c`
- Fixed GOT/PE crash in `apply_sgr` — `FB_ANSI_PALETTE` got
`__attribute__((visibility("hidden")))` in both `framebuffer.h` and
`framebuffer.c`; EXEC-DOE now runs to full completion (160,673 rows)
- Added framebuffer host render test (`tools/fbtest.c`) and QEMU screendump
(`scripts/qemu_screenshot.sh`) to the amd64 `qemu` target
- CLAUDE.md: one-process-at-a-time build rule
- Design doc: `docs/reference/kernel-args/DESIGN.md` — UEFI
command-line argument system (KernelArgs)
---
## Task 0 — Fix doe.4th EXEC regression (do first)
All three architectures boot to `ok>` but `S" doe.4th" EXEC` fails at
runtime with "EXEC: failed: doe.4th" on every arch. Root cause: merge
conflict resolution took the remote's self-executing `doe.4th` (480 runs)
and `init.4th` (calls `S" doe.4th" EXEC`), but the capsule fails at runtime.
`EXEC-DOE` word is also absent (removed from `init.4th` by the remote).
Investigation starting point:
- Check `capsule_exec_init` return path — add diagnostic to distinguish
NOT_FOUND vs HASH_MISMATCH vs runtime error
- Verify new `doe.4th` block structure (correct block numbers, no undefined words)
- Consider restoring `EXEC-DOE` as an alias once doe.4th runs correctly
---
## Task 1 — Carry-over acceptance tests (do first, one at a time)
All three architectures now confirmed on `lithosananke`:
amd64 ✓ aarch64 ✓ riscv64 ✓
These were completed at end of session. No action needed unless a new
change is made — then re-run all three before merging.
```bash
make -f Makefile.starkernel ARCH=aarch64 clean qemu
make -f Makefile.starkernel ARCH=riscv64 clean qemu
```
Commit logs after each run. Do not proceed to any implementation task
until all three architectures have a clean `ok>` log committed.
---
## Task 2 — Memory size audit
Before tuning anything, measure the actual headroom:
- BSS stack (`g_kernel_stack`): currently 2 MB — log the deepest RSP
observed during EXEC-DOE and compare against the stack base
- VM data stack / return stack depths — check `vm.h` for current limits
- Rolling window buffer (`ROLLING_WINDOW_SIZE=4096`) — verify it isn't
being silently truncated under DoE load
- `KERNEL_HEAP_SIZE` (2 GB allocated, 1 GB physical in QEMU) — confirm
kmalloc never hits the limit during a full DoE run
There are no hard rules on these sizes; increase freely if headroom is
tight. Document findings in `docs/lithosananke/memory-audit.md`.
---
## Task 3 — Implement KernelArgs
Design doc: `docs/reference/kernel-args/DESIGN.md`
Implementation order (one commit per step):
1. `include/starkernel/kernel_args.h` — struct + default macros
2. `include/starkernel/boot_info_offsets.h` — assembly-visible offsets
with `_Static_assert` checks in C
3. `include/starkernel/uefi.h` — add `kernel_stack_base`,
`kernel_stack_size`, `KernelArgs args` to `BootInfo`
4. `include/starkernel/cmdline.h` + `src/starkernel/boot/cmdline.c` —
UCS-2→ASCII, tokeniser, parser
5. `src/starkernel/boot/uefi_loader.c` — call `cmdline_parse`, allocate
dynamic stack via `AllocatePages`
6. `src/starkernel/arch/amd64/kernel_entry.S` — dynamic stack switch,
fall back to BSS if `kernel_stack_base == 0`
7. `src/starkernel/kernel_main.c` — use `args.heap_size`, honour
`args.run_doe` and `args.log_level`
8. `Makefile.starkernel` — pass `--doe` via OVMF boot entry; remove socat
EXEC-DOE injection
Run all three arch acceptance tests after step 8.
---
## Task 4 — ISO real-hardware boot audit
The ISO built by xorriso works in QEMU but has a known gap for real
hardware (xorriso warns: "no directory /EFI/BOOT"). Real commodity UEFI
firmware expects `BOOTX64.EFI` present in the ISO *filesystem* at
`/EFI/BOOT/BOOTX64.EFI`, not just as an El Torito boot image.
Targets:
- **amd64** — commodity x86-64 machine: add `/EFI/BOOT/BOOTX64.EFI` to
the ISO filesystem tree in the Makefile xorriso invocation
- **aarch64 / RPi4** — needs `BOOTAA64.EFI`; RPi4 requires the
tianocore RPi4 UEFI firmware layer on the SD card/USB first; the ISO
sits on top
- **aarch64 / BeagleBone AI-64** (aspirational) — same EFI path as RPi4
Document the verified boot procedure for each target in
`docs/lithosananke/hardware-boot.md`.
---
## Task 5 — `REBOOT` word
A FORTH word that optionally accepts a next-boot argument string and
performs a cold reset via UEFI Runtime Services.
Key design decisions (agreed this session):
- **Not interpreter-only at the C level** — no `STATE` check, no special
flag
- **ACL-controlled** — the word-level ACL system (Task 6) governs access
- **On ACL denial**: emit warning, return to REPL; system keeps running
- **No abort** — consistent with how all sensitive words will work under ACL
Implementation sketch:
```forth
S" --doe --stack=8M" REBOOT \ reboot with next-boot args
REBOOT \ plain cold reboot
```
Under the hood:
1. If a string is on the stack: write it to a UEFI variable
(`StarForthNextArgs` under a custom GUID) via `RT->SetVariable`
2. Call `RT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL)`
3. Loader reads the variable on next boot, merges with `LoadOptions`;
clears the variable after reading (one-shot)
`REBOOT` with no args is a plain cold reboot.
---
## Task 6 — `USE` word and resilient capsule loading
A general FORTH word (not capsule-specific) for loading external blobs.
```forth
S" hires-video.4th" USE
S" sound-card-1" USE \ fails → line gets commented out
S" sound-card-2" USE
```
On failure, `USE`:
1. Locates the calling line in the block buffer
2. Prepends `\ ` to comment it out (writes to RAM block)
3. Continues — one failure does not stop subsequent `USE` calls
4. Up to 16 lines per block may be commented out
**Self-healing property:** over multiple boots the system converges to a
stable configuration. Hardware that isn't present or drivers that don't
work are silently excluded. Hardware that works is locked in.
`REBOOT` integrates naturally:
```forth
S" hires-video.4th" USE
REBOOT \ apply hardware init needing a cold reset
hires-video-init? NOT IF
\ didn't take — USE mechanism will comment it out on next boot
THEN
```
---
## Task 7 — Forward word declarations
A FORTH analog of C prototypes: declare a word's name and stack effect
before its implementing capsule is loaded. Enables circular dependencies
between capsules without load-order brittleness.
```forth
FORWARD: init-network ( -- ) \ stub; filled when net capsule loads
FORWARD: video-mode? ( -- f ) \ stub; filled when video capsule loads
```
If a forward-declared word is called before its definition arrives, it
emits a warning and returns without crashing. When the implementing
capsule loads and defines the word, the stub is replaced.
This is a general VM feature — not kernel or capsule specific.
---
## Task 8 — Word-level ACL system (existing design, next to implement)
Design doc: `docs/reference/word-acl/DESIGN.md`
This is already designed. It is the policy engine that makes Tasks 5–7
safe. Implement before or alongside Task 5 (`REBOOT`) since `REBOOT`
depends on ACL for its safety guarantees.
---
## Pointer for Next Session
Start with Task 1 (aarch64 + riscv64 acceptance). Read this file and the
design docs listed above before touching any code. Present the task order
to Captain Bob for approval before each implementation step.
All development stays on the working branch; never merge to master.
@@ -0,0 +1,82 @@
> **HISTORICAL (docs triage 2026-10-14).** A generated diagnostic report from one test run, 2026-06-30.
> Instead: the boot POST in any current logs/ run. Moved here from `docs/BREAK_ME_REPORT.md`.
# 🔥 STARFORTH BREAK-ME DIAGNOSTIC REPORT 🔥
## Executive Summary
**Generated:** 2026-06-30 16:53:09
**Test Mode:** ULTRA-COMPREHENSIVE DIAGNOSTIC
**Purpose:** This report documents the results_run_01_2025_12_08 of the most exhaustive testing suite ever run on StarForth. Every word, every edge case, every pathological scenario has been tested to ensure rock-solid reliability and FORTH-79 standard compliance.
---
## 📊 Performance Metrics
| Metric | Value |
|--------|-------|
| Test Duration | 0.00 seconds |
| Total Tests | 1003 |
| Tests/Second | inf |
## 🖥️ System Information
| Component | Specification |
|-----------|---------------|
| VM Architecture | Direct-threaded |
| Standard | FORTH-79 + StarForth Extensions |
| Cell Size | 8 bytes |
| Stack Size | 1024 cells |
| Memory | 5242880 bytes |
---
## 🎉 EASTER EGG: THE STARFORTH CHALLENGE 🎉
```
⭐ C O N G R A T U L A T I O N S ⭐
You've discovered the hidden StarForth challenge!
Your system just survived 1003 exhaustive tests.
But can YOU survive the ULTIMATE FORTH CHALLENGE?
🏆 THE STARFORTH MASTER CHALLENGE 🏆
Write a Forth program that:
1. Prints the Fibonacci sequence up to 1000
2. Uses ONLY the following words:
: ; DUP OVER DROP SWAP . CR < IF THEN DO LOOP
3. Fits in exactly 79 characters (FORTH-79 tribute!)
Submit your solution to the StarForth community!
Hint: Think recursively, but remember FORTH-79
doesn't have RECURSE... 😉
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
BONUS SECRET: If you ran --break-me, you're already
in the top 1% of Forth enthusiasts. Welcome to the
elite club! Your system just proved it can handle
anything you throw at it.
May your stacks be balanced and your words defined,
-- The StarForth Development Team ⭐
```
### 🎮 More Easter Eggs to Find:
1. Try defining a word called `STARSHIP` and see what happens
2. Run `42 ENTROPY@ .` to see the universe's favorite number
3. Type `WORDS` and count how many contain 'STAR'
4. Check what happens when you `FORGET FORGET` (just kidding, don't!)
---
*Generated by StarForth --break-me mode*
*Copyright (c) 2025 Robert A. James - StarshipOS Forth Project*
@@ -0,0 +1,100 @@
> **HISTORICAL (docs triage 2026-10-14).** The write-up of one fix (APIC timer ISR, amd64), done.
> Instead: the code itself (kernel/src/arch/amd64/). Moved here from `docs/lithosananke/amd64-isr-fix/README.md`.
# APIC Timer ISR Fix — amd64
**Date**: 2026-06-03
**Branch**: `claude/starforth-architecture-review-oubN0`
**Commits**: `fb0c256`, `901f827`
---
## Problem
The LithosAnanke amd64 kernel was triple-faulting on the first APIC timer interrupt,
causing QEMU to exit immediately after printing `ok>`. The adaptive heartbeat never
fired and `Heartbeat: N ticks` never appeared in serial logs.
## Root Cause
The kernel is compiled with `-fPIC -fvisibility=hidden` (required for UEFI PE
relocation). Assembly symbols `isr_stub_table` and `isr_stub0` in `isr.S` were
declared `.global` with **default visibility**. The C compiler therefore accessed
them through GOT indirection. However, the linker — building a final non-shared
binary — collapsed the GOT references to point directly at the symbols themselves.
The net effect: "load from GOT[`isr_stub_table`]" loaded the 8-byte instruction
bytes of `isr_stub0` (`0x006a90eb006a006a`) rather than its address. Both
`link_time_addr` and `runtime_addr` in `arch_interrupts_init()` became the same
wrong value (instruction bytes), so `reloc_offset = 0` and all 256 IDT entries
received garbage handler addresses. IDT[32] was set to `0x6a006afffffe91e9`
(non-canonical), which triggered #GP → double fault → triple fault on the first
timer delivery.
The bug was confirmed by disassembling `arch_interrupts_init()` in the loader PE:
the compiler emitted a `mov` (load from memory) for `&isr_stub0` instead of a
`lea` (compute address), reading the function's instruction bytes.
## Fix
Two changes, one line each:
**`src/starkernel/arch/amd64/isr.S`** — Added `.hidden` directives for all symbols
referenced from C:
```asm
.hidden isr_stub_table
.hidden isr_stub0
.hidden isr_stub32
.hidden isr_stub_default
.hidden isr_common_entry
```
**`src/starkernel/arch/amd64/interrupts.c`** — Added visibility attributes to the
`extern` declarations:
```c
extern void *isr_stub_table[IDT_ENTRIES] __attribute__((visibility("hidden")));
extern void isr_stub0(void) __attribute__((visibility("hidden")));
```
With hidden visibility, the compiler uses direct RIP-relative `lea` instead of GOT
indirection, yielding correct runtime addresses for all 256 IDT entries.
## Result
| Criterion | Before | After |
|---|---|---|
| IDT[32] handler | `0x6a006afffffe91e9` (corrupt) | `0x3d90251c` (valid canonical address) |
| First timer interrupt | #GP → triple fault → QEMU exit | ISR fires cleanly, returns via `iretq` |
| `PARITY:OK` | ✅ (unaffected) | ✅ |
| `Init: init.4th OK` | ✅ (unaffected) | ✅ |
| `ok>` REPL | ✅ reached, then immediate crash | ✅ runs indefinitely |
| `Heartbeat: N ticks` | Never | Every second at 100 Hz, TIME-TRUST ≈ 0.999 |
## Secondary Fix
`repl_print_dec32`, `repl_lapic_ccr`, `repl_print_hex32`, and `idle_iters` in
`repl.c` are x86-64 specific (LAPIC MMIO, `pushfq`). They were unguarded, causing
`-Werror=unused-function` / `unused-variable` failures on aarch64 (clang) and
riscv64 (gcc). All moved inside `#ifdef ARCH_AMD64`.
## Acceptance Testing
All three architectures must boot to `ok>` with `PARITY:OK` and `Init: init.4th OK`.
amd64 additionally shows `Heartbeat: N ticks TIME-TRUST≈0.999` repeating at 1 Hz.
```bash
make -f Makefile.starkernel ARCH=amd64 clean qemu
make -f Makefile.starkernel ARCH=aarch64 clean qemu
make -f Makefile.starkernel ARCH=riscv64 clean qemu
```
Verify each log:
```bash
grep "PARITY:OK" logs/qemu-<arch>-*.log
grep "Init: init.4th OK" logs/qemu-<arch>-*.log
grep "ok>" logs/qemu-<arch>-*.log
grep "Heartbeat:" logs/qemu-amd64-*.log | head -5
```
@@ -0,0 +1,412 @@
> **HISTORICAL (docs triage 2026-10-14).** The child-VM birthing plan and its acceptance record; built and live since (M7.1).
> Instead: docs/reference/M7.1.md and docs/fabric/. Moved here from `docs/birthing/PLAN.md`.
# Birthing Plan: Child VMs Born of Hera
**Status:** DRAFT — requires Captain Bob approval before any implementation begins
**Branch:** `birthing` (off `lithosananke`)
**Authors:** Claude Code + Captain Bob
**Date:** 2026-05-24
---
## 1. Vision
Three named VMs form the initial constellation of LithosAnanke:
| VM Name | Role |
|---------|------|
| **Hera** | Mama VM — orchestrates all other VMs; runs `capsules/init.4th` |
| **Hermes** | Messaging stratum — pub/sub between VMs; runs `capsules/hermes/init.4th` |
| **Artemis** | Storage and memory manager; runs `capsules/artemis/init.4th` |
**Hades** remains the kernel + HAL substrate beneath all of them.
For now, Hera's job is simply: birth, start, stop, and kill VM instances.
Concurrent scheduling, inter-VM messaging, and storage management are later milestones.
Every VM — including Hermes and Artemis — carries the same lifecycle primitives.
A VM can birth and manage other VMs. The infrastructure is uniform.
---
## 2. Hard Constraints
Fixed by the execution model. Hera's implementation is not constrained — she expands
as the design requires.
| Constraint | Implication |
|------------|-------------|
| Same process as Hera | No `fork()`, no `pthread_create()` |
| No threads | Scheduling is cooperative, inside the interpreter loop |
| No OS processes | VMs share Hera's address space |
| ANSI C99, `-Wall -Werror` | No GNU extensions |
| Hades is the substrate | All I/O, timing, and memory from Hades (kernel+HAL) |
---
## 3. VM Identity and Naming
### 3.1 Every VM Has a Name
The current `VMRegistryEntry` tracks VMs by numeric ID only. This must be extended with a
symbolic name field. A VM's name:
- Is set at birth (derived from the capsule namespace — see §5)
- Is displayed in every log line emitted by that VM
- Is the argument to all lifecycle words: `S" Artemis" BIRTH`, `S" Artemis" KILL`, etc.
- Is unique within a session (no two live VMs share a name)
- Is case-preserved but case-insensitive for lookup
### 3.2 VM Registry Extension
`VMRegistryEntry` needs a `name` field (at minimum `char name[64]`). The name is:
- Set by `BIRTH` at VM creation time
- Cleared on `KILL` (slot becomes reusable)
- Logged in every parity record alongside the numeric VM ID
### 3.3 Log Prefix — Critical
Every line of console output emitted by a VM is prefixed with its name:
```
[Hera] ok
[Hermes] pub/sub ready
[Artemis] storage initialized
[Hera] 2 VMs alive
```
This applies to `EMIT`, `TYPE`, `.`, `.S`, `CR`, and all I/O words. The prefix is injected
at the HAL console layer — the VM does not format it; Hades prints it automatically based
on the current active VM context.
---
## 4. The Five Primitive Forth Words
These words are **built-in C primitives** registered in every VM's dictionary at startup.
They are not defined in Forth — they are part of the base word set, available to all VMs.
### Stack signatures use the counted-string convention: `( c-addr u -- )`
---
### `BIRTH ( c-addr u -- )`
Birth a new VM from the capsule whose namespace matches the given name.
**Mapping:** `S" Artemis"` → lowercase `"artemis"` → capsule name `artemis:init.4th`
(the standard capsule for a named VM is `<name>:init.4th`).
**Sequence:**
1. Lowercase the name string
2. Construct capsule name: `<name>:init.4th`
3. Look up capsule in the directory by name
4. Verify capsule is `FLAG_PRODUCTION` + `FLAG_ACTIVE` and not `FLAG_REVOKED`
5. Allocate a new VM context (full VM — Hera expands her pool as needed)
6. Execute the capsule init (via existing `capsule_exec_init` path)
7. Register VM under the symbolic name in the extended `VMRegistryEntry`
8. Log parity record: `PARITY:BIRTH name=Artemis vm_id=N capsule_id=X`
9. On success: push 0; on failure: push error code
**If a VM named "Artemis" is already alive:** check its health. If healthy, skip the birth
and log the fact. Do not error, do not replace. BIRTH is idempotent for healthy VMs.
---
### `KILL ( c-addr u -- )`
Destroy a named VM. The VM's resources are freed and its registry slot is cleared.
**Sequence:**
1. Look up VM by name in registry
2. If not found: push error code, return
3. Forcibly terminate any pending execution in that VM
4. Free the VM's stacks, dictionary, and memory
5. Clear registry slot (name + state = DEAD)
6. Log parity record: `PARITY:KILL name=Artemis vm_id=N`
7. Push 0 on success
**Note:** KILL is unconditional. It does not wait for the VM to reach a yield point.
At this phase (no concurrent execution), the VM is idle when KILL is called.
---
### `START ( c-addr u -- )`
Begin or resume execution of a named VM.
**At this phase:** `START` runs the VM to completion (or until it calls `STOP` on itself)
before returning control to the caller. Concurrent interleaved execution is a later milestone.
**Sequence:**
1. Look up VM by name
2. If state is EMBRYO or STOPPED: set state to LIVE, transfer execution
3. If state is LIVE: error (already running)
4. On VM completion or self-STOP: return control to the calling VM
5. Push 0 on success
---
### `STOP ( c-addr u -- )`
Suspend a named VM. Its execution state is preserved; `START` will resume it.
Any VM can STOP any other. Authority comes from identity — a VM may assume another
identity for failsafe and recovery. The identity assumption mechanism is a future
milestone; in Phase 1, cross-VM STOP is permitted without restriction.
**Sequence:**
1. Verify name matches the current VM
2. Save execution state (IP, stacks)
3. Set state to STOPPED
4. Return control to the VM that called `START`
---
### `USE ( c-addr u -- )`
Make a named VM the active console target. Subsequent REPL input and output is directed
to and from that VM until another `USE` call or the VM dies.
```forth
S" Hermes" USE \ REPL now talks to Hermes
: send-test S" hello" PUBLISH ;
S" Hera" USE \ REPL returns to Hera
```
USE is **system-wide** — it is not scoped to a capsule or identity. All REPL input and
output redirects to the named VM until the next `USE` call. The `[Name]` prefix in the
console reflects the active USE target.
**Sequence:**
1. Look up VM by name in registry
2. Set as the active system-wide REPL/console VM
3. Console prefix changes to `[VMName]`
4. Stack unchanged (no return value)
---
## 5. Capsule Namespace Convention
### 5.1 Directory Structure
Each named VM owns a subdirectory under `capsules/`:
```
capsules/
├── init.4th ← Hera's capsule ONLY (root level, no subdir)
├── hermes/
│ └── init.4th ← Hermes' capsule
└── artemis/
└── init.4th ← Artemis' capsule
```
**`capsules/init.4th` is Hera's exclusive init.** No other VM uses the root-level init.
Do not place general capsules there. Do not recreate the old `conf/` directory.
### 5.2 How mkcapsule Names Capsules
`tools/mkcapsule.c` scans `capsules/` recursively. It encodes relative paths by replacing
`/` with `:`. So:
| File path | Capsule name |
|-----------|-------------|
| `capsules/init.4th` | `init.4th` |
| `capsules/hermes/init.4th` | `hermes:init.4th` |
| `capsules/artemis/init.4th` | `artemis:init.4th` |
### 5.3 BIRTH Name → Capsule Name Mapping
`BIRTH` lowercases the VM name and appends `:init.4th`:
| Forth call | Capsule looked up |
|------------|------------------|
| `S" Hera" BIRTH` | `init.4th` (special case — root) |
| `S" Hermes" BIRTH` | `hermes:init.4th` |
| `S" Artemis" BIRTH` | `artemis:init.4th` |
| `S" MyWorker" BIRTH` | `myworker:init.4th` |
The root-level `init.4th` is a special case: `S" Hera" BIRTH` is how a future VM would
re-birth Hera; at bootstrap, Hera boots from it automatically.
### 5.4 mkcapsule Flag Mapping
The capsule flag (`FLAG_PRODUCTION` vs `FLAG_EXPERIMENT`) is determined by the directory
prefix — **not the file name**. Under the current `mkcapsule` logic:
- `capsules/hermes/init.4th` → does not match `production:*`, `core:*`, or `domains:*`
→ currently gets `FLAG_EXPERIMENT`
**All capsules carry both `FLAG_PRODUCTION` and `FLAG_EXPERIMENT`.** Birth eligibility is
not gated on the flag type — any capsule can be used for any identity. mkcapsule will be
updated to set both flags on every capsule it generates. The distinction between production
and experiment remains in the flags for audit/logging purposes but does not block BIRTH.
---
## 6. Capsule Content (Stubs)
Hermes and Artemis capsule directories exist but are empty (`.gitkeep` only). They need
`init.4th` stubs before the system can BIRTH them.
### `capsules/hermes/init.4th` (stub)
Should:
- Print `[Hermes] initializing` (or similar boot message)
- Define Hermes' pub/sub vocabulary (placeholder for now)
- Leave Hermes in a known state (not just empty)
### `capsules/artemis/init.4th` (stub)
Should:
- Print `[Artemis] initializing`
- Define Artemis' storage/memory vocabulary (placeholder)
**These stubs must be written before `make -f Makefile.starkernel` is run, because
mkcapsule runs at build time and produces `capsule_generated.c` from whatever is in
`capsules/` at that moment.**
---
## 7. VM Lifecycle Model
```
(capsule exists in directory)
│
▼
[BIRTH]
│
▼
EMBRYO ──────────────────[KILL]──────► DEAD
│ ▲
[START] │
│ [KILL]
▼ │
LIVE/RUNNING ──────────[STOP]──► STOPPED─┘
│
(completes)
│
▼
DEAD (natural)
```
States:
- **EMBRYO** — VM born (capsule executed) but `START` not yet called
- **LIVE** — executing (at this phase: running synchronously inside `START`)
- **STOPPED** — suspended; state saved; resumable via `START`
- **DEAD** — killed or naturally completed; slot reclaimable
---
## 8. Scheduling Model (Phase 1)
At this phase, scheduling is **sequential and explicit**:
- `START` runs a VM synchronously — the calling VM suspends while the started VM runs
- No round-robin, no time-slicing, no preemption
- The REPL is always in exactly one VM's context at a time
- `USE` switches the REPL/console target
**This is intentionally simple.** Cooperative concurrent scheduling (multiple VMs
interleaved in the interpreter loop) is a future milestone, designed separately after
the basic lifecycle works.
---
## 9. Dictionary and Namespace
The five lifecycle words (BIRTH, KILL, START, STOP, USE) are C primitives in **every VM's
base dictionary**. They are registered at VM initialization, before any capsule init runs.
A child VM born by Hermes or Artemis also has these words — all VMs can manage other VMs.
**Dictionary isolation:** Each VM has its own dictionary. Words defined by Artemis's
`init.4th` do not appear in Hera's dictionary or Hermes' dictionary. VMs communicate
through the messaging layer (Hermes), not shared dictionary state.
---
## 10. Hades Interface
All VMs access Hades through the same HAL interface. At this phase:
- No capability bitmask enforcement
- All VMs can call any HAL function (I/O, memory, time)
- The log prefix (`[VMName]`) is injected by the HAL console layer based on the currently
executing VM context — not by the VM itself
Capability enforcement (limiting what a child VM can do in Hades) is a future milestone.
---
## 11. Physics / SSM Integration
Each VM has its own independent SSM/L8 Jacquard state — this is already the natural
consequence of each VM being a full VM instance with its own `VM` struct. No shared physics.
The heartbeat runs per-VM. Hera's SSM does not observe Hermes' or Artemis' execution.
---
## 12. Decisions — RESOLVED
| # | Decision | Resolution |
|---|----------|-----------|
| D1 | BIRTH name collision | **Idempotent — check health of existing VM; if healthy, skip and log. No error, no replace.** |
| D2 | Production flag | **All capsules carry both `FLAG_PRODUCTION` and `FLAG_EXPERIMENT`. Birth eligibility is not gated on flag type. mkcapsule updated accordingly.** |
| D3 | `BIRTH` return value | **Nothing — BIRTH is a pure side-effect word, leaves stack clean.** |
| D4 | `USE` scope | **REPL only, but system-wide. Not bound to any specific capsule or identity. All REPL I/O redirects to the named VM.** |
| D5 | STOP across VMs | **Any VM may assume another identity for failsafe and recovery purposes, enabling cross-VM STOP. Identity assumption mechanism is a future milestone; Phase 1 allows any VM to STOP any other.** |
| D6 | Max named VMs | **Dynamic — Hera allocates as needed. No fixed ceiling.** |
| D7 | Log prefix format | **`[Name]`** — e.g., `[Hera]`, `[Hermes]`, `[Artemis]` |
---
## 13. What This Is NOT
- **Not a thread scheduler.** No preemption. Sequential execution at this phase.
- **Not a process model.** VMs share Hera's address space.
- **Not a security boundary yet.** No capability enforcement in this phase.
- **Not constrained by Hera's current implementation.** Hera expands as the design requires.
---
## 14. Implementation Phases
No code until Captain Bob approves the plan.
| Phase | Scope | Deliverable |
|-------|-------|-------------|
| 0 | Design approval | This document, signed off |
| 1 | VM registry naming | Add `name[64]` to `VMRegistryEntry`; name lookup functions |
| 2 | Log prefix | HAL console layer emits `[VMName]` prefix per active VM |
| 3 | Capsule stubs | Write `capsules/hermes/init.4th`, `capsules/artemis/init.4th` |
| 4 | mkcapsule flag update | Set both `FLAG_PRODUCTION` and `FLAG_EXPERIMENT` on all capsules |
| 5 | BIRTH word | C primitive; name→capsule lookup; health-check idempotence; full VM alloc |
| 6 | KILL word | C primitive; teardown; registry clear |
| 7 | START word | C primitive; synchronous execution hand-off |
| 8 | STOP word | C primitive; cross-VM; state save; return to caller |
| 9 | USE word | C primitive; system-wide REPL/console redirect |
| 10 | Hera init.4th update | Use new words to birth Hermes and Artemis at boot |
| 11 | Integration test | Boot sequence: Hera → BIRTH Hermes → BIRTH Artemis → `[Name]` in logs |
---
## 15. Mythological Framing Reference
| Name | Role |
|------|------|
| **Hades** | Kernel + HAL — the underworld substrate |
| **Hera** | Mama VM — queen, orchestrator, eternal; `capsules/init.4th` |
| **Hermes** | Messenger — pub/sub stratum; `capsules/hermes/init.4th` |
| **Artemis** | Hunter/keeper — storage and memory; `capsules/artemis/init.4th` |
| **BIRTH** | The word that brings a new VM into being |
| **KILL** | The word that destroys a VM |
| **START** | The word that gives a VM its first breath (or resumes it) |
| **STOP** | The word that suspends a VM |
| **USE** | The word that shifts the speaker's attention to a VM |
---
*This document is a planning artifact only. No code changes have been made.
Captain Bob's approval of the open decisions in §12 is required before Phase 1 begins.*
@@ -0,0 +1,25 @@
> **HISTORICAL (docs triage 2026-10-14).** The child-VM birthing plan and its acceptance record; built and live since (M7.1).
> Instead: docs/reference/M7.1.md and docs/fabric/. Moved here from `docs/birthing/README.md`.
# docs/working/archive/historical/2026-07-birthing/
Design and status for VM "birthing" — the mechanism by which Hera (the Tripod
governor) spawns Hermes and Artemis as child VMs at boot. See
`docs/working/archive/superseded/2026-08-tripod/TRIPOD.md` for the architectural contract this
work implements.
- **[PLAN.md](PLAN.md)** — Birthing plan for the initial three-VM constellation
(Hera/Hermes/Artemis). Marked DRAFT, requires Captain Bob approval before
implementation.
- **[STATUS.md](STATUS.md)** — Current work status: execution model (single
OS process, no threads/fork, VMs share one heap and address space, the C
call stack doubles as the execution stack), the birth-graph vs.
execution-stack distinction, and phase completion tracking.
- **[acceptance-logs/](acceptance-logs/)** — Three-architecture QEMU
acceptance test logs and summary for the lifecycle words (`BIRTH KILL
START STOP USE`).
## See also
- [`docs/working/archive/superseded/2026-08-tripod/README.md`](../03-architecture/tripod/README.md)
- [Project root](../../README.md)
@@ -0,0 +1,307 @@
> **HISTORICAL (docs triage 2026-10-14).** The child-VM birthing plan and its acceptance record; built and live since (M7.1).
> Instead: docs/reference/M7.1.md and docs/fabric/. Moved here from `docs/birthing/STATUS.md`.
# Birthing — Work Status and Context
**Branch:** `birthing` (off `lithosananke`)
**Last updated:** 2026-05-27
**Current phase:** Phases 1–11 complete (kernel QEMU acceptance passed all three architectures)
---
## Execution Model — Single Process, VM Graph
**Hard constraints:**
- One OS process. No threads. No fork. No shared memory between processes.
- All VMs live in the same heap, same address space.
- The C call stack IS the execution stack.
**The graph:**
VMs are nodes. Edges are relationships — birth (who created whom) and execution (who
STARTed whom). These are distinct:
```
Birth graph (static, ownership): Execution stack (dynamic, runtime):
Hera C call stack:
/ \ hera_interp()
Hermes Artemis └─ vm_start("Hermes")
└─ hermes_interp()
└─ vm_start("Artemis")
└─ artemis_interp()
└─ STOP → unwind
```
**`START` = push.** Calling `S" Hermes" START` from Hera literally calls Hermes's
interpreter loop from within Hera's C execution context. Hera blocks in the `vm_start()`
call until Hermes returns.
**`STOP` = pop.** A VM stops itself — execution returns up the C call stack to whoever
called `vm_start()`. In Phase 1, STOP is always self-stop. Cross-VM STOP (via identity
assumption) is a future milestone.
**`BIRTH` does not equal `START`.** BIRTH allocates and initializes the VM. START runs it.
A VM can be birthed and left dormant.
**`USE` is orthogonal.** It redirects the REPL I/O independently of which VM is currently
executing. It does not affect the C call stack.
**Any VM can birth sub-VMs.** Hermes can call `S" Companion" BIRTH` — it is not Hera's
exclusive privilege. This makes the birth graph a true directed graph (rooted at Hera),
not a strict two-level tree.
---
## What This Branch Is
We are designing and implementing the multi-VM birth system for LithosAnanke. Hera (the
primary Forth VM) gains the ability to birth, name, start, stop, and kill peer VMs. All
VMs run inside the same process — no threads, no OS processes.
---
## The Three Named VMs
| VM | Role | Capsule |
|----|------|---------|
| **Hera** | Mama VM — orchestrates all others | `capsules/init.4th` (root, exclusive) |
| **Hermes** | Messaging stratum — pub/sub | `capsules/hermes/init.4th` |
| **Artemis** | Storage and memory manager | `capsules/artemis/init.4th` |
**Hades** = kernel + HAL substrate beneath all VMs.
---
## The Five Forth Primitives (C-level, in every VM's dictionary)
All words take a counted string `( c-addr u -- )` and leave the stack clean.
| Word | Behavior |
|------|----------|
| `BIRTH` | Birth a VM from `<name>:init.4th`. Idempotent — if healthy VM exists, skip + log. |
| `KILL` | Destroy a named VM unconditionally. Free resources, clear registry slot. |
| `START` | Begin or resume a named VM. Runs synchronously (Phase 1). |
| `STOP` | Suspend a named VM. Any VM can STOP any other. Saves execution state. |
| `USE` | System-wide REPL/console redirect to the named VM. Not capsule-scoped. |
Example usage:
```forth
S" Artemis" BIRTH
S" Artemis" START
S" Artemis" USE
S" Artemis" STOP
S" Artemis" KILL
```
---
## Resolved Decisions
| # | Decision | Resolution |
|---|----------|-----------|
| D1 | BIRTH name collision | Idempotent — healthy VM: skip and log. No error, no replace. |
| D2 | Capsule production flag | All capsules get both `FLAG_PRODUCTION` + `FLAG_EXPERIMENT`. Birth not gated on flag type. |
| D3 | BIRTH return value | Nothing — stack clean. Pure side-effect word. |
| D4 | USE scope | System-wide REPL redirect. Not bound to any capsule or identity. |
| D5 | STOP authority | Any VM can STOP any other. Identity assumption (future) adds nuance. |
| D6 | Max VMs | Dynamic — Hera allocates as needed. No fixed ceiling. |
| D7 | Log prefix format | `[Name]` — e.g., `[Hera]`, `[Hermes]`, `[Artemis]` |
---
## Capsule Namespace Convention
`mkcapsule` encodes relative paths by replacing `/` with `:`.
| File | Capsule name | Used by |
|------|-------------|---------|
| `capsules/init.4th` | `init.4th` | Hera only |
| `capsules/hermes/init.4th` | `hermes:init.4th` | Hermes |
| `capsules/artemis/init.4th` | `artemis:init.4th` | Artemis |
`BIRTH` maps `S" Artemis"` → lowercase → `artemis:init.4th`.
`capsules/hermes/` and `capsules/artemis/` currently exist but contain only `.gitkeep`.
Stub `init.4th` files must be written before the kernel build runs `mkcapsule`.
---
## Implementation Checklist
### Phase 0 — Design and Approval
- [x] `birthing` branch created off `lithosananke` HEAD
- [x] `docs/working/archive/historical/2026-07-birthing/PLAN.md` written
- [x] All seven decisions resolved with Captain Bob
- [x] `docs/working/archive/historical/2026-07-birthing/STATUS.md` created (this file)
- [x] **Captain Bob approves plan — gate for Phase 1**
---
### Phase 1 — VM Registry Naming
- [x] Add `char name[VM_NAME_MAX]` + `VM_STATE_STOPPED` to `VMRegistryEntry` (`include/starkernel/capsule_run.h`)
- [x] Replace static `vm_registry[64]` with dynamic kmalloc linked list (`src/starkernel/capsule/capsule_birth.c`)
- [x] Hera (VM 0) registered as `"Hera"` in `capsule_vm_registry_init()`
- [x] Add `capsule_vm_find_by_name()` — walks linked list, copies entry on match
- [x] Add `capsule_vm_registry_set_name()` — sets symbolic name by vm_id
- [x] Declare both new functions in `include/starkernel/capsule_birth.h`
- [x] Kernel build (`make -f Makefile.starkernel ARCH=amd64 STARFORTH_ENABLE_VM=1`) passes clean
- [ ] Tests: find by name, not-found returns -1, name persists across states
---
**Gap 1 (deferred to Phase 4):** `CAPSULE_MODE_VALID` enforces XOR between `FLAG_PRODUCTION`
and `FLAG_EXPERIMENT`. Captain Bob's answer about D2 points at a runtime logger/mode
selector (`LOG-DOE`) that does not yet exist. Design of `LOG-DOE` and the runtime mode
selection is a separate task before Phase 4 (mkcapsule flag update) can proceed.
---
### Phase 2 — Log Prefix `[Name]`
- [x] Identify the HAL console output path (`src/starkernel/hal/console.c`)
- [x] Add "active VM" context pointer to the HAL console layer
- [x] Every `hal_console_putchar` / `hal_console_puts` prefixes `[VMName] ` at line start
- [x] Hera's boot output shows `[Hera]` from first character
- [ ] QEMU verification pending Captain Bob
---
### Phase 3 — Capsule Stubs
- [x] Write `capsules/hermes/init.4th` (boot message + placeholder vocabulary)
- [x] Write `capsules/artemis/init.4th` (boot message + placeholder vocabulary)
- [ ] Verify `mkcapsule` generates descriptors for both (requires kernel build env)
- [ ] Verify capsule names resolve correctly (`hermes:init.4th`, `artemis:init.4th`)
---
### Phase 4 — mkcapsule Flag Update
- [ ] Update `tools/mkcapsule.c` to set both `FLAG_PRODUCTION` and `FLAG_EXPERIMENT` on
every capsule (remove the directory-prefix-based flag logic, or extend it to set both)
- [ ] Rebuild and verify `capsule_generated.c` shows both flags on all entries
- [ ] Confirm birth eligibility check in `capsule_birth.c` no longer blocks on flag type
---
### Phase 5 — `BIRTH` Word
- [x] Register `BIRTH` as a C primitive in `register_mama_forth_words()` (mama_forth_words.c)
- [x] Lowercase the name string from the stack
- [x] Construct capsule name: `<name>:init.4th` (special case: `hera` → rejected)
- [x] Look up capsule in directory by name
- [x] Health check: if VM with that name is alive and healthy, log and return (idempotent)
- [x] Allocate new VM (dynamic — no fixed pool ceiling)
- [x] Execute capsule init via `capsule_birth_baby` path
- [x] Register VM under symbolic name in `VMRegistryEntry`
- [x] Emit parity log via `capsule_parity_log_birth`
- [x] Stack clean on exit
- [x] Fixed caddr+1 offset bug — now reads chars directly at caddr per FORTH-79 S"
---
### Phase 6 — `KILL` Word
- [x] Register `KILL` as a C primitive
- [x] Look up VM by name (case-insensitive)
- [x] If not found: log, return (no stack effect)
- [x] Tear down VM, free via `vm_cleanup` + `sf_free`
- [x] Clear registry slot (state → DEAD, name cleared)
- [x] Emit parity log via `capsule_parity_log_kill`
- [x] Stack clean on exit
- [x] Hera kill rejected
---
### Phase 7 — `START` Word
- [x] Register `START` as a C primitive
- [x] Look up VM by name
- [x] If EMBRYO or STOPPED: set state → LIVE
- [x] Call `sk_repl_run(target)` — blocks until target->halted
- [x] On target halt: state → STOPPED, caller resumes
- [x] If target already LIVE: log error, return clean
- [x] Stack clean on exit
---
### Phase 8 — `STOP` Word
- [x] Register `STOP` as a C primitive
- [x] Self-stop: sets `vm->halted = 1`, sk_repl_run loop exits
- [x] State updated to STOPPED by START word after REPL returns
- [x] Stack clean (STOP takes no arguments)
---
### Phase 9 — `USE` Word
- [x] Register `USE` as a C primitive
- [x] Look up VM by name
- [x] Set active system-wide REPL VM via `sk_repl_set_active_vm`
- [x] HAL console prefix changes to `[VMName]` via `console_set_vm_name`
- [x] Stack clean on exit
---
### Phase 10 — Hera `init.4th` Update
- [x] `S" Hermes" BIRTH` in `capsules/init.4th`
- [x] `S" Artemis" BIRTH` in `capsules/init.4th`
- [x] S" fixed to FORTH-79 ( -- c-addr u ) — stores at HERE, no count-byte prefix
- [x] Boot sequence QEMU verified — all three architectures (amd64, aarch64, riscv64)
---
### Phase 11 — Integration Test (kernel QEMU)
- [x] Boot QEMU: kernel loads, Hera starts, births Hermes and Artemis — all three architectures
- [x] Serial log shows `[Hera]`, `[Hermes]`, `[Artemis]` prefixes
- [x] `."` compile-mode fixed (do-string inline approach) — "Hermes Up" / "Artimis Up" print correctly
- [x] 734 passed / 0 failed / 0 errors on amd64, aarch64, riscv64
- [ ] `S" Hermes" USE` switches console to Hermes — interactive test (requires Captain Bob)
- [ ] `S" Hera" USE` switches back — interactive test (requires Captain Bob)
- [ ] KILL + re-BIRTH a VM in the same session — interactive test (requires Captain Bob)
**Logs:** `docs/working/archive/historical/2026-07-birthing/acceptance-logs/` — kernel QEMU serial logs for all three architectures
---
## Key Files
| File | Purpose |
|------|---------|
| `docs/working/archive/historical/2026-07-birthing/PLAN.md` | Full architectural plan |
| `docs/working/archive/historical/2026-07-birthing/STATUS.md` | This file — living checklist |
| `tools/mkcapsule.c` | Build-time capsule packager |
| `capsules/init.4th` | Hera's init (root, exclusive) |
| `capsules/hermes/init.4th` | Hermes stub (to be written) |
| `capsules/artemis/init.4th` | Artemis stub (to be written) |
| `src/starkernel/capsule/capsule_birth.c` | C-level VM birth logic |
| `src/starkernel/capsule/capsule_loader.c` | Capsule load + exec |
| `src/starkernel/capsule/capsule_registry.c` | Capsule directory |
| `src/starkernel/hal/console.c` | HAL console — add `[Name]` prefix here |
| `include/starkernel/capsule.h` | `CapsuleDesc`, `VMRegistryEntry` structs |
| `include/starkernel/capsule_birth.h` | Birth protocol headers |
---
## Branch and Commit History
```
birthing (HEAD)
d2766d6 plan: lock all seven decisions into birthing plan
ba27226 plan: overhaul birthing plan — named VMs, five Forth primitives, capsule namespacing
d258b12 plan: update birthing plan — Hera is not constrained
84e1c61 plan: add birthing plan for child VMs born of Hera
91e0b3d (lithosananke HEAD at branch point) docs: comprehensive CLAUDE.md update
```
---
## Notes and Open Threads
- **Identity assumption (D5 future):** Cross-VM STOP requires a VM to assume another's
identity. Not in scope for current phases — design separately. Phase 1 STOP is self-stop.
- **Cooperative scheduling / YIELD:** The single-process graph model means VMs run one at a
time (depth-first down the call stack). True cooperative interleaving (Hermes and Artemis
sharing time while Hera waits) would require an explicit `YIELD` mechanism and a trampoline
scheduler — future milestone, designed separately.
- **Graph depth — CONFIRMED unlimited:** Any VM can BIRTH sub-VMs at any depth. The birth
graph is a true rooted directed graph. Deep graphs consume C stack space — note for kernel
stack budgeting. No enforced limit; document safe depth in practice.
- **Hermes pub/sub and Artemis storage:** Their full vocabularies are future work. Current
phase only needs stub `init.4th` files.
- **`capsules/hermes/` and `capsules/artemis/`** currently contain only `.gitkeep`. Stub
`init.4th` files must exist before `make -f Makefile.starkernel` calls `mkcapsule`.
@@ -0,0 +1,22 @@
> **HISTORICAL (docs triage 2026-10-14).** The child-VM birthing plan and its acceptance record; built and live since (M7.1).
> Instead: docs/reference/M7.1.md and docs/fabric/. Moved here from `docs/birthing/acceptance-logs/README.md`.
# docs/working/archive/historical/2026-07-birthing/acceptance-logs/
Kernel QEMU acceptance test results for the VM lifecycle words (`BIRTH KILL
START STOP USE`) and the `."` compile-mode fix, run across all three
supported architectures.
- **[SUMMARY.md](SUMMARY.md)** — Consolidated results table (800 tests run,
734 passed, 0 failed/errored on amd64/aarch64/riscv64), key serial-log
evidence, list of source files changed, and the remaining interactive
tests that require Captain Bob (`S" Hermes" USE`, KILL + re-BIRTH in the
same session).
- **[amd64.log](amd64.log)** — Raw QEMU serial log, amd64.
- **[arm64.log](arm64.log)** — Raw QEMU serial log, aarch64.
- **[riscv64.log](riscv64.log)** — Raw QEMU serial log, riscv64.
## See also
- [`docs/working/archive/historical/2026-07-birthing/README.md`](../README.md)
- [Project root](../../../README.md)
@@ -0,0 +1,66 @@
> **HISTORICAL (docs triage 2026-10-14).** The child-VM birthing plan and its acceptance record; built and live since (M7.1).
> Instead: docs/reference/M7.1.md and docs/fabric/. Moved here from `docs/birthing/acceptance-logs/SUMMARY.md`.
# Birthing — Kernel QEMU Acceptance Test Summary
**Date:** 2026-05-27
**Branch:** `birthing`
**Feature:** Lifecycle words (BIRTH KILL START STOP USE) + `."` compile-mode fix
## Scope
These logs cover the **kernel UEFI build** (`make -f Makefile.starkernel ARCH=<arch> clean qemu`).
All three architectures booted to `ok>`, ran POST, and executed `capsules/init.4th` successfully.
## Kernel QEMU Results
| Arch | Tests | Passed | Failed | Errors | BIRTH Hermes | BIRTH Artemis | `."` |
|------|-------|--------|--------|--------|-------------|---------------|------|
| amd64 | 800 | 734 | 0 | 0 | `[Hermes] Hermes Up` / live | `[Artemis] Artimis Up` / live | PASS |
| aarch64 | 800 | 734 | 0 | 0 | `[Hermes] Hermes Up` / live | `[Artemis] Artimis Up` / live | PASS |
| riscv64 | 800 | 734 | 0 | 0 | `[Hermes] Hermes Up` / live | `[Artemis] Artimis Up` / live | PASS |
## Key Evidence (all three architectures identical)
```
[Hera] POST: PASSED
[Hera] Init: loading init.4th...
[Hermes] Hermes UpBIRTH: Hermes live
[Artemis] Artimis UpBIRTH: Artemis live
[Hera] Init: init.4th OK
```
`."` in compile mode now uses the `(do-string)` inline runtime — string bytes live
inside the threaded code body, not at `body_addr`. The previous LIT-addr-LIT-len-TYPE
approach overwrote the start of the word body with string bytes, causing a triple fault
when `execute_colon_word` read them as DictEntry pointers.
## What Changed
- `src/word_source/io_words.c` — `."` compile mode replaced with `(do-string)` inline
approach; `(do-string)` runtime word reads inline string via return-stack IP, prints,
advances IP past padded block
- `src/starkernel/capsule/mama_forth_words.c` — BIRTH KILL START STOP USE kernel
implementations; fixed caddr+1 offset bug to align with FORTH-79 S"
- `src/word_source/string_words.c` — S" fixed to FORTH-79 standard ( -- c-addr u )
- `src/word_source/lifecycle_words_hosted.c` — hosted Linux stubs (guarded #ifndef __STARKERNEL__)
- `src/main.c` — register_lifecycle_words(&vm) wired in for hosted build
- `capsules/init.4th` — S" Hermes" BIRTH + S" Artemis" BIRTH
- `capsules/hermes/init.4th` — stub: `: UP ." Hermes Up" ; UP`
- `capsules/artemis/init.4th` — stub: `: UP ." Artimis Up" ; UP`
## Serial Logs
| Arch | Log file |
|------|----------|
| amd64 | `logs/qemu-amd64-20260526-234957.log` |
| aarch64 | `logs/qemu-aarch64-20260526-235056.log` |
| riscv64 | `logs/qemu-riscv64-20260527-000127.log` |
(`logs/` is gitignored — run locally to reproduce)
## Remaining Interactive Tests (require Captain Bob)
- `S" Hermes" USE` — switches system console to Hermes
- `S" Hera" USE` — switches back
- KILL + re-BIRTH a VM in the same session
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2dbe1a4abd9342a0ec96fbd4c4c15ab039385b2af9639c7489eda6fe9dfc6fa4
size 10216
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:25dc9dcce2403f30ef6b2c0d14e5462d7e17e42070c1afa443f92cf85985cd99
size 9889
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2af00462812d21a44807da17be38ad5fb5e97ca56b4c2b883cf192b7ef1778db
size 9885
@@ -0,0 +1,186 @@
> **HISTORICAL (docs triage 2026-10-14).** The write-up of one fix (kernel stack trampoline, riscv64), done.
> Instead: the code itself (kernel/src/arch/riscv64/). Moved here from `docs/lithosananke/riscv64-stack-fix/README.md`.
# Kernel Stack Trampoline Fix — riscv64
**Date**: 2026-08-02
**Branch**: `master`
**Commit**: `7366275`
---
## Problem
The riscv64 kernel crashed partway through VM bootstrap during the 2026-08-01
DoE campaign run, well after amd64 and aarch64 had both booted cleanly to
`ok>` in the same session. The crash was a wild jump: execution landed at an
address nowhere inside the kernel's own linked image, then almost immediately
faulted trying to load from a small, near-null address.
```
Registering FORTH-79 Standard word set...
Registering FORTH-79 arithmetic words...
FORTH-79 Standard word set registration complete
*** EXCEPTION (riscv64) ***
scause = 0x000000000000000d
sepc = 0x00000000be27c3c2
stval = 0x00000000000074d8
```
`scause = 0xd` is a supervisor-mode load page fault. `sepc` (~0xbe27c3c2) sat
near the top of QEMU's 1 GB RAM window — nowhere close to the kernel's own
`.text`/`.data`/`.bss` footprint (`0x400000`–`0xcdf9a0`, confirmed via `nm`/
`readelf` on the exact build that produced the log). `stval` (0x74d8, ~30 KB)
stayed fixed across rebuilds even as `sepc` drifted — the signature of a
corrupted return address rather than a fixed logic bug at one source line.
## Investigation
Two dead ends were ruled out before the real cause surfaced:
1. **ELF relocation / buffer overlap in the split-build loader.** The
codebase has a `!MONOLITHIC_BUILD` path (`elf_load_kernel()` in
`elf_loader.c`) that loads `kernel.elf` from the ESP into a UEFI
`AllocateAnyPages` buffer. This looked like a plausible overlap candidate
at first, but `Makefile.starkernel` defaults to `MONOLITHIC=1`, meaning
`kernel_main` is linked directly into the loader and that code path never
runs. Confirmed by checking the built binary for the investigation's own
diagnostic strings — absent, because the compilation unit was built with
`-DMONOLITHIC_BUILD` and the code was preprocessed out.
2. **`RAW_LOG()` silently no-ops on every non-amd64 arch.** All of
`load_kernel_from_esp()`'s narration (and an early ConOut-based
diagnostic) never reached the captured serial log, on riscv64, in any
build. `RAW_LOG` was defined only for `ARCH_AMD64`; everywhere else it
expanded to `((void)0)`. This made straightforward diagnosis impossible
until a real raw-UART writer was added for riscv64 (see Secondary Fix).
With real output available, `console_println()` checkpoints were bisected
through `vm_init_with_host()` and `sk_vm_bootstrap_parity()`. Every checkpoint
inside `vm_init_with_host()` printed successfully, including the very last
line of the function — but the checkpoint immediately after its *return*
never appeared. Re-running with a trivial, unrelated local-variable addition
shifted the crash earlier and changed the exception type entirely (from a
load fault to an instruction-fetch fault at `sepc == stval`, i.e. the CPU
tried to *execute* an unmapped address). A crash whose location and even
category shift under unrelated code changes is the standard signature of
stack corruption, not a fixed bug at a specific call site.
## Root Cause
`kernel_main.c` documented the gap directly, once read closely:
> On amd64, `kernel_entry.S` switches the stack from UEFI's default to a
> 2 MiB zero-initialised BSS stack and tail-calls this function as
> `kernel_main_impl`. On aarch64 and riscv64 the assembly trampoline is not
> yet implemented and the UEFI loader calls `kernel_main` directly.
amd64 has carried a dedicated stack-switch trampoline
(`src/starkernel/arch/amd64/kernel_entry.S`) since early on, with its own
comment explaining why: *"UEFI hands control to kernel_main() running on a
small UEFI-provided stack (typically 128 KB–256 KB). The FORTH interpreter +
DOE experiment loop can easily exceed that depth."* riscv64 never had the
equivalent. It ran the entire VM bootstrap — 27 chained word-registration
modules, physics/SSM init, Tripod capsule birth — directly on whatever small
stack EDK2's riscv64 firmware handed the loader, overflowing it and
corrupting a return address. aarch64 has the same theoretical exposure but
happens not to trip it, apparently because its firmware's default boot stack
is larger — incidental, not a guarantee.
## Fix
**`src/starkernel/arch/riscv64/kernel_entry.S`** (new) — RISC-V stack-switch
trampoline mirroring amd64's:
```asm
.section .bss
.align 4
.global g_kernel_stack
g_kernel_stack:
.space 0x200000
g_kernel_stack_top:
.global g_kernel_stack_top
.section .text
.extern kernel_main_impl
.global kernel_main
kernel_main:
ld t0, BOOT_INFO_KERNEL_STACK_BASE_OFFSET(a0)
bnez t0, .Ldynamic_stack
la t0, g_kernel_stack_top
j .Lstack_ready
.Ldynamic_stack:
ld t1, BOOT_INFO_KERNEL_STACK_SIZE_OFFSET(a0)
add t0, t0, t1
.Lstack_ready:
andi t0, t0, -16
mv sp, t0
mv s0, zero
tail kernel_main_impl
```
**`src/starkernel/kernel_main.c`** — riscv64 now builds `kernel_main_impl`
(invoked via the trampoline) instead of `kernel_main` directly, same pattern
as amd64:
```c
#if defined(__x86_64__) || defined(__riscv)
void kernel_main_impl(BootInfo *boot_info) {
#else
void kernel_main(BootInfo *boot_info) {
#endif
```
**`Makefile.starkernel`** — wires the new file into the riscv64 loader build:
```makefile
ifeq ($(ARCH),riscv64)
LOADER_ASM += $(KERNEL_SRC)/arch/$(ARCH)/kernel_entry.S
endif
```
## Secondary Fix
`RAW_LOG()` in `src/starkernel/boot/uefi_loader.c` was a no-op on every arch
except amd64, silencing all of the loader's own diagnostic messages on
riscv64 (and aarch64). Added a real raw-UART writer for riscv64, targeting
QEMU virt's 16550-compatible `uart8250` at MMIO `0x10000000` (matches
`Domain0 Region03` in the OpenSBI boot banner) — the same byte-polling
protocol as the existing amd64 port-I/O version, just MMIO instead of `outb`/
`inb`. Existing and future `RAW_LOG()` call sites in the loader now actually
produce output on riscv64.
## Result
| Criterion | Before | After |
|---|---|---|
| `sepc` after word registration | Wild address outside kernel image (`0xbe27c3c2`-ish, drifting per build) | N/A — no longer occurs |
| Exception | Load or instruction-fetch page fault, non-deterministic between builds | None |
| `[Hera] ok>` (riscv64) | Never reached | ✅ reached, Tripod fleet (Hera/Hermes/Artemis) runs to completion |
| `PASS: E2E msg flow` | Never logged | ✅ |
| `PARITY:MAMA_INIT` / `Init: Mama birth OK` | Never logged | ✅ |
| Loader `RAW_LOG()` output on riscv64 | Silent no-op | ✅ visible in serial log |
## Acceptance Testing
All three architectures must boot to `ok>`, run the Tripod fleet, and reach
`[Hera] ok>`. Per repo convention, run in this exact order, one QEMU instance
at a time, always `clean` before `qemu`:
```bash
make -f Makefile.starkernel ARCH=amd64 clean qemu
make -f Makefile.starkernel ARCH=aarch64 clean qemu
make -f Makefile.starkernel ARCH=riscv64 clean qemu
```
Verify each log:
```bash
grep "ok>" logs/<session>/<arch>/qemu-<arch>-*.log
grep "PASS: E2E msg flow" logs/<session>/<arch>/qemu-<arch>-*.log
grep "PARITY:MAMA_INIT" logs/<session>/<arch>/qemu-<arch>-*.log
grep "EXCEPTION" logs/<session>/<arch>/qemu-<arch>-*.log # must be empty
```
All three architectures confirmed clean on 2026-08-02 (see
`logs/20260802-064050/riscv64/`, `logs/20260802-064424/amd64/`,
`logs/20260802-064656/aarch64/`, committed alongside this fix).
@@ -0,0 +1,198 @@
> **HISTORICAL (docs triage 2026-10-14).** An orientation page for the old docs/lithosananke/ folder, flagged partly stale on 2026-10-09; the folder is gone (its parts are in docs/reference/ and this archive).
> Instead: docs/README.md. Moved here from `docs/lithosananke/README.md`.
# LithosAnanke — StarForth Kernel Branch
> **⚠ PARTIALLY STALE (flagged 2026-10-09).** This page predates the repo split and the
> Tripod/kernel reshuffle. There is no `lithosananke` branch in this repo — `master` is the
> sole production line — and the VM fleet is now **Hera / Artemis / Hestia** (the Hermes VM
> was removed; messaging moved into the kernel as kernel-Hermes). M7.1 is **live**, not
> merely designed. For authoritative status see `.claude/CLAUDE.md` and
> `docs/fabric/FABRIC-2.md` / `FABRIC-3.md` / `FABRIC-3.5.md` / `FABRIC-3.6.md`; for the
> milestone plan see `ROADMAP.md` (this file is an orientation page).
**Line:** `master` (sole production line post-split)
**Status:** M7 Complete (VM Parity) · M7.1 Live (capsules, Tripod, Stadium, word-level ACL Phases 1–7)
---
## What is LithosAnanke?
LithosAnanke is the kernel branch of StarForth — a UEFI-bootable microkernel with the StarForth VM as its native execution engine.
**Etymology:** *Lithos* (stone/foundation) + *Ananke* (necessity/inevitability)
The name reflects the project's nature: a necessary foundation for StarshipOS.
---
## Architecture
```
┌─────────────────────────────────────────────────────────────┐
│ UEFI Firmware │
│ • ExitBootServices → handoff to kernel │
└─────────────────────┬───────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────────┐
│ LithosAnanke Boot (M0) │
│ • UEFI loader collects BootInfo │
│ • Memory map, ACPI tables, framebuffer │
└─────────────────────┬───────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────────┐
│ LithosAnanke HAL (M1-M6) │
│ • PMM: Physical Memory Manager (bitmap) │
│ • VMM: Virtual Memory Manager (4-level paging) │
│ • IDT: Interrupt Descriptor Table │
│ • APIC: Timer + IRQ routing │
│ • Heap: kmalloc/kfree │
│ • Console: Serial UART │
└─────────────────────┬───────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────────┐
│ StarForth VM (M7+) │
│ • 295 FORTH-79 words │
│ • Parity validation (hash=0x684bbf2fa1d96d55) │
│ • Physics-driven adaptive runtime │
│ • Init capsule system (M7.1) │
└─────────────────────────────────────────────────────────────┘
```
---
## Current Milestones
| Milestone | Description | Status |
|-----------|-------------|--------|
| M0 | UEFI Boot + Serial Output | Complete |
| M1 | Physical Memory Manager | Complete |
| M2 | Virtual Memory Manager | Complete |
| M3 | IDT + Interrupts | Complete |
| M4 | APIC Timer | Complete |
| M5 | Timer Calibration | Complete |
| M6 | Kernel Heap | Complete |
| **M7** | **VM Parity Validation** | **Complete** |
| **M7.1** | **Capsules · Tripod · Stadium · ACL** | **Live** (see FABRIC docs) |
| M8 | REPL (keyboard input) | Superseded — see FABRIC-0 §25.5 item 4.4 |
| M9 | Block Storage / Block I/O | Live (virtio-blk + block subsystem) |
---
## Build & Run
```bash
# Build kernel with VM integration (loader + kernel)
make -f kernel/Makefile ARCH=amd64 STARFORTH_ENABLE_VM=1
# Run in QEMU
make -f kernel/Makefile ARCH=amd64 STARFORTH_ENABLE_VM=1 qemu
# Other architectures
make -f kernel/Makefile ARCH=aarch64 qemu
make -f kernel/Makefile ARCH=riscv64 qemu
```
**Output artifacts:**
- `build/amd64/kernel/starkernel_loader.efi` — UEFI loader
- `build/amd64/kernel/starkernel_kernel.elf` — Kernel binary
---
## Documentation
### Core Design
| Document | Description |
|----------|-------------|
| [M7.1.md](M7.1.md) | Init Capsule Architecture |
| [ROADMAP.md](ROADMAP.md) | Milestone roadmap |
| [amd64-isr-fix/README.md](amd64-isr-fix/README.md) | APIC timer ISR fix + kernel 3-arch acceptance test |
| [hosted-acceptance-test/README.md](hosted-acceptance-test/README.md) | Hosted VM 3-arch acceptance test (amd64 native, aarch64/riscv64 under QEMU user-mode) |
### HAL (Hardware Abstraction Layer)
| Document | Description |
|----------|-------------|
| [hal/overview.md](hal/overview.md) | HAL architecture and principles |
| [hal/interfaces.md](hal/interfaces.md) | HAL interface specifications |
| [hal/lithosananke-integration.md](hal/lithosananke-integration.md) | Kernel-specific HAL implementation |
| [hal/platform-implementations.md](hal/platform-implementations.md) | Platform implementation guide |
| [hal/migration-plan.md](hal/migration-plan.md) | Migration from hosted to kernel |
---
## Key Concepts
### One Truth Per VM
Every VM has exactly one birth capsule — its identity and provenance.
```
PARITY:BIRTH vm_id=42 capsule_id=0xA13F mode=p capsule_hash=0x... dict_hash=0x...
```
### DOMAIN vs PERSONALITY
**DOMAIN** is a construction concept that exists **only in Mama FORTH**. It's how Mama classifies, composes, and selects capsules. DOMAIN is never visible to baby VMs.
**PERSONALITY** is the result of executing a production `(p)` INIT capsule. It's what the baby VM *is* — its vocabulary, invariants, capabilities. PERSONALITY is immutable and defines the VM's entire worldview.
### Production (p) vs Experiment (e)
- **(p) capsules** are truth-bearing — they can birth VMs
- **(e) capsules** are Mama-only workloads — experiments that never touch babies
A baby VM never sees, executes, or knows about (e) capsules.
### Content-Addressed Capsules
Capsules are identified by content hash, not names. Names lie. Hashes don't.
### Mama FORTH
The root VM that holds all truths, manages child VMs, and enforces the birth protocol. Mama:
- Maintains the capsule directory
- Selects (p) capsules for birth
- Executes (e) capsules for experimentation
- Logs all births and runs for provenance
---
## Directory Structure
```
src/starkernel/
├── boot/ # UEFI loader, ELF loader
├── hal/ # Console, host services
├── memory/ # PMM, VMM, kmalloc
├── arch/amd64/ # x86_64 specific (APIC, IDT, timer)
├── vm/ # VM integration
│ ├── arena.c # VM memory arena
│ ├── parity.c # Parity validation
│ ├── bootstrap/ # sk_vm_bootstrap
│ └── host/ # Host services shim
└── kernel_main.c # Entry point
```
---
## Contributing
The contributing rules are:
1. Maintain parity validation (M7 baseline)
2. Pass the three-arch QEMU boot test (`ARCH={amd64,aarch64,riscv64}`)
3. Not break the hosted VM build (plain `make` at the repo root)
---
## References
- [StarForth README](../../README.md) — Main project
- [FORTH-79 Standard](http://www.forth.org/forth-79.html)
- [OSDev Wiki](https://wiki.osdev.org/)
- [UEFI Specification](https://uefi.org/specifications)