Compare commits

...
10 Commits
Author SHA1 Message Date
Robert Allan James 58c59e87e5 Initial commit
Signed-off-by: Robert Allan James <robert.allan.james@gmail.com>
2026-09-01 12:07:32 -04:00
Robert Allan James d2a0305703 Record driving deadlines for #1 (provisional expiry) and #2 (December deliverable)
Clarified 2026-08-29 with the author: "no hurry" is wrong for #1 and #2.

  - #1 (Hosted StarForth): the provisional will expire before conversion. Its
    priority claim is time-boxed (provisional filed ~Dec 2025, window ~Dec
    2026); if the non-provisional isn't filed claiming benefit before the
    window lapses the priority is lost and the same subject matter can't be
    re-staked by refiling thereafter. Hard clock regardless of December scope.
  - #2 (full StarshipOS): the December deliverable that keeps the flagship
    covered; pending counsel confirmation it may also be the conversion
    vehicle for #1's provisional.

Open point to resolve: is #2 (or the December delivery) the conversion vehicle
for #1, or is #1 converted by a filing separate from #2? Decision record only;
no filing made. Authoritative form in ROADMAP.md; FABRIC-3.md tracks it.
2026-08-29 10:36:19 -04:00
Robert Allan James 31dfc5de63 Record IP framing of the three products: 3 patent applications + 3 marks (StarForth, StarshipOS/LithosAnanke, Compudynamics)
The three-product split is treated as three patent applications, each matched
to a trademark (decided 2026-08-29):

  - Patent 1 + mark StarForth                  -> hosted/interpreted runtime
  - Patent 2 + marks StarshipOS (canonical spelling; noted as "StarshopOS"
    in the decision words) + LithosAnanke       -> full standalone OS
  - Patent 3 + mark Compudynamics               -> Zynq steady-state machinery
    with sealed executions, HOL-proven, anchored by the physics-adaptive runtime

Flagged open for counsel (not assumed/filed): the repo already carries a
"Patent pending" USPTO provisional filed Dec 2025 for the Compudynamics
physics-adaptive runtime (docs/patent/). Whether patent 3 is a continuation/
refinement of that provisional, and whether the three product applications are
additive to or fold it in, must be reconciled. Records intent only; no legal
text drafted or filed. Authoritative form in ROADMAP.md; FABRIC-3.md tracks it.
2026-08-29 10:32:04 -04:00
Robert Allan James 936d046ca6 Record the FPGA three-product split: Hosted StarForth / full StarshipOS / HOL-proven sealed-execution hardware
The Zynq FPGA is not a fourth platform to port to — it is the pivot that
forces the project into three distinct products, each with its own host,
delivery, and proof character (decided 2026-08-29):

  1. Hosted StarForth - the existing hosted/interpreted StarForth runtime
     (3-arch acceptance-tested), delivered as a portable embedded runtime.
  2. A full StarshipOS - the standalone OS built on LithosAnanke
     (LithosAnanke -> StarshipOS), a self-booting OS on general silicon
     (SER5/RasPi/Milk-V line).
  3. Hardware steady-state machinery with sealed executions, HOL-proven -
     the FPGA-native product: hardware-enforced sealed executions and
     steady-state machinery machine-checked in a proof assistant (HOL);
     delivery is the bitstream + HOL proof artifacts, not just an OS port.

The coupling is the point: product 3 is born on the FPGA, and its existence
is what cleanly separates 1 from 2 from 3. Product 1 ships hosted on an OS,
product 2 as an OS on general silicon, product 3 as proven hardware. Per-
product gates and the even-major line carrying the three as separate tracks
are scoped at v2.5.0 close / during the coloring-in phase. Complements, and
does not retract, the existing hardware bare-metal release policy.

Authoritative form in ROADMAP.md; FABRIC-3.md tracks the same horizon.
2026-08-29 10:30:09 -04:00
Robert Allan James 8e94522d10 Record trajectory beyond v2.5.0: Zynq FPGA next, after a "coloring in" hardening phase
The next big milestone after the three-board bare-metal cut (v2.5.0) is
transferring the battle-tested amd64/aarch64/riscv64 story to a Zynq (AMD
Xilinx) FPGA SoC — configurable silicon with soft/hard CPU cores, PL fabric,
and a non-standard memory map, a genuinely larger step than any prior board
(expected on a new even-major line). Between v2.5.0 and the Zynq sits a
"coloring in" period: hardening that thickens the shape of what exists rather
than adding silicon (USB BOT/xHCI + block robustness, live-entropy and
Zuse-cert hardening on real ASICs, SMP/multi-core + IRQ routing from the HAL
notes, driver breadth) so the FPGA carries a production-honest shape forward.

Authoritative form in ROADMAP.md "Beyond v2.5.0"; FABRIC-3.md tracks the same
horizon in the post-release section and re-points G.6's Next at the
v2.2.0/v2.4.0/v2.5.0 cadence.
2026-08-29 10:28:22 -04:00
Robert Allan James 25276ae359 Decide board-by-board hardware rollout: v2.2.0 (SER5 amd64) / v2.4.0 (RasPi5 aarch64) / v2.5.0 (all three)
Real silicon arrives incrementally (Beelink SER5 in hand now; RasPi 5 + Milk-V
orderable around Mon 2026-08-31), so the hardware release is split per board
in hand, each an even-minor LTS point-in-time cut on the same line:

  - v2.2.0  amd64 bare metal  — Beelink SER5 (two 16GB sticks: one boots the
                                thumbdrive image, one mints a real Zuse user)
  - v2.4.0  aarch64 bare metal — Raspberry Pi 5
  - v2.5.0  all three bare     — adds Milk-V (riscv64)

Each closes only when its board's items are proven live (boot to ok>, block-
fence Zuse true, backend entropy non-deterministic), never build-only.

