Reorganize source tree: kernel/, v3/, v4/ split and board infrastructure

Source tree reorganization:
- Move StarForth v3 engine to v3/ (src/, include/, Makefile)
- Move kernel to kernel/ (src/, include/, linker/, Makefile)
- Create v4/ skeleton for F18-ISA golden model (DECOMPOSITION.md, JUSTIFICATION.md)
- Move FABRIC-0..4.md to docs/fabric/
- Move ONTOLOGY.md and ROADMAP.md to docs/

Board infrastructure:
- Add boards/ser5/, boards/raspi/, boards/milkv/, boards/zynq7020/
- Each board has board.mk (ISA, CPU flags, boot recipe) and README.md
- Root Makefile becomes thin dispatcher: boot_image, all, clean, docs take TARGET
- make boot_image TARGET=SER5|RASPI|MILKV builds one GPT/MBR image per board
- ZYNQ7020 target exists but stops with clear error (ARMv7 port not built yet)
- scripts/mkdiskimage.sh builds disk images for all boards

Docs pipeline:
- docs/book/ with LaTeX master (main.tex) and Makefile
- pandoc converts Markdown to LaTeX at build time
- Two Lua filters: table-widths.lua (wide tables wrap), code-breaks.lua (inline code breaks)
- make docs builds single PDF (754 pages, 0 missing characters)
- make docs TARGET=<board> adds board appendix
- build/docs/<book|board>/meta.tex stamps git commit into PDF

Bug fixes:
- 42 include paths that only worked by accident now use correct relative paths
- clang-18 hardcode replaced with configurable CC variable (fixed aarch64 build)
- Pi 5: kernel_2712.img linked at 0x80000, .bss zeroed, memory reserved
- Doxyfile, .clang-tidy, README.md, Kconfig paths updated

Verified:
- Hosted v3 build passes 1012 tests, 0 failures
- SER5 image boots in QEMU (OVMF), POST passes, K exact (65536 = Q48_ONE)
- Milk-V image boots in QEMU (OpenSBI + U-Boot + bootefi), POST passes
- make clean TARGET=<board> removes only that board and its ISA objects
- make all builds all boards, hosted v3, and docs in one run

