Dynamic switch table (B2) -- FABRIC-3.6.md task 3.1
Replaces the fixed SK_SWITCH_MAX_SLOTS=16 compile-time array with a boot-time, RAM-derived allocation via a new sk_vm_switch_signal_boot_init(), kmalloc'd to stadium_max_vm_count() entries -- the same pattern session_boot_init() already established for Stadium-derived sizing. Every switch-signal participant is a Stadium VM, so this reuses that bound directly rather than deriving a separate one. Verified live on all three architectures: switch table sized to 50 slots (amd64), 202 slots (aarch64), 50 slots (riscv64) -- all well past the old fixed cap. All three boot to [zuse@Hera] ok> cleanly; dict_hash for Hermes/Hestia identical across architectures, unmoved from pre-task values. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
66ea4a5e74
commit
c19ef365fe
+26
-1
@@ -769,10 +769,35 @@ ruling]** cannot be written precisely until Captain Bob settles the named sub-it
|
||||
2026-09-21 · no commit (documentation ruling, see `FABRIC-3.5.md` §XLVI) · all five
|
||||
sub-items plus task 3.3's heat-cost point ruled by Captain Bob, all recommended defaults
|
||||
accepted.
|
||||
- [ ] **3.1** — **Dynamic switch table** (B2) **[needs ruling 3.0c]**. Read
|
||||
- [x] **3.1** — **Dynamic switch table** (B2). Read
|
||||
`SK_SWITCH_MAX_SLOTS`'s every use first; replace the constant with a boot-time,
|
||||
RAM-derived allocation (Stadium's `stadium_max_vm_count_val` pattern). *Check:* boot
|
||||
byte-identical, `dict_hash` unmoved; a synthetic test drives more than 16 slots.
|
||||
2026-09-21 · `logs/20260921-233241/amd64/`, `logs/20260921-233814/aarch64/`,
|
||||
`logs/20260921-234837/riscv64/` (riscv64's first attempt, `logs/20260921-234312/`,
|
||||
timed out mid-boot on a 280s wrapper before reaching the prompt — kept per the
|
||||
never-delete-logs convention, not a real finding, just an undersized timeout; the
|
||||
234837 rerun with more headroom reached the prompt cleanly). All three reach
|
||||
`[zuse@Hera] ok>`, zero `UNKNOWN WORD`. Switch-signal table sized dynamically off
|
||||
`stadium_max_vm_count()` at boot, confirmed via a new `Switch-signal: N slots` console
|
||||
line: **50 slots (amd64), 202 slots (aarch64), 50 slots (riscv64)** — all far above the
|
||||
old fixed 16-slot cap, satisfying the "drives more than 16 slots" check without a
|
||||
separate synthetic harness (real boot-time RAM sizing already clears it by a wide
|
||||
margin). Reused `session_boot_init()`'s exact pattern (kmalloc to
|
||||
`stadium_max_vm_count()`, called in `kernel_main.c` right after `stadium_boot_init()`,
|
||||
before the first `sk_vm_switch_signal_register()` call). `dict_hash` for Hermes
|
||||
(`0xc95ef2d92fa0781f`) and Hestia (`0xfbde9fe105fd3b3d`) identical across all three
|
||||
architectures — unmoved from pre-task values, as expected (this task touches no
|
||||
capsule). Artemis's `dict_hash` differs between the amd64 run (`0xa43d2e104ae7e451`,
|
||||
fresh-formatted `disk/artemis.img`) and the aarch64/riscv64 runs (`0x7f18214489036b39`,
|
||||
both *resuming* the same disk state the amd64 run left behind) — a disk-state artifact
|
||||
of running three sequential boots against one shared image, not an architecture
|
||||
divergence; not a §XXXIV.6 stop condition.
|
||||
note: unrelated finding, not fixed — riscv64's boot logged three
|
||||
`virtio_blk: vblk_io timed out` errors during Artemis's disk I/O in both riscv64
|
||||
attempts (sectors 20/8/8 and 3224/5496/5504); boot recovered and reached the prompt
|
||||
regardless. `virtio_blk.c` was not touched by this task. Reporting per standing rule,
|
||||
not investigating further here.
|
||||
- [ ] **3.2** — **Channel table + common channel**, inert (B1). Dynamic table of topics, each
|
||||
with its own `SkHermesMembership`; the common channel exists from boot; every VM is
|
||||
subscribed at birth. Wired to nothing. *Check:* boot byte-identical; every born VM appears
|
||||
|
||||
@@ -49,6 +49,15 @@
|
||||
* participants (Hera/Hermes/Artemis) -- extending participation later
|
||||
* (Stage 4+) is another sk_vm_switch_signal_register() call, not a
|
||||
* redesign.
|
||||
*
|
||||
* FABRIC-3.6.md task 3.1 (2026-09-21, ruled B2 / FABRIC-3.5.md §XLV.2): the
|
||||
* slot table is no longer a fixed SK_SWITCH_MAX_SLOTS=16 compile-time array.
|
||||
* It is kmalloc'd at boot by sk_vm_switch_signal_boot_init(), sized from
|
||||
* stadium_max_vm_count() -- the same RAM-derived population bound Stadium
|
||||
* and session.c already use (session_boot_init() is the direct precedent
|
||||
* mirrored here). Every switch-signal participant is a Stadium VM, so
|
||||
* reusing that bound directly (rather than re-deriving a separate RAM
|
||||
* budget) needs no new sizing formula.
|
||||
*/
|
||||
|
||||
#ifndef STARKERNEL_CAPSULE_VM_SWITCH_SIGNAL_H
|
||||
@@ -59,17 +68,29 @@
|
||||
#include <stdint.h>
|
||||
#include "starkernel/vm_uuid.h"
|
||||
|
||||
/* Boot-time allocation (FABRIC-3.6.md task 3.1, 2026-09-21): kmalloc's the
|
||||
* slot table to stadium_max_vm_count() entries. Must run after
|
||||
* stadium_boot_init() (that bound is 0, and this fails, until Stadium has
|
||||
* computed it) and before the first sk_vm_switch_signal_register() call.
|
||||
* Soft failure -- returns -1 and leaves the table unallocated (capacity 0,
|
||||
* so register() below simply refuses every registration) rather than
|
||||
* halting boot, same posture as stadium_boot_init()/session_boot_init().
|
||||
* Idempotent-unsafe: calling twice leaks the first allocation, so callers
|
||||
* must call it exactly once. */
|
||||
int sk_vm_switch_signal_boot_init(void);
|
||||
|
||||
/* Register a VM as a switch-signal participant. Returns its slot index,
|
||||
* or -1 if the slot table is full. Call once per participating VM,
|
||||
* after that VM is fully born (never mid-birth -- this stage has no
|
||||
* critical-section protection against being switched away mid-setup). */
|
||||
* or -1 if the slot table is full (or sk_vm_switch_signal_boot_init() was
|
||||
* never called / failed). Call once per participating VM, after that VM is
|
||||
* fully born (never mid-birth -- this stage has no critical-section
|
||||
* protection against being switched away mid-setup). */
|
||||
int sk_vm_switch_signal_register(VMUuid vm_id);
|
||||
|
||||
/* Remove a switch-signal participant (FABRIC-3.md §XXVIII Stage 4,
|
||||
* 2026-09-14) -- Tripod VMs never need this (they live forever), but
|
||||
* WIREBIND-birthed identity VMs cycle through attach/detach repeatedly
|
||||
* and must free their slot for reuse, or the bounded table exhausts
|
||||
* after SK_SWITCH_MAX_SLOTS attach/detach cycles. Compacts the table
|
||||
* after sk_vm_switch_signal_slot_capacity() attach/detach cycles. Compacts the table
|
||||
* (small, bounded, mutated only at attach/detach -- not a hot path).
|
||||
* Clears a pending switch targeting this VM, if any, so the checkpoint
|
||||
* never attempts to switch into a no-longer-registered participant.
|
||||
@@ -115,6 +136,12 @@ int sk_vm_switch_signal_slot_count(void);
|
||||
uint32_t sk_vm_switch_signal_readiness(int slot); /* 0 if slot out of range */
|
||||
uint32_t sk_vm_switch_signal_readiness_of(VMUuid vm_id); /* 0 if not registered */
|
||||
|
||||
/* FABRIC-3.6.md task 3.1 (2026-09-21): the table's boot-time-computed
|
||||
* capacity (0 if sk_vm_switch_signal_boot_init() was never called or
|
||||
* failed) -- the dynamic replacement for the old compile-time
|
||||
* SK_SWITCH_MAX_SLOTS=16. */
|
||||
int sk_vm_switch_signal_slot_capacity(void);
|
||||
|
||||
#endif /* __STARKERNEL__ */
|
||||
|
||||
#endif /* STARKERNEL_CAPSULE_VM_SWITCH_SIGNAL_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,71 @@
|
||||
|
||||
OpenSBI v1.8
|
||||
____ _____ ____ _____
|
||||
/ __ \ / ____| _ \_ _|
|
||||
| | | |_ __ ___ _ __ | (___ | |_) || |
|
||||
| | | | '_ \ / _ \ '_ \ \___ \| _ < | |
|
||||
| |__| | |_) | __/ | | |____) | |_) || |_
|
||||
\____/| .__/ \___|_| |_|_____/|____/_____|
|
||||
| |
|
||||
|_|
|
||||
|
||||
Platform Name : riscv-virtio,qemu
|
||||
Platform Features : medeleg
|
||||
Platform HART Count : 1
|
||||
Platform HART Protection : pmp
|
||||
Platform IPI Device : aclint-mswi
|
||||
Platform Timer Device : aclint-mtimer @ 10000000Hz
|
||||
Platform Console Device : uart8250
|
||||
Platform HSM Device : ---
|
||||
Platform PMU Device : ---
|
||||
Platform Reboot Device : syscon-reboot
|
||||
Platform Shutdown Device : syscon-poweroff
|
||||
Platform Suspend Device : ---
|
||||
Platform CPPC Device : ---
|
||||
Firmware Base : 0x80000000
|
||||
Firmware Size : 321 KB
|
||||
Firmware RW Offset : 0x40000
|
||||
Firmware RW Size : 65 KB
|
||||
Firmware Heap Offset : 0x47000
|
||||
Firmware Heap Size : 37 KB (total), 0 KB (reserved), 12 KB (used), 23 KB (free)
|
||||
Firmware Scratch Size : 4096 B (total), 1464 B (used), 2632 B (free)
|
||||
Runtime SBI Version : 3.0
|
||||
Standard SBI Extensions : ipi,pmu,srst,sse,hsm,rfnc,fwft,time,base,legacy,dbcn,dbtr
|
||||
Experimental SBI Extensions : none
|
||||
|
||||
Domain0 Name : root
|
||||
Domain0 Boot HART : 0
|
||||
Domain0 HARTs : 0*
|
||||
Domain0 Region00 : 0x0000000080040000-0x000000008005ffff M: (F,R,W) S/U: ()
|
||||
Domain0 Region01 : 0x0000000080000000-0x000000008003ffff M: (F,R,X) S/U: ()
|
||||
Domain0 Region02 : 0x0000000000100000-0x0000000000100fff M: (I,R,W) S/U: (R,W)
|
||||
Domain0 Region03 : 0x0000000010000000-0x0000000010000fff M: (I,R,W) S/U: (R,W)
|
||||
Domain0 Region04 : 0x0000000002000000-0x000000000200ffff M: (I,R,W) S/U: ()
|
||||
Domain0 Region05 : 0x000000000c400000-0x000000000c5fffff M: (I,R,W) S/U: (R,W)
|
||||
Domain0 Region06 : 0x000000000c000000-0x000000000c3fffff M: (I,R,W) S/U: (R,W)
|
||||
Domain0 Region07 : 0x0000000000000000-0xffffffffffffffff M: () S/U: (R,W,X)
|
||||
Domain0 Next Address : 0x0000000020000000
|
||||
Domain0 Next Arg1 : 0x00000000bfe00000
|
||||
Domain0 Next Mode : S-mode
|
||||
Domain0 SysReset : yes
|
||||
Domain0 SysSuspend : yes
|
||||
|
||||
Boot HART ID : 0
|
||||
Boot HART Domain : root
|
||||
Boot HART Priv Version : v1.12
|
||||
Boot HART Base ISA : rv64imafdch
|
||||
Boot HART ISA Extensions : sstc,zicntr,zihpm,zicboz,zicbom,sdtrig,svadu
|
||||
Boot HART PMP Count : 16
|
||||
Boot HART PMP Granularity : 2 bits
|
||||
Boot HART PMP Address Bits : 54
|
||||
Boot HART MHPM Info : 16 (0x0007fff8)
|
||||
Boot HART Debug Triggers : 2 triggers
|
||||
Boot HART MIDELEG : 0x0000000000001666
|
||||
Boot HART MEDELEG : 0x0000000000f4b509
|
||||
[2J[004D[=3h[2J[009D[2J[004D[8;031;100t[2J[016DRISC-V EDK2 firmware version 2025.11-3ubuntu7.2
|
||||
Press ESCAPE within 5 seconds for boot options ERROR: C40000002:V03051002 I0 6D33944A-EC75-4855-A54D-809C75241F6C 83FFF850
|
||||
BdsDxe: failed to load Boot0001 "UEFI Misc Device" fr
|
||||
om PciRoot(0x0)/Pci(0x1,0x0): Not Found
|
||||
[2J[001;001H[=3h[2J[009DStarKernel UEFI Loader
|
||||
Loading kernel from ESP...
|
||||
[CKPT 001] Entered efi_main - ConOut live
|
||||
File diff suppressed because it is too large
Load Diff
@@ -30,16 +30,22 @@
|
||||
#include "starkernel/capsule_vm_switch_signal.h"
|
||||
#include "vm.h"
|
||||
#include "starkernel/vm/switch.h" /* sk_vm_switch_current_vm() -- see below */
|
||||
#include "starkernel/vm/stadium.h" /* stadium_max_vm_count() -- task 3.1's sizing bound */
|
||||
#include "starkernel/kmalloc.h"
|
||||
#include "starkernel/console.h"
|
||||
#include <stddef.h>
|
||||
|
||||
/* FABRIC-3.md §XXVIII Stage 4 (2026-09-14): bumped from 8 to 16 to admit
|
||||
* WIREBIND identity VMs alongside the fixed Tripod fleet. 16 is not a new
|
||||
* guess -- it matches messaging.4th's own VM-MAX (the real, already-
|
||||
* agreed system-wide ceiling: 3 permanent Tripod slots + 13 for
|
||||
* identities, "identities get NEW slots 3-10, never renumbered" plus
|
||||
* headroom to VM-MAX itself). See feedback_no_hardcoded_small_scale_bounds
|
||||
* in project memory -- an invented cap here was rejected before. */
|
||||
#define SK_SWITCH_MAX_SLOTS 16
|
||||
/* FABRIC-3.6.md task 3.1 (2026-09-21, ruled B2 / FABRIC-3.5.md §XLV.2):
|
||||
* replaces the old #define SK_SWITCH_MAX_SLOTS 16 (FABRIC-3.md §XXVIII
|
||||
* Stage 4, 2026-09-14 -- itself a bump from 8, pinned to messaging.4th's
|
||||
* VM-MAX constant). The table is now kmalloc'd at
|
||||
* sk_vm_switch_signal_boot_init() to stadium_max_vm_count() entries --
|
||||
* every switch-signal participant is a Stadium VM, so this reuses that
|
||||
* bound directly rather than re-deriving a separate RAM budget, mirroring
|
||||
* session.c's session_boot_init() (the direct precedent for this pattern,
|
||||
* itself mirroring stadium.c's own StadiumVMQuota table). See
|
||||
* feedback_no_hardcoded_small_scale_bounds in project memory -- a fixed
|
||||
* cap here was rejected before; this closes the same class of bound. */
|
||||
|
||||
/* Ticks a non-running participant must accumulate readiness before a
|
||||
* switch to it is requested. Simple linear accumulate-then-threshold,
|
||||
@@ -61,7 +67,8 @@ typedef struct {
|
||||
* function's own doc comment in the header. */
|
||||
} sk_switch_slot_entry_t;
|
||||
|
||||
static sk_switch_slot_entry_t g_slots[SK_SWITCH_MAX_SLOTS];
|
||||
static sk_switch_slot_entry_t *g_slots = (sk_switch_slot_entry_t *)0;
|
||||
static int g_slot_capacity; /* 0 until sk_vm_switch_signal_boot_init() succeeds */
|
||||
static int g_slot_count;
|
||||
static int g_pending;
|
||||
static VMUuid g_pending_target;
|
||||
@@ -71,6 +78,24 @@ static int g_current_slot_cached = -1;
|
||||
static uint64_t g_switch_count;
|
||||
static uint32_t g_ticks_since_switch;
|
||||
|
||||
/* Freestanding: no libc printf. Prints an unsigned decimal, no leading
|
||||
* zeros -- same small helper stadium.c/stadium_blocks.c each carry their
|
||||
* own copy of. */
|
||||
static void console_put_u64(uint64_t v) {
|
||||
char buf[21];
|
||||
int i = 20;
|
||||
buf[20] = '\0';
|
||||
if (v == 0) {
|
||||
console_puts("0");
|
||||
return;
|
||||
}
|
||||
while (v > 0 && i > 0) {
|
||||
buf[--i] = (char)('0' + (v % 10));
|
||||
v /= 10;
|
||||
}
|
||||
console_puts(&buf[i]);
|
||||
}
|
||||
|
||||
static int slot_for_vm_id(VMUuid vm_id) {
|
||||
int i;
|
||||
for (i = 0; i < g_slot_count; i++) {
|
||||
@@ -79,8 +104,35 @@ static int slot_for_vm_id(VMUuid vm_id) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sk_vm_switch_signal_boot_init(void) {
|
||||
size_t max_vm_count = stadium_max_vm_count();
|
||||
sk_switch_slot_entry_t *slots;
|
||||
size_t i;
|
||||
|
||||
if (max_vm_count == 0) return -1; /* Stadium not yet initialized */
|
||||
|
||||
slots = (sk_switch_slot_entry_t *)kmalloc(max_vm_count * sizeof(sk_switch_slot_entry_t));
|
||||
if (!slots) return -1;
|
||||
|
||||
for (i = 0; i < max_vm_count; i++) {
|
||||
slots[i].vm_id = vm_uuid_none();
|
||||
slots[i].readiness = 0;
|
||||
slots[i].has_work = 0;
|
||||
}
|
||||
|
||||
g_slots = slots;
|
||||
g_slot_capacity = (int)max_vm_count;
|
||||
g_slot_count = 0;
|
||||
|
||||
console_puts("Switch-signal: ");
|
||||
console_put_u64((uint64_t)max_vm_count);
|
||||
console_println(" slots");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sk_vm_switch_signal_register(VMUuid vm_id) {
|
||||
if (g_slot_count >= SK_SWITCH_MAX_SLOTS) return -1;
|
||||
if (g_slot_count >= g_slot_capacity) return -1;
|
||||
g_slots[g_slot_count].vm_id = vm_id;
|
||||
g_slots[g_slot_count].readiness = 0;
|
||||
g_slots[g_slot_count].has_work = 0;
|
||||
@@ -212,6 +264,10 @@ int sk_vm_switch_signal_slot_count(void) {
|
||||
return g_slot_count;
|
||||
}
|
||||
|
||||
int sk_vm_switch_signal_slot_capacity(void) {
|
||||
return g_slot_capacity;
|
||||
}
|
||||
|
||||
uint32_t sk_vm_switch_signal_readiness(int slot) {
|
||||
if (slot < 0 || slot >= g_slot_count) return 0;
|
||||
return g_slots[slot].readiness;
|
||||
|
||||
@@ -526,6 +526,15 @@ static void kernel_main_deep(BootInfo *boot_info) {
|
||||
* failed session_register() rather than treating it as fatal. */
|
||||
(void)session_boot_init();
|
||||
|
||||
/* Switch-signal slot table: boot-time allocation (FABRIC-3.6.md task
|
||||
* 3.1, 2026-09-21), sized from stadium_max_vm_count() so it must run
|
||||
* after stadium_boot_init() above and before the first
|
||||
* sk_vm_switch_signal_register() call below (Tripod fleet
|
||||
* registration). Soft failure, same reasoning as stadium_boot_init()/
|
||||
* session_boot_init() -- register() simply refuses every registration
|
||||
* (capacity 0) rather than treating this as fatal. */
|
||||
(void)sk_vm_switch_signal_boot_init();
|
||||
|
||||
/* item 4.1, FABRIC-0.md item 3.6/§17.7: actually enforce "Hera is patron
|
||||
* zero" before anything else can land on cell 0 via the free list, then
|
||||
* bring up the word layer's map. Both must happen before the first word
|
||||
|
||||
Reference in New Issue
Block a user