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:
co-authored by
Claude Opus 5.5
parent
1a4b163861
commit
7aed588f78
@@ -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)
|
||||
Reference in New Issue
Block a user