Route VM-dictionary sf_malloc/sf_free through the kernel's kmalloc heap
Captain Bob's call after seeing the identity-heap-capacity findings (FABRIC-3.md §X.4): the number of concurrently-running VMs is not known in advance, and once this is a complete operating system the heap should be able to use whatever memory is actually available -- not a hardcoded compile-time ceiling. This was already half-built and just not wired up. src/starkernel/vm/alloc_kernel.c previously implemented sf_malloc()/ sf_free() (platform_alloc.h's allocator abstraction -- what vm_create_word() calls for every VM's word dictionary) as its own isolated static 4MB arena: first-fit free list, no splitting or coalescing. That's exactly the allocator that topped out around 6 concurrent WIREBIND-born identities, failing from fragmentation before true capacity exhaustion (§X.4's own measurements). Sitting right next to it, unused for this purpose: src/starkernel/memory/ kmalloc.c, the kernel's general heap. Already initialized at boot (M6, kernel_main.c, well before any VM is ever born), reserved from real PMM-tracked physical memory rather than a fixed array, defaults to a 2 GiB floor explicitly sized "for 256+ baby VMs" per its own comment, overridable via the --heap= boot flag, and its free list actually coalesces neighboring blocks on every free. Change: alloc_kernel.c's sf_malloc()/sf_free() now delegate to kmalloc_aligned()/kfree() instead of managing a separate arena. sf_alloc_init() becomes a no-op (kmalloc is already initialized by the time any VM allocation can happen, and "resetting" a heap now shared by every kernel subsystem would be actively wrong -- confirmed no external caller depended on its old reset semantics). sf_alloc_get_stats() reads kmalloc_get_stats() fresh rather than shadowing byte counts locally; alloc_count/free_count (which kmalloc.c doesn't track) stay as simple local counters. sf_calloc()/sf_realloc() are otherwise unchanged. Kernel- only: the hosted (non-kernel) StarForth build keeps its own separate alloc_host.c implementation, untouched. Verified live: replaying the exact hotplug sequence that previously topped out at 6 identities (Zuse + 8 identities, one at a time via QMP device_add) now succeeds for all 9, where identity 05 specifically used to fail. Three-arch clean qemu acceptance (single Zuse device, the standard regression case) passed on amd64, aarch64, and riscv64 -- one aarch64 attempt hit an unrelated, already-documented one-off QEMU hiccup (empty log, boot never progressed past firmware) and passed cleanly on retry with no rebuild. Not addressed here: the underlying free-list itself is still first-fit without splitting (only coalescing changed, inherited from kmalloc.c); per-VM dictionary sizing (shrinking what each WIREBIND VM's word set actually needs) is a separate, still-open lever from FABRIC-3.md §X.4's open architecture question. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014Ec88YKxxhZGG1RNnune78
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
36f1d6ae9e
commit
56e19a00f9