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
+11
View File
@@ -0,0 +1,11 @@
# src/starkernel/hal/
Hardware-abstraction-layer implementation, backing `include/starkernel/hal/hal.h`.
- `hal.c` — top-level HAL dispatch.
- `console.c` — UART 16550 console driver.
- `framebuffer.c`, `font_8x16.c`, `vt100.c` — framebuffer console driver,
its bitmap font, and VT100 terminal emulation over the framebuffer.
- `memory.c` — HAL-level memory query interface.
- `host_services.c` — host-service shims used by kernel code that needs a
narrow, testable interface to hardware/firmware services.
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
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+277
View File
@@ -0,0 +1,277 @@
/*
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.
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.
*/
/**
* vm_host.c - Kernel host services implementation
*
* Provides kernel implementations of host service hooks.
* All VM allocations/time/mutex go through these functions.
*/
#ifdef __STARKERNEL__
#include "vm_host.h"
#include "starkernel/hal/hal.h"
#include "kmalloc.h"
#include "console.h"
#include "timer.h"
#include "arch.h"
#include "starkernel/vm/arena.h"
#include <stdbool.h>
/**
* Parity mode: deterministic fake time
* Increments by 1000ns (1us) per call for reproducibility
*/
#ifndef PARITY_MODE
#define PARITY_MODE 0
#endif
static VMHostServices kernel_services;
static uint64_t parity_fake_ns = 0;
static bool host_services_initialized = false;
static bool host_services_logged = false;
/* ============================================================================
* Memory Allocation
* ============================================================================ */
static void* kernel_alloc(size_t size, size_t align) {
if (size == 0) {
return (void*)0;
}
size_t arena_size = sk_vm_arena_size();
if (size == arena_size) {
if (!sk_vm_arena_is_initialized()) {
/* Hera (first call): use the PMM-backed arena singleton */
if (sk_vm_arena_alloc() == 0) {
return NULL;
}
return sk_vm_arena_ptr();
}
/* Baby VM: each needs its own isolated region; returning the singleton
* here causes all VMs to share Hera's memory, overwriting her compiled
* word bodies when the baby registers its dictionary. */
void *p = (align <= sizeof(void*)) ? kmalloc(size)
: kmalloc_aligned(size, align);
if (p) {
uint8_t *b = (uint8_t *)p;
size_t i;
for (i = 0; i < size; i++) b[i] = 0;
}
return p;
}
void *ptr;
if (align <= sizeof(void*)) {
ptr = kmalloc(size);
} else {
ptr = kmalloc_aligned(size, align);
}
return ptr;
}
static void kernel_free(void *ptr) {
if (!ptr) {
return;
}
/* VM arena lifetime is managed separately; ignore free requests */
if (ptr == sk_vm_arena_ptr()) {
return;
}
kfree(ptr);
}
/* ============================================================================
* Monotonic Time
* ============================================================================ */
static uint64_t kernel_monotonic_ns(void) {
#if PARITY_MODE
/* Deterministic: 1us per call */
parity_fake_ns += 1000;
return parity_fake_ns;
#else
/* Delegate to timer_now_ns() rather than reimplementing TSC->ns
* conversion here. This used to check timer_tsc_hz() itself and give
* up (return 0) whenever TSC calibration failed -- which it reliably
* does under QEMU/TCG (no invariant TSC, CPUID/PM-Timer frequency
* derivation both fail: see "Timer: trust=1 (REL), TSC=0 Hz" in the
* boot log). timer_now_ns() already has the correct fallback for
* exactly this case (RELATIVE mode via the ACPI PM Timer,
* timer_now_ns_vm_relative()) that this function never used. Every
* caller of vm_monotonic_ns() -- including vm_physics_touch and
* word-level background decay -- was silently receiving now_ns=0
* forever as a result. Found via VM-FLEET-ATTRACTOR-DESIGN-20260705.md
* rev g/h. */
return timer_now_ns();
#endif
}
/* ============================================================================
* Mutex Operations (No-op in single-threaded kernel)
* ============================================================================ */
static int kernel_mutex_init(void *mutex) {
(void)mutex;
return 0; /* Success */
}
static int kernel_mutex_lock(void *mutex) {
(void)mutex;
return 0; /* Success */
}
static int kernel_mutex_unlock(void *mutex) {
(void)mutex;
return 0; /* Success */
}
static void kernel_mutex_destroy(void *mutex) {
(void)mutex;
/* Nothing to do */
}
/* ============================================================================
* Console Output
* ============================================================================ */
static int kernel_puts(const char *str) {
if (!str) return -1;
console_puts(str);
/* Count characters (console_puts doesn't return count) */
int count = 0;
while (str[count]) count++;
return count;
}
static int kernel_putc(int c) {
console_putc((char)c);
return c;
}
static bool kernel_xt_entry_owned(const void *ptr, size_t bytes) {
if (!ptr || bytes == 0) {
return false;
}
uintptr_t addr = (uintptr_t)ptr;
uintptr_t entry_end = addr + bytes;
if (entry_end < addr) {
return false; /* Overflow check */
}
/* Check if in VM arena (dictionary entries are allocated here) */
if (sk_vm_arena_is_initialized()) {
uint8_t *arena_ptr = sk_vm_arena_ptr();
size_t arena_size = sk_vm_arena_size();
uintptr_t arena_base = (uintptr_t)arena_ptr;
uintptr_t arena_end = arena_base + arena_size;
if (addr >= arena_base && entry_end <= arena_end) {
return true;
}
}
/* Check if in kmalloc heap (for other allocations) */
uintptr_t heap_base = kmalloc_heap_base_addr();
uintptr_t heap_end = kmalloc_heap_end_addr();
if (heap_base != 0 && heap_end != 0) {
if (addr >= heap_base && entry_end <= heap_end) {
return true;
}
}
return false;
}
/* Static wrappers for HAL functions - avoids GOT references in PE.
* With -fPIC, cross-TU function pointer assignments use GOT-relative loads,
* but PE files don't have a working GOT. These wrappers provide local
* addresses that use RIP-relative LEA instead of GOT loads. */
static bool kernel_is_executable_ptr(const void *ptr) {
return sk_hal_is_executable_ptr(ptr);
}
static void kernel_panic(const char *message) {
sk_hal_panic(message);
}
static void host_services_dump_table(void) {
host_services_logged = true;
}
const VMHostServices* sk_host_services(void) {
if (!host_services_initialized) {
sk_host_init();
}
return &kernel_services;
}
void sk_host_init(void) {
if (host_services_initialized) {
host_services_dump_table();
return;
}
/* Reset parity time if needed */
parity_fake_ns = 0;
kernel_services.alloc = kernel_alloc;
kernel_services.free = kernel_free;
kernel_services.monotonic_ns = kernel_monotonic_ns;
kernel_services.mutex_init = kernel_mutex_init;
kernel_services.mutex_lock = kernel_mutex_lock;
kernel_services.mutex_unlock = kernel_mutex_unlock;
kernel_services.mutex_destroy = kernel_mutex_destroy;
kernel_services.puts = kernel_puts;
kernel_services.putc = kernel_putc;
kernel_services.is_executable_ptr = kernel_is_executable_ptr;
kernel_services.owns_xt_entry = kernel_xt_entry_owned;
kernel_services.panic = kernel_panic;
kernel_services.parity_mode = PARITY_MODE;
kernel_services.verbose = 0;
host_services_initialized = true;
host_services_dump_table();
}
#endif /* __STARKERNEL__ */
+64
View File
@@ -0,0 +1,64 @@
/*
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.
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.
*/
/**
* memory.c - HAL memory wrappers
*/
#include <stddef.h>
#include "hal_memory.h"
#include "kmalloc.h"
void *hal_mem_alloc(size_t size)
{
return kmalloc(size);
}
void *hal_mem_alloc_aligned(size_t size, size_t align)
{
return kmalloc_aligned(size, align);
}
void hal_mem_free(void *ptr)
{
kfree(ptr);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff