From 2ae0cc2d423879170f7874c3db16d9de3d2c2a47 Mon Sep 17 00:00:00 2001 From: Robert James Date: Fri, 6 Nov 2026 03:40:43 +0000 Subject: [PATCH 1/9] build: add T= shorthand alias for TARGET= in both Makefiles Lets you type make T=fastest or make -f Makefile.starkernel ARCH=amd64 T=kernel instead of the full TARGET= form. T= is resolved before the strip pass so it behaves identically to TARGET= in all cases. Co-Authored-By: Claude Sonnet 4.6 --- Makefile | 7 +++++-- Makefile.starkernel | 6 +++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index d3757f86..811afaf6 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,8 @@ # # Quick Start: # make - Standard optimized build (auto ARCH, TARGET=standard) -# make TARGET=fastest - Maximum performance build -# make ARCH=arm64 TARGET=fastest - Build for arm64 (e.g., Raspberry Pi 4) +# make TARGET=fastest - Maximum performance build (T= is a shorthand: make T=fastest) +# make ARCH=arm64 T=fastest - Build for arm64 (e.g., Raspberry Pi 4) # make help - Show all available targets # # ============================================================================== @@ -26,6 +26,9 @@ ISABELLE ?= isabelle ARCH ?= $(shell uname -m) ARCH := $(strip $(ARCH)) TARGET ?= standard +ifdef T +TARGET := $(T) +endif TARGET := $(strip $(TARGET)) # Friendly guardrail: 32-bit builds are not supported diff --git a/Makefile.starkernel b/Makefile.starkernel index ccb035d1..f00a7aad 100644 --- a/Makefile.starkernel +++ b/Makefile.starkernel @@ -7,6 +7,7 @@ # make -f Makefile.starkernel ARCH=amd64 qemu — build + boot (x86_64) # make -f Makefile.starkernel ARCH=aarch64 qemu — build + boot (aarch64) # make -f Makefile.starkernel ARCH=riscv64 qemu — build + boot (riscv64) +# make -f Makefile.starkernel ARCH=amd64 T=kernel — T= is a shorthand for TARGET= # make -f Makefile.starkernel help — show all targets # ============================================================================== @@ -42,8 +43,11 @@ endif KCONFIG_ARCH_DIR := $(ARCH) include mk/Kconfig.mk -# Target type (default: kernel) +# Target type (default: kernel). T= is a shorthand alias. TARGET ?= kernel +ifdef T +TARGET := $(T) +endif # Kernel-only flags (Phase 6): repointed through the Kconfig bridge, same # drop-in-replacement-for-`?=` behavior as every other family in this From 81caf71511fcf21ee6e8c281137030d9fc1283a2 Mon Sep 17 00:00:00 2001 From: Robert James Date: Fri, 6 Nov 2026 03:43:15 +0000 Subject: [PATCH 2/9] build: T= aliases ARCH= (board/SBC selection), lock StarForth to fastest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit T= is now shorthand for ARCH=, selecting the target board (raspi, amd64, aarch64, riscv64). StarForth TARGET is locked to fastest — it's the only build profile. Makefile.starkernel T= wired the same way before ARCH normalization runs. Co-Authored-By: Claude Sonnet 4.6 --- Makefile | 18 +++++++++--------- Makefile.starkernel | 16 ++++++++-------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Makefile b/Makefile index 811afaf6..35d6cfa9 100644 --- a/Makefile +++ b/Makefile @@ -3,9 +3,10 @@ # ============================================================================== # # Quick Start: -# make - Standard optimized build (auto ARCH, TARGET=standard) -# make TARGET=fastest - Maximum performance build (T= is a shorthand: make T=fastest) -# make ARCH=arm64 T=fastest - Build for arm64 (e.g., Raspberry Pi 4) +# make - Build for host arch (fastest profile, always) +# make T=raspi - Build for Raspberry Pi 4 (T= is a shorthand for ARCH=) +# make T=amd64 - Build for x86_64 +# make T=riscv64 - Build for RISC-V 64 # make help - Show all available targets # # ============================================================================== @@ -22,14 +23,13 @@ CC = gcc # See docs/DEVELOPER.md for installation instructions ISABELLE ?= isabelle -# Architecture / target selection +# Architecture / target selection — T= is a shorthand for ARCH= (board/SBC) +ifdef T +ARCH ?= $(T) +endif ARCH ?= $(shell uname -m) ARCH := $(strip $(ARCH)) -TARGET ?= standard -ifdef T -TARGET := $(T) -endif -TARGET := $(strip $(TARGET)) +TARGET := fastest # Friendly guardrail: 32-bit builds are not supported unsupported_32bit_arches := i386 i486 i586 i686 x86 armv6 armv7 armv7l arm diff --git a/Makefile.starkernel b/Makefile.starkernel index f00a7aad..80a936c5 100644 --- a/Makefile.starkernel +++ b/Makefile.starkernel @@ -4,10 +4,9 @@ # # Quick start: # make -f Makefile.starkernel — build for host arch -# make -f Makefile.starkernel ARCH=amd64 qemu — build + boot (x86_64) -# make -f Makefile.starkernel ARCH=aarch64 qemu — build + boot (aarch64) -# make -f Makefile.starkernel ARCH=riscv64 qemu — build + boot (riscv64) -# make -f Makefile.starkernel ARCH=amd64 T=kernel — T= is a shorthand for TARGET= +# make -f Makefile.starkernel T=amd64 qemu — build + boot (x86_64) T= is shorthand for ARCH= +# make -f Makefile.starkernel T=aarch64 qemu — build + boot (aarch64) +# make -f Makefile.starkernel T=riscv64 qemu — build + boot (riscv64) # make -f Makefile.starkernel help — show all targets # ============================================================================== @@ -27,6 +26,10 @@ canon_arch = $(strip \ $(if $(filter riscv riscv64,$1),riscv64,$1)))))) UNAME_M := $(shell uname -m) +# T= is a shorthand for ARCH= (board/SBC selection) +ifdef T +ARCH ?= $(T) +endif ARCH ?= $(call canon_arch,$(UNAME_M)) override ARCH := $(call canon_arch,$(ARCH)) @@ -43,11 +46,8 @@ endif KCONFIG_ARCH_DIR := $(ARCH) include mk/Kconfig.mk -# Target type (default: kernel). T= is a shorthand alias. +# Target type (default: kernel) TARGET ?= kernel -ifdef T -TARGET := $(T) -endif # Kernel-only flags (Phase 6): repointed through the Kconfig bridge, same # drop-in-replacement-for-`?=` behavior as every other family in this From 0820ee7d321a1b022d3f29e3b951ec46e2ab1538 Mon Sep 17 00:00:00 2001 From: Robert James Date: Fri, 6 Nov 2026 04:10:07 +0000 Subject: [PATCH 3/9] build: introduce mk/boards.mk board target table, T= selects board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit T= now names a specific board (qemu, pc, pi4, pi5, milkv) rather than an arch alias. mk/boards.mk is the single table: sets ARCH, BOARD, and BOARD_NAME. Each Makefile applies board-specific compiler flags after its arch block — pi5 gets Cortex-A76 tuning, pi4 gets Cortex-A72, qemu uses portable x86-64 baseline instead of -march=native. Zynq-7020 is stubbed in comments for future 32-bit ARM support. ARCH= override still works for raw arch selection without a named board. Co-Authored-By: Claude Sonnet 4.6 --- Makefile | 60 +++++++++++++++++++++++++++++++++------------ Makefile.starkernel | 36 ++++++++++++++++++--------- mk/boards.mk | 48 ++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 27 deletions(-) create mode 100644 mk/boards.mk diff --git a/Makefile b/Makefile index 35d6cfa9..f2c523e2 100644 --- a/Makefile +++ b/Makefile @@ -4,9 +4,11 @@ # # Quick Start: # make - Build for host arch (fastest profile, always) -# make T=raspi - Build for Raspberry Pi 4 (T= is a shorthand for ARCH=) -# make T=amd64 - Build for x86_64 -# make T=riscv64 - Build for RISC-V 64 +# make T=qemu - Build portable x86-64 for QEMU +# make T=pc - Build for x86-64 PC (native tuning) +# make T=pi4 - Cross-compile for Raspberry Pi 4 (Cortex-A72) +# make T=pi5 - Cross-compile for Raspberry Pi 5 (Cortex-A76) +# make T=milkv - Cross-compile for Milk-V Pioneer (RISC-V 64) # make help - Show all available targets # # ============================================================================== @@ -23,10 +25,8 @@ CC = gcc # See docs/DEVELOPER.md for installation instructions ISABELLE ?= isabelle -# Architecture / target selection — T= is a shorthand for ARCH= (board/SBC) -ifdef T -ARCH ?= $(T) -endif +# Board / architecture selection — T= picks a board (see mk/boards.mk) +include mk/boards.mk ARCH ?= $(shell uname -m) ARCH := $(strip $(ARCH)) TARGET := fastest @@ -105,6 +105,33 @@ else ASM_SYNTAX = endif +# Board-specific overrides — refine arch defaults for exact hardware +# QEMU: use portable baseline, not -march=native +ifeq ($(BOARD),qemu) + ARCH_FLAGS := -march=x86-64 -mtune=generic + ARCH_DEFINES += -DBOARD_QEMU=1 +# PC: native tuning (already the amd64 default; explicit for clarity) +else ifeq ($(BOARD),pc) + ARCH_FLAGS := -march=native + ARCH_DEFINES += -DBOARD_PC=1 +# Raspberry Pi 4 — Cortex-A72, ARMv8-A +else ifeq ($(BOARD),pi4) + ARCH_FLAGS := -march=armv8-a+crc+simd -mtune=cortex-a72 + ARCH_DEFINES += -DBOARD_RPI4=1 -DRASPBERRY_PI_BUILD=1 +# Raspberry Pi 5 — Cortex-A76, ARMv8.2-A +else ifeq ($(BOARD),pi5) + ARCH_FLAGS := -march=armv8.2-a+crypto+fp16+rcpc+dotprod -mtune=cortex-a76 + ARCH_DEFINES += -DBOARD_RPI5=1 -DRASPBERRY_PI_BUILD=1 +# Milk-V Pioneer — SG2042 RISC-V 64 +else ifeq ($(BOARD),milkv) + ARCH_FLAGS := -march=rv64gc -mabi=lp64d -mcmodel=medany + ARCH_DEFINES += -DBOARD_MILKV=1 +endif +# Use board name in ARCH_NAME when T= is set +ifdef BOARD_NAME + ARCH_NAME := $(BOARD_NAME) +endif + # Compiler flags # Feature switches (default: enabled) # Physics/SSM knob family: repointed through the Kconfig bridge (see @@ -1251,18 +1278,19 @@ help: @echo "════════════════════════════════════════════════════════════" @echo "" @echo "🛠️ Variables:" - @echo " ARCH= (default: $(ARCH); canonical directory: $(ARCH_DIR))" - @echo " TARGET= (standard | fast | fastest | turbo)" + @echo " T= Board target (preferred). Supported:" + @echo " qemu — portable x86-64 for QEMU" + @echo " pc — x86-64 PC (native tuning)" + @echo " pi4 — Raspberry Pi 4 (Cortex-A72)" + @echo " pi5 — Raspberry Pi 5 (Cortex-A76)" + @echo " milkv — Milk-V Pioneer (SG2042 RISC-V 64)" + @echo " ARCH= Low-level arch override (amd64 | arm64 | riscv64)" + @echo " Active: $(ARCH) / board: $(or $(BOARD_NAME),$(ARCH_NAME))" @echo "" - @echo "🏆 OPTIMIZATION BUILDS:" - @echo " fastest - Maximum performance (ASM + direct threading + LTO)" - @echo " fast - Fast without LTO (easier debugging)" - @echo " turbo - Assembly optimizations only" + @echo "🏆 BUILD PROFILE: fastest (always — ASM + direct threading + LTO)" @echo "" @echo "🥧 PLATFORM-SPECIFIC BUILDS:" - @echo " rpi4 - Native build on Raspberry Pi 4" - @echo " rpi4-cross - Cross-compile from x86_64" - @echo " rpi4-fastest - Maximum optimization for RPi4" + @echo " rpi4-cross - Cross-compile for Raspberry Pi 4 (legacy; use T=pi4)" @echo " riscv64-clang - Cross-compile for RISC-V 64 via clang (GCC fails here)" @echo " minimal - Minimal/embedded build" @echo "" diff --git a/Makefile.starkernel b/Makefile.starkernel index 80a936c5..12bc2759 100644 --- a/Makefile.starkernel +++ b/Makefile.starkernel @@ -26,10 +26,8 @@ canon_arch = $(strip \ $(if $(filter riscv riscv64,$1),riscv64,$1)))))) UNAME_M := $(shell uname -m) -# T= is a shorthand for ARCH= (board/SBC selection) -ifdef T -ARCH ?= $(T) -endif +# T= selects the board target (see mk/boards.mk for the full table) +include mk/boards.mk ARCH ?= $(call canon_arch,$(UNAME_M)) override ARCH := $(call canon_arch,$(ARCH)) @@ -245,6 +243,13 @@ endif LOADER_CC ?= $(CC) LOADER_LD ?= $(LD) +# Board-specific ARCH_CFLAGS overrides — refine CPU tuning beyond arch default +ifeq ($(BOARD),pi4) + ARCH_CFLAGS := -march=armv8-a -mcpu=cortex-a72 -DARCH_AARCH64 -mno-outline-atomics +else ifeq ($(BOARD),pi5) + ARCH_CFLAGS := -march=armv8.2-a -mcpu=cortex-a76 -DARCH_AARCH64 -mno-outline-atomics +endif + # ============================================================================== # COMPILER FLAGS # ============================================================================== @@ -1246,6 +1251,7 @@ endif info: @echo "StarKernel Build Configuration" @echo "===============================" + @echo "Board: $(or $(BOARD_NAME),$(ARCH) (no board selected))" @echo "Architecture: $(ARCH)" @echo "Target: $(TARGET)" @echo "Compiler: $(CC)" @@ -1263,10 +1269,17 @@ help: @echo "StarKernel Build System" @echo "=======================" @echo "" - @echo "Usage: make -f Makefile.starkernel [ARCH=] [TARGET=] " + @echo "Usage: make -f Makefile.starkernel [T=] [TARGET=] " @echo "" - @echo "Architectures (aliases accepted):" - @echo " ARCH=amd64 / x86_64 — x86-64 (default on x86 host)" + @echo "Board targets (T=):" + @echo " T=qemu — QEMU x86_64 (portable baseline)" + @echo " T=pc — x86_64 PC (native tuning)" + @echo " T=pi4 — Raspberry Pi 4 (Cortex-A72, aarch64)" + @echo " T=pi5 — Raspberry Pi 5 (Cortex-A76, aarch64)" + @echo " T=milkv — Milk-V Pioneer (SG2042, riscv64)" + @echo "" + @echo "Low-level arch override (bypasses board table):" + @echo " ARCH=amd64 / x86_64 — x86-64" @echo " ARCH=aarch64 / arm64 — ARM64" @echo " ARCH=riscv64 / riscv — RISC-V 64-bit" @echo "" @@ -1293,8 +1306,9 @@ help: @echo " help — show this message" @echo "" @echo "Examples:" - @echo " make -f Makefile.starkernel ARCH=amd64 qemu" - @echo " make -f Makefile.starkernel ARCH=aarch64 clean qemu" - @echo " make -f Makefile.starkernel ARCH=riscv64 clean qemu" - @echo " make -f Makefile.starkernel ARCH=x86_64 qemu # alias works" + @echo " make -f Makefile.starkernel T=qemu qemu" + @echo " make -f Makefile.starkernel T=pi4 clean qemu" + @echo " make -f Makefile.starkernel T=pi5 clean qemu" + @echo " make -f Makefile.starkernel T=milkv clean all" @echo " make -f Makefile.starkernel kernel-all" + @echo " make -f Makefile.starkernel ARCH=riscv64 clean qemu # arch override still works" diff --git a/mk/boards.mk b/mk/boards.mk new file mode 100644 index 00000000..212a2b85 --- /dev/null +++ b/mk/boards.mk @@ -0,0 +1,48 @@ +# Board target table — T= selects board, sets ARCH + BOARD + BOARD_NAME. +# Included early by both Makefile and Makefile.starkernel, before arch +# normalization runs. Each Makefile applies board-specific flag overrides +# after its own arch block. +# +# Adding a new board: add an ifeq block here, then add compiler-flag +# overrides in the board-override sections of Makefile and +# Makefile.starkernel if the board needs tuning beyond the arch default. + +ifdef T + +ifeq ($(T),qemu) + ARCH ?= amd64 + BOARD := qemu + BOARD_NAME := QEMU x86_64 + +else ifeq ($(T),pc) + ARCH ?= amd64 + BOARD := pc + BOARD_NAME := x86_64 PC (native) + +else ifeq ($(T),pi4) + ARCH ?= aarch64 + BOARD := pi4 + BOARD_NAME := Raspberry Pi 4 (Cortex-A72) + +else ifeq ($(T),pi5) + ARCH ?= aarch64 + BOARD := pi5 + BOARD_NAME := Raspberry Pi 5 (Cortex-A76) + +else ifeq ($(T),milkv) + ARCH ?= riscv64 + BOARD := milkv + BOARD_NAME := Milk-V Pioneer (SG2042 RISC-V 64) + +# ── Future boards (uncomment + add flag overrides in Makefile / Makefile.starkernel) ── +# else ifeq ($(T),zynq7020) +# ARCH ?= arm +# BOARD := zynq7020 +# BOARD_NAME := Xilinx Zynq-7020 (Cortex-A9, 32-bit) +# # NOTE: requires removing the 32-bit guardrail and adding armhf toolchain support + +else + $(error Unknown board target T='$(T)'. Supported: qemu pc pi4 pi5 milkv) +endif + +endif # ifdef T From b191ace026f77c640f9710fcde0d9a7ed4272a2a Mon Sep 17 00:00:00 2001 From: Robert James Date: Fri, 6 Nov 2026 04:17:12 +0000 Subject: [PATCH 4/9] ci: board-matrix build pipeline with Nexus Maven publish Builds all boards (qemu, pc, pi4, pi5, milkv) in parallel. Installs cross-compilers (aarch64-linux-gnu, riscv64-linux-gnu) and clang-18 for the aarch64 loader. Packs ISO (amd64/aarch64) and GPT image (riscv64). On master push, publishes to Nexus starshipos-releases using Maven coordinates org.f18:kernel:-: and org.f18:starforth:-:. CROSS_COMPILE wired into StarForth Makefile via mk/boards.mk so make T=pi4 picks up aarch64-linux-gnu-gcc automatically. Co-Authored-By: Claude Sonnet 4.6 --- .gitea/workflows/build.yml | 207 ++++++++++++++++++++++++++----------- Makefile | 4 + mk/boards.mk | 42 ++++---- 3 files changed, 172 insertions(+), 81 deletions(-) diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 9f0c32b8..547135e4 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -1,87 +1,168 @@ -name: Build +name: StarshipOS Build on: push: - branches: - - master + branches: [master] + pull_request: + branches: [master] + +env: + NEXUS: https://nexus.starshipos-f18.org/repository/starshipos-releases jobs: - build-amd64-iso: + build: + name: ${{ matrix.board }} runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Build kernel (amd64) - run: make -f Makefile.starkernel ARCH=amd64 - - name: Pack El Torito ISO (amd64) - run: | - set -e - BUILD_DIR=build/amd64/kernel - mkdir -p "$BUILD_DIR/iso" - dd if=/dev/zero of="$BUILD_DIR/iso/efi.img" bs=512 count=8192 - mformat -i "$BUILD_DIR/iso/efi.img" :: - mmd -i "$BUILD_DIR/iso/efi.img" ::/EFI - mmd -i "$BUILD_DIR/iso/efi.img" ::/EFI/BOOT - mcopy -i "$BUILD_DIR/iso/efi.img" "$BUILD_DIR/starkernel_loader.efi" ::/EFI/BOOT/BOOTX64.EFI - xorriso -as mkisofs -r -J -e efi.img -no-emul-boot \ - -o "$BUILD_DIR/starkernel.iso" "$BUILD_DIR/iso" - - uses: actions/upload-artifact@v3 - with: - name: lithosananke-amd64-iso - path: build/amd64/kernel/starkernel.iso - build-aarch64-iso: - runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + board: [qemu, pc, pi4, pi5, milkv] + include: + - board: qemu + karch: amd64 + vm_arch: amd64 + img_type: iso + efi_name: BOOTX64.EFI + - board: pc + karch: amd64 + vm_arch: amd64 + img_type: iso + efi_name: BOOTX64.EFI + - board: pi4 + karch: aarch64 + vm_arch: arm64 + img_type: iso + efi_name: BOOTAA64.EFI + - board: pi5 + karch: aarch64 + vm_arch: arm64 + img_type: iso + efi_name: BOOTAA64.EFI + - board: milkv + karch: riscv64 + vm_arch: riscv64 + img_type: img + efi_name: BOOTRISCV64.EFI + steps: - uses: actions/checkout@v4 - - name: Build kernel (aarch64) + + - name: Install toolchains + run: | + apt-get update -qq + apt-get install -y --no-install-recommends \ + build-essential make curl ca-certificates \ + gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu \ + gcc-riscv64-linux-gnu binutils-riscv64-linux-gnu \ + mtools xorriso dosfstools gdisk + + - name: Install clang-18 (aarch64 loader) + if: matrix.karch == 'aarch64' + run: | + curl -fsSL https://apt.llvm.org/llvm.sh | bash -s -- 18 + + - name: Extract versions + id: ver + run: | + LITHOS=$(grep 'LITHOS_VERSION\s*?=' Makefile.starkernel | head -1 | sed 's/.*= *//') + SF=$(grep '^VERSION\s*?=' Makefile | head -1 | sed 's/.*= *//') + SHA=$(git rev-parse --short HEAD) + echo "lithos=${LITHOS}-${SHA}" >> $GITHUB_OUTPUT + echo "sf=${SF}-${SHA}" >> $GITHUB_OUTPUT + echo "sha=${SHA}" >> $GITHUB_OUTPUT + + - name: Build StarForth VM + run: make T=${{ matrix.board }} + + - name: Build kernel + run: | + export PATH=/usr/lib/llvm-18/bin:$PATH + make -f Makefile.starkernel T=${{ matrix.board }} + + - name: Pack ISO (amd64 / aarch64) + if: matrix.img_type == 'iso' env: - PATH: /usr/lib/llvm-18/bin:/usr/bin:/bin - run: make -f Makefile.starkernel ARCH=aarch64 - - name: Pack El Torito ISO (aarch64) + BUILD_DIR: build/${{ matrix.karch }}/kernel + EFI: ${{ matrix.efi_name }} + BOARD: ${{ matrix.board }} + VER: ${{ steps.ver.outputs.lithos }} run: | set -e - BUILD_DIR=build/aarch64/kernel mkdir -p "$BUILD_DIR/iso/EFI/BOOT" - cp "$BUILD_DIR/starkernel_loader.efi" "$BUILD_DIR/iso/EFI/BOOT/BOOTAA64.EFI" - printf "FS0:\\\\EFI\\\\BOOT\\\\BOOTAA64.EFI\r\n" > "$BUILD_DIR/iso/startup.nsh" + cp "$BUILD_DIR/starkernel_loader.efi" "$BUILD_DIR/iso/EFI/BOOT/$EFI" + printf 'FS0:\\EFI\\BOOT\\%s\r\n' "$EFI" > "$BUILD_DIR/iso/startup.nsh" dd if=/dev/zero of="$BUILD_DIR/iso/efi.img" bs=512 count=8192 mformat -i "$BUILD_DIR/iso/efi.img" :: - mmd -i "$BUILD_DIR/iso/efi.img" ::/EFI mmd -i "$BUILD_DIR/iso/efi.img" ::/EFI/BOOT - mcopy -i "$BUILD_DIR/iso/efi.img" "$BUILD_DIR/starkernel_loader.efi" ::/EFI/BOOT/BOOTAA64.EFI + mcopy -i "$BUILD_DIR/iso/efi.img" "$BUILD_DIR/starkernel_loader.efi" "::/EFI/BOOT/$EFI" xorriso -as mkisofs -r -J -e efi.img -no-emul-boot \ - -o "$BUILD_DIR/starkernel.iso" "$BUILD_DIR/iso" - - uses: actions/upload-artifact@v3 - with: - name: lithosananke-aarch64-iso - path: build/aarch64/kernel/starkernel.iso + -o "$BUILD_DIR/kernel-${VER}-${BOARD}.iso" "$BUILD_DIR/iso" - build-riscv64-img: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Build kernel (riscv64) - run: make -f Makefile.starkernel ARCH=riscv64 - - name: Pack GPT/FAT32 disk image (riscv64) - # El Torito ISO and -bios QEMU mode don't work on riscv64 virt, - # so this arch ships a raw GPT disk image instead of an ISO - # (same distinction Makefile.starkernel's own qemu target makes). + - name: Pack GPT image (riscv64) + if: matrix.img_type == 'img' + env: + BUILD_DIR: build/riscv64/kernel + BOARD: ${{ matrix.board }} + VER: ${{ steps.ver.outputs.lithos }} run: | set -e - BUILD_DIR=build/riscv64/kernel - DISK="$BUILD_DIR/starkernel_rv64.img" + DISK="$BUILD_DIR/kernel-${VER}-${BOARD}.img" dd if=/dev/zero of="$DISK" bs=1M count=64 sgdisk -n 1:2048:131038 -t 1:ef00 -c 1:"EFI System" "$DISK" - dd if=/dev/zero of="$BUILD_DIR/esp_rv64.img" bs=512 count=128991 - mkfs.fat -F 32 -n "ESP" "$BUILD_DIR/esp_rv64.img" - mmd -i "$BUILD_DIR/esp_rv64.img" ::/EFI - mmd -i "$BUILD_DIR/esp_rv64.img" ::/EFI/BOOT - mcopy -i "$BUILD_DIR/esp_rv64.img" "$BUILD_DIR/starkernel_loader.efi" ::/EFI/BOOT/BOOTRISCV64.EFI - mcopy -i "$BUILD_DIR/esp_rv64.img" "$BUILD_DIR/starkernel_kernel.elf" ::/kernel.elf + dd if=/dev/zero of="$BUILD_DIR/esp.img" bs=512 count=128991 + mkfs.fat -F 32 -n "ESP" "$BUILD_DIR/esp.img" + mmd -i "$BUILD_DIR/esp.img" ::/EFI/BOOT + mcopy -i "$BUILD_DIR/esp.img" "$BUILD_DIR/starkernel_loader.efi" ::/EFI/BOOT/BOOTRISCV64.EFI + mcopy -i "$BUILD_DIR/esp.img" "$BUILD_DIR/starkernel_kernel.elf" ::/kernel.elf printf 'FS0:\\EFI\\BOOT\\BOOTRISCV64.EFI\r\n' > "$BUILD_DIR/startup.nsh" - mcopy -i "$BUILD_DIR/esp_rv64.img" "$BUILD_DIR/startup.nsh" ::/startup.nsh - dd if="$BUILD_DIR/esp_rv64.img" of="$DISK" bs=512 seek=2048 conv=notrunc - - uses: actions/upload-artifact@v3 + mcopy -i "$BUILD_DIR/esp.img" "$BUILD_DIR/startup.nsh" ::/startup.nsh + dd if="$BUILD_DIR/esp.img" of="$DISK" bs=512 seek=2048 conv=notrunc + + - name: Upload artifacts (Gitea) + uses: actions/upload-artifact@v3 with: - name: lithosananke-riscv64-img - path: build/riscv64/kernel/starkernel_rv64.img + name: starshipos-${{ matrix.board }}-${{ steps.ver.outputs.sha }} + path: | + build/${{ matrix.karch }}/kernel/starkernel_loader.efi + build/${{ matrix.karch }}/kernel/starkernel_kernel.elf + build/${{ matrix.karch }}/kernel/kernel-${{ steps.ver.outputs.lithos }}-${{ matrix.board }}.* + build/${{ matrix.vm_arch }}/fastest/starforth + + - name: Publish to Nexus + if: github.ref == 'refs/heads/master' + env: + NEXUS_PASS: ${{ secrets.NEXUS_CI_PASSWORD }} + BOARD: ${{ matrix.board }} + KARCH: ${{ matrix.karch }} + VM_ARCH: ${{ matrix.vm_arch }} + KVER: ${{ steps.ver.outputs.lithos }} + SFVER: ${{ steps.ver.outputs.sf }} + IMG_TYPE: ${{ matrix.img_type }} + run: | + set -e + push() { + local coord="$1" file="$2" + echo "→ org.f18:${coord}" + curl -fsS --retry 3 \ + -u "ci-publisher:${NEXUS_PASS}" \ + -H "Content-Type: application/octet-stream" \ + -X PUT "${NEXUS}/org/f18/${coord}" \ + --upload-file "$file" + } + + # kernel//kernel---loader.efi + push "kernel/${KVER}/kernel-${KVER}-${BOARD}-loader.efi" \ + "build/${KARCH}/kernel/starkernel_loader.efi" + + # kernel//kernel---kernel.elf + push "kernel/${KVER}/kernel-${KVER}-${BOARD}-kernel.elf" \ + "build/${KARCH}/kernel/starkernel_kernel.elf" + + # kernel//kernel--. + push "kernel/${KVER}/kernel-${KVER}-${BOARD}.${IMG_TYPE}" \ + "build/${KARCH}/kernel/kernel-${KVER}-${BOARD}.${IMG_TYPE}" + + # starforth//starforth-- + push "starforth/${SFVER}/starforth-${SFVER}-${BOARD}" \ + "build/${VM_ARCH}/fastest/starforth" diff --git a/Makefile b/Makefile index f2c523e2..4f4ee197 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,10 @@ ISABELLE ?= isabelle # Board / architecture selection — T= picks a board (see mk/boards.mk) include mk/boards.mk +# Cross-compiler: boards.mk sets CROSS_COMPILE for SBC targets +ifdef CROSS_COMPILE +CC := $(CROSS_COMPILE)gcc +endif ARCH ?= $(shell uname -m) ARCH := $(strip $(ARCH)) TARGET := fastest diff --git a/mk/boards.mk b/mk/boards.mk index 212a2b85..6e0c55d2 100644 --- a/mk/boards.mk +++ b/mk/boards.mk @@ -10,35 +10,41 @@ ifdef T ifeq ($(T),qemu) - ARCH ?= amd64 - BOARD := qemu - BOARD_NAME := QEMU x86_64 + ARCH ?= amd64 + BOARD := qemu + BOARD_NAME := QEMU x86_64 + CROSS_COMPILE := else ifeq ($(T),pc) - ARCH ?= amd64 - BOARD := pc - BOARD_NAME := x86_64 PC (native) + ARCH ?= amd64 + BOARD := pc + BOARD_NAME := x86_64 PC (native) + CROSS_COMPILE := else ifeq ($(T),pi4) - ARCH ?= aarch64 - BOARD := pi4 - BOARD_NAME := Raspberry Pi 4 (Cortex-A72) + ARCH ?= aarch64 + BOARD := pi4 + BOARD_NAME := Raspberry Pi 4 (Cortex-A72) + CROSS_COMPILE := aarch64-linux-gnu- else ifeq ($(T),pi5) - ARCH ?= aarch64 - BOARD := pi5 - BOARD_NAME := Raspberry Pi 5 (Cortex-A76) + ARCH ?= aarch64 + BOARD := pi5 + BOARD_NAME := Raspberry Pi 5 (Cortex-A76) + CROSS_COMPILE := aarch64-linux-gnu- else ifeq ($(T),milkv) - ARCH ?= riscv64 - BOARD := milkv - BOARD_NAME := Milk-V Pioneer (SG2042 RISC-V 64) + ARCH ?= riscv64 + BOARD := milkv + BOARD_NAME := Milk-V Pioneer (SG2042 RISC-V 64) + CROSS_COMPILE := riscv64-linux-gnu- # ── Future boards (uncomment + add flag overrides in Makefile / Makefile.starkernel) ── # else ifeq ($(T),zynq7020) -# ARCH ?= arm -# BOARD := zynq7020 -# BOARD_NAME := Xilinx Zynq-7020 (Cortex-A9, 32-bit) +# ARCH ?= arm +# BOARD := zynq7020 +# BOARD_NAME := Xilinx Zynq-7020 (Cortex-A9, 32-bit) +# CROSS_COMPILE := arm-linux-gnueabihf- # # NOTE: requires removing the 32-bit guardrail and adding armhf toolchain support else From 08daef99710c700c19773c97880a5816b5f8dcb9 Mon Sep 17 00:00:00 2001 From: Robert James Date: Fri, 6 Nov 2026 04:20:00 +0000 Subject: [PATCH 5/9] ci: add Isabelle/HOL proof verification job Runs StarForth session (52 theories) in parallel with the board build matrix. Caches the Isabelle2024 installation (~800MB) and the compiled heaps keyed on proof/**/*.thy + ROOT, so only theory changes trigger a full rebuild. Uploads the build log as an artifact on every run (pass or fail) for audit. Co-Authored-By: Claude Sonnet 4.6 --- .gitea/workflows/build.yml | 46 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 547135e4..53ceffae 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -166,3 +166,49 @@ jobs: # starforth//starforth-- push "starforth/${SFVER}/starforth-${SFVER}-${BOARD}" \ "build/${VM_ARCH}/fastest/starforth" + + verify-isabelle: + name: Isabelle/HOL Proofs + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Cache Isabelle installation + uses: actions/cache@v3 + id: isabelle-install-cache + with: + path: /opt/Isabelle2024 + key: isabelle-2024-linux + + - name: Install Isabelle + if: steps.isabelle-install-cache.outputs.cache-hit != 'true' + run: | + apt-get update -qq + apt-get install -y --no-install-recommends curl ca-certificates + curl -fsSL \ + "https://isabelle.in.tum.de/dist/Isabelle2024_linux.tar.gz" \ + -o /tmp/isabelle.tar.gz + tar -xzf /tmp/isabelle.tar.gz -C /opt + rm /tmp/isabelle.tar.gz + + - name: Cache Isabelle heaps + uses: actions/cache@v3 + with: + path: ~/.isabelle/Isabelle2024 + key: isabelle-heaps-${{ hashFiles('proof/**/*.thy', 'proof/ROOT') }} + restore-keys: isabelle-heaps- + + - name: Verify StarForth proofs + run: | + export PATH=/opt/Isabelle2024/bin:$PATH + isabelle build -v -d proof StarForth 2>&1 | tee /tmp/isabelle-build.log + # Exit code reflects proof success/failure + grep -q "Finished StarForth" /tmp/isabelle-build.log + + - name: Upload proof log + if: always() + uses: actions/upload-artifact@v3 + with: + name: isabelle-proof-log-${{ github.sha }} + path: /tmp/isabelle-build.log From a6329fc0c543db9a60d2e80fcadbe5974d979744 Mon Sep 17 00:00:00 2001 From: Robert James Date: Fri, 6 Nov 2026 04:20:59 +0000 Subject: [PATCH 6/9] ci: add documentation build job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Runs api-docs (Doxygen → AsciiDoc), docs-latex (AsciiDoc → LaTeX via asciidoctor), and math-companion (LaTeX → PDF) in a dedicated job parallel to builds and Isabelle verification. Installs doxygen, Ruby + asciidoctor-latex gem, and texlive. Uploads docs as a Gitea artifact on every run regardless of pass/fail. Co-Authored-By: Claude Sonnet 4.6 --- .gitea/workflows/build.yml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 53ceffae..1246e1f5 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -212,3 +212,39 @@ jobs: with: name: isabelle-proof-log-${{ github.sha }} path: /tmp/isabelle-build.log + + build-docs: + name: Documentation + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install doc toolchain + run: | + apt-get update -qq + apt-get install -y --no-install-recommends \ + doxygen python3 \ + ruby ruby-dev build-essential \ + texlive-latex-base texlive-latex-extra \ + texlive-science texlive-fonts-recommended + gem install asciidoctor asciidoctor-latex --no-document + + - name: API docs (Doxygen → AsciiDoc) + run: make api-docs + + - name: LaTeX docs (AsciiDoc → LaTeX) + run: make docs-latex + + - name: Math companion PDF (LaTeX → PDF) + run: make math-companion + + - name: Upload documentation + if: always() + uses: actions/upload-artifact@v3 + with: + name: docs-${{ github.sha }} + path: | + docs/src/appendix/ + docs/latex/ + docs/SSRN_companion/Math_Companion_SSRN.pdf From 02946a5318493872f32bdbb58137241d9f3f0087 Mon Sep 17 00:00:00 2001 From: Robert James Date: Fri, 6 Nov 2026 04:28:38 +0000 Subject: [PATCH 7/9] ci: add nightly snapshot build (02:00 UTC schedule) Scheduled runs use -SNAPSHOT version suffix and publish to starshipos-snapshots Nexus repo instead of starshipos-releases. Push-to-master releases continue to use - suffix. Co-Authored-By: Claude Sonnet 4.6 --- .gitea/workflows/build.yml | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 1246e1f5..cc66757a 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -5,9 +5,12 @@ on: branches: [master] pull_request: branches: [master] + schedule: + - cron: '0 2 * * *' # 02:00 UTC nightly snapshot env: - NEXUS: https://nexus.starshipos-f18.org/repository/starshipos-releases + NEXUS: https://nexus.starshipos-f18.org/repository/starshipos-releases + NEXUS_SNAP: https://nexus.starshipos-f18.org/repository/starshipos-snapshots jobs: build: @@ -68,9 +71,15 @@ jobs: LITHOS=$(grep 'LITHOS_VERSION\s*?=' Makefile.starkernel | head -1 | sed 's/.*= *//') SF=$(grep '^VERSION\s*?=' Makefile | head -1 | sed 's/.*= *//') SHA=$(git rev-parse --short HEAD) - echo "lithos=${LITHOS}-${SHA}" >> $GITHUB_OUTPUT - echo "sf=${SF}-${SHA}" >> $GITHUB_OUTPUT - echo "sha=${SHA}" >> $GITHUB_OUTPUT + if [ "${{ github.event_name }}" = "schedule" ]; then + SUFFIX="-SNAPSHOT" + else + SUFFIX="-${SHA}" + fi + echo "lithos=${LITHOS}${SUFFIX}" >> $GITHUB_OUTPUT + echo "sf=${SF}${SUFFIX}" >> $GITHUB_OUTPUT + echo "sha=${SHA}" >> $GITHUB_OUTPUT + echo "is_snapshot=${{ github.event_name == 'schedule' }}" >> $GITHUB_OUTPUT - name: Build StarForth VM run: make T=${{ matrix.board }} @@ -130,7 +139,7 @@ jobs: build/${{ matrix.vm_arch }}/fastest/starforth - name: Publish to Nexus - if: github.ref == 'refs/heads/master' + if: github.ref == 'refs/heads/master' || github.event_name == 'schedule' env: NEXUS_PASS: ${{ secrets.NEXUS_CI_PASSWORD }} BOARD: ${{ matrix.board }} @@ -139,15 +148,18 @@ jobs: KVER: ${{ steps.ver.outputs.lithos }} SFVER: ${{ steps.ver.outputs.sf }} IMG_TYPE: ${{ matrix.img_type }} + IS_SNAPSHOT: ${{ steps.ver.outputs.is_snapshot }} run: | set -e + REPO="${IS_SNAPSHOT:+$NEXUS_SNAP}" + REPO="${REPO:-$NEXUS}" push() { local coord="$1" file="$2" echo "→ org.f18:${coord}" curl -fsS --retry 3 \ -u "ci-publisher:${NEXUS_PASS}" \ -H "Content-Type: application/octet-stream" \ - -X PUT "${NEXUS}/org/f18/${coord}" \ + -X PUT "${REPO}/org/f18/${coord}" \ --upload-file "$file" } From caad527e261febfae4c4bae0bd250d504258c2aa Mon Sep 17 00:00:00 2001 From: "Robert A. James (Captain Bob)" Date: Fri, 6 Nov 2026 14:05:45 +0000 Subject: [PATCH 8/9] ci: add workflow_dispatch trigger for manual test runs --- .gitea/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index cc66757a..1bf74cf3 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -7,6 +7,7 @@ on: branches: [master] schedule: - cron: '0 2 * * *' # 02:00 UTC nightly snapshot + workflow_dispatch: env: NEXUS: https://nexus.starshipos-f18.org/repository/starshipos-releases From 7f574c54fffd748a280be8c6eaabb1845e8e41d4 Mon Sep 17 00:00:00 2001 From: rajames Date: Fri, 6 Nov 2026 14:50:51 +0000 Subject: [PATCH 9/9] ci: nightly images and nightly documents, from StarForth-v4.0.0, to Nexus Gitea runs schedules from the default branch only, so until StarForth-v4.0.0 is merged here, master carries copies of that branch's two nightly workflows, identical to them but for the checkout's ref: nightly.yml 03:00 UTC: the acceptance protocol (zuse amd64, aarch64, riscv64; the PC stick loaded high; dict_hash equal on the three; test-32), the Isabelle/HOL proofs, the board images, then org.starship:kernelImage:-SNAPSHOT -- classifiers pc (iso), raspi5, milkv (img.xz), logs nightly-docs.yml 04:00 UTC: the book, the formal volumes, the API reference -> org.starship:documentation:-SNAPSHOT Both publish to starshipos-snapshots as ci-publisher (secret NEXUS_CI_PASSWORD), and only if every stage before passed. The work is that branch's scripts/nightly.sh. At the merge, take that branch's copies (this ref line goes). build.yml's own 02:00 schedule is untouched. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2 --- .gitea/workflows/nightly-docs.yml | 48 +++++++++++++++++++++ .gitea/workflows/nightly.yml | 72 +++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 .gitea/workflows/nightly-docs.yml create mode 100644 .gitea/workflows/nightly.yml diff --git a/.gitea/workflows/nightly-docs.yml b/.gitea/workflows/nightly-docs.yml new file mode 100644 index 00000000..f3c287d1 --- /dev/null +++ b/.gitea/workflows/nightly-docs.yml @@ -0,0 +1,48 @@ +# Nightly snapshot of the documents: the book, the formal volumes and the API reference +# (scripts/nightly.sh docs), then Nexus. +# +# org.starship:documentation:-SNAPSHOT, starshipos-snapshots +# classifier book the book (make docs) +# classifier vol1, vol2, vol3 the formal volumes (make -C docs/formal vols) +# classifier api the API reference (make -C docs/formal doxygen) +# +# Gitea runs a schedule from the default branch. Until StarForth-v4.0.0 is merged to master, +# master carries a copy of this file whose checkout names that branch. +name: Nightly documents + +on: + schedule: + - cron: '0 4 * * *' # 04:00 UTC, after the images (nightly.yml, 03:00) + workflow_dispatch: + +jobs: + docs: + name: Book, volumes, API reference + runs-on: ubuntu-latest + timeout-minutes: 90 + steps: + - uses: actions/checkout@v4 + with: + ref: StarForth-v4.0.0 # until it is merged to master; then this line goes + fetch-depth: 0 + lfs: false + + - name: Install the documents' dependencies + run: | + make ARCH=amd64 init INIT_PROOFS=0 + DEBIAN_FRONTEND=noninteractive apt-get install -y -qq maven default-jre-headless + + - name: Documents + run: scripts/nightly.sh docs + + - name: Publish to Nexus + env: + NEXUS_USER: ci-publisher + NEXUS_PASSWORD: ${{ secrets.NEXUS_CI_PASSWORD }} + run: scripts/nightly.sh publish-docs https://nexus.starshipos-f18.org/repository/starshipos-snapshots + + - name: Keep the documents + uses: actions/upload-artifact@v3 + with: + name: documents-${{ github.run_number }} + path: build/nightly-docs/ diff --git a/.gitea/workflows/nightly.yml b/.gitea/workflows/nightly.yml new file mode 100644 index 00000000..94fb5731 --- /dev/null +++ b/.gitea/workflows/nightly.yml @@ -0,0 +1,72 @@ +# Nightly snapshot of the kernel images: the acceptance protocol, the proofs, the board images, +# then Nexus. Each stage is a step of scripts/nightly.sh (its header says what each does); any +# failure stops the run, and nothing is published unless every stage before it passed. +# +# org.starship:kernelImage:-SNAPSHOT, starshipos-snapshots +# classifier pc StarshipOS.iso amd64, UEFI -- the ISO the amd64 acceptance boot booted +# classifier raspi5 raspi5.img.xz Raspberry Pi 5, for Raspberry Pi Imager +# classifier milkv MilkV.img.xz Milk-V Mars +# classifier logs logs.tar.gz this run's serial logs, proof log and DoE CSVs +# +# Gitea runs a schedule from the default branch. Until StarForth-v4.0.0 is merged to master, +# master carries a copy of this file whose checkout names that branch. +name: Nightly snapshot + +on: + schedule: + - cron: '0 3 * * *' # 03:00 UTC; the documents are at 04:00 (nightly-docs.yml) + workflow_dispatch: + +jobs: + nightly: + name: Acceptance, proofs, images + runs-on: ubuntu-latest + timeout-minutes: 150 + steps: + - uses: actions/checkout@v4 + with: + ref: StarForth-v4.0.0 # until it is merged to master; then this line goes + fetch-depth: 0 # the SBOM's version is git describe + lfs: false # only the logs and DoE CSVs are in LFS; the build needs neither + + - name: Install the build's dependencies + run: | + make ARCH=amd64,aarch64,riscv64 init INIT_DOCS=0 + DEBIAN_FRONTEND=noninteractive apt-get install -y -qq maven default-jre-headless + + - name: Acceptance amd64 + run: scripts/nightly.sh accept amd64 + - name: Acceptance aarch64 + run: scripts/nightly.sh accept aarch64 + - name: Acceptance riscv64 + run: scripts/nightly.sh accept riscv64 + - name: Acceptance PC stick loaded high + run: scripts/nightly.sh accept stick-high + - name: Acceptance 32-bit build + run: scripts/nightly.sh test-32 + - name: Isabelle/HOL proofs + run: scripts/nightly.sh proofs + + - name: Images + run: scripts/nightly.sh images + + - name: Publish to Nexus + env: + NEXUS_USER: ci-publisher + NEXUS_PASSWORD: ${{ secrets.NEXUS_CI_PASSWORD }} + run: scripts/nightly.sh publish https://nexus.starshipos-f18.org/repository/starshipos-snapshots + + - name: Keep the images + uses: actions/upload-artifact@v3 + with: + name: kernel-images-${{ github.run_number }} + path: build/nightly/ + + - name: Keep the logs and DoE CSVs + if: always() + uses: actions/upload-artifact@v3 + with: + name: logs-${{ github.run_number }} + path: | + logs/ + experiments/bare_metal/runs/