Compare commits
10
Commits
09857b7228
...
58c59e87e5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58c59e87e5 | ||
|
|
d2a0305703 | ||
|
|
31dfc5de63 | ||
|
|
936d046ca6 | ||
|
|
8e94522d10 | ||
|
|
25276ae359 | ||
|
|
28de700645 | ||
|
|
19bc90c97d | ||
|
|
bd266942ce | ||
|
|
2efd7fe7e7 |
+1
-1
@@ -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
@@ -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
|
||||
(M0–M9 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
@@ -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,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.
|
||||
|
||||
|
||||
@@ -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. -->
|
||||
|
||||
Binary file not shown.
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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. */
|
||||
|
||||
Reference in New Issue
Block a user