diff --git a/boards/pc/board.mk b/boards/pc/board.mk index 4313c39a..ad113bbe 100644 --- a/boards/pc/board.mk +++ b/boards/pc/board.mk @@ -4,9 +4,12 @@ # any x86-64 PC whose firmware boots a UEFI removable medium. (The first to be # brought up on the bench is a Beelink SER5, an AMD Ryzen mini-PC -- see # boards/BRINGUP.md.) The monolithic loader embeds the whole kernel, so the -# image is a GPT disk with one FAT32 EFI System Partition holding +# image is a GPT disk whose FAT32 EFI System Partition holds # EFI/BOOT/BOOTX64.EFI. Write it to a USB stick with dd. BOARD_DESC := Generic PC (x86-64, UEFI, ACPI) BOARD_ARCH := amd64 BOARD_BOOT := uefi-esp BOARD_IMAGE := lithos-pc.img +# The StarshipOS stick (docs/v4.0.0/STICK.md 4): the ESP, then the StarshipOS identity and +# Artemis partitions, Artemis formatted and signed at build. Sizes in kernel/Makefile. +BOARD_STICK := 1 diff --git a/disk/README.md b/disk/README.md index 9827cfbd..f3aec100 100644 --- a/disk/README.md +++ b/disk/README.md @@ -160,6 +160,15 @@ carrying timestamp noise in git history. `thumbdrives/zuse-thumb-ident.img`, which stay blank (that call is Captain Bob's). +- **The StarshipOS stick and data stick are not here** (2026-10-27, + `docs/v4.0.0/STICK.md` §4, §9): they are build output, made fresh by + `make boot_image TARGET=PC` (`build/boards/pc/lithos-pc.img`: ESP, StarshipOS + identity, StarshipOS Artemis) and `make -f kernel/Makefile ARCH= datastick` + (`build//kernel/datastick.img`: identity and Artemis), Artemis formatted + and signed at build by `tools/mkartemis.c`; `scripts/check_images.sh` checks + both. The convention below is for fixtures kept as they are, not images the + build writes every time. + **Convention, standing as of 2026-08-22: every virtual disk/thumb-drive image used for testing — Artemis persistence disks above, and USB Mass Storage backing images alike — lives in this directory and is a tracked, committed diff --git a/experiments/bare_metal/runs/doe-aarch64-20261027-133417.csv b/experiments/bare_metal/runs/doe-aarch64-20261027-133417.csv new file mode 100644 index 00000000..e69de29b diff --git a/experiments/bare_metal/runs/doe-amd64-20261027-133146.csv b/experiments/bare_metal/runs/doe-amd64-20261027-133146.csv new file mode 100644 index 00000000..e69de29b diff --git a/experiments/bare_metal/runs/doe-riscv64-20261027-133815.csv b/experiments/bare_metal/runs/doe-riscv64-20261027-133815.csv new file mode 100644 index 00000000..e69de29b diff --git a/kernel/Makefile b/kernel/Makefile index 2882acc0..77b3a658 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -180,6 +180,12 @@ MKCAPSULE_SRC = tools/mkcapsule.c tools/pkcs8_ed25519.c \ kernel/src/crypto/scalar25519.c \ kernel/src/crypto/sha512.c MKCAPSULE_BIN = $(BUILD_DIR)/tools/mkcapsule +# mkartemis: formats and signs an Artemis partition at build with the kernel's own +# block-subsystem and artemis_sig code (tools/mkartemis.c), built as v4/Makefile builds them. +MKARTEMIS_SRC = tools/mkartemis.c kernel/src/artemis_sig.c \ + $(addprefix v3/src/,block_subsystem.c blkio_ram.c blkio_file.c log.c \ + platform/platform_init.c platform/linux/time.c) +MKARTEMIS_BIN = $(BUILD_DIR)/tools/mkartemis # Milestone 6 (Phase 8): the snakeoil intermediate's private key, generated # offline outside this repo entirely (see FABRIC-2.md's Phase 8 §Milestone 6 # writeup) -- not present in CI or a fresh checkout, so signing is skipped @@ -213,6 +219,17 @@ BOARD_OUT := build/boards/$(BOARD) endif BOOT_IMAGE_SIZE_MIB ?= 128 +# The StarshipOS stick and data stick (docs/v4.0.0/STICK.md 4, "sizes: a minimum, and dynamic +# above it"; set here and nowhere else). A board whose board.mk sets BOARD_STICK := 1 (the PC) +# gets the stick: an ESP, the StarshipOS identity partition, and Artemis to the end, formatted +# and signed at build. The data stick -- identity and Artemis, no ESP -- is what the `qemu` +# targets attach with DATASTICK=1 (docs/v4.0.0/plans/2026-10-27-stick-3-images.md). +STICK_IMAGE_MIB := 2048 +STICK_ESP_MIB := 64 +STICK_IDENT_MIB := 500 +DATASTICK_MIB := 1536 +DATASTICK_IMG = $(BUILD_DIR)/datastick.img + # ============================================================================== # TOOLCHAIN # ============================================================================== @@ -740,6 +757,17 @@ $(MKCAPSULE_BIN): $(MKCAPSULE_SRC) @echo "HOSTCC $(MKCAPSULE_SRC)" @cc -std=c99 -Wall -Wextra -O2 -Iv3/include -Ikernel/include -Itools -o $@ $(MKCAPSULE_SRC) +$(MKARTEMIS_BIN): $(MKARTEMIS_SRC) $(wildcard v3/include/*.h) kernel/include/starkernel/artemis_sig.h + @mkdir -p $(dir $@) + @echo "HOSTCC tools/mkartemis.c" + @cc -std=gnu99 -Wall -O2 -Iv3/include -Ikernel/include -o $@ $(MKARTEMIS_SRC) + +# datastick -- the data stick, fresh every time it is made (STICK.md 9: "fresh for each boot"). +.PHONY: datastick +datastick: $(MKARTEMIS_BIN) + @bash scripts/mkdiskimage.sh --out $(DATASTICK_IMG) --table gpt --size-mib $(DATASTICK_MIB) \ + --label DATASTICK --starship $(STICK_IDENT_MIB) --mkartemis $(MKARTEMIS_BIN) --esp-mib 0 + # Generate capsule_generated.c from capsules/ CAPSULE_SRCS := $(shell find $(CAPSULES_DIR) -type f ! -name '.*' 2>/dev/null) $(CAPSULE_GENERATED): $(MKCAPSULE_BIN) $(CAPSULE_SRCS) @@ -1316,7 +1344,7 @@ boot_image: @echo " make boot_image TARGET=PC|RASPI|MILKV|ZYNQ7020" @exit 1 else ifeq ($(BOARD_BOOT),uefi-esp) -boot_image: all +boot_image: all $(if $(BOARD_STICK),$(MKARTEMIS_BIN)) @mkdir -p $(BOARD_OUT) @printf 'FS0:\\EFI\\BOOT\\%s\r\n' "$(EFI_BOOTNAME)" > $(BOARD_OUT)/startup.nsh @# The boot arguments, always written: system=v4 first -- v4 is the @@ -1324,7 +1352,9 @@ boot_image: all @# stick (A6); KERNEL_ARGS after it, and a later system= wins. @printf '%s\n' 'system=v4 $(KERNEL_ARGS)' > $(BOARD_OUT)/starforth.cfg @bash scripts/mkdiskimage.sh --out $(BOARD_OUT)/$(BOARD_IMAGE) --table gpt \ - --size-mib $(BOOT_IMAGE_SIZE_MIB) --label LITHOS \ + $(if $(BOARD_STICK),--size-mib $(STICK_IMAGE_MIB) --starship $(STICK_IDENT_MIB) \ + --mkartemis $(MKARTEMIS_BIN) --esp-mib $(STICK_ESP_MIB),--size-mib $(BOOT_IMAGE_SIZE_MIB)) \ + --label LITHOS \ $(LOADER_EFI):/EFI/BOOT/$(EFI_BOOTNAME) \ $(BOARD_OUT)/startup.nsh:/startup.nsh \ $(BOARD_OUT)/starforth.cfg:/starforth.cfg diff --git a/logs/20261027-133146/amd64/qemu-amd64-20261027-133146.log b/logs/20261027-133146/amd64/qemu-amd64-20261027-133146.log new file mode 100644 index 00000000..8d5b61bd --- /dev/null +++ b/logs/20261027-133146/amd64/qemu-amd64-20261027-133146.log @@ -0,0 +1,158 @@ +[=3hBdsDxe: loading Boot0002 "UEFI QEMU DVD-ROM QM00005 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x2,0xFFFF,0x0) +BdsDxe: starting Boot0002 "UEFI QEMU DVD-ROM QM00005 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x2,0xFFFF,0x0) +[=3hStarKernel UEFI Loader +Loading kernel from ESP... +[CKPT 001] Entered efi_main - ConOut live +RAW SERIAL UP +[CKPT 002] Serial (COM1) initialized +Monolithic build - kernel linked directly +Collecting boot information... +CmdLine: parsed OK +[CKPT 004] Command line parsed +[CKPT 005] Kernel stack allocation decided +[CKPT 006] Boot info collected (ACPI table located) +GOP: linear framebuffer found +[CKPT 007] GOP: linear framebuffer found +[CKPT 008] About to enter ExitBootServices retry loop +EBS... +EBS OK +Calling kernel_main (monolithic)... + + + _____ _ _ __ _ + / ____| | | |/ / | | + | (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| | + \___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ | + ____) | || (_| | | | . \ __/ | | | | | __/ | + |_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_| + +LithosAnanke v2.1.0 amd64 +Architecture: amd64 +Build: Oct 27 2026 13:31:19 + +UEFI BootServices: EXITED +Console: serial line is a 16550 at port 0x00000000000003f8 (COM1, probed) + +=== StarKernel Boot Information === +Memory map entries: 135 +Total memory: 1023 MB +Usable memory: 966 MB +=================================== + +PMM initialized. +PMM statistics: + Total pages: 248669 + Free pages : 247146 + Used pages : 1523 + Total MB : 971 + Free MB : 965 + Used MB : 5 + +VMM initialized (mapped RAM, CR3 switched) +VMM initialized (mapped RAM, CR3 switched) +VMM self-test: mapped OK at 0xffff800000000000 +VMM self-test complete. + +IDT installed. + +APIC: init... +APIC: IA32_APIC_BASE MSR=0x00000000fee00900 +APIC: stale-ISR drain: 0 EOI(s) issued +APIC: initialized (xAPIC MMIO, TPR=0, SIVR=0x1FF, EOI-clear) +APIC: init done + +I/O APIC: init... +I/O APIC: base=0xfec00000, gsi_base=0, overrides=5 + override: source=00 gsi=2 flags=0x0000 + override: source=05 gsi=5 flags=0x000d + override: source=09 gsi=9 flags=0x000d + override: source=0a gsi=10 flags=0x000d + override: source=0b gsi=11 flags=0x000d +i8042: keyboard ACKed enable-scanning +i8042: IRQ1 enabled in controller config byte +I/O APIC: keyboard IRQ1 routed (masked) + +Timer: init... +Timer: init start +Timer: PM_TMR_BLK discovered from FADT at port 1544 +Timer: VM mode detected (hypervisor present). +Timer: HPET calibration disabled (VM-exit MMIO would poison timing). +Timer: WARNING: invariant TSC not present under hypervisor. +Timer: continuing in RELATIVE mode (no determinism guarantees). +Timer: RDTSCP not present; using RDTSC (less serialized). +Timer: CPUID frequency unavailable; trying PM Timer... +Timer: trust=1 (0=NONE,1=REL,2=ABS), TSC=2102367869 Hz +Timer: init done + +Kernel heap initialized. +Heap statistics: + Total bytes: 536870872 + Free bytes: 536870872 + Used bytes: 0 + Peak bytes: 0 + Heap base addr: 24641536 + Heap end addr: 561512448 + +Heartbeat: init... +APIC Timer: calibrating... +APIC Timer: apic_hz=1012154133, tick_hz=100, initial_count=10121541 +APIC Timer: configured (masked, ready to start) +Heartbeat: init done +Kernel initialization complete. +Boot successful! + +System: StarForth v4 (this build's default) +StarForth v4: one host node, the F18-derived engine +V4: capsule v4:sys:map-64.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:map-64.f18 capsule_hash=0x949eb6a1e9260e49 +V4: capsule v4:sys:core.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:core.f18 capsule_hash=0xb8f167892ec18c28 +V4: capsule v4:sys:input.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:input.f18 capsule_hash=0x85d3ec486d929a79 +V4: capsule v4:sys:dict.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:dict.f18 capsule_hash=0x1379bd3b5de811dc +V4: capsule v4:sys:codegen.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:codegen.f18 capsule_hash=0x36d2ae84d2911b90 +V4: capsule v4:sys:compile.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:compile.f18 capsule_hash=0x11145c4c2ab819d8 +V4: capsule v4:sys:quit.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:quit.f18 capsule_hash=0x43cadf3b21ddbf3e +V4: capsule v4:sys:forth.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:forth.f18 capsule_hash=0x16cab4a1268b85da +V4: capsule v4:sys:numout.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:numout.f18 capsule_hash=0x85a240ad3fb2b299 +V4: capsule v4:sys:words.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:words.f18 capsule_hash=0xb1d381f927d9f14e +V4: capsule v4:sys:system.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:system.f18 capsule_hash=0xd92203664c2915bd +V4: capsule v4:sys:qmath.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:qmath.f18 capsule_hash=0xdb4140713dd857f3 +V4: capsule v4:sys:blocks.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:blocks.f18 capsule_hash=0x76307ef48678dc2a +V4: capsule v4:sys:log.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:log.f18 capsule_hash=0xfc6540e6b824a52b +V4: capsule v4:sys:acl.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:acl.f18 capsule_hash=0x6845aa048db7eb22 +V4: capsule v4:sys:end.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:end.f18 capsule_hash=0x5ef01312c07b79cc +PARITY:V4_ROM words=2372 rom_hash=0x87b23d3ae2643c8d instructions=59145258 +V4: capsule v4:forth79.4th signature: missing (unsigned) +PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x033e1c05c09a1df8 +PARITY:V4_POST tests=538 pass=538 fail=0 +PARITY:V4_SYSTEM word_count=317 dict_hash=0xfec8c47cfc6f437f +PARITY:OK +POST: PASSED +PCI: init... +PCI: ECAM mapped (amd64) +virtio-blk: found device +Artemis: virtio-blk attached +virtio-input: no device on PCI bus 0 +Starting heartbeat... +APIC Timer: started (LVT=0x00020020 ICR=10121541) +I/O APIC: keyboard IRQ1 unmasked +Heartbeat running. +blkio_usb: MSC device ready +[Hera] Zuse: identity confirmed from attached thumbdrive +[zuse@Hera] ok> 3 4 + . +[zuse@Hera] 7 ok +[zuse@Hera] ok>  \ No newline at end of file diff --git a/logs/20261027-133417/aarch64/qemu-aarch64-20261027-133417.log b/logs/20261027-133417/aarch64/qemu-aarch64-20261027-133417.log new file mode 100644 index 00000000..46c97ac8 --- /dev/null +++ b/logs/20261027-133417/aarch64/qemu-aarch64-20261027-133417.log @@ -0,0 +1,130 @@ +UEFI firmware (version 2025.11-3ubuntu7.3 built at 15:40:26 on Sep 23 2026) +[=3hBdsDxe: failed to load Boot0002 "UEFI Misc Device" from PciRoot(0x0)/Pci(0x2,0x0): Not Found +BdsDxe: failed to load Boot0003 "UEFI QEMU QEMU USB HARDDRIVE 1-0000:00:04.0-1" from PciRoot(0x0)/Pci(0x4,0x0)/USB(0x0,0x0): Not Found +BdsDxe: loading Boot0004 "UEFI Misc Device 2" from PciRoot(0x0)/Pci(0x6,0x0) +BdsDxe: starting Boot0004 "UEFI Misc Device 2" from PciRoot(0x0)/Pci(0x6,0x0) +[=3hStarKernel UEFI Loader +Loading kernel from ESP... +[CKPT 001] Entered efi_main - ConOut live +Collecting boot information... +[CKPT 004] Command line parsed +[CKPT 005] Kernel stack allocation decided +[CKPT 006] Boot info collected (ACPI table located) +[CKPT 007] GOP: linear framebuffer found +[CKPT 008] About to enter ExitBootServices retry loop + + + _____ _ _ __ _ + / ____| | | |/ / | | + | (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| | + \___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ | + ____) | || (_| | | | . \ __/ | | | | | __/ | + |_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_| + +LithosAnanke v2.1.0 aarch64 +Architecture: aarch64 +Build: Oct 27 2026 13:33:50 + +UEFI BootServices: EXITED +Console: serial line is a PL011 at 0x0000000009000000 (no devicetree: QEMU's) + +=== StarKernel Boot Information === +Memory map entries: 108 +Total memory: 4093 MB +Usable memory: 4054 MB +=================================== + +PMM initialized. +PMM statistics: + Total pages: 1039275 + Free pages : 1037864 + Used pages : 1411 + Total MB : 4059 + Free MB : 4054 + Used MB : 5 + +VMM initialized (mapped RAM, CR3 switched) +VMM initialized (mapped RAM, CR3 switched) +VMM self-test: mapped OK at 0xffff800000000000 +VMM self-test complete. + +AArch64: running at EL1 +IDT installed. + +APIC: init... +PSCI: no DTB -- using HVC (QEMU virt-machine default) +GICv2: no DTB GIC node -- using QEMU virt-machine defaults +GICv2: distributor+CPU interface enabled, PPI 30 +APIC: init done + +Timer: init... +Timer: AArch64 generic timer initialised. +Timer: init done + +Kernel heap initialized. +Heap statistics: + Total bytes: 2147483608 + Free bytes: 2147483608 + Used bytes: 0 + Peak bytes: 0 + Heap base addr: 1207959552 + Heap end addr: 3355443200 + +Heartbeat: init... +Heartbeat: init done +Kernel initialization complete. +Boot successful! + +System: StarForth v4 (this build's default) +StarForth v4: one host node, the F18-derived engine +V4: capsule v4:sys:map-64.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:map-64.f18 capsule_hash=0x949eb6a1e9260e49 +V4: capsule v4:sys:core.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:core.f18 capsule_hash=0xb8f167892ec18c28 +V4: capsule v4:sys:input.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:input.f18 capsule_hash=0x85d3ec486d929a79 +V4: capsule v4:sys:dict.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:dict.f18 capsule_hash=0x1379bd3b5de811dc +V4: capsule v4:sys:codegen.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:codegen.f18 capsule_hash=0x36d2ae84d2911b90 +V4: capsule v4:sys:compile.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:compile.f18 capsule_hash=0x11145c4c2ab819d8 +V4: capsule v4:sys:quit.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:quit.f18 capsule_hash=0x43cadf3b21ddbf3e +V4: capsule v4:sys:forth.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:forth.f18 capsule_hash=0x16cab4a1268b85da +V4: capsule v4:sys:numout.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:numout.f18 capsule_hash=0x85a240ad3fb2b299 +V4: capsule v4:sys:words.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:words.f18 capsule_hash=0xb1d381f927d9f14e +V4: capsule v4:sys:system.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:system.f18 capsule_hash=0xd92203664c2915bd +V4: capsule v4:sys:qmath.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:qmath.f18 capsule_hash=0xdb4140713dd857f3 +V4: capsule v4:sys:blocks.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:blocks.f18 capsule_hash=0x76307ef48678dc2a +V4: capsule v4:sys:log.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:log.f18 capsule_hash=0xfc6540e6b824a52b +V4: capsule v4:sys:acl.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:acl.f18 capsule_hash=0x6845aa048db7eb22 +V4: capsule v4:sys:end.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:end.f18 capsule_hash=0x5ef01312c07b79cc +PARITY:V4_ROM words=2372 rom_hash=0x87b23d3ae2643c8d instructions=59145258 +V4: capsule v4:forth79.4th signature: missing (unsigned) +PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x033e1c05c09a1df8 +PARITY:V4_POST tests=538 pass=538 fail=0 +PARITY:V4_SYSTEM word_count=317 dict_hash=0xfec8c47cfc6f437f +PARITY:OK +POST: PASSED +PCI: init... +virtio-blk: found device +Artemis: virtio-blk attached +virtio-input: found device +virtio-input: driver ready +Starting heartbeat... +Heartbeat running. +blkio_usb: MSC device ready +[Hera] Zuse: identity confirmed from attached thumbdrive +[zuse@Hera] ok> 3 4 + . +[zuse@Hera] 7 ok +[zuse@Hera] ok>  \ No newline at end of file diff --git a/logs/20261027-133815/riscv64/qemu-riscv64-20261027-133815.log b/logs/20261027-133815/riscv64/qemu-riscv64-20261027-133815.log new file mode 100644 index 00000000..4e86b6e1 --- /dev/null +++ b/logs/20261027-133815/riscv64/qemu-riscv64-20261027-133815.log @@ -0,0 +1,201 @@ + +OpenSBI v1.8 + ____ _____ ____ _____ + / __ \ / ____| _ \_ _| + | | | |_ __ ___ _ __ | (___ | |_) || | + | | | | '_ \ / _ \ '_ \ \___ \| _ < | | + | |__| | |_) | __/ | | |____) | |_) || |_ + \____/| .__/ \___|_| |_|_____/|____/_____| + | | + |_| + +Platform Name : riscv-virtio,qemu +Platform Features : medeleg +Platform HART Count : 1 +Platform HART Protection : pmp +Platform IPI Device : aclint-mswi +Platform Timer Device : aclint-mtimer @ 10000000Hz +Platform Console Device : uart8250 +Platform HSM Device : --- +Platform PMU Device : --- +Platform Reboot Device : syscon-reboot +Platform Shutdown Device : syscon-poweroff +Platform Suspend Device : --- +Platform CPPC Device : --- +Firmware Base : 0x80000000 +Firmware Size : 321 KB +Firmware RW Offset : 0x40000 +Firmware RW Size : 65 KB +Firmware Heap Offset : 0x47000 +Firmware Heap Size : 37 KB (total), 0 KB (reserved), 12 KB (used), 23 KB (free) +Firmware Scratch Size : 4096 B (total), 1464 B (used), 2632 B (free) +Runtime SBI Version : 3.0 +Standard SBI Extensions : ipi,pmu,srst,sse,hsm,rfnc,fwft,time,base,legacy,dbcn,dbtr +Experimental SBI Extensions : none + +Domain0 Name : root +Domain0 Boot HART : 0 +Domain0 HARTs : 0* +Domain0 Region00 : 0x0000000080040000-0x000000008005ffff M: (F,R,W) S/U: () +Domain0 Region01 : 0x0000000080000000-0x000000008003ffff M: (F,R,X) S/U: () +Domain0 Region02 : 0x0000000000100000-0x0000000000100fff M: (I,R,W) S/U: (R,W) +Domain0 Region03 : 0x0000000010000000-0x0000000010000fff M: (I,R,W) S/U: (R,W) +Domain0 Region04 : 0x0000000002000000-0x000000000200ffff M: (I,R,W) S/U: () +Domain0 Region05 : 0x000000000c400000-0x000000000c5fffff M: (I,R,W) S/U: (R,W) +Domain0 Region06 : 0x000000000c000000-0x000000000c3fffff M: (I,R,W) S/U: (R,W) +Domain0 Region07 : 0x0000000000000000-0xffffffffffffffff M: () S/U: (R,W,X) +Domain0 Next Address : 0x0000000020000000 +Domain0 Next Arg1 : 0x00000000bfe00000 +Domain0 Next Mode : S-mode +Domain0 SysReset : yes +Domain0 SysSuspend : yes + +Boot HART ID : 0 +Boot HART Domain : root +Boot HART Priv Version : v1.12 +Boot HART Base ISA : rv64imafdch +Boot HART ISA Extensions : sstc,zicntr,zihpm,zicboz,zicbom,sdtrig,svadu +Boot HART PMP Count : 16 +Boot HART PMP Granularity : 2 bits +Boot HART PMP Address Bits : 54 +Boot HART MHPM Info : 16 (0x0007fff8) +Boot HART Debug Triggers : 2 triggers +Boot HART MIDELEG : 0x0000000000001666 +Boot HART MEDELEG : 0x0000000000f4b509 +[=3hRISC-V EDK2 firmware version 2025.11-3ubuntu7.3 +Press ESCAPE within 5 seconds for boot options ERROR: C40000002:V03051002 I0 6D33944A-EC75-4855-A54D-809C75241F6C 83FFF850 +BdsDxe: failed to load Boot0001 "UEFI Misc Device" fr +om PciRoot(0x0)/Pci(0x1,0x0): Not Found +[=3hStarKernel UEFI Loader +Loading kernel from ESP... +[CKPT 001] Entered efi_main - ConOut live +Monolithic build - kernel linked directly +Collecting boot information... +CmdLine: parsed OK +[CKPT 004] Command line parsed +[CKPT 005] Kernel stack allocation decided +[CKPT 006] Boot info collected (ACPI table located) +GOP: linear framebuffer found +[CKPT 007] GOP: linear framebuffer found +[CKPT 008] About to enter ExitBootServices retry loop +Calling kernel_main (monolithic)... +riscv64 item 4.3.5a: satp state at kernel entry (before switch) + satp.MODE = 0x000000000000000a + satp.PPN = 0x00000000000bf868 + __kernel_start = 0x00000000bdc21efa +riscv64: satp cleared -- Bare mode, explicit (item 4.3.5a) + + + _____ _ _ __ _ + / ____| | | |/ / | | + | (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| | + \___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ | + ____) | || (_| | | | . \ __/ | | | | | __/ | + |_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_| + +LithosAnanke v2.1.0 riscv64 +Architecture: riscv64 +Build: Oct 27 2026 13:37:35 + +UEFI BootServices: EXITED +Console: serial line is a 16550 at 0x0000000010000000 (no devicetree: QEMU's) + +=== StarKernel Boot Information === +Memory map entries: 98 +Total memory: 1020 MB +Usable memory: 974 MB +=================================== + +PMM initialized. +PMM statistics: + Total pages: 250196 + Free pages : 249544 + Used pages : 652 + Total MB : 977 + Free MB : 974 + Used MB : 2 + +VMM initialized (mapped RAM, CR3 switched) +VMM initialized (mapped RAM, CR3 switched) +VMM self-test: mapped OK at 0xffff800000000000 +VMM self-test complete. + +IDT installed. + +APIC: init... +PLIC: no DTB PLIC node -- using QEMU virt-machine default (base=0x0c000000) +PLIC: init (S-mode context 1, threshold=0) +APIC: init done + +Timer: init... +Timer: RISC-V time CSR @ 10000000 Hz (FALLBACK, no devicetree) +Timer: init done + +Kernel heap initialized. +Heap statistics: + Total bytes: 536870872 + Free bytes: 536870872 + Used bytes: 0 + Peak bytes: 0 + Heap base addr: 2214588416 + Heap end addr: 2751459328 + +Heartbeat: init... +Heartbeat: init done +Kernel initialization complete. +Boot successful! + +System: StarForth v4 (this build's default) +StarForth v4: one host node, the F18-derived engine +V4: capsule v4:sys:map-64.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:map-64.f18 capsule_hash=0x949eb6a1e9260e49 +V4: capsule v4:sys:core.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:core.f18 capsule_hash=0xb8f167892ec18c28 +V4: capsule v4:sys:input.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:input.f18 capsule_hash=0x85d3ec486d929a79 +V4: capsule v4:sys:dict.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:dict.f18 capsule_hash=0x1379bd3b5de811dc +V4: capsule v4:sys:codegen.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:codegen.f18 capsule_hash=0x36d2ae84d2911b90 +V4: capsule v4:sys:compile.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:compile.f18 capsule_hash=0x11145c4c2ab819d8 +V4: capsule v4:sys:quit.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:quit.f18 capsule_hash=0x43cadf3b21ddbf3e +V4: capsule v4:sys:forth.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:forth.f18 capsule_hash=0x16cab4a1268b85da +V4: capsule v4:sys:numout.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:numout.f18 capsule_hash=0x85a240ad3fb2b299 +V4: capsule v4:sys:words.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:words.f18 capsule_hash=0xb1d381f927d9f14e +V4: capsule v4:sys:system.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:system.f18 capsule_hash=0xd92203664c2915bd +V4: capsule v4:sys:qmath.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:qmath.f18 capsule_hash=0xdb4140713dd857f3 +V4: capsule v4:sys:blocks.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:blocks.f18 capsule_hash=0x76307ef48678dc2a +V4: capsule v4:sys:log.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:log.f18 capsule_hash=0xfc6540e6b824a52b +V4: capsule v4:sys:acl.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:acl.f18 capsule_hash=0x6845aa048db7eb22 +V4: capsule v4:sys:end.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:end.f18 capsule_hash=0x5ef01312c07b79cc +PARITY:V4_ROM words=2372 rom_hash=0x87b23d3ae2643c8d instructions=59145258 +V4: capsule v4:forth79.4th signature: missing (unsigned) +PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x033e1c05c09a1df8 +PARITY:V4_POST tests=538 pass=538 fail=0 +PARITY:V4_SYSTEM word_count=317 dict_hash=0xfec8c47cfc6f437f +PARITY:OK +POST: PASSED +PCI: init... +virtio-blk: found device +Artemis: virtio-blk attached +virtio-input: found device +virtio-input: driver ready +Starting heartbeat... +SBI: timer armed (TIME extension) +Heartbeat running. +blkio_usb: MSC device ready +[Hera] Zuse: identity confirmed from attached thumbdrive +[zuse@Hera] ok> 3 4 + . +[zuse@Hera] 7 ok +[zuse@Hera] ok>  \ No newline at end of file diff --git a/scripts/check_images.sh b/scripts/check_images.sh new file mode 100755 index 00000000..561e25a6 --- /dev/null +++ b/scripts/check_images.sh @@ -0,0 +1,103 @@ +#!/usr/bin/env bash +# check_images.sh -- build the stick and the data stick and check them +# (docs/v4.0.0/plans/2026-10-27-stick-3-images.md, Task 1; docs/v4.0.0/STICK.md 4). +# +# The stick: make boot_image TARGET=PC -> build/boards/pc/lithos-pc.img +# The data stick: make -f kernel/Makefile ARCH=amd64 datastick -> build/amd64/kernel/datastick.img +# +# Prints PASS:/FAIL: per check and RESULT:; exits 0 only if every check passes. +set -uo pipefail +cd "$(dirname "$0")/.." +PATH="$PATH:/usr/sbin:/sbin" + +STICK=build/boards/pc/lithos-pc.img +DATA=build/amd64/kernel/datastick.img +MKARTEMIS=build/amd64/kernel/tools/mkartemis +ESP_T=C12A7328-F81F-11D2-BA4B-00A0C93EC93B +IDENT_T=23BEBFE1-4817-4CF3-A537-9069BF159788 +ART_T=BCD7B586-1C8E-4EEF-86A3-273A8D8EE624 +ok=1 + +check() { # check "what" command... + local what="$1"; shift + if "$@" >/dev/null 2>&1; then echo "PASS: $what"; else echo "FAIL: $what"; ok=0; fi +} + +# part IMG N FIELD -- a field (start, size, type) of partition N (1-based) from sfdisk --json +part() { + sfdisk --json "$1" 2>/dev/null | python3 -c " +import json, sys +p = json.load(sys.stdin)['partitiontable'] +parts = p['partitions'] +n = int(sys.argv[1]) +if sys.argv[2] == 'count': print(len(parts)) +elif sys.argv[2] == 'lastlba': print(p['lastlba']) +elif n <= len(parts): print(str(parts[n - 1][sys.argv[2]]).upper()) +" "$2" "$3" 2>/dev/null +} + +eq() { [ "$1" = "$2" ]; } + +# geometry IMG -- every partition starts and ends on a whole MiB, the last one within a MiB of +# the last usable LBA, and each starts where the one before it ends +geometry() { + local img="$1" n i prev=2048 s z last + n=$(part "$img" 0 count); last=$(part "$img" 0 lastlba) + for i in $(seq 1 "$n"); do + s=$(part "$img" "$i" start); z=$(part "$img" "$i" size) + [ "$s" = "$prev" ] && [ $((s % 2048)) -eq 0 ] && [ $((z % 2048)) -eq 0 ] || return 1 + prev=$((s + z)) + done + [ $((prev - 1)) -le "$last" ] && [ $((last - (prev - 1))) -lt 2048 ] +} + +zeros() { # zeros IMG N -- partition N is all zeros + local s z + s=$(part "$1" "$2" start); z=$(part "$1" "$2" size) + [ -n "$s" ] && [ -n "$z" ] && cmp -s -i "$((s * 512)):0" -n "$((z * 512))" "$1" /dev/zero +} + +artemis_check() { # artemis_check IMG N -- mkartemis --check on partition N + "$MKARTEMIS" --check "$1" --first-lba "$(part "$1" "$2" start)" --sectors "$(part "$1" "$2" size)" +} + +uuid() { artemis_check "$1" "$2" 2>/dev/null | sed -n 's/.*disk_uuid \([0-9a-f]*\).*/\1/p'; } + +echo "== building" +make boot_image TARGET=PC >/dev/null 2>&1; echo "boot_image exit $?" +make -f kernel/Makefile ARCH=amd64 datastick >/dev/null 2>&1; echo "datastick exit $?" + +echo "== the stick ($STICK)" +check "it exists, 2048 MiB" eq "$(stat -c %s "$STICK" 2>/dev/null)" "$((2048 * 1048576))" +check "three partitions" eq "$(part "$STICK" 0 count)" 3 +check "1: EFI System, 64 MiB at LBA 2048" eq "$(part "$STICK" 1 type)/$(part "$STICK" 1 start)/$(part "$STICK" 1 size)" "$ESP_T/2048/131072" +check "2: StarshipOS identity, 500 MiB" eq "$(part "$STICK" 2 type)/$(part "$STICK" 2 start)/$(part "$STICK" 2 size)" "$IDENT_T/133120/1024000" +check "3: StarshipOS Artemis, the rest" eq "$(part "$STICK" 3 type)/$(part "$STICK" 3 start)" "$ART_T/1157120" +check "whole MiB, contiguous, Artemis to the end" geometry "$STICK" +check "sfdisk --verify: the GPT is clean" sfdisk --verify "$STICK" +OFF=$((2048 * 512)) +check "the ESP holds EFI/BOOT/BOOTX64.EFI" mdir -i "$STICK@@$OFF" ::/EFI/BOOT/BOOTX64.EFI +check "the ESP holds startup.nsh" mdir -i "$STICK@@$OFF" ::/startup.nsh +check "starforth.cfg's first word is system=v4" eq "$(mtype -i "$STICK@@$OFF" ::/starforth.cfg 2>/dev/null | awk '{print $1; exit}')" "system=v4" +check "the identity partition is all zeros" zeros "$STICK" 2 +check "Artemis: STFR v2, signature ok" artemis_check "$STICK" 3 + +echo "== the data stick ($DATA)" +check "it exists, 1536 MiB" eq "$(stat -c %s "$DATA" 2>/dev/null)" "$((1536 * 1048576))" +check "two partitions" eq "$(part "$DATA" 0 count)" 2 +check "1: StarshipOS identity, 500 MiB at LBA 2048" eq "$(part "$DATA" 1 type)/$(part "$DATA" 1 start)/$(part "$DATA" 1 size)" "$IDENT_T/2048/1024000" +check "2: StarshipOS Artemis, the rest" eq "$(part "$DATA" 2 type)/$(part "$DATA" 2 start)" "$ART_T/1026048" +check "whole MiB, contiguous, Artemis to the end" geometry "$DATA" +check "sfdisk --verify: the GPT is clean" sfdisk --verify "$DATA" +check "the identity partition is all zeros" zeros "$DATA" 1 +check "Artemis: STFR v2, signature ok" artemis_check "$DATA" 2 +U1=$(uuid "$DATA" 2) +make -f kernel/Makefile ARCH=amd64 datastick >/dev/null 2>&1 +U2=$(uuid "$DATA" 2) +check "made again, it is fresh: its own disk_uuid ($U1 / $U2)" test -n "$U1" -a -n "$U2" -a "$U1" != "$U2" + +# the builds regenerate these; put them back as committed (as qemu_session.py does) +git checkout -q -- v3/include/version.h capsules/BLOCK_MAP.md sbom.spdx sbom.spdx.json + +echo "RESULT: $([ $ok = 1 ] && echo PASS || echo FAIL)" +[ $ok = 1 ] diff --git a/scripts/mkdiskimage.sh b/scripts/mkdiskimage.sh index f0bb89c7..1ab9c6e6 100644 --- a/scripts/mkdiskimage.sh +++ b/scripts/mkdiskimage.sh @@ -15,6 +15,14 @@ # SRC:DEST [SRC:DEST ...] # # --table gpt -> partition type "EFI System" (UEFI firmware, U-Boot bootefi) +# +# The StarshipOS stick and data stick (docs/v4.0.0/STICK.md 4; --table gpt only): +# --starship IDENT_MIB --mkartemis TOOL --esp-mib E +# lays out an ESP of E MiB holding the SRC:DEST files (E=0: no ESP, no files), +# then a StarshipOS identity partition of IDENT_MIB MiB (all zeros), then a +# StarshipOS Artemis partition to the last whole MiB before the backup GPT, +# formatted and signed by TOOL (tools/mkartemis.c). Every partition starts and +# ends on a whole MiB, so on 1 KiB blocks, as the kernel's GPT reader needs. # --table mbr -> partition type 0x0c FAT32 (LBA) (Raspberry Pi firmware) # DEST is an absolute path inside the FAT filesystem; parent directories are # created as needed. @@ -23,13 +31,16 @@ # root, no loop devices. set -euo pipefail -OUT="" TABLE="" SIZE_MIB="" LABEL="" +OUT="" TABLE="" SIZE_MIB="" LABEL="" IDENT_MIB="" MKARTEMIS="" ESP_MIB="" while [ $# -gt 0 ]; do case "$1" in --out) OUT="$2"; shift 2 ;; --table) TABLE="$2"; shift 2 ;; --size-mib) SIZE_MIB="$2"; shift 2 ;; --label) LABEL="$2"; shift 2 ;; + --starship) IDENT_MIB="$2"; shift 2 ;; + --mkartemis) MKARTEMIS="$2"; shift 2 ;; + --esp-mib) ESP_MIB="$2"; shift 2 ;; --) shift; break ;; -*) echo "mkdiskimage.sh: unknown option $1" >&2; exit 2 ;; *) break ;; @@ -38,7 +49,12 @@ done [ -n "$OUT" ] && [ -n "$TABLE" ] && [ -n "$SIZE_MIB" ] && [ -n "$LABEL" ] || { echo "mkdiskimage.sh: --out, --table, --size-mib and --label are required" >&2; exit 2; } -[ $# -gt 0 ] || { echo "mkdiskimage.sh: no SRC:DEST files given" >&2; exit 2; } +if [ -n "$IDENT_MIB" ]; then + [ "$TABLE" = gpt ] && [ -n "$MKARTEMIS" ] && [ -n "$ESP_MIB" ] || { + echo "mkdiskimage.sh: --starship needs --table gpt, --mkartemis and --esp-mib" >&2; exit 2; } + [ "$ESP_MIB" -gt 0 ] || [ $# -eq 0 ] || { echo "mkdiskimage.sh: --esp-mib 0 takes no files" >&2; exit 2; } +fi +[ $# -gt 0 ] || [ "${ESP_MIB:-}" = 0 ] || { echo "mkdiskimage.sh: no SRC:DEST files given" >&2; exit 2; } for tool in sfdisk mkfs.fat mmd mcopy; do command -v "$tool" >/dev/null 2>&1 || PATH="$PATH:/usr/sbin:/sbin" @@ -54,13 +70,37 @@ case "$TABLE" in *) echo "mkdiskimage.sh: --table must be gpt or mbr" >&2; exit 2 ;; esac PART_SECTORS=$(( LAST - START + 1 )) +# StarshipOS partition types (kernel/src/gpt.c) +IDENT_TYPE="23BEBFE1-4817-4CF3-A537-9069BF159788" +ART_TYPE="BCD7B586-1C8E-4EEF-86A3-273A8D8EE624" +if [ -n "$IDENT_MIB" ]; then + PART_SECTORS=$(( ESP_MIB * 2048 )) + IDENT_START=$(( START + PART_SECTORS )) + IDENT_SECTORS=$(( IDENT_MIB * 2048 )) + ART_START=$(( IDENT_START + IDENT_SECTORS )) + ART_SECTORS=$(( (LAST + 1 - ART_START) / 2048 * 2048 )) + [ "$ART_SECTORS" -gt 0 ] || { echo "mkdiskimage.sh: no room for Artemis in ${SIZE_MIB} MiB" >&2; exit 2; } +fi ESP="$OUT.part1" rm -f "$OUT" "$ESP" mkdir -p "$(dirname "$OUT")" truncate -s $(( TOTAL_SECTORS * 512 )) "$OUT" -if [ "$TABLE" = gpt ]; then +if [ -n "$IDENT_MIB" ]; then + { + echo "label: gpt" + [ "$ESP_MIB" -gt 0 ] && printf 'start=%d, size=%d, type=%s, name="EFI System"\n' "$START" "$PART_SECTORS" "$PTYPE" + printf 'start=%d, size=%d, type=%s, name="StarshipOS identity"\n' "$IDENT_START" "$IDENT_SECTORS" "$IDENT_TYPE" + printf 'start=%d, size=%d, type=%s, name="StarshipOS Artemis"\n' "$ART_START" "$ART_SECTORS" "$ART_TYPE" + } | sfdisk --quiet "$OUT" + "$MKARTEMIS" --format "$OUT" --first-lba "$ART_START" --sectors "$ART_SECTORS" >/dev/null || { + echo "mkdiskimage.sh: formatting Artemis failed" >&2; rm -f "$OUT"; exit 1; } + if [ "$ESP_MIB" = 0 ]; then + echo " IMAGE $OUT (gpt, ${SIZE_MIB} MiB: StarshipOS identity ${IDENT_MIB} MiB, Artemis $(( ART_SECTORS / 2048 )) MiB)" + exit 0 + fi +elif [ "$TABLE" = gpt ]; then printf 'label: gpt\nstart=%d, size=%d, type=%s, name="EFI System"\n' \ "$START" "$PART_SECTORS" "$PTYPE" | sfdisk --quiet "$OUT" else @@ -88,4 +128,8 @@ done dd if="$ESP" of="$OUT" bs=512 seek="$START" conv=notrunc status=none rm -f "$ESP" -echo " IMAGE $OUT ($TABLE, ${SIZE_MIB} MiB, FAT32 '$LABEL')" +if [ -n "$IDENT_MIB" ]; then + echo " IMAGE $OUT (gpt, ${SIZE_MIB} MiB: ESP ${ESP_MIB} MiB FAT32 '$LABEL', StarshipOS identity ${IDENT_MIB} MiB, Artemis $(( ART_SECTORS / 2048 )) MiB)" +else + echo " IMAGE $OUT ($TABLE, ${SIZE_MIB} MiB, FAT32 '$LABEL')" +fi diff --git a/tools/mkartemis.c b/tools/mkartemis.c new file mode 100644 index 00000000..e1f02f88 --- /dev/null +++ b/tools/mkartemis.c @@ -0,0 +1,184 @@ +/* mkartemis.c -- format, or check, an Artemis partition inside a disk image. + * + * The stick's Artemis partition is formatted when the image is built, not on + * first boot (docs/v4.0.0/STICK.md 4): its STFR v2 volume header, BAM and + * relocation table, and its artemis_sig_t genesis signature. This tool does + * it with the kernel's own code -- v3's block_subsystem.c + * (blk_subsys_confirm_format) and kernel/src/artemis_sig.c + * (artemis_sig_genesis_stamp, artemis_sig_check) -- through a blkio device + * over a byte range of the image file, so the bytes are exactly those the + * kernel writes. Zuse's genesis marker is not written: the first boot does + * that. docs/v4.0.0/plans/2026-10-27-stick-3-images.md. + * + * mkartemis --format IMG --first-lba L --sectors N + * mkartemis --check IMG --first-lba L --sectors N + * + * L and N count 512-byte sectors; both must be even (1 KiB blocks). + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include "blkio.h" +#include "block_subsystem.h" +#include "starkernel/artemis_sig.h" +#include "starkernel/rng.h" + +/* The kernel draws disk_uuid from its entropy backend; on the build machine + * that is the host's own, getrandom(2). */ +int rng_get_bytes(uint8_t *buf, size_t n) +{ + while (n > 0) { + ssize_t got = getrandom(buf, n, 0); + if (got < 0) { + if (errno == EINTR) continue; + return -1; + } + buf += got; + n -= (size_t)got; + } + return 0; +} + +/* ---- a blkio device over [first_lba, first_lba + sectors) of a file ---- */ + +typedef struct { + int fd; + off_t base; /* first_lba * 512 */ + uint32_t blocks; /* sectors / 2 */ + int read_only; +} range_t; + +static int range_open(blkio_dev_t *dev, const blkio_params_t *p) +{ + range_t *r = (range_t *)p->opaque; + dev->state = r; + dev->forth_block_size = BLKIO_FORTH_BLOCK_SIZE; + dev->total_blocks = r->blocks; + return BLKIO_OK; +} + +static int range_close(blkio_dev_t *dev) { (void)dev; return BLKIO_OK; } + +static int range_read(blkio_dev_t *dev, uint32_t fblock, void *dst) +{ + range_t *r = (range_t *)dev->state; + if (fblock >= r->blocks) return BLKIO_EINVAL; + if (pread(r->fd, dst, BLKIO_FORTH_BLOCK_SIZE, r->base + (off_t)fblock * BLKIO_FORTH_BLOCK_SIZE) + != (ssize_t)BLKIO_FORTH_BLOCK_SIZE) return BLKIO_EIO; + return BLKIO_OK; +} + +static int range_write(blkio_dev_t *dev, uint32_t fblock, const void *src) +{ + range_t *r = (range_t *)dev->state; + if (fblock >= r->blocks) return BLKIO_EINVAL; + if (r->read_only) return BLKIO_EIO; + if (pwrite(r->fd, src, BLKIO_FORTH_BLOCK_SIZE, r->base + (off_t)fblock * BLKIO_FORTH_BLOCK_SIZE) + != (ssize_t)BLKIO_FORTH_BLOCK_SIZE) return BLKIO_EIO; + return BLKIO_OK; +} + +static int range_flush(blkio_dev_t *dev) +{ + range_t *r = (range_t *)dev->state; + if (r->read_only) return BLKIO_OK; + return fsync(r->fd) == 0 ? BLKIO_OK : BLKIO_EIO; +} + +static int range_info(blkio_dev_t *dev, blkio_info_t *out) +{ + range_t *r = (range_t *)dev->state; + out->forth_block_size = BLKIO_FORTH_BLOCK_SIZE; + out->total_blocks = r->blocks; + out->phys_sector_size = 512u; + out->phys_size_bytes = (uint64_t)r->blocks * BLKIO_FORTH_BLOCK_SIZE; + out->read_only = (uint8_t)r->read_only; + return BLKIO_OK; +} + +static const blkio_vtable_t g_range_vt = { range_open, range_close, range_read, range_write, range_flush, range_info }; + +extern void sf_time_init(void); /* v3/src/platform/platform_init.c: the clock the volume header's times come from */ + +static uint8_t g_ram[(size_t)BLK_RAM_BLOCKS * BLK_FORTH_SIZE]; + +static int usage(void) +{ + fprintf(stderr, "usage: mkartemis --format|--check IMG --first-lba L --sectors N\n"); + return 2; +} + +int main(int argc, char **argv) +{ + const char *mode, *img; + unsigned long long first_lba, sectors; + range_t r; + blkio_dev_t dev; + blkio_params_t params; + uint32_t start_lbn = 0, count = 0; + artemis_sig_t sig; + int i, format; + + if (argc != 7 || strcmp(argv[3], "--first-lba") != 0 || strcmp(argv[5], "--sectors") != 0) return usage(); + mode = argv[1]; + img = argv[2]; + if (strcmp(mode, "--format") == 0) format = 1; + else if (strcmp(mode, "--check") == 0) format = 0; + else return usage(); + first_lba = strtoull(argv[4], NULL, 10); + sectors = strtoull(argv[6], NULL, 10); + if (first_lba % 2u != 0u || sectors % 2u != 0u || sectors == 0u || sectors / 2u > 0xFFFFFFFFull) { + fprintf(stderr, "mkartemis: the partition must start and end on a 1 KiB block (even LBA and sector count)\n"); + return 1; + } + + r.fd = open(img, format ? O_RDWR : O_RDONLY); + if (r.fd < 0) { fprintf(stderr, "mkartemis: %s: %s\n", img, strerror(errno)); return 1; } + r.base = (off_t)first_lba * 512; + r.blocks = (uint32_t)(sectors / 2u); + r.read_only = !format; + params.forth_block_size = BLKIO_FORTH_BLOCK_SIZE; + params.total_blocks = r.blocks; + params.opaque = &r; + if (blkio_open(&dev, &g_range_vt, ¶ms) != BLKIO_OK) { fprintf(stderr, "mkartemis: cannot open the range\n"); return 1; } + + sf_time_init(); + if (blk_subsys_init(g_ram, sizeof(g_ram)) != BLK_OK || blk_subsys_attach_device(&dev) != BLK_OK || + blk_get_device_range(&dev, &start_lbn, &count) != BLK_OK) { + fprintf(stderr, "mkartemis: the block subsystem would not take the partition\n"); + return 1; + } + + if (format) { + if (artemis_sig_check(&dev, &sig) != ARTEMIS_SIG_BLANK) { + fprintf(stderr, "mkartemis: the partition is not blank -- not formatted\n"); + return 1; + } + if (blk_subsys_confirm_format(start_lbn) != BLK_OK) { fprintf(stderr, "mkartemis: format failed\n"); return 1; } + blk_subsys_shutdown(); + if (artemis_sig_genesis_stamp(&dev) != 0) { fprintf(stderr, "mkartemis: the signature stamp failed\n"); return 1; } + printf("mkartemis: formatted %u blocks, STFR v2, signature stamped\n", r.blocks); + } else { + blk_volume_meta_t meta; + artemis_sig_result_t src; + if (blk_get_volume_meta(&meta) != BLK_OK || meta.magic != 0x53544652u || meta.version != 2u) { + fprintf(stderr, "mkartemis: no STFR v2 volume header\n"); + return 1; + } + src = artemis_sig_check(&dev, &sig); + if (src != ARTEMIS_SIG_OK) { fprintf(stderr, "mkartemis: the Artemis signature does not check out (%d)\n", (int)src); return 1; } + printf("mkartemis: STFR v2, %u user blocks, signature ok, disk_uuid ", count); + for (i = 0; i < 16; i++) printf("%02x", sig.disk_uuid[i]); + printf("\n"); + blk_subsys_shutdown(); + } + close(r.fd); + return 0; +}