Punch list §25 item 3.8 complete. Added after starting item 4.1
surfaced the need to thread a vm_id into stadium_admit()'s new quota
parameter; Captain Bob ruled UUID/GUID rather than keeping the
narrower uint32_t.
New VMUuid type (vm_uuid.h/vm_uuid.c): two uint64_t halves, RFC-4122-
shaped for logging. Not real randomness -- checked directly against
QEMU 10.2.1's actual CPU feature set: amd64 RDRAND and riscv64 Zkr are
both real, available features here; aarch64 has no RNG property on any
CPU model including "max" (verified exhaustively via QMP
query-cpu-model-expansion). Captain Bob ruled a uniform fallback
across all three ISAs rather than a per-architecture split.
Fallback is a deterministic PRNG (splitmix64) seeded from the Mama
capsule's content hash, pre-filling a 16-entry FIFO pool at boot and
refilling with another batch of the same stream when exhausted --
exactly the shape requested. Same capsule booted twice produces the
same id sequence, preserving the dict_hash reproducibility this
session has relied on throughout.
Hera keeps a fixed, reserved all-zero id, not drawn from the pool --
capsule_birth.c uses vm_id == 0 as a load-bearing sentinel in three
places (KILL protection x2, fleet heat-fanout parent-chain
terminator), found by reading before writing any code.
Two real sentinel-collision bugs caught before shipping, same class as
STADIUM_CONTAINS_NONE: vm_uuid_none() (all-ones, not all-zero) for
"not yet assigned"/"no VM" placeholders; confirmed item 3.7's quota
table already used an in_use boolean rather than a vm_id sentinel, so
no second collision was actually possible there -- the dead,
never-referenced STADIUM_QUOTA_SLOT_EMPTY macro was removed.
Blast radius larger than first scoped, flagged mid-work rather than
silently absorbed: capsule_vm_physics.c/.h (the fleet heat-transfer
layer item 2.1 modified earlier this session) has its own vm_id-keyed
node table and walks parent_vm_id chains through the same identity
space, so it needed the same change, plus its callers in
mama_forth_words.c and sk_vm_bootstrap.c.
One live FORTH word contract changed, by explicit ruling: CAPSULE-BIRTH
was ( capsule-id -- vm-id ), a single cell -- can't hold 128 bits.
Captain Bob picked pushing two cells ("there is doubles support in the
FORTH std word set anyway"): ( capsule-id -- vm-id-hi vm-id-lo ).
MAMA-VM-ID changed the same way: ( -- 0 0 ).
Verified: full (not standalone-file) kernel rebuild to catch cross-file
breakage given the size of this change -- it surfaced the
capsule_vm_physics.c blast radius a narrower check would have missed.
Three-architecture boot (amd64, aarch64, riscv64), all reaching ok>
with identical dict_hash=0x3d4e1daf289da94f matching the item-3.7
baseline.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
279 lines
8.8 KiB
C
279 lines
8.8 KiB
C
/*
|
||
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_birth.h - VM Birth Protocol (M7.1)
|
||
*
|
||
* Functions for birthing VMs from capsules:
|
||
* - Mama init: Execute core/init.4th to establish Mama's PERSONALITY
|
||
* - Baby birth: Create new VM from (p) capsule
|
||
* - Experiment run: Execute (e) capsule on Mama
|
||
*/
|
||
|
||
#ifndef STARKERNEL_CAPSULE_BIRTH_H
|
||
#define STARKERNEL_CAPSULE_BIRTH_H
|
||
|
||
#include <stdint.h>
|
||
#include "starkernel/capsule.h"
|
||
#include "starkernel/capsule_run.h"
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
/*===========================================================================
|
||
* VM Execution Hook
|
||
*
|
||
* The birth protocol needs to execute FORTH code on a VM.
|
||
* This hook is provided by the VM layer.
|
||
*===========================================================================*/
|
||
|
||
/**
|
||
* VM execution function type
|
||
*
|
||
* @param vm_ctx Opaque pointer to VM context
|
||
* @param code FORTH source code to execute
|
||
* @param code_len Length of code in bytes
|
||
* @return 0 on success, non-zero on error
|
||
*/
|
||
typedef int (*CapsuleExecFn)(void *vm_ctx, const char *code, uint64_t code_len);
|
||
|
||
/**
|
||
* Dictionary hash function type
|
||
*
|
||
* @param vm_ctx Opaque pointer to VM context
|
||
* @return 64-bit hash of dictionary state
|
||
*/
|
||
typedef uint64_t (*CapsuleDictHashFn)(void *vm_ctx);
|
||
|
||
/**
|
||
* VM allocation function type (for baby birth)
|
||
*
|
||
* @return Opaque pointer to new VM context, or NULL on failure
|
||
*/
|
||
typedef void *(*CapsuleVMAllocFn)(void);
|
||
|
||
/**
|
||
* capsule_birth_set_hooks - Configure VM execution hooks
|
||
*
|
||
* Must be called before any birth operations.
|
||
*
|
||
* @param exec_fn Function to execute FORTH code on VM
|
||
* @param dict_hash_fn Function to compute dictionary hash
|
||
* @param vm_alloc_fn Function to allocate new VM (for babies)
|
||
*/
|
||
void capsule_birth_set_hooks(
|
||
CapsuleExecFn exec_fn,
|
||
CapsuleDictHashFn dict_hash_fn,
|
||
CapsuleVMAllocFn vm_alloc_fn
|
||
);
|
||
|
||
/*===========================================================================
|
||
* Mama Init
|
||
*===========================================================================*/
|
||
|
||
/**
|
||
* capsule_birth_mama - Execute Mama's init capsule
|
||
*
|
||
* Finds the MAMA_INIT capsule by flag, validates it, executes it on Mama's VM.
|
||
*
|
||
* @param mama_vm Mama's VM context
|
||
* @param dir Capsule directory header
|
||
* @param descs Capsule descriptor array
|
||
* @param names Capsule name entry array (parallel to descs)
|
||
* @param arena Capsule payload arena
|
||
* @return CAPSULE_RUN_OK on success, error code otherwise
|
||
*/
|
||
CapsuleRunResult capsule_birth_mama(
|
||
void *mama_vm,
|
||
const CapsuleDirHeader *dir,
|
||
const CapsuleDesc *descs,
|
||
const CapsuleNameEntry *names,
|
||
const uint8_t *arena
|
||
);
|
||
|
||
/*===========================================================================
|
||
* Baby Birth
|
||
*===========================================================================*/
|
||
|
||
/**
|
||
* capsule_birth_baby - Birth a new VM from a named (p) capsule
|
||
*
|
||
* Finds the capsule by colon-separated name, validates it, allocates a new
|
||
* VM, executes the capsule payload as IDENTITY, then (if present) executes
|
||
* unit.4th from the baby's block space as PERSONALITY.
|
||
*
|
||
* @param capsule_name Colon-separated capsule name, e.g. "production:myvm.4th"
|
||
* @param dir Capsule directory header
|
||
* @param descs Capsule descriptor array
|
||
* @param names Capsule name entry array (parallel to descs)
|
||
* @param arena Capsule payload arena
|
||
* @param out_vm_id Output: assigned VM ID
|
||
* @param out_vm_ctx Output: new VM context
|
||
* @return CAPSULE_RUN_OK on success, error code otherwise
|
||
*/
|
||
CapsuleRunResult capsule_birth_baby(
|
||
const char *capsule_name,
|
||
const CapsuleDirHeader *dir,
|
||
const CapsuleDesc *descs,
|
||
const CapsuleNameEntry *names,
|
||
const uint8_t *arena,
|
||
VMUuid *out_vm_id,
|
||
void **out_vm_ctx
|
||
);
|
||
|
||
/*===========================================================================
|
||
* Experiment Execution
|
||
*===========================================================================*/
|
||
|
||
/**
|
||
* capsule_run_experiment - Execute a named (e) capsule on Mama
|
||
*
|
||
* Finds the experiment capsule by colon-separated name, validates it,
|
||
* executes it on Mama's VM without creating a new VM.
|
||
*
|
||
* @param mama_vm Mama's VM context
|
||
* @param capsule_name Colon-separated capsule name, e.g. "experiments:doe-l8:init-l8-stable.4th"
|
||
* @param dir Capsule directory header
|
||
* @param descs Capsule descriptor array
|
||
* @param names Capsule name entry array (parallel to descs)
|
||
* @param arena Capsule payload arena
|
||
* @param out_run_id Output: assigned run ID
|
||
* @return CAPSULE_RUN_OK on success, error code otherwise
|
||
*/
|
||
CapsuleRunResult capsule_run_experiment(
|
||
void *mama_vm,
|
||
const char *capsule_name,
|
||
const CapsuleDirHeader *dir,
|
||
const CapsuleDesc *descs,
|
||
const CapsuleNameEntry *names,
|
||
const uint8_t *arena,
|
||
uint64_t *out_run_id
|
||
);
|
||
|
||
/*===========================================================================
|
||
* VM Hook Registration
|
||
*===========================================================================*/
|
||
|
||
/**
|
||
* capsule_vm_hooks_register - Wire concrete VM hooks into the capsule subsystem
|
||
*
|
||
* Registers capsule_exec_hook, capsule_dict_hash_hook, and capsule_vm_alloc_hook.
|
||
* Must be called after vm_init() on Mama's VM and before any birth operations.
|
||
*/
|
||
void capsule_vm_hooks_register(void);
|
||
|
||
/*===========================================================================
|
||
* VM Registry
|
||
*===========================================================================*/
|
||
|
||
/**
|
||
* capsule_vm_registry_init - Initialize VM registry
|
||
*
|
||
* Allocates Mama's registry node (VM 0, name "Hera") via kmalloc and
|
||
* stores mama_vm_ptr so KILL can guard against destroying Mama.
|
||
* Must be called after kmalloc_init().
|
||
*
|
||
* @param mama_vm_ptr Pointer to Mama's VM object (e.g. &sk_mama_vm)
|
||
*/
|
||
void capsule_vm_registry_init(void *mama_vm_ptr);
|
||
|
||
/**
|
||
* capsule_vm_kill - Destroy a named VM and release all its resources
|
||
*
|
||
* Looks up the VM by name (case-insensitive). Hera (VM 0) cannot be
|
||
* killed. If the VM is already DEAD the call is a no-op.
|
||
* On success: vm_cleanup + sf_free, state → VM_STATE_DEAD, name cleared.
|
||
*
|
||
* @param name Symbolic name of the VM to kill (case-insensitive)
|
||
* @return 0 on success (or already dead), -1 if not found or refused
|
||
*/
|
||
int capsule_vm_kill(const char *name);
|
||
|
||
/**
|
||
* capsule_vm_registry_get - Get VM registry entry by ID
|
||
*
|
||
* @param vm_id VM ID to look up
|
||
* @param out Output: registry entry copy
|
||
* @return 0 on success, -1 if not found
|
||
*/
|
||
int capsule_vm_registry_get(VMUuid vm_id, VMRegistryEntry *out);
|
||
|
||
/**
|
||
* capsule_vm_registry_count - Get number of registered VMs
|
||
*/
|
||
uint32_t capsule_vm_registry_count(void);
|
||
|
||
/**
|
||
* capsule_vm_find_by_name - Find VM registry entry by symbolic name
|
||
*
|
||
* Case-sensitive. Returns the first match.
|
||
*
|
||
* @param name Symbolic VM name, e.g. "Hermes"
|
||
* @param out Output: registry entry copy
|
||
* @return 0 if found, -1 if not found
|
||
*/
|
||
int capsule_vm_find_by_name(const char *name, VMRegistryEntry *out);
|
||
|
||
/**
|
||
* capsule_vm_find_by_name_nocase - Find VM registry entry by name (case-insensitive)
|
||
*
|
||
* Used by BIRTH for idempotency: prevents birthing a second VM with the
|
||
* same name regardless of case differences.
|
||
*
|
||
* @param name Symbolic VM name (compared case-insensitively)
|
||
* @param out Output: registry entry copy
|
||
* @return 0 if found, -1 if not found
|
||
*/
|
||
int capsule_vm_find_by_name_nocase(const char *name, VMRegistryEntry *out);
|
||
|
||
/**
|
||
* capsule_vm_set_state - Update a VM's state in the registry
|
||
*
|
||
* @param vm_id VM ID to update
|
||
* @param state New VMState value
|
||
*/
|
||
void capsule_vm_set_state(VMUuid vm_id, uint32_t state);
|
||
|
||
/**
|
||
* capsule_vm_registry_set_name - Assign a symbolic name to a registered VM
|
||
*
|
||
* Truncates to VM_NAME_MAX-1 characters. No-op if vm_id not found.
|
||
*
|
||
* @param vm_id VM ID to name
|
||
* @param name Symbolic name string
|
||
*/
|
||
void capsule_vm_registry_set_name(VMUuid vm_id, const char *name);
|
||
|
||
/**
|
||
* capsule_vm_kill_all_nonmama - Kill every non-Mama VM in the registry.
|
||
*
|
||
* Sets halted, calls vm_cleanup + sf_free, marks state DEAD. Used by
|
||
* Hera's BYE immediately before arch_cold_reset() to reap all children.
|
||
*/
|
||
void capsule_vm_kill_all_nonmama(void);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#endif /* STARKERNEL_CAPSULE_BIRTH_H */ |