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`:
|
Two independently tracked version strings flow into the generated `include/version.h`:
|
||||||
`VERSION` (`Makefile.starkernel` — the embedded StarForth engine version, currently `3.1.0`;
|
`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
|
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)
|
### 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
|
v2.0.0 cut). Nothing
|
||||||
is deferred that QEMU alone could already prove out; only what genuinely needs real silicon.
|
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
|
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
|
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
|
(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
|
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
|
path seeded from it produces a valid distinct cert per boot when bleached, and QEMU
|
||||||
behavior is unchanged.
|
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
|
Boot the generic thumbdrive image (`make -f Makefile.starkernel ARCH=<arch> thumbdrive`) on
|
||||||
acceptance story QEMU keeps green: POST `1012/0/0` + `ok>`, block-fence Zuse load true to the
|
each real board in hand, confirming the same acceptance story QEMU keeps green: POST
|
||||||
already-minted Artemis image, and the G.4 RNG backend working live. The board pool is
|
`1012/0/0` + `ok>`, block-fence Zuse load true to the already-minted Artemis image, and the
|
||||||
SER5 (if still in hand), RasPi 6 (aarch64), Milk-V (riscv64) — the goal is at least one
|
corresponding G.4 RNG backend working live. **Mapping onto the board-by-board cadence
|
||||||
board per architecture, but each board that boots is a separate, recorded data point.
|
(decided 2026-08-29):** v2.2.0 = SER5 (amd64, in hand now — two 16 GB sticks available, one
|
||||||
This is the genuine transfer proof that the zero-degradation QEMU claim holds on real
|
to boot the image, one to mint a real Zuse identity on real hardware); v2.4.0 = RasPi 5
|
||||||
silicon — the thing v2.0.0 cannot honestly claim.
|
(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),
|
(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
|
and its G.4 RNG backend returns non-deterministic bytes live. A milestone does not close on
|
||||||
board's G.4/G.x item being build-only.
|
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.
|
- 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).
|
- Re-run the DoE on the new substrate (§A 5.1).
|
||||||
- First-touch allocation first-call-free.
|
- 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".
|
||||||
|
|||||||
+94
-6
@@ -71,12 +71,16 @@ MAKEFLAGS += -j$(NPROC)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
# Version
|
# 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.0.x — serial-only production (released)
|
||||||
# v1.5.x — framebuffer VT100 terminal/console milestone (current)
|
# v1.5.x — framebuffer VT100 terminal/console milestone (released)
|
||||||
# v2.0.0 — StarForth SDK release; v2.x.x development begins from there
|
# 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
|
VERSION ?= 3.1.0
|
||||||
LITHOS_VERSION ?= 1.5.4
|
LITHOS_VERSION ?= 2.0.1
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# BUILD PATHS
|
# BUILD PATHS
|
||||||
@@ -554,6 +558,7 @@ KERNEL_OBJS := \
|
|||||||
|
|
||||||
.PHONY: all clean clean-kernel kernel kernel-all
|
.PHONY: all clean clean-kernel kernel kernel-all
|
||||||
.PHONY: qemu qemu-esp qemu-gdb
|
.PHONY: qemu qemu-esp qemu-gdb
|
||||||
|
.PHONY: thumbdrive iso-usb
|
||||||
.PHONY: info help
|
.PHONY: info help
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
@@ -999,8 +1004,89 @@ else ifeq ($(ARCH),riscv64)
|
|||||||
echo "=== Serial log: $$LOG ==="; \
|
echo "=== Serial log: $$LOG ==="; \
|
||||||
echo "=== Extracting DOE CSV ==="; \
|
echo "=== Extracting DOE CSV ==="; \
|
||||||
bash scripts/extract_doe.sh $$LOG $$CSV || true; \
|
bash scripts/extract_doe.sh $$LOG $$CSV || true; \
|
||||||
cp $$CSV $(DOE_LATEST_DIR)/riscv64.csv 2>/dev/null || true
|
cp $$CSV $(DOE_LATEST_DIR)/riscv64.csv 2>/dev/null || true
|
||||||
endif
|
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,
|
# 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
|
# no auto-kill/timeout/DOE-injection logic — stays up until you quit it
|
||||||
@@ -1134,6 +1220,8 @@ help:
|
|||||||
@echo " qemu — clean boot, serial tee'd live + logs/<session>/<arch>/ + DOE CSV → doe/ (all arches)"
|
@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-esp — quick boot from FAT directory (amd64, aarch64)"
|
||||||
@echo " qemu-gdb — boot with GDB stub on :1234"
|
@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 ""
|
||||||
@echo "QEMU display:"
|
@echo "QEMU display:"
|
||||||
@echo " QEMU_DISPLAY=gtk — framebuffer window backend for 'qemu' goal (default: gtk)"
|
@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.
|
**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
|
# 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. -->
|
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
||||||
<!-- Hand-written justifications and immutability notes live -->
|
<!-- Hand-written justifications and immutability notes live -->
|
||||||
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
<!-- 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
|
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.
|
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
|
## Milestone Overview
|
||||||
|
|||||||
@@ -128,6 +128,24 @@ void console_puts(const char *s);
|
|||||||
*/
|
*/
|
||||||
void console_println(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)
|
* Read a single character from serial console (non-blocking)
|
||||||
* Returns -1 if no character available
|
* Returns -1 if no character available
|
||||||
|
|||||||
@@ -120,12 +120,20 @@ int sk_console_key_available(void);
|
|||||||
* uses internally, so a mid-word EXPECT behaves identically to typing at
|
* uses internally, so a mid-word EXPECT behaves identically to typing at
|
||||||
* "ok>" itself.
|
* "ok>" itself.
|
||||||
*
|
*
|
||||||
* @param buf Destination buffer
|
* @param buf Destination buffer
|
||||||
* @param size Buffer capacity, including the NUL terminator
|
* @param size Buffer capacity, including the NUL terminator
|
||||||
* @param active_vm VM whose idle dispatch runs while waiting
|
* @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
|
* @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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,18 @@ extern void kernel_main(BootInfo *boot_info);
|
|||||||
|
|
||||||
#if defined(ARCH_AMD64)
|
#if defined(ARCH_AMD64)
|
||||||
#define COM1_BASE 0x3F8
|
#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).
|
* @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);
|
raw_outb(COM1_BASE + 2, 0xC7);
|
||||||
/* RTS/DSR set */
|
/* RTS/DSR set */
|
||||||
raw_outb(COM1_BASE + 4, 0x0B);
|
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)
|
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);
|
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 char g_active_vm_name_buf[CONSOLE_VM_NAME_BUF];
|
||||||
static const char *g_active_vm_name = (void *)0;
|
static const char *g_active_vm_name = (void *)0;
|
||||||
static int g_line_start = 1;
|
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) {
|
void console_set_vm_name(const char *name) {
|
||||||
/* Empty string treated the same as NULL: console_save_vm_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.
|
* 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.
|
* Also mirrors output to the framebuffer VT100 terminal when available.
|
||||||
* Serial output is ALWAYS active regardless of framebuffer state.
|
* 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) {
|
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) --- */
|
/* --- serial UART path (always on) --- */
|
||||||
if (g_active_vm_name && g_line_start && c != '\n') {
|
if (g_active_vm_name && g_line_start && c != '\n') {
|
||||||
emit_prefix();
|
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
|
* 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)
|
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
|
/* Artemis Milestone 2d: xHCI Event Ring servicing. This is exactly the
|
||||||
* "interrupt-driven, coarse cadence, cheap early-exit" trigger Section
|
* "interrupt-driven, coarse cadence, cheap early-exit" trigger Section
|
||||||
* U item 6 asked for -- xhci_poll_events() is a no-op read (loop
|
* 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
|
* 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
|
* 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.
|
* 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;
|
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';
|
buf[0] = '\0';
|
||||||
console_fb_draw_cursor(); /* show the cursor at the bare prompt, before any input */
|
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;
|
g_last_beat_tick = now;
|
||||||
sk_repl_idle(active_vm);
|
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
|
* Do NOT use hlt here: QEMU single-threaded TCG can't process
|
||||||
* its APIC timer callbacks while the guest CPU is halted (the
|
* 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);
|
console_puts(SK_PROMPT_TEXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
sk_console_readline(input, sizeof(input), vm);
|
sk_console_readline(input, sizeof(input), vm, 1);
|
||||||
|
|
||||||
if (input[0] == '\0') {
|
if (input[0] == '\0') {
|
||||||
console_puts(" ok\n");
|
console_puts(" ok\n");
|
||||||
@@ -763,7 +811,7 @@ void sk_repl_run(VM *vm)
|
|||||||
* step()'s matching comment above. */
|
* step()'s matching comment above. */
|
||||||
console_puts(SK_PROMPT_TEXT);
|
console_puts(SK_PROMPT_TEXT);
|
||||||
|
|
||||||
sk_console_readline(input, sizeof(input), active);
|
sk_console_readline(input, sizeof(input), active, 1);
|
||||||
|
|
||||||
if (input[0] == '\0') {
|
if (input[0] == '\0') {
|
||||||
console_puts(" ok\n");
|
console_puts(" ok\n");
|
||||||
|
|||||||
@@ -6,8 +6,16 @@
|
|||||||
|
|
||||||
v2.0.0: virtio-rng is the sole active backend (QEMU-only, uniform across all
|
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
|
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,
|
seam where the v2.5.0 real per-arch drivers plug in without touching the call
|
||||||
aarch64 peripheral RNG) plug in without touching the call path.
|
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__
|
#ifndef __STARKERNEL__
|
||||||
@@ -19,23 +27,80 @@
|
|||||||
#include "starkernel/console.h"
|
#include "starkernel/console.h"
|
||||||
|
|
||||||
/* Number of entropy backends known to this build. Each maps to one case in
|
/* 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 {
|
enum {
|
||||||
RNG_BACKEND_NONE = 0,
|
RNG_BACKEND_NONE = 0,
|
||||||
RNG_BACKEND_VIRTIO, /* virtio-rng (QEMU, all three arches) */
|
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;
|
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) {
|
int rng_init(void) {
|
||||||
/* Probe backends in priority order; first success wins. virtio-rng is
|
/* 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) {
|
if (virtio_rng_init() == 0) {
|
||||||
g_rng_backend = RNG_BACKEND_VIRTIO;
|
g_rng_backend = RNG_BACKEND_VIRTIO;
|
||||||
console_println("rng: backend = virtio-rng");
|
console_println("rng: backend = virtio-rng");
|
||||||
return 0;
|
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. */
|
/* Refuse loudly: never fall through to a deterministic seed. */
|
||||||
g_rng_backend = RNG_BACKEND_NONE;
|
g_rng_backend = RNG_BACKEND_NONE;
|
||||||
console_println(
|
console_println(
|
||||||
@@ -49,12 +114,17 @@ int rng_ready(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int rng_get_bytes(uint8_t *buf, size_t n) {
|
int rng_get_bytes(uint8_t *buf, size_t n) {
|
||||||
|
if (!buf || n == 0) return RNG_ERR_NO_BACKEND;
|
||||||
switch (g_rng_backend) {
|
switch (g_rng_backend) {
|
||||||
case RNG_BACKEND_VIRTIO:
|
case RNG_BACKEND_VIRTIO:
|
||||||
return virtio_rng_get_bytes(buf, n);
|
return virtio_rng_get_bytes(buf, n);
|
||||||
|
#if defined(__x86_64__) || defined(__amd64__)
|
||||||
|
case RNG_BACKEND_RDRAND:
|
||||||
|
return rdrand_fill(buf, n);
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
/* v2.5.0 real per-arch cases land here. No backend: refuse loudly,
|
/* No backend: refuse loudly, never return a deterministic
|
||||||
* never return a deterministic throwaway. */
|
* throwaway. */
|
||||||
return RNG_ERR_NO_BACKEND;
|
return RNG_ERR_NO_BACKEND;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1154,7 +1154,7 @@ static VM *shim_console_vm(void) {
|
|||||||
char *fgets(char *s, int size, FILE *stream) {
|
char *fgets(char *s, int size, FILE *stream) {
|
||||||
(void)stream;
|
(void)stream;
|
||||||
if (!s || size <= 0) return NULL;
|
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;
|
return s;
|
||||||
}
|
}
|
||||||
/** @brief Kernel @c fputc(): ignores stream; emits @p c to kernel console. */
|
/** @brief Kernel @c fputc(): ignores stream; emits @p c to kernel console. */
|
||||||
|
|||||||
Reference in New Issue
Block a user