Co-authored-by: Junie <junie@jetbrains.com>
This commit is contained in:
rajames
2026-10-01 15:40:09 -04:00
co-authored by Junie
parent 3c709c115b
commit a8b70e88d3
630 changed files with 2646 additions and 2036 deletions
+304
View File
@@ -0,0 +1,304 @@
/*
StarForth — Steady-State Virtual Machine Runtime
Copyright (c) 2023–2025 Robert A. James
All rights reserved.
This file is part of the StarForth project.
Licensed under the StarForth License, Version 1.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
https://github.com/star.4th@proton.me/StarForth/LICENSE.txt
This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
express or implied, including but not limited to the warranties of
merchantability, fitness for a particular purpose, and noninfringement.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* capsule.h - Init Capsule Architecture (M7.1)
*
* Content-addressed, immutable init capsules for VM birth.
* See docs/lithosananke/M7.1.md for full specification.
*
* Key invariants:
* - Exactly ONE production (p) INIT defines a baby VM
* - capsule_id == content_hash (content-addressed)
* - No shared/implicit base INITs
* - DOMAIN is Mama-only, PERSONALITY is baby-only
*/
#ifndef STARKERNEL_CAPSULE_H
#define STARKERNEL_CAPSULE_H
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/*===========================================================================
* Constants
*===========================================================================*/
/** Magic signatures */
#define CAPSULE_DESC_MAGIC 0x53504143ULL /* 'CAPS' little-endian */
#define CAPSULE_DIR_MAGIC 0x44504143ULL /* 'CAPD' little-endian */
/** Version */
#define CAPSULE_VERSION_0 0
/** Limits */
#define CAPSULE_MAX_COUNT 256
/** Maximum capsule name length (colon-separated path, null-terminated) */
#define CAPSULE_NAME_MAX 512
/*===========================================================================
* Hash Algorithm Enum
*===========================================================================*/
typedef enum {
CAPSULE_HASH_XXHASH64 = 0,
CAPSULE_HASH_SHA256 = 1,
CAPSULE_HASH_BLAKE3 = 2,
} CapsuleHashAlg;
/*===========================================================================
* Flags
*===========================================================================*/
/** State flags */
#define CAPSULE_FLAG_ACTIVE 0x00000001 /* Eligible for use */
#define CAPSULE_FLAG_REVOKED 0x00000002 /* Birth-blocked forever */
#define CAPSULE_FLAG_DEPRECATED 0x00000004 /* Eligible but discouraged */
#define CAPSULE_FLAG_PINNED 0x00000008 /* Immune to GC */
/** Mode flags (D2: babies carry both) */
#define CAPSULE_FLAG_PRODUCTION 0x00000010 /* (p) truth-bearing */
#define CAPSULE_FLAG_EXPERIMENT 0x00000020 /* (e) workload only */
/** Mama init flag (exactly one capsule must have this) */
#define CAPSULE_FLAG_MAMA_INIT 0x00000040 /* (m) Mama's init */
/** Contributor capsule flag (FABRIC-2.md §I.5, 2026-09-04) -- path-match
* on capsules/contrib/, mirrors FLAG_MAMA_INIT's own exact-match pattern
* in mkcapsule.c's flags_from_name(). Trust-tier enforcement (QEMU-vs-
* real-hardware, decided in conversation) is a runtime check in
* capsule_validate()'s callers, not encoded in this bit itself -- the
* bit only marks "this capsule's provenance is a contributor, not this
* project's own source," same as CAPSULE_FLAG_PRODUCTION/_EXPERIMENT
* mark mode, not policy. */
#define CAPSULE_FLAG_CONTRIB 0x00000080 /* (c) contributor-submitted */
/** Validate mode flags.
* Mama: neither (p) nor (e) may be set.
* Babies: at least one of (p) or (e) must be set (both is fine — D2). */
#define CAPSULE_MODE_VALID(f) \
((((f) & CAPSULE_FLAG_MAMA_INIT) != 0) ? \
(!((f) & (CAPSULE_FLAG_PRODUCTION | CAPSULE_FLAG_EXPERIMENT))) : \
(((f) & CAPSULE_FLAG_PRODUCTION) || ((f) & CAPSULE_FLAG_EXPERIMENT)))
/** Check if capsule is Mama's init */
#define CAPSULE_IS_MAMA_INIT(f) \
(((f) & CAPSULE_FLAG_MAMA_INIT) && ((f) & CAPSULE_FLAG_ACTIVE))
/** Birth eligibility: active and not revoked (flag type irrelevant — D2) */
#define CAPSULE_BIRTH_ELIGIBLE(f) \
(((f) & CAPSULE_FLAG_ACTIVE) && \
!((f) & CAPSULE_FLAG_REVOKED))
/** DoE eligibility: experiment, active, not revoked */
#define CAPSULE_DOE_ELIGIBLE(f) \
(((f) & CAPSULE_FLAG_EXPERIMENT) && \
((f) & CAPSULE_FLAG_ACTIVE) && \
!((f) & CAPSULE_FLAG_REVOKED))
/*===========================================================================
* Magic Field Packing
*
* bits 0..31 : 'CAPS' (0x53504143 little-endian)
* bits 32..39 : version (0 for v0)
* bits 40..47 : hashAlg (enum CapsuleHashAlg)
* bits 48..63 : reserved (zero)
*===========================================================================*/
#define CAPSULE_MAGIC_PACK(ver, alg) \
(CAPSULE_DESC_MAGIC | ((uint64_t)(ver) << 32) | ((uint64_t)(alg) << 40))
#define CAPSULE_MAGIC_GET_SIG(m) ((uint32_t)((m) & 0xFFFFFFFFULL))
#define CAPSULE_MAGIC_GET_VERSION(m) ((uint8_t)(((m) >> 32) & 0xFF))
#define CAPSULE_MAGIC_GET_HASHALG(m) ((uint8_t)(((m) >> 40) & 0xFF))
/*===========================================================================
* CapsuleDesc - Capsule Descriptor (64 bytes, cache-line aligned)
*===========================================================================*/
typedef struct __attribute__((aligned(64))) {
uint64_t magic; /* 0x00: 'CAPS' | ver | hashAlg | reserved */
uint64_t capsule_id; /* 0x08: == content_hash (content-addressed) */
uint64_t content_hash; /* 0x10: hash of payload bytes */
uint64_t offset; /* 0x18: byte offset into payload arena */
uint64_t length; /* 0x20: payload length in bytes */
uint32_t flags; /* 0x28: state + policy bits */
uint32_t owner_vm; /* 0x2C: 0 = mama, else child VM ID */
uint64_t birth_count; /* 0x30: how many VMs born from this */
uint64_t created_ns; /* 0x38: monotonic timestamp at registration */
} CapsuleDesc; /* 0x40 = 64 bytes */
/*===========================================================================
* CapsuleNameEntry - Capsule Name (parallel array to CapsuleDesc[])
*
* Indexed 1:1 with capsule_descriptors[]. Name is the full relative path
* from the capsule root with '/' replaced by ':', e.g.:
* "core:init.4th"
* "experiments:doe-l8:init-l8-diverse.4th"
* "production:myvm.4th"
*===========================================================================*/
typedef struct {
char name[CAPSULE_NAME_MAX]; /* null-terminated, colon-separated path */
} CapsuleNameEntry;
/*===========================================================================
* CapsuleSigEntry - Ed25519 signature (parallel array to CapsuleDesc[])
*
* Milestone 6 (Phase 8): each capsule's payload bytes (the same bytes
* content_hash already covers), signed by mkcapsule at build time with
* the snakeoil intermediate's private key. has_sig=0 for a capsule built
* before this feature existed or otherwise unsigned -- a real, distinct
* state, not "signature is all-zero bytes" (which sig[64] full of 0x00
* would otherwise look ambiguous with). Indexed 1:1 with
* capsule_descriptors[], same convention as CapsuleNameEntry.
*===========================================================================*/
typedef struct {
uint8_t sig[64]; /* raw Ed25519 R||S, see ed25519_sign()/ed25519_verify() */
uint8_t has_sig; /* 0 = no signature present, 1 = sig[] is real */
uint8_t _pad[7];
} CapsuleSigEntry;
/*===========================================================================
* CapsuleDirHeader - Directory Header
*===========================================================================*/
typedef struct {
uint64_t magic; /* 'CAPD' | ver | reserved */
uint64_t arena_base; /* phys or virt base of payload arena */
uint64_t arena_size; /* bytes */
uint32_t desc_count; /* current number of descriptors */
uint32_t desc_capacity; /* max (fixed at compile time for Phase A) */
uint32_t name_count; /* == desc_count, kept separate for validation */
uint32_t reserved; /* padding */
uint64_t dir_hash; /* hash of descriptor table (for parity) */
} CapsuleDirHeader;
/*===========================================================================
* Validation
*===========================================================================*/
typedef enum {
CAPSULE_VALID = 0,
CAPSULE_ERR_BAD_MAGIC,
CAPSULE_ERR_BAD_VERSION,
CAPSULE_ERR_BAD_HASH_ALG,
CAPSULE_ERR_BOUNDS,
CAPSULE_ERR_MODE_INVALID,
CAPSULE_ERR_REVOKED_ACTIVE,
CAPSULE_ERR_HASH_MISMATCH,
CAPSULE_ERR_NULL_PTR,
} CapsuleValidateResult;
/**
* capsule_validate - Validate a capsule descriptor
*
* @param desc Capsule descriptor to validate
* @param arena_base Base address of payload arena
* @param arena_size Size of payload arena in bytes
* @param verify_hash If true, recompute and compare content hash
* @return CAPSULE_VALID on success, error code otherwise
*/
CapsuleValidateResult capsule_validate(
const CapsuleDesc *desc,
const uint8_t *arena_base,
uint64_t arena_size,
int verify_hash
);
/**
* capsule_validate_result_str - Get string for validation result
*/
const char *capsule_validate_result_str(CapsuleValidateResult result);
/*===========================================================================
* Lookup
*===========================================================================*/
/**
* capsule_find_by_id - Find capsule by content hash ID
*
* @param dir Directory header
* @param descs Descriptor array
* @param id Capsule ID (content hash) to find
* @return Pointer to descriptor, or NULL if not found
*/
const CapsuleDesc *capsule_find_by_id(
const CapsuleDirHeader *dir,
const CapsuleDesc *descs,
uint64_t id
);
/**
* capsule_find_by_name - Find capsule by colon-separated name
*
* @param dir Directory header
* @param descs Descriptor array
* @param names Name entry array (parallel to descs)
* @param name Colon-separated capsule name, e.g. "core:init.4th"
* @return Pointer to descriptor, or NULL if not found
*/
const CapsuleDesc *capsule_find_by_name(
const CapsuleDirHeader *dir,
const CapsuleDesc *descs,
const CapsuleNameEntry *names,
const char *name
);
/**
* capsule_get_payload - Get pointer to capsule payload bytes
*
* @param desc Capsule descriptor
* @param arena_base Base address of payload arena
* @return Pointer to payload bytes, or NULL on error
*/
const uint8_t *capsule_get_payload(
const CapsuleDesc *desc,
const uint8_t *arena_base
);
/**
* capsule_find_mama_init - Find the Mama init capsule
*
* Searches the descriptor array for the capsule with CAPSULE_FLAG_MAMA_INIT.
* There must be exactly one such capsule.
*
* @param dir Directory header
* @param descs Descriptor array
* @return Pointer to Mama's init descriptor, or NULL if not found
*/
const CapsuleDesc *capsule_find_mama_init(
const CapsuleDirHeader *dir,
const CapsuleDesc *descs
);
#ifdef __cplusplus
}
#endif
#endif /* STARKERNEL_CAPSULE_H */