Records the decision in the authoritative Release Versioning Policy
(docs/lithosananke/ROADMAP.md, "Board-by-board hardware rollout, decided
2026-08-29") and re-maps G.4/G.5 in FABRIC-3.md onto the new cadence, noting
v2.0.0 was cut (tag v2.0.0).
2026-08-29 10:22:36 -04:00
Robert Allan James 28de700645 v2.0.1: G.4 amd64 RDRAND backend behind rng_get_bytes() (SER5 entropy)
First real per-arch RNG backend, added to the v2.0.0 unified entry point in
src/starkernel/rng/rng.c, #if-guarded to amd64: CPUID.01H:ECX[30] RDRAND
detection + inline-asm rdrand draws feeding rdrand_fill() (whole-byte
emission from the low end; a partial final draw is discarded -- throwing
away entropy is always safe).

Probe order honors the release policy: virtio-rng is tried first, so the
QEMU path stays on virtio-rng unchanged; RDRAND is the fallback only real
hardware (which has no virtio-rng device) reaches. QEMU-verified both ways
on amd64: with virtio-rng present -> "rng: backend = virtio-rng" (unchanged);
with virtio-rng absent and RDRAND exposed (-cpu max) -> "rng: backend =
rdrand" + "entropy: ready" + Zuse attach confirmed. rdrand_fill()'s exact
logic host-proven: fills 32-byte/16-byte buffers and yields differing draws
run-to-run (non-deterministic). aarch64/riscv64 builds unaffected (guarded
off). riscv64 Zkr and aarch64 peripheral-RNG backends remain parked for their
real boards.

FABRIC-3.md G.4 amd64 slice marked BUILT + QEMU-verified.
2026-08-29 10:18:07 -04:00
Robert Allan James 19bc90c97d v2.0.1: document G.6 generic thumbdrive image milestone in FABRIC-3.md 2026-08-29 10:12:58 -04:00
Robert Allan James bd266942ce v2.0.1: generic GPT/FAT32 UEFI bootable thumbdrive image (thumbdrive goal)
New `make -f Makefile.starkernel thumbdrive` goal builds a generic
UEFI-bootable GPT disk image (disk image -> GPT + one FAT32 "STARKERNEL"
EFI System partition with EFI/BOOT/BOOT<ARCH>.EFI + startup.nsh) that can be
written directly to a USB thumbdrive with dd and boots on any real amd64 UEFI
firmware (Beelink SER5 path) as well as under QEMU. The monolithic loader
embeds the whole kernel, so the ESP needs only the UEFI fallback boot path.

Verified under QEMU by attaching the image as a USB mass-storage device (not
cdrom): OVMF BDS auto-selected "UEFI QEMU QEMU USB HARDDRIVE" (Boot0002),
then kernel booted normally -- LithosAnanke v2.0.0, POST 1012/0/0 + ok>,
rng: backend = virtio-rng + entropy: ready, Artemis ready, and the USB BOT/
xHCI storage path enumerated (READ CAPACITY10 -> MSC device ready -> READ10
CSW PASS). This mirrors the real-hardware SER5 flow: firmware boots the USB
thumbdrive's ESP, and the OS's own storage rides the same USB BOT/xHCI path.

Works for all three arches via the arch-mapped EFI boot name.
2026-08-29 10:12:43 -04:00
Robert Allan James 2efd7fe7e7 v2.0.0: QEMU release — bump LITHOS_VERSION to 2.0.0
The §G v2.0.0 QEMU release-gate punch list is complete (G.1 xHCI stall
recovery, G.2 unified rng_get_bytes() entropy entry point, G.3 NVRAM
de-scoped). Bump the kernel version to 2.0.0 (even major = LTS, per the
Release Versioning Policy: X.0.0 = QEMU release, X.5.0 = hardware bare-metal
release). Update README and .claude/CLAUDE.md version references and the
Makefile.starkernel version-roadmap comment.

Verified: all three arches (amd64/aarch64/riscv64) build clean with v2.0.0
embedded; QEMU amd64 boot shows "LithosAnanke v2.0.0", POST 1012/0/0 + ok>,
rng: backend = virtio-rng + entropy: ready, and Zuse identity confirmed from
the attached thumbdrive.
2026-08-29 10:09:37 -04:00
14 changed files with 533 additions and 35 deletions
+1 -1
View File
@@ -211,7 +211,7 @@ Output: `build/<arch>/kernel/starkernel_loader.efi` + `build/<arch>/kernel/stark
Two independently tracked version strings flow into the generated `include/version.h`:
`VERSION` (`Makefile.starkernel` — the embedded StarForth engine version, currently `3.1.0`;
note this does **not** auto-sync with the standalone StarForth repo's own version) and
`LITHOS_VERSION` (`Makefile.starkernel` — the kernel version, currently `1.5.4`).
`LITHOS_VERSION` (`Makefile.starkernel` — the kernel version, currently `2.0.1`).
### Build configuration (Kconfig — real, wired, not vestigial)
+91 -11
View File
@@ -3292,6 +3292,14 @@ author expects to have money for the SBCs — RasPi 6, Milk-V — within about a
v2.0.0 cut). Nothing
is deferred that QEMU alone could already prove out; only what genuinely needs real silicon.
**v2.0.0 was CUT 2026-08-29 (annotated tag `v2.0.0`, the three-arch QEMU release).** With
real boards arriving incrementally (Beelink SER5 in hand now; RasPi 5 + Milk-V orderable
around Mon 2026-08-31), the hardware rollout is split per board in hand into **v2.2.0
(amd64/SER5), v2.4.0 (aarch64/RasPi 5), v2.5.0 (all three, adds Milk-V riscv64)** — each an
even-minor LTS point-in-time cut on the same line. Authoritative form in `ROADMAP.md`
"Release Versioning Policy": **Board-by-board hardware rollout, decided 2026-08-29**. The
G.2/G.4/G.5 items below are re-mapped onto that cadence in each section's completion notes.
Everything about the state being shipped by v2.0.0 is unchanged by this versioning: the
current tree is a complete, deterministic, three-architecture OS that boots UEFI under QEMU
(M0M9 core milestones complete, M7.1 Capsules live, M9 Block I/O live, terminal/REPL I/O
@@ -3413,21 +3421,59 @@ there.
primitive) returns genuinely non-deterministic bytes (two boots differ), the Zuse mint
path seeded from it produces a valid distinct cert per boot when bleached, and QEMU
behavior is unchanged.
- **v2.0.1 — amd64 RDRAND backend BUILT + QEMU-verified 2026-08-29 (SER5 slice).** The first
real per-arch backend lands in `src/starkernel/rng/rng.c`, behind the v2.0.0 unified
entry point, `#if`-guarded to amd64: CPUID.01H:ECX[30] detection + inline-asm `rdrand`
draws feeding `rdrand_fill()` (whole-byte emission, partial draw discarded — throwing
away entropy is always safe). Probe order honors the policy: virtio-rng is tried first,
so the QEMU path stays on virtio-rng unchanged; RDRAND is the fallback that only real
hardware (which has no virtio-rng) reaches. QEMU-verified both ways on amd64: with
virtio-rng present → `rng: backend = virtio-rng` (unchanged); with virtio-rng absent and
RDRAND exposed (`-cpu max`) → `rng: backend = rdrand` + `entropy: ready` + Zuse attach
confirmed. `rdrand_fill()`'s exact logic host-proven to fill 32-byte/16-byte buffers and
produce differing draws run-to-run (non-deterministic). aarch64/riscv64 builds unaffected
(guarded off). Still parked for their real boards: riscv64 Zkr (RNDR), aarch64 peripheral
RNG. Next: prove RDRAND live on the real SER5 (v2.2.0), then add Zkr (v2.5.0/Milk-V) and the
aarch64 peripheral RNG (v2.4.0/RasPi 5) as those boards reach v2.2.0-level closure.
#### G.5 [v2.5.0] Real-machine boot validation (SER5 / RasPi 6 / Milk-V)
#### G.5 [v2.2.0 / v2.4.0 / v2.5.0] Real-machine boot validation (SER5 / RasPi 5 / Milk-V)
Flash `starkernel.iso` to real media and boot each real board in hand, confirming the same
acceptance story QEMU keeps green: POST `1012/0/0` + `ok>`, block-fence Zuse load true to the
already-minted Artemis image, and the G.4 RNG backend working live. The board pool is
SER5 (if still in hand), RasPi 6 (aarch64), Milk-V (riscv64) — the goal is at least one
board per architecture, but each board that boots is a separate, recorded data point.
This is the genuine transfer proof that the zero-degradation QEMU claim holds on real
silicon — the thing v2.0.0 cannot honestly claim.
Boot the generic thumbdrive image (`make -f Makefile.starkernel ARCH=<arch> thumbdrive`) on
each real board in hand, confirming the same acceptance story QEMU keeps green: POST
`1012/0/0` + `ok>`, block-fence Zuse load true to the already-minted Artemis image, and the
corresponding G.4 RNG backend working live. **Mapping onto the board-by-board cadence
(decided 2026-08-29):** v2.2.0 = SER5 (amd64, in hand now — two 16 GB sticks available, one
to boot the image, one to mint a real Zuse identity on real hardware); v2.4.0 = RasPi 5
(aarch64, orderable around Mon 2026-08-31); v2.5.0 = adds Milk-V (riscv64), the full
three-arch bare-metal cut. Each board that boots is a separate, recorded data point, and
each milestone closes only when its board's items are proven live (not build-only).
- **Exit criterion:** each board in hand cold-boots to `ok>` with Arena conservation
- **Exit criterion (per milestone):** the board cold-boots to `ok>` with Arena conservation
(43691/21845/65536), Zuse cert loads from the fence (or mints fresh on bleached media),
and its G.4 RNG backend returns non-deterministic bytes live. v2.5.0 does not close on any
board's G.4/G.x item being build-only.
and its G.4 RNG backend returns non-deterministic bytes live. A milestone does not close on
any of its board's G.4/G.x items being build-only.
#### G.6 [v2.0.1] Generic UEFI-bootable thumbdrive image (SER5 path — **BUILT + VERIFIED 2026-08-29**)
First concrete v2.0.1/SER5 work item, taken up because the Beelink SER5 is in hand and a
"generic thumbdrive bootable OS" is the target. The new `make -f Makefile.starkernel
thumbdrive` goal builds a generic GPT/FAT32 disk image (one "STARKERNEL" EFI System
partition with `EFI/BOOT/BOOT<ARCH>.EFI` + `startup.nsh`) writable to a USB stick with
`dd` and bootable on any real amd64 UEFI firmware as well as under QEMU. The monolithic
loader embeds the entire kernel, so the ESP needs only the UEFI fallback boot path —
this is what makes the image "as generic as possible."
- **Verified** by attaching the image to QEMU as a **USB mass-storage device** (not cdrom):
OVMF BDS auto-selected `Boot0002 "UEFI QEMU QEMU USB HARDDRIVE"`, then the kernel booted
normally — v2.0.0 banner, POST `1012/0/0` + `ok>`, `rng: backend = virtio-rng` +
`entropy: ready`, Artemis ready, and the USB BOT/xHCI storage path enumerated
(READ CAPACITY10 → MSC device ready → READ10 CSW PASS). This mirrors the real SER5 flow:
firmware boots the thumbdrive's ESP, and the OS's own storage rides the same USB BOT/xHCI
path. Works for all three arches via the arch-mapped EFI boot name.
- **Next (v2.0.1→v2.2.0):** G.5 real-board proof on the SER5 (in hand) — boot the thumbdrive
image, live RDRAND entropy, real Zuse mint on a second stick — then extend per arch to
v2.4.0 (RasPi 5) and v2.5.0 (Milk-V). Authoritative cadence in `ROADMAP.md`
"Board-by-board hardware rollout".
---
@@ -3447,3 +3493,37 @@ the punch lists above explicitly delimit what is excluded from each milestone:
- Dirty-event granularity (1.11, blocked on 4.3) and the §17.4 framebuffer heat/decay design.
- Re-run the DoE on the new substrate (§A 5.1).
- First-touch allocation first-call-free.
**Beyond v2.5.0 — Zynq FPGA, then a coloring-in period, decided 2026-08-29.** The next big
milestone after the three-board bare-metal cut (v2.5.0) is transferring the story to a
**Zynq FPGA** (configurable silicon — soft/hard cores, PL fabric, non-standard memory map) —
a genuinely larger step than any prior board, expected on a new even-major line. Between
v2.5.0 and starting the Zynq sits a **"coloring in"** hardening phase: making v2.5.0's
real-hardware story production-honest (USB BOT/xHCI + block robustness; live-entropy and
Zuse-cert hardening on real ASICs; SMP/multi-core + IRQ routing from the HAL notes; driver
breadth) so the FPGA carries a thickened, not thin, shape forward.
**The FPGA creates a three-product split, decided 2026-08-29.** The Zynq is the pivot that
forces the project into three distinct products, each with its own host, delivery, and proof
character: (1) **Hosted StarForth** — the existing hosted/interpreted StarForth runtime;
(2) **A full StarshipOS** — the standalone OS on general silicon (LithosAnanke → StarshipOS);
(3) **Hardware steady-state machinery with sealed executions, HOL-proven** — the FPGA-native
product: hardware-enforced sealed executions and steady-state machinery machine-checked in a
proof assistant (HOL); delivery is the bitstream + HOL proof artifacts. Product 3 is born on
the FPGA and its existence is what cleanly separates 1 from 2 from 3. Full form in
`ROADMAP.md` "Release Versioning Policy → The FPGA creates a three-product split".
**IP framing, decided 2026-08-29.** The three products are treated as three patent
applications with a matching mark each: Patent 1 + **StarForth** (hosted runtime); Patent 2 +
**StarshipOS + LithosAnanke** (full standalone OS); Patent 3 + **Compudynamics** (Zynq
steady-state/sealed-execution HOL-proven hardware, anchored by the physics-adaptive runtime).
Open for reconciliation with counsel: the repo already has a **"Patent pending"** USPTO
provisional (filed Dec 2025) for the Compudynamics physics-adaptive runtime (`docs/patent/`);
patent 3 and the three product applications must be positioned relative to it (continuation?
additive?) — recorded as intent here, nothing filed or drafted. **Driving deadlines
(clarified 2026-08-29):** #1's provisional will **expire before conversion** (filed ~Dec
2025, window ~Dec 2026 — priority lost if unconverted; the subject matter can't be re-staked
by refiling after lapse), so #1 is on a hard clock; **#2 (full StarshipOS) is the December
deliverable** that keeps the flagship covered — and, pending counsel confirmation, may be the
conversion vehicle for #1. Authoritative form in `ROADMAP.md` "IP framing of the three
products".
+92 -4
View File
@@ -71,12 +71,16 @@ MAKEFLAGS += -j$(NPROC)
endif
# Version
# Roadmap:
# Roadmap (per docs/lithosananke/ROADMAP.md "Release Versioning Policy" and
# FABRIC-3.md §G — X.0.0 = QEMU release, X.5.0 = hardware bare-metal release):
# v1.0.x — serial-only production (released)
# v1.5.x — framebuffer VT100 terminal/console milestone (current)
# v2.0.0 — StarForth SDK release; v2.x.x development begins from there
# v1.5.x — framebuffer VT100 terminal/console milestone (released)
# v2.0.0 — QEMU release (even major = LTS): three-arch QEMU story complete
# v2.0.1 — SER5 hardware-track line: RDRAND backend + generic thumbdrive image goal
# v2.2.0 — amd64 bare-metal (Beelink SER5) — see ROADMAP "Board-by-board rollout"
# v2.5.0 — hardware bare-metal release: real per-arch RNG + real-board boot
VERSION ?= 3.1.0
LITHOS_VERSION ?= 1.5.4
LITHOS_VERSION ?= 2.0.1
# ==============================================================================
# BUILD PATHS
@@ -554,6 +558,7 @@ KERNEL_OBJS := \
.PHONY: all clean clean-kernel kernel kernel-all
.PHONY: qemu qemu-esp qemu-gdb
.PHONY: thumbdrive iso-usb
.PHONY: info help
# ==============================================================================
@@ -1002,6 +1007,87 @@ else ifeq ($(ARCH),riscv64)
cp $$CSV $(DOE_LATEST_DIR)/riscv64.csv 2>/dev/null || true
endif
# thumbdrive — build a generic UEFI-bootable GPT/FAT32 disk image that can be
# written directly to a USB thumbdrive (dd) and boots on real amd64 UEFI
# hardware (e.g. Beelink SER5) as well as under QEMU. This is the "generic
# thumbdrive bootable OS" image for the v2.5.0/SER5 bare-metal path: the
# monolithic loader embeds the whole kernel, so the ESP needs only the UEFI
# fallback boot path EFI/BOOT/BOOT<ARCH>.EFI. Storage on real hardware is the
# USB BOT/xHCI path (already live), not virtio.
thumbdrive: all
@mkdir -p $(BUILD_DIR)
@if ! which sgdisk >/dev/null 2>&1; then echo "Error: sgdisk not found. Install gdisk (apt-get install gdisk)."; exit 1; fi
@if ! which mkfs.fat >/dev/null 2>&1; then echo "Error: mkfs.fat not found. Install dosfstools (apt-get install dosfstools)."; exit 1; fi
@case "$(ARCH)" in \
amd64) BOOTNAME="BOOTX64.EFI" ;; \
aarch64) BOOTNAME="BOOTAA64.EFI" ;; \
riscv64) BOOTNAME="BOOTRISCV64.EFI" ;; \
*) echo "Error: no thumbdrive EFI boot name for ARCH=$(ARCH)"; exit 1 ;; \
esac; \
# Geometry: 128 MiB disk (262144 sectors), GPT partition 1 spans sectors \
# 2048..262110 (the GPT last-usable sector for this disk size), i.e. \
# 260063 sectors. The FAT32 ESP image MUST match the partition size \
# exactly; a larger ESP overruns the disk (GPT grows corrupt) or \
# spills past the partition end, both of which made earlier builds \
# unbootable on hardware. \
DISK=$(BUILD_DIR)/starkernel-thumbdrive.img; \
ESP_SECTORS=260063; \
rm -f $$DISK $(BUILD_DIR)/thumbdrive-esp.img; \
dd if=/dev/zero of=$(BUILD_DIR)/thumbdrive-esp.img bs=512 count=$$ESP_SECTORS 2>/dev/null; \
mkfs.fat -F 32 -n "STARKERNEL" $(BUILD_DIR)/thumbdrive-esp.img >/dev/null 2>&1; \
mmd -i $(BUILD_DIR)/thumbdrive-esp.img ::/EFI; \
mmd -i $(BUILD_DIR)/thumbdrive-esp.img ::/EFI/BOOT; \
mcopy -i $(BUILD_DIR)/thumbdrive-esp.img $(LOADER_EFI) ::/EFI/BOOT/$$BOOTNAME; \
printf 'FS0:\\EFI\\BOOT\\%s\r\n' "$$BOOTNAME" > $(BUILD_DIR)/thumbdrive-startup.nsh; \
mcopy -i $(BUILD_DIR)/thumbdrive-esp.img $(BUILD_DIR)/thumbdrive-startup.nsh ::/startup.nsh; \
dd if=/dev/zero of=$$DISK bs=1M count=128 2>/dev/null; \
sgdisk -n 1:2048:0 -t 1:ef00 -c 1:"EFI System" $$DISK >/dev/null 2>&1; \
dd if=$(BUILD_DIR)/thumbdrive-esp.img of=$$DISK bs=512 seek=2048 conv=notrunc 2>/dev/null; \
rm -f $(BUILD_DIR)/thumbdrive-esp.img $(BUILD_DIR)/thumbdrive-startup.nsh; \
echo "Thumbdrive image: $$DISK"; \
echo "Write to a USB stick with: dd if=$$DISK of=/dev/sdX bs=4M status=progress"
# iso-usb — build a PURE UEFI isohybrid ISO for the Iso Image Writer workflow
# (GNOME Disks "Restore Disk Image...", or dd). Writes a single .iso to a USB
# stick as a raw image; the ISO carries a clean GPT with an EFI System
# Partition holding EFI/BOOT/BOOT<ARCH>.EFI, so real UEFI firmware (e.g.
# Beelink SER5) scans the ESP and boots it. No GRUB, no isolinux, no MBR boot
# code — the protective MBR template is zeroed (partition metadata only).
# Also still boots under QEMU via -cdrom. This is the novice path: one ISO,
# picked with a GUI, written to the stick.
iso-usb: all
@mkdir -p $(BUILD_DIR)
@if ! which xorriso >/dev/null 2>&1; then echo "Error: xorriso not found. Install xorriso (apt-get install xorriso)."; exit 1; fi
@if ! which mformat >/dev/null 2>&1 || ! which mmd >/dev/null 2>&1 || ! which mcopy >/dev/null 2>&1; then echo "Error: mtools not found. Install mtools (apt-get install mtools)."; exit 1; fi
@case "$(ARCH)" in \
amd64) BOOTNAME="BOOTX64.EFI" ;; \
aarch64) BOOTNAME="BOOTAA64.EFI" ;; \
*) echo "Error: iso-usb EFI boot name only defined for amd64/aarch64 yet"; exit 1 ;; \
esac; \
ISODIR=$(BUILD_DIR)/iso-usb; \
rm -rf $$ISODIR; mkdir -p $$ISODIR; \
dd if=/dev/zero of=$$ISODIR/efi.img bs=512 count=8192 2>/dev/null; \
mformat -i $$ISODIR/efi.img :: >/dev/null 2>&1; \
mmd -i $$ISODIR/efi.img ::/EFI; mmd -i $$ISODIR/efi.img ::/EFI/BOOT; \
mcopy -i $$ISODIR/efi.img $(LOADER_EFI) ::/EFI/BOOT/$$BOOTNAME; \
printf 'FS0:\\EFI\\BOOT\\%s\r\n' "$$BOOTNAME" > $$ISODIR/startup.nsh; \
mcopy -i $$ISODIR/efi.img $$ISODIR/startup.nsh ::/startup.nsh; \
head -c 432 /dev/zero > $$ISODIR/protmbr.bin; \
ISO=$(BUILD_DIR)/starkernel-iso-usb.iso; \
rm -f $$ISO; \
xorriso -as mkisofs \
-V STARKERNEL -r -J \
-isohybrid-mbr $$ISODIR/protmbr.bin \
-eltorito-alt-boot -e efi.img -no-emul-boot \
-isohybrid-gpt-basdat \
-o $$ISO $$ISODIR >/dev/null 2>&1; \
rm -rf $$ISODIR; \
echo "Iso Image Writer ISO (pure UEFI): $$ISO"; \
echo " In GNOME Disks, pick the ISO with 'Restore Disk Image...' and select your USB stick."; \
echo " Or: dd if=$$ISO of=/dev/sdX bs=4M status=progress"
# qemu-esp — interactive dev boot from FAT directory (no disk image rebuild,
# no auto-kill/timeout/DOE-injection logic — stays up until you quit it
# yourself with Ctrl-A X or by closing the window).
@@ -1134,6 +1220,8 @@ help:
@echo " qemu — clean boot, serial tee'd live + logs/<session>/<arch>/ + DOE CSV → doe/ (all arches)"
@echo " qemu-esp — quick boot from FAT directory (amd64, aarch64)"
@echo " qemu-gdb — boot with GDB stub on :1234"
@echo " thumbdrive — build generic GPT/FAT32 UEFI disk image (write to a USB stick with dd; real-hardware/SER5 path)"
@echo " iso-usb — build UEFI isohybrid ISO for Iso Image Writer / GNOME Disks 'Restore Disk Image...' (novice path; real-hardware/SER5)"
@echo ""
@echo "QEMU display:"
@echo " QEMU_DISPLAY=gtk — framebuffer window backend for 'qemu' goal (default: gtk)"
+1 -1
View File
@@ -1,4 +1,4 @@
# LithosAnanke v1.5.4
# LithosAnanke v2.0.1
**UEFI-bootable FORTH microkernel.** Boots from firmware, initialises memory and interrupts, then runs the StarForth VM as its sole userspace runtime. No libc. No OS. Just stone and necessity.
+2 -1
View File
@@ -1,5 +1,6 @@
# Capsule Block Manifest — Auto-generated
<!-- Generated by mkcapsule --manifest 2026-08-29T13:51:54Z -->
<!-- Generated by mkcapsule --manifest 2026-08-30T08:47:40Z -->
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
<!-- Hand-written justifications and immutability notes live -->
<!-- in MANIFEST.md alongside this auto-generated index. -->
BIN
View File
Binary file not shown.
+108
View File
@@ -30,6 +30,114 @@ Applied to the two planned releases: the **v2.0.0** cut (even major, so LTS) is
release; **v2.5.0** is the hardware bare-metal release that transfers v2.0.0's QEMU story to
real boards. See `FABRIC-3.md` §G for the release-gate punch lists.
**Board-by-board hardware rollout, decided 2026-08-29 (extends the above as boards come
online).** Real silicon is arriving incrementally (Beelink SER5 in hand now; RasPi 5 + Milk-V
orderable around Mon 2026-08-31), so the hardware release is split per real board in hand,
each its own even-minor cut on the same line (each `X.Y.0` here is an LTS point-in-time cut,
not a separate dev line):
- **v2.2.0 — amd64 bare metal.** Beelink SER5 (in hand). Gate: the generic GPT/FAT32
thumbdrive image (`make -f Makefile.starkernel ARCH=amd64 thumbdrive`) flashes to and boots
on the real SER5 via its real UEFI; POST + `ok>`; the amd64 **RDRAND** backend
(`rng: backend = rdrand`) serves live entropy; and a real Zuse identity is minted on a
second thumbdrive in real hardware and re-attaches. Two 16 GB sticks available: one to boot
the image, one to mint the Zuse user.
- **v2.4.0 — aarch64 bare metal.** Raspberry Pi 5 (orderable ~Mon 2026-08-31). Gate: boots
on the real board, aarch64 peripheral-RNG backend live, Zuse mint/attach on real media.
- **v2.5.0 — all three bare metal.** Adds Milk-V (riscv64) to the above; the Zkr (RNDR)
backend live. This is the full "same story on all three arches on real silicon" cut.
**Beyond v2.5.0 — Zynq FPGA is the next big milestone, after a hardening phase.** Once the
three general-purpose boards close, the next major transfer is to a **Zynq (AMD Xilinx)
FPGA** SoC — the step where the battle-tested amd64/aarch64/riscv64 story rides on
configurable silicon. That is a genuinely bigger milestone than any single prior board: an
FPGA demands its platform be carried forward rather than ported with trivial
architecture-delta work, and it reshapes the hardware story (soft/hard CPU cores, PL fabric,
non-standard memory map, custom peripherals). Expect a new even-major line for it once the
coloring-in period below lands.
**The FPGA creates a three-product split, decided 2026-08-29.** The Zynq is not just a fourth
platform to port to — it is the pivot that forces the project to separate into three
distinct products, each with its own host, delivery, and proof character. This is the neat
partition the FPGA's configurable-silicon nature makes possible and demands:
1. **Hosted StarForth** — the hosted/interpreted StarForth product that already exists
(3-arch acceptance-tested; runs StarForth hosted on an OS). Its delivery is the Forth
+ VM + capsule semantics as a portable, embeddable interpreted runtime.
2. **A full StarshipOS** — the standalone operating system built on LithosAnanke
(LithosAnanke → StarshipOS). Its delivery is a self-booting OS on general-purpose
silicon (the SER5/RasPi/Milk-V line already covers this).
3. **Hardware steady-state machinery with sealed executions, HOL-proven** — the
FPGA-native product: hardware-enforced sealed executions and steady-state machinery
whose guarantees are machine-checked in a proof assistant (HOL). This is the product only
configurable silicon can honor — secret/hardware-boundary enforcement and formally
verified behavior carried in silicon rather than software. Its delivery is the bitstream +
the HOL proof artifacts (not just a port of the OS).
The coupling is the point: the FPGA is where product 3 is born, and product 3's existence is
what cleanly separates 1 from 2 from 3. Product 1 ships hosted on an OS; product 2 ships as
an OS on general silicon; product 3 ships as proven hardware. Anything that straddles those
boundaries after this decision is a conscious product-line choice, not an accident of history.
Scoping of each product's concrete gates, and the new even-major line that carries products 1
through 3 as separate tracks, is defined at v2.5.0 close / during the coloring-in phase.
(This complements, and does not retract, the existing "hardware bare-metal release" policy
above.)
**IP framing of the three products — 3 patent applications + 3 marks, decided 2026-08-29.**
The three products are treated as **three patent applications**, each matched to a trademark,
with one caveat about the pre-existing provisional:
- **Patent 1 + mark StarForth.** The hosted/interpreted StarForth runtime product.
- **Patent 2 + marks StarshipOS + LithosAnanke.** The full standalone OS
(LithosAnanke → StarshipOS). (Noted as "StarshopOS" in the 2026-08-29 decision words;
canonical repo spelling and mark is **StarshipOS** — confirmed as the literal mark
to register.)
- **Patent 3 + mark Compudynamics.** The Zynq hardware steady-state machinery with sealed
executions, HOL-proven — anchored by the physics-adaptive runtime.
**Driving deadlines (why "no hurry" is wrong for #1 and #2), clarified 2026-08-29.** Two
clocks bind the near term, independent of product #3 and the FPGA:
- **#1 — the provisional will expire before conversion.** Its priority claim is time-boxed:
if the non-provisional isn't filed claiming benefit before the provisional's window lapses
(provisional filed ~Dec 2025 → window ~Dec 2026), the provisional's priority is lost and
the same subject matter cannot be re-staked by refiling thereafter. So #1 is on a hard
clock regardless of the December scope.
- **#2 — full StarshipOS is the December deliverable.** This is what "keeps the flagship
covered": the standalone-OS product (and, pending confirmation below, possibly the vehicle
that converts #1's provisional) must deliver by December.
- **Open point to resolve with counsel:** is **#2's** application (or the December delivery)
the **conversion vehicle** for #1's provisional — i.e., does it claim benefit from the
#1 provisional and thereby secure what would otherwise lapse — or is #1 converted by a
filing separate from #2? Captured as a decision record; no filing made.
**Relationship to the existing provisional (must be reconciled, not assumed).** The repo
already carries a **"Patent pending"** USPTO **provisional filed December 2025** for the
physics-grounded self-adaptive runtime (the Compudynamics adaptive runtime), sourced in
`docs/patent/` and referenced in `README.md`. Compudynamics is therefore already staked as
the brand of that foundation. Open points to resolve with counsel before any filing, so
nothing is invented or double-filed: is patent 3 the continuation/refinement of that
provisional (its HOL hardware realization) or a fresh application? Are the three product
applications additive to, or folding in, the Dec-2025 provisional? This record states intent;
it does not file, claim, or draft legal text.
**Before the FPGA — "coloring in", decided 2026-08-29.** The period between the all-three
bare-metal cut (v2.5.0) and starting the Zynq is finishing/hardening work that thickens the
shape of what already exists rather than adding new silicon. This is not idle time; it is
the point where v2.5.0's real-hardware story is made production-honest before the FPGA asks
to carry it further. Concrete items to define during it (draft scope, to be firmed at v2.5.0
close): Zynq-preflight robustness of the USB BOT/xHCI and block paths; live-entropy and
Zuse-cert hardening on the three real boards; SMP/multi-core bring-up and IRQ routing on real
ASICs (parked in the HAL notes); driver set expansion beyond the three boards before
committing an FPGA port; and whatever v2.5.0's real-board validation surfaces. As boards
land and the v2.5.0 gates close, this list is edited down to the concrete coloring-in punch
list, and the Zynq becomes the even-major target after it.
QEMU remains the zero-degradation reference on every line; each `X.Y.0` must reproduce the
QEMU acceptance story (`POST 1012/0/0` + `ok>`, block-fence Zuse true, backend entropy
non-deterministic) on its board before it closes.
---
## Milestone Overview
+18
View File
@@ -128,6 +128,24 @@ void console_puts(const char *s);
*/
void console_println(const char *s);
/**
* console_ensure_line_start - Make sure the next console_putc() starts at
* the beginning of a fresh output line, emitting a newline if output is
* currently mid-line (e.g. dangling behind a re-anchored prompt).
* No-op if already at line start. Mirrors console_putc()'s dual
* serial+framebuffer behavior (a bare '\n' reaches both).
*/
void console_ensure_line_start(void);
/**
* console_tx_count - Monotonic count of console_putc() calls delivered to
* either output (serial and/or framebuffer). In use by the REPL to detect
* that an idle bottom half (heartbeat, USB attach/detach) wrote to the
* console while the top-level prompt was showing, so it can re-anchor the
* prompt afterward. Never decreases.
*/
uint64_t console_tx_count(void);
/**
* Read a single character from serial console (non-blocking)
* Returns -1 if no character available
+9 -1
View File
@@ -123,9 +123,17 @@ int sk_console_key_available(void);
* @param buf Destination buffer
* @param size Buffer capacity, including the NUL terminator
* @param active_vm VM whose idle dispatch runs while waiting
* @param reanchor_prompt Nonzero to re-print the "ok> " prompt whenever
* an idle bottom half (heartbeat, USB attach/detach) writes
* to the console while this readline blocks at a bare,
* untyped prompt -- keeps the top-level prompt as the last
* thing shown once the chatter dies down. Callers whose
* prompt line is their own (shim.c's fgets(), i.e.
* QUERY/EXPECT/ACCEPT) pass 0 so "ok> " never gets stamped
* onto their mid-word input context.
* @return number of characters placed in buf, not counting the NUL
*/
int sk_console_readline(char *buf, int size, VM *active_vm);
int sk_console_readline(char* buf, int size, VM* active_vm, int reanchor_prompt);
#ifdef __cplusplus
}
+49 -1
View File
@@ -68,6 +68,18 @@ extern void kernel_main(BootInfo *boot_info);
#if defined(ARCH_AMD64)
#define COM1_BASE 0x3F8
/* Set by raw_serial_init() only after a 16550 presence probe succeeds.
* When 0, raw_serial_putc() drops bytes immediately so boot can never
* wedge on a board whose 0x3F8 decode has no UART behind it (real
* mini-PCs like the Beelink SER5 typically expose no legacy COM port,
* whereas QEMU always emulates one — this is why this hang only bites
* on hardware). */
static int raw_serial_ready = 0;
/* Bounded THRE poll bound: provides the same "drop, don't hang" safety
* even if the probe above passes on a phantom decode. */
#define RAW_SERIAL_THRE_MAX_SPIN 100000u
/**
* @brief Write a byte to an x86 I/O port via @c OUT (early-boot raw path).
*
@@ -137,6 +149,29 @@ static void raw_serial_init(void)
raw_outb(COM1_BASE + 2, 0xC7);
/* RTS/DSR set */
raw_outb(COM1_BASE + 4, 0x0B);
/* 16550 presence probe: the scratch register (COM1+7) reads back what
* was written only when a real UART owns this decode. Unclaimed ports
* (or no I/O bridge routing) return garbage/0xFF, so the probe fails
* and serial is disabled — otherwise raw_serial_putc()'s THRE poll
* could spin forever on a board with no COM port. */
raw_outb(COM1_BASE + 7, 0x5A);
raw_serial_ready = (raw_inb(COM1_BASE + 7) == 0x5A) ? 1 : 0;
if (raw_serial_ready)
{
/* Sanity-check that THRE can actually be observed; if not, the
* decode is a phantom — disable serial rather than risk a spin. */
unsigned int spin = 0;
while ((raw_inb(COM1_BASE + 5) & 0x20) == 0 && spin < RAW_SERIAL_THRE_MAX_SPIN)
{
++spin;
}
if (spin >= RAW_SERIAL_THRE_MAX_SPIN)
{
raw_serial_ready = 0;
}
}
}
/**
@@ -154,7 +189,20 @@ static void raw_serial_init(void)
*/
static void raw_serial_putc(char c)
{
while ((raw_inb(COM1_BASE + 5) & 0x20) == 0) { }
/* No UART behind 0x3F8 (or probe failed): drop the byte, never block. */
if (!raw_serial_ready) return;
unsigned int spin = 0;
while ((raw_inb(COM1_BASE + 5) & 0x20) == 0)
{
/* Bounded: on hardware whose probe passed but THRE never asserts
* (phantom decode), drop the character instead of hanging boot. */
if (++spin >= RAW_SERIAL_THRE_MAX_SPIN)
{
raw_serial_ready = 0;
return;
}
}
raw_outb(COM1_BASE + 0, (uint8_t)c);
}
+29
View File
@@ -176,6 +176,7 @@ static int serial_transmit_empty(void) {
static char g_active_vm_name_buf[CONSOLE_VM_NAME_BUF];
static const char *g_active_vm_name = (void *)0;
static int g_line_start = 1;
static uint64_t g_console_tx_count; /* monotonic console_putc() counter (BSS) */
void console_set_vm_name(const char *name) {
/* Empty string treated the same as NULL: console_save_vm_name()
@@ -258,8 +259,23 @@ static void emit_prefix(void) {
* Emits "[VMName] " at the start of each new line when a VM name is set.
* Also mirrors output to the framebuffer VT100 terminal when available.
* Serial output is ALWAYS active regardless of framebuffer state.
*
* console_putc_inner(): the same body minus the tx-counter increment.
* console_ensure_line_start() uses the inner form so its format-only
* newline does not read as "real output" to the REPL's prompt re-anchor
* (repl.c) -- a silent idle beat that merely closes a dangling prompt line
* must not be mistaken for chatter and trigger a prompt repaint. The
* counter counts characters the caller actually intended to emit.
*/
static void console_putc_inner(char c);
void console_putc(char c) {
g_console_tx_count++;
console_putc_inner(c);
}
static void console_putc_inner(char c)
{
/* --- serial UART path (always on) --- */
if (g_active_vm_name && g_line_start && c != '\n') {
emit_prefix();
@@ -288,6 +304,19 @@ void console_puts(const char *s) {
}
}
uint64_t console_tx_count(void)
{
return g_console_tx_count;
}
void console_ensure_line_start(void)
{
if (!g_line_start)
{
console_putc_inner('\n');
}
}
/**
* Write a string with newline to serial console
*/
+51 -3
View File
@@ -141,6 +141,16 @@ static int g_idle_pump_active; /* zero-initialized (BSS) */
static void sk_repl_idle(VM *active_vm)
{
/* Close any dangling output line before this bottom half emits its own
* chatter (xhci attach/detach progress, block-subsystem notices). If we
* are mid-prompt-line -- the REPL started the attach while sitting at
* "ok> " -- a bare console_println() would otherwise glue its text onto
* the prompt and inherit no {VMName} prefix (g_line_start is 0). A
* fresh line first keeps every idle line prefix-tagged and readable,
* matching what an interactive typing session expects. No-op when the
* console is already at a line boundary. */
console_ensure_line_start();
/* Artemis Milestone 2d: xHCI Event Ring servicing. This is exactly the
* "interrupt-driven, coarse cadence, cheap early-exit" trigger Section
* U item 6 asked for -- xhci_poll_events() is a no-op read (loop
@@ -498,11 +508,22 @@ int sk_console_key_available(void)
* for the REPL's own top-level prompt, since it's the same underlying
* console. Any g_console_pending_key left over from a ?TERMINAL peek is
* consumed first so a line read never drops a byte ?TERMINAL already saw.
* @param reanchor_prompt nonzero from the REPL's own prompt sites (which
* print SK_PROMPT_TEXT immediately before): re-print the prompt whenever an
* idle bottom half wrote to the console while this call blocked at the bare
* prompt (see the re-anchor block in the idle branch). shim.c's fgets()
* passes 0 -- its prompt context is caller-owned.
*===========================================================================*/
int sk_console_readline(char *buf, int size, VM *active_vm)
int sk_console_readline(char* buf, int size, VM* active_vm, int reanchor_prompt)
{
int n = 0;
/* TX counter value right after the caller printed its prompt. Any
* console output that lands while this readline blocks (heartbeat
* status, sk_repl_idle()'s USB attach/detach chatter) pushes the
* counter past this mark and away from a bare prompt; when that
* happens, re-anchor the prompt (below). */
uint64_t prompt_tx_mark = console_tx_count();
buf[0] = '\0';
console_fb_draw_cursor(); /* show the cursor at the bare prompt, before any input */
@@ -531,6 +552,33 @@ int sk_console_readline(char *buf, int size, VM *active_vm)
g_last_beat_tick = now;
sk_repl_idle(active_vm);
}
/*
* Re-anchor the prompt (FABRIC.md 4.4a unified prompt: print
* only "ok> " here -- console_putc() auto-prefixes the current
* [VMName] on a fresh line). When an idle bottom half above
* pushed output past prompt_tx_mark, the console cursor is now
* below/after new lines and the "ok> " the caller printed has
* been scrolled or buried -- once the flood passes, the screen
* and serial log would end on a stale line with no prompt
* (FABRIC-3.md: the bare prompt must be the last thing shown
* while the REPL sits idle). Reprinting it restores that
* invariant. Skipped while a line is being edited (n > 0) so
* partial echo stays attached to its own prompt; shim.c's
* fgets() (QUERY/EXPECT/ACCEPT) calls in with reanchor_prompt
* == 0 for the same reason -- its prompt line is caller-owned
* text, not the REPL's. Each silent beat leaves the mark
* unchanged, so the final state after the chatter dies down is
* a fresh prompt on the last visible line, cursor on it.
*/
if (reanchor_prompt && n == 0 &&
console_tx_count() != prompt_tx_mark)
{
console_puts(SK_PROMPT_TEXT);
console_fb_draw_cursor();
prompt_tx_mark = console_tx_count();
}
/*
* Do NOT use hlt here: QEMU single-threaded TCG can't process
* its APIC timer callbacks while the guest CPU is halted (the
@@ -720,7 +768,7 @@ int sk_repl_step(VM *vm)
console_puts(SK_PROMPT_TEXT);
}
sk_console_readline(input, sizeof(input), vm);
sk_console_readline(input, sizeof(input), vm, 1);
if (input[0] == '\0') {
console_puts(" ok\n");
@@ -763,7 +811,7 @@ void sk_repl_run(VM *vm)
* step()'s matching comment above. */
console_puts(SK_PROMPT_TEXT);
sk_console_readline(input, sizeof(input), active);
sk_console_readline(input, sizeof(input), active, 1);
if (input[0] == '\0') {
console_puts(" ok\n");
+76 -6
View File
@@ -6,8 +6,16 @@
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 (amd64 RDRAND, riscv64 Zkr,
aarch64 peripheral RNG) plug in without touching the call path.
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__
@@ -19,23 +27,80 @@
#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 has exactly one: virtio-rng. */
* 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
* the sole backend at v2.0.0; v2.5.0 adds real per-arch drivers here. */
* 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(
@@ -49,12 +114,17 @@ int rng_ready(void) {
}
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:
/* v2.5.0 real per-arch cases land here. No backend: refuse loudly,
* never return a deterministic throwaway. */
/* No backend: refuse loudly, never return a deterministic
* throwaway. */
return RNG_ERR_NO_BACKEND;
}
}
+1 -1
View File
@@ -1154,7 +1154,7 @@ static VM *shim_console_vm(void) {
char *fgets(char *s, int size, FILE *stream) {
(void)stream;
if (!s || size <= 0) return NULL;
sk_console_readline(s, size, shim_console_vm());
sk_console_readline(s, size, shim_console_vm(), 0);
return s;
}
/** @brief Kernel @c fputc(): ignores stream; emits @p c to kernel console. */