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
+130
View File
@@ -0,0 +1,130 @@
/*
StarKernel — Unified entropy layer (rng_get_bytes)
Single entropy entry point for the kernel; see include/starkernel/rng.h for
the contract and the probe-and-refuse-loudly discipline this implements.
v2.0.0: virtio-rng is the sole active backend (QEMU-only, uniform across all
three arches). The backend-selection switch in rng_get_bytes() is the exact
seam where the v2.5.0 real per-arch drivers plug in without touching the call
path.
v2.0.1 (G.4, metadata): the real per-arch backends begin to land here, each
guarded by its ISA. amd64 RDRAND is first (SER5). Backend probe order matters
and honors the release policy: virtio-rng is tried first so the QEMU path
stays on virtio-rng unchanged; the real CPU primitive (RDRAND on amd64) is
the fallback that only real hardware reaches, because real boards have no
virtio-rng device. Each backend prints its identity at rng_init() so a boot
log states exactly which source serves entropy.
*/
#ifndef __STARKERNEL__
#error "rng.c is kernel-only"
#endif
#include "starkernel/rng.h"
#include "starkernel/virtio_rng.h"
#include "starkernel/console.h"
/* Number of entropy backends known to this build. Each maps to one case in
* rng_init() and rng_get_bytes(). v2.0.0: virtio-rng. v2.0.1 adds the amd64
* RDRAND backend (real-hardware/SER5 path). */
enum {
RNG_BACKEND_NONE = 0,
RNG_BACKEND_VIRTIO, /* virtio-rng (QEMU, all three arches) */
#if defined(__x86_64__) || defined(__amd64__)
RNG_BACKEND_RDRAND, /* amd64 RDRAND (real hardware, e.g. Beelink SER5) */
#endif
};
static int g_rng_backend = RNG_BACKEND_NONE;
/* --- amd64 RDRAND backend (G.4) ---------------------------------------- */
#if defined(__x86_64__) || defined(__amd64__)
/* CPUID.01H:ECX bit 30 = RDRAND supported. */
static inline int rdrand_available(void) {
uint32_t eax, ebx, ecx, edx;
__asm__ volatile ("cpuid"
: "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
: "a"(1u), "c"(0u));
(void)eax; (void)ebx; (void)edx;
return (int)((ecx >> 30) & 1u);
}
/* Execute RDRAND; returns 1 on a valid draw (CF=1), 0 otherwise. */
static inline int rdrand64(uint64_t *out) {
uint8_t ok;
__asm__ volatile ("rdrand %0; setc %1"
: "=r"(*out), "=qm"(ok)
:
: "cc");
return (int)ok;
}
static int rdrand_fill(uint8_t *buf, size_t n) {
size_t filled = 0;
uint32_t attempts = 0;
const uint32_t MAX_ATTEMPTS = 128u; /* generous: hardware RDRAND is fast */
while (filled < n) {
uint64_t w;
if (!rdrand64(&w)) {
if (++attempts > MAX_ATTEMPTS) return RNG_ERR_NO_BACKEND;
continue;
}
/* Emit whole bytes from the low end. The last (partial) draw is
* simply discarded — throwing away entropy is always safe. */
for (size_t i = 0; i < sizeof(w) && filled < n; i++)
buf[filled++] = (uint8_t)(w >> (8 * i));
}
return 0;
}
#endif /* amd64 */
int rng_init(void) {
/* Probe backends in priority order; first success wins. virtio-rng is
* tried first so the QEMU path stays on virtio-rng unchanged; the real
* per-arch primitive is the fallback that only real hardware reaches. */
if (virtio_rng_init() == 0) {
g_rng_backend = RNG_BACKEND_VIRTIO;
console_println("rng: backend = virtio-rng");
return 0;
}
#if defined(__x86_64__) || defined(__amd64__)
if (rdrand_available()) {
g_rng_backend = RNG_BACKEND_RDRAND;
console_println("rng: backend = rdrand");
return 0;
}
#endif
/* Refuse loudly: never fall through to a deterministic seed. */
g_rng_backend = RNG_BACKEND_NONE;
console_println(
"rng: WARNING — no entropy backend available; rng_get_bytes() "
"will refuse (no deterministic seed fallback)");
return -1;
}
int rng_ready(void) {
return g_rng_backend != RNG_BACKEND_NONE;
}
int rng_get_bytes(uint8_t *buf, size_t n) {
if (!buf || n == 0) return RNG_ERR_NO_BACKEND;
switch (g_rng_backend) {
case RNG_BACKEND_VIRTIO:
return virtio_rng_get_bytes(buf, n);
#if defined(__x86_64__) || defined(__amd64__)
case RNG_BACKEND_RDRAND:
return rdrand_fill(buf, n);
#endif
default:
/* No backend: refuse loudly, never return a deterministic
* throwaway. */
return RNG_ERR_NO_BACKEND;
}
}