From 3e83ad973d90fad9ab386cb04d94b6ceae5784e7 Mon Sep 17 00:00:00 2001 From: AprilNEA Date: Fri, 7 Aug 2026 14:15:37 +0800 Subject: [PATCH 1/2] feat(config): add arm64 microvm flavor config for Firecracker sandboxes (CORE-79) Dedicated guest kernel config for the sandbox microVMs that run nested inside the System VM. Replaces the stock Firecracker CI kernel (built to run their test matrix, not to boot fast): virtio-mmio device model only, no PCI/ACPI/EFI/netfilter/BPF/audit, HZ=100 + PREEMPT_NONE (nested ticks are expensive), static ip= only, ext4 only, everything built in. Load-bearing keeps: DEVTMPFS_MOUNT (the sandbox template rootfs ships an empty /dev), UNIX98_PTYS + devpts (vm-agent PTY sessions), vsock, IP_PNP, PL031 + RTC_HCTOSYS (cold-boot wall clock), ptp_kvm (CORE-75 post-restore resync), VMGenID (restored-clone RNG reseed), IKCONFIG for forensics. NETDEVICES/NET_CORE and VIRT_DRIVERS are stated explicitly: they are not default-on, and omitting them makes olddefconfig silently drop VIRTIO_NET and VMGENID respectively. --- configs/arcbox-microvm-arm64.config | 252 ++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 configs/arcbox-microvm-arm64.config diff --git a/configs/arcbox-microvm-arm64.config b/configs/arcbox-microvm-arm64.config new file mode 100644 index 0000000..5a7f69a --- /dev/null +++ b/configs/arcbox-microvm-arm64.config @@ -0,0 +1,252 @@ +# ArcBox microVM (sandbox) kernel configuration for ARM64 +# +# Guest kernel for Firecracker sandbox microVMs, which run NESTED inside the +# ArcBox System VM (KVM inside a VZ guest on Apple Silicon). +# +# Optimized for: +# - kernel entry -> /sbin/vm-agent (PID 1) in ~200-300 ms under nested virt +# - Firecracker aarch64 device model only: virtio-mmio via DT, 16550 UART +# (ttyS0), PL031 RTC, GICv3, PSCI — no PCI, no ACPI, no EFI +# - plain ext4 rootfs over virtio-blk (dm-snapshot CoW lives in the System +# VM, the microVM sees an ordinary block device) +# - arbitrary user workloads from Docker-image templates (busybox userland, +# node/python/etc.) driven by vm-agent's vsock exec/PTY protocol +# - Firecracker memory snapshot/restore (transparent to the guest; VMGenID +# reseeds the RNG in restored clones; ptp_kvm + PL031 give the guest a +# host-clock source for post-restore wall-time resync, CORE-75) +# +# Everything built in; CONFIG_MODULES stays off. Fragment style matches +# configs/arcbox-arm64.config: copied to .config, resolved by olddefconfig, +# then asserted by scripts/build-kernel.sh (microvm assertion set). +# EXPERT is required to expose the VT/INPUT/... disables below. + +# Basic setup +CONFIG_LOCALVERSION="-arcbox-microvm" +CONFIG_DEFAULT_HOSTNAME="arcbox-sandbox" +CONFIG_EXPERT=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +# CONFIG_MODULES is not set + +# Processor type and features +CONFIG_ARM64=y +CONFIG_64BIT=y +CONFIG_MMU=y +CONFIG_SMP=y +CONFIG_NR_CPUS=32 +# Firecracker never hotplugs vCPUs, and dropping HOTPLUG_CPU removes the +# cpuhp state machinery from boot. +# CONFIG_HOTPLUG_CPU is not set +# Apple Silicon cores have no AArch32 EL0, so 32-bit compat is dead weight +# (and vdso32 would need a separate 32-bit toolchain). +# CONFIG_COMPAT is not set +# The sandbox never hosts further guests; KVM init has no business here. +# CONFIG_VIRTUALIZATION is not set + +# Core syscall surface for arbitrary workloads. Several of these are +# EXPERT-gated defaults; stated explicitly so a Kconfig default change can +# never silently drop them. +CONFIG_MULTIUSER=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_TIMERS=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_AIO=y +CONFIG_IO_URING=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_MEMBARRIER=y +CONFIG_RSEQ=y +CONFIG_SHMEM=y +CONFIG_KALLSYMS=y +CONFIG_ELF_CORE=y +CONFIG_COREDUMP=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_SCRIPT=y + +# Timing / scheduler: HZ=100 + NO_HZ_IDLE + PREEMPT_NONE match the +# Firecracker CI kernel the 15 ms warm-exec number was measured on; nested +# timer ticks are expensive (each L2 tick is an L1 KVM arch-timer +# injection), so keep them rare. This deliberately differs from the System +# VM kernel's HZ=1000/voluntary (ABX-498): that guest churns containers, +# this one runs a single workload. +CONFIG_HIGH_RES_TIMERS=y +CONFIG_NO_HZ_IDLE=y +CONFIG_HZ_100=y +CONFIG_HZ=100 +CONFIG_PREEMPT_NONE=y +# PSI taxes the scheduler wakeup fast path (ABX-498); nothing in the +# microVM consumes /proc/pressure. +# CONFIG_PSI is not set + +# Isolation primitives workloads actually use: Chromium/Puppeteer sandboxes +# need USER_NS + seccomp; language runtimes probe /proc/self/cgroup (core +# cgroups only, no controllers — a sandbox is a single workload, memory +# limiting is VM sizing). +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y +CONFIG_PID_NS=y +CONFIG_NET_NS=y +CONFIG_IPC_NS=y +CONFIG_UTS_NS=y +CONFIG_TIME_NS=y +CONFIG_SECCOMP=y +CONFIG_SECCOMP_FILTER=y +CONFIG_CGROUPS=y + +# Boot-time fat from the Firecracker CI kernel, explicitly OFF +# CONFIG_AUDIT is not set +# CONFIG_PROFILING is not set +# CONFIG_BPF_SYSCALL is not set +# CONFIG_KEXEC is not set +# CONFIG_KEXEC_FILE is not set +# CONFIG_CRASH_DUMP is not set +# CONFIG_EFI is not set +# CONFIG_ACPI is not set +# CONFIG_PCI is not set +# CONFIG_NUMA is not set +# CONFIG_SWAP is not set +# CONFIG_SUSPEND is not set +# CONFIG_HIBERNATION is not set +# CONFIG_PM is not set +# CONFIG_CPU_IDLE is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_RANDOMIZE_BASE is not set +# CONFIG_IOMMU_SUPPORT is not set +# CONFIG_VT is not set +# CONFIG_INPUT is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_SOUND is not set +# CONFIG_WLAN is not set +# CONFIG_WIRELESS is not set +# CONFIG_RFKILL is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_FTRACE is not set +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_SCHED_DEBUG is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_JUMP_LABEL=y + +# Memory management. THP=madvise: opt-in for workloads that ask, without +# khugepaged churning snapshot dirty-page sets in the background. +CONFIG_TRANSPARENT_HUGEPAGE=y +CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y +# CONFIG_MEMORY_HOTPLUG is not set +# CONFIG_ZSWAP is not set + +# Networking. Static addressing comes from the kernel ip= parameter that +# arcbox-vm/sandbox/boot.rs appends (ip=:::::eth0:off), +# handled by IP_PNP; the autoconf protocols are never used. NAT/firewalling +# for sandboxes happens in the System VM (L1) — vm-agent uses raw +# SIOCSIFADDR/SIOCADDRT ioctls, no iptables in the microVM. +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +CONFIG_IPV6=y +# CONFIG_NETFILTER is not set +# CONFIG_BRIDGE is not set +CONFIG_VSOCKETS=y +CONFIG_VIRTIO_VSOCKETS=y + +# Firecracker device model. NETDEVICES/NET_CORE are NOT default-on: without +# them olddefconfig silently drops VIRTIO_NET (the exact silent-degrade +# class the build assertions exist for). ETHERNET is the vendor-NIC +# umbrella; virtio-net does not need it. +CONFIG_BLOCK=y +CONFIG_BLK_DEV=y +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_ETHERNET is not set +CONFIG_VIRTIO=y +CONFIG_VIRTIO_MENU=y +CONFIG_VIRTIO_MMIO=y +CONFIG_VIRTIO_BLK=y +CONFIG_VIRTIO_NET=y +# Balloon: the only memory-reclaim lever Firecracker offers; kept built-in +# so a future reclaim feature (and snapshots that include a balloon device) +# need no kernel change. Costs nothing at boot when the device is absent. +CONFIG_VIRTIO_BALLOON=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_VIRTIO=y +CONFIG_HW_RANDOM_ARM_SMCCC_TRNG=y +CONFIG_TTY=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=1 +CONFIG_SERIAL_8250_RUNTIME_UARTS=1 +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SERIAL_EARLYCON=y +CONFIG_UNIX98_PTYS=y +CONFIG_DEVPTS_FS=y +# CONFIG_LEGACY_PTYS is not set +# The default sandbox rootfs ships an EMPTY /dev; without the devtmpfs +# automount PID 1 has no /dev/console for stdio (vm-agent mounts /dev +# itself, but only after its fds are already bound). +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# Firecracker boots the root directly from virtio-blk; there is no +# initramfs stage. +# CONFIG_BLK_DEV_INITRD is not set + +# Time: cold-boot wall clock + post-restore resync (CORE-75). Firecracker +# aarch64 exposes a PL031 RTC backed by the L1 host clock: RTC_HCTOSYS sets +# CLOCK_REALTIME at cold boot with no host RPC; RTC_INTF_DEV lets vm-agent +# RTC_RD_TIME-resync (seconds granularity) after restore. ptp_kvm exposes +# the L1 host CLOCK_REALTIME at ns granularity via the KVM SMCCC vendor +# service (/dev/ptp0) for a precise one-shot resync. SYSTOHC stays off: the +# virtual RTC mirrors the host clock, the guest must not write back into +# it. (PTP_1588_CLOCK_VMCLOCK is deliberately absent: it depends on ACPI, +# which this config cuts, and Firecracker presents no vmclock device.) +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_DRV_PL031=y +# CONFIG_RTC_SYSTOHC is not set +CONFIG_PTP_1588_CLOCK=y +CONFIG_PTP_1588_CLOCK_KVM=y +# Steal-time accounting is inert until Firecracker configures KVM pvtime, +# but PARAVIRT is cheap and future-proofs it. +CONFIG_PARAVIRT=y +CONFIG_PARAVIRT_TIME_ACCOUNTING=y +# DT-based VMGenID (kernel >= 6.10): reseeds the guest RNG when a restored +# clone diverges from its snapshot origin. VIRT_DRIVERS is the (default-off) +# menu gate it lives under. +CONFIG_VIRT_DRIVERS=y +CONFIG_VMGENID=y + +# File systems. ext4 only: template rootfs images are flattened ext4 +# (oci2rootfs); the dm-snapshot CoW layer lives outside the microVM. No +# overlayfs consumer exists inside the microVM today (verified against +# rootfs_builder.rs and the sandbox boot path). +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +CONFIG_INOTIFY_USER=y +CONFIG_FANOTIFY=y +CONFIG_FILE_LOCKING=y +# CONFIG_OVERLAY_FS is not set +# CONFIG_FUSE_FS is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_QUOTA is not set + +# Crypto (ext4 metadata checksums) +CONFIG_CRYPTO=y +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRC32=y From 8549ae3fb3aeded89257dabd6f0d0029df33d0f7 Mon Sep 17 00:00:00 2001 From: AprilNEA Date: Fri, 7 Aug 2026 14:15:50 +0800 Subject: [PATCH 2/2] feat(build): build the microvm flavor alongside the system kernel (CORE-79) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit build-kernel.sh grows a FLAVOR dimension (system|microvm, default system — existing invocations unchanged): flavor resolves the config file, the output name (microvm-kernel-{arch}) and the post-olddefconfig assertion set. The microvm assertions pin the Firecracker sandbox contract (virtio-mmio/blk/net/vsock, DEVTMPFS_MOUNT, IP_PNP, PTYs, ext4, PL031, ptp_kvm, VMGenID) and that the cut subsystems (PCI, netfilter, modules, ACPI, EFI) stayed cut. Both the native and Docker paths share one flavor resolution; the assertion lists are interpolated into the Docker script. CI matrix gains an arm64 microvm job; releases now attach microvm-kernel-arm64 (+ .sha256) next to the system kernels. The boot-assets repository-dispatch hook is untouched. microvm is arm64-only: Firecracker x86_64 boots an ELF vmlinux and needs its own config. --- .github/workflows/build.yml | 39 ++++++++---- CLAUDE.md | 25 +++++++- README.md | 24 +++++++- scripts/build-kernel.sh | 114 ++++++++++++++++++++++++++---------- scripts/package-release.sh | 16 ++--- 5 files changed, 161 insertions(+), 57 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bbed8ba..9f8a794 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,18 +23,29 @@ env: jobs: # ========================================================================== - # Build kernel for each architecture (native runners, no cross-compile). + # Build kernel for each architecture x flavor (native runners, no + # cross-compile). `system` boots the VZ/HV System VM; `microvm` boots + # Firecracker sandbox microVMs (arm64-only for now — Firecracker x86_64 + # needs an ELF vmlinux and its own config). # ========================================================================== build-kernel: - name: Build Kernel (${{ matrix.arch }}) + name: Build Kernel (${{ matrix.arch }}, ${{ matrix.flavor }}) runs-on: ${{ matrix.runner }} strategy: matrix: include: - arch: arm64 + flavor: system + artifact: kernel-arm64 runner: ubuntu-24.04-arm - arch: x86_64 + flavor: system + artifact: kernel-x86_64 runner: ubuntu-24.04 + - arch: arm64 + flavor: microvm + artifact: microvm-kernel-arm64 + runner: ubuntu-24.04-arm steps: - name: Checkout @@ -56,6 +67,7 @@ jobs: run: | USE_DOCKER=0 \ ARCH=${{ matrix.arch }} \ + FLAVOR=${{ matrix.flavor }} \ KERNEL_VERSION=${{ env.KERNEL_VERSION }} \ OUTPUT_DIR="$(pwd)/output" \ ./scripts/build-kernel.sh @@ -63,15 +75,15 @@ jobs: - name: Generate checksum run: | cd output - sha256sum "kernel-${{ matrix.arch }}" > "kernel-${{ matrix.arch }}.sha256" + sha256sum "${{ matrix.artifact }}" > "${{ matrix.artifact }}.sha256" - name: Upload kernel artifact uses: actions/upload-artifact@v4 with: - name: kernel-${{ matrix.arch }} + name: ${{ matrix.artifact }} path: | - output/kernel-${{ matrix.arch }} - output/kernel-${{ matrix.arch }}.sha256 + output/${{ matrix.artifact }} + output/${{ matrix.artifact }}.sha256 retention-days: 14 # ========================================================================== @@ -92,11 +104,11 @@ jobs: - name: Prepare release files run: | mkdir -p release - for ARCH in arm64 x86_64; do - DIR="artifacts/kernel-$ARCH" - if [ -f "$DIR/kernel-$ARCH" ]; then - cp "$DIR/kernel-$ARCH" "release/kernel-$ARCH" - cp "$DIR/kernel-$ARCH.sha256" "release/kernel-$ARCH.sha256" + for NAME in kernel-arm64 kernel-x86_64 microvm-kernel-arm64; do + DIR="artifacts/$NAME" + if [ -f "$DIR/$NAME" ]; then + cp "$DIR/$NAME" "release/$NAME" + cp "$DIR/$NAME.sha256" "release/$NAME.sha256" fi done echo "=== Release files ===" @@ -112,8 +124,9 @@ jobs: Self-compiled Linux kernel for ArcBox VMs (`CONFIG_MODULES=n`, all drivers built-in). ### Files - - `kernel-arm64` — ARM64 Image (Apple Silicon / ARM VMs) - - `kernel-x86_64` — x86_64 bzImage + - `kernel-arm64` — ARM64 Image, System VM (Apple Silicon / ARM VMs) + - `kernel-x86_64` — x86_64 bzImage, System VM + - `microvm-kernel-arm64` — ARM64 Image, Firecracker sandbox microVMs files: release/* draft: false prerelease: ${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') }} diff --git a/CLAUDE.md b/CLAUDE.md index 16eddb9..7749879 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,6 +6,23 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co `arcbox-kernel` provides optimized Linux kernel and initramfs builds for ArcBox VMs, targeting Apple Virtualization.framework (primary) and KVM (secondary). +Two kernel **flavors** build from the same source — do not conflate them: + +- `system` (default): the System VM guest kernel (`configs/arcbox-{arch}.config`, + artifact `kernel-{arch}`). Full container stack: netfilter, cgroups + controllers, dm, overlayfs, NFS, HZ=1000/voluntary (ABX-498 tuning). +- `microvm`: the Firecracker sandbox guest kernel + (`configs/arcbox-microvm-arm64.config`, artifact `microvm-kernel-arm64`, + arm64-only). Runs NESTED inside the System VM; optimized for kernel entry + → `/sbin/vm-agent` in the 200–300 ms class. virtio-mmio only — no + PCI/ACPI/EFI/netfilter/BPF; HZ=100/PREEMPT_NONE (nested ticks are + expensive). Consumed by boot-assets `upstream.toml` as the `vmlinux` + binary (`install_dir = "kernel"`). + +A flavor's load-bearing symbols are asserted post-`olddefconfig` in +`scripts/build-kernel.sh` — extend the flavor's assertion list when adding a +symbol whose silent loss would only surface at guest runtime. + ## Build Commands ```bash @@ -15,6 +32,9 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co # Build kernel for x86_64 ARCH=x86_64 ./scripts/build-kernel.sh +# Build the Firecracker sandbox microVM kernel (arm64-only) +FLAVOR=microvm ./scripts/build-kernel.sh + # Build kernel with specific version KERNEL_VERSION=6.18.0 ./scripts/build-kernel.sh @@ -44,8 +64,9 @@ cargo build -p arcbox-agent --target aarch64-unknown-linux-musl --release ``` arcbox-kernel/ ├── configs/ -│ ├── arcbox-arm64.config # ARM64 kernel config (Apple Silicon) -│ └── arcbox-x86_64.config # x86_64 kernel config +│ ├── arcbox-arm64.config # ARM64 System VM config (Apple Silicon) +│ ├── arcbox-x86_64.config # x86_64 System VM config +│ └── arcbox-microvm-arm64.config # ARM64 Firecracker sandbox config ├── scripts/ │ ├── build-kernel.sh # Kernel build (Docker-based) │ ├── build-initramfs.sh # Initramfs build (Alpine + agent) diff --git a/README.md b/README.md index 4f1db07..372354c 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,25 @@ This repository contains: - Build scripts for kernel and initramfs - GitHub Actions CI for automated releases +## Kernel Flavors + +Two independent guest kernels are built from the same kernel source: + +| Flavor | Config | Artifact | Boots | +|--------|--------|----------|-------| +| `system` (default) | `configs/arcbox-{arch}.config` | `kernel-{arch}` | ArcBox System VM (VZ/HV backends) | +| `microvm` | `configs/arcbox-microvm-arm64.config` | `microvm-kernel-arm64` | Firecracker sandbox microVMs, nested inside the System VM | + +The microvm flavor is arm64-only for now: Firecracker x86_64 boots an ELF +`vmlinux` (not a bzImage) and needs its own config +(`VIRTIO_MMIO_CMDLINE_DEVICES`, kvmclock). It targets kernel entry → +PID 1 in the 200–300 ms class under nested virtualization: virtio-mmio +device model only, no PCI/ACPI/EFI/netfilter, everything built in. + +```bash +FLAVOR=microvm ./scripts/build-kernel.sh +``` + ## Features | Feature | Description | @@ -49,8 +68,9 @@ tar -xzf arcbox-kernel-arm64-v0.1.0.tar.gz ``` arcbox-kernel/ ├── configs/ -│ ├── arcbox-arm64.config # ARM64 kernel config -│ └── arcbox-x86_64.config # x86_64 kernel config +│ ├── arcbox-arm64.config # ARM64 System VM kernel config +│ ├── arcbox-x86_64.config # x86_64 System VM kernel config +│ └── arcbox-microvm-arm64.config # ARM64 Firecracker sandbox kernel config ├── scripts/ │ ├── build-kernel.sh # Kernel build script │ ├── build-initramfs.sh # Initramfs build script diff --git a/scripts/build-kernel.sh b/scripts/build-kernel.sh index f64b3fe..73346dc 100755 --- a/scripts/build-kernel.sh +++ b/scripts/build-kernel.sh @@ -2,9 +2,17 @@ # Build Linux kernel for ArcBox # # Usage: -# ./build-kernel.sh # Build for ARM64 +# ./build-kernel.sh # Build System VM kernel for ARM64 # ARCH=x86_64 ./build-kernel.sh # Build for x86_64 +# FLAVOR=microvm ./build-kernel.sh # Build the sandbox microVM kernel # KERNEL_VERSION=6.18.0 ./build-kernel.sh # Use specific version +# +# Flavors: +# system (default) — System VM guest kernel (VZ/HV backends), +# configs/arcbox-{arch}.config, output kernel-{arch} +# microvm — Firecracker sandbox guest kernel (arm64 only), +# configs/arcbox-microvm-{arch}.config, +# output microvm-kernel-{arch} set -e @@ -14,16 +22,15 @@ PROJECT_DIR="$(dirname "$SCRIPT_DIR")" # Configuration KERNEL_VERSION="${KERNEL_VERSION:-6.18.38}" TARGET_ARCH="${ARCH:-arm64}" +FLAVOR="${FLAVOR:-system}" OUTPUT_DIR="${OUTPUT_DIR:-$PROJECT_DIR/output}" CONFIG_DIR="$PROJECT_DIR/configs" -# Determine config file +# Determine architecture parameters if [ "$TARGET_ARCH" = "arm64" ]; then - CONFIG_FILE="$CONFIG_DIR/arcbox-arm64.config" CROSS_COMPILE="aarch64-linux-gnu-" KERNEL_IMAGE="Image" elif [ "$TARGET_ARCH" = "x86_64" ]; then - CONFIG_FILE="$CONFIG_DIR/arcbox-x86_64.config" CROSS_COMPILE="" KERNEL_IMAGE="bzImage" else @@ -31,12 +38,58 @@ else exit 1 fi +# Determine flavor parameters: config file, output name, and the post- +# olddefconfig assertion sets. olddefconfig silently drops unknown or +# unsatisfiable symbols; each flavor asserts its load-bearing ones actually +# resolved (a renamed choice symbol or a new dependency gate in the fragment +# otherwise degrades silently — 6.18 did exactly that to the legacy iptables +# stack via NETFILTER_XTABLES_LEGACY). +if [ "$FLAVOR" = "system" ]; then + CONFIG_FILE="$CONFIG_DIR/arcbox-$TARGET_ARCH.config" + OUTPUT_NAME="kernel-$TARGET_ARCH" + # CONFIG_PREEMPT_VOLUNTARY is load-bearing for container-teardown + # latency (see the config comment); a future KERNEL_VERSION that drops + # the voluntary choice must fail loudly here rather than silently fall + # back to lazy/full. + ASSERT_Y="CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU CONFIG_IP_NF_NAT + CONFIG_IP6_NF_NAT CONFIG_HZ_1000 CONFIG_PSI_DEFAULT_DISABLED + CONFIG_PREEMPT_VOLUNTARY" + ASSERT_N="" +elif [ "$FLAVOR" = "microvm" ]; then + if [ "$TARGET_ARCH" != "arm64" ]; then + echo "Error: microvm flavor is arm64-only (Firecracker x86_64 needs an ELF vmlinux and a separate config)" + exit 1 + fi + CONFIG_FILE="$CONFIG_DIR/arcbox-microvm-$TARGET_ARCH.config" + OUTPUT_NAME="microvm-kernel-$TARGET_ARCH" + # The Firecracker sandbox contract: virtio-mmio devices, vsock exec/PTY, + # devtmpfs automount over the empty template /dev, static ip=, PL031 + + # ptp_kvm clocks, VMGenID RNG reseed. Also assert that the deliberately + # cut subsystems stayed cut (a fragment typo re-enabling PCI/netfilter + # would otherwise ship silently). + ASSERT_Y="CONFIG_VIRTIO_MMIO CONFIG_VIRTIO_BLK CONFIG_VIRTIO_NET + CONFIG_VIRTIO_VSOCKETS CONFIG_DEVTMPFS_MOUNT CONFIG_IP_PNP + CONFIG_UNIX98_PTYS CONFIG_EXT4_FS CONFIG_SERIAL_8250_CONSOLE + CONFIG_RTC_DRV_PL031 CONFIG_PTP_1588_CLOCK_KVM CONFIG_VMGENID" + ASSERT_N="CONFIG_PCI CONFIG_NETFILTER CONFIG_MODULES CONFIG_ACPI CONFIG_EFI" +else + echo "Error: Unsupported flavor: $FLAVOR (expected 'system' or 'microvm')" + exit 1 +fi + +# Collapse the multi-line assertion lists to one line: they are textually +# interpolated into the Docker build script, where an embedded newline would +# terminate the `for ... in` list early. +ASSERT_Y=$(echo $ASSERT_Y) +ASSERT_N=$(echo $ASSERT_N) + echo "========================================" echo " ArcBox Kernel Build" echo "========================================" echo "" echo " Kernel Version: $KERNEL_VERSION" echo " Target Arch: $TARGET_ARCH" +echo " Flavor: $FLAVOR" echo " Output Dir: $OUTPUT_DIR" echo "" @@ -56,6 +109,7 @@ mkdir -p "$OUTPUT_DIR" # - CWD = extracted kernel source root (linux-$KERNEL_VERSION) # - $ARCBOX_SRC = path to arcbox-kernel repo # - $TARGET_ARCH, $KERNEL_IMAGE, $CROSS_COMPILE set +# - $CONFIG_FILE, $ASSERT_Y, $ASSERT_N set (flavor-resolved above) # - $OUTPUT_PATH = where to copy the final kernel binary do_build() { local ARCBOX_SRC="$1" @@ -65,30 +119,21 @@ do_build() { sh "$ARCBOX_SRC/scripts/inject-drivers.sh" "$ARCBOX_SRC" # Copy config and update for this kernel version. - cp "$ARCBOX_SRC/configs/arcbox-$TARGET_ARCH.config" .config + cp "$CONFIG_FILE" .config make ARCH=$TARGET_ARCH ${CROSS_COMPILE:+CROSS_COMPILE=$CROSS_COMPILE} olddefconfig - # olddefconfig silently drops unknown or unsatisfiable symbols; assert the - # load-bearing ones actually resolved (a renamed choice symbol or a new - # dependency gate in the fragment otherwise degrades silently — 6.18 did - # exactly that to the legacy iptables stack via NETFILTER_XTABLES_LEGACY). - for sym in CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU CONFIG_IP_NF_NAT \ - CONFIG_IP6_NF_NAT CONFIG_HZ_1000 \ - CONFIG_PSI_DEFAULT_DISABLED; do + for sym in $ASSERT_Y; do grep -q "^$sym=y" .config || { echo "ERROR: $sym missing after olddefconfig" >&2 exit 1 } done - - # Voluntary preemption is load-bearing for container-teardown latency - # (see the config comment). Assert it survived olddefconfig; a future - # KERNEL_VERSION that drops the voluntary choice must fail loudly here - # rather than silently fall back to lazy/full. - grep -q '^CONFIG_PREEMPT_VOLUNTARY=y' .config || { - echo 'ERROR: CONFIG_PREEMPT_VOLUNTARY missing after olddefconfig' >&2 - exit 1 - } + for sym in $ASSERT_N; do + if grep -q "^$sym=y" .config; then + echo "ERROR: $sym enabled after olddefconfig (must stay off)" >&2 + exit 1 + fi + done # Build. echo "Building kernel..." @@ -113,6 +158,9 @@ else fi if [ "$BUILD_IN_DOCKER" = "1" ]; then + # $ASSERT_Y/$ASSERT_N/$OUTPUT_NAME and the config basename are expanded + # host-side into the container script, so both paths share one + # flavor-resolution. docker run --rm \ -v "$PROJECT_DIR:/workspace" \ -v "$OUTPUT_DIR:/output" \ @@ -127,23 +175,25 @@ curl -L --retry 8 --retry-all-errors -o linux.tar.xz https://cdn.kernel.org/pub/ tar -xJf linux.tar.xz && rm linux.tar.xz cd linux-$KERNEL_VERSION sh /workspace/scripts/inject-drivers.sh /workspace -cp /workspace/configs/arcbox-$TARGET_ARCH.config .config +cp /workspace/configs/$(basename "$CONFIG_FILE") .config make ARCH=$TARGET_ARCH olddefconfig -for sym in CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU CONFIG_IP_NF_NAT CONFIG_IP6_NF_NAT CONFIG_HZ_1000 CONFIG_PSI_DEFAULT_DISABLED; do +for sym in $ASSERT_Y; do grep -q \"^\$sym=y\" .config || { echo \"ERROR: \$sym missing after olddefconfig\" >&2 exit 1 } done -grep -q '^CONFIG_PREEMPT_VOLUNTARY=y' .config || { - echo 'ERROR: CONFIG_PREEMPT_VOLUNTARY missing after olddefconfig' >&2 - exit 1 -} +for sym in $ASSERT_N; do + if grep -q \"^\$sym=y\" .config; then + echo \"ERROR: \$sym enabled after olddefconfig (must stay off)\" >&2 + exit 1 + fi +done echo 'Building kernel...' make ARCH=$TARGET_ARCH -j\$(nproc) $KERNEL_IMAGE -cp arch/$TARGET_ARCH/boot/$KERNEL_IMAGE /output/kernel-$TARGET_ARCH +cp arch/$TARGET_ARCH/boot/$KERNEL_IMAGE /output/$OUTPUT_NAME echo 'Build complete!' -ls -lh /output/kernel-$TARGET_ARCH +ls -lh /output/$OUTPUT_NAME " else BUILD_DIR="/tmp/arcbox-kernel-build-$$" @@ -157,7 +207,7 @@ else rm "linux.tar.xz" cd "linux-$KERNEL_VERSION" - do_build "$PROJECT_DIR" "$OUTPUT_DIR/kernel-$TARGET_ARCH" + do_build "$PROJECT_DIR" "$OUTPUT_DIR/$OUTPUT_NAME" rm -rf "$BUILD_DIR" fi @@ -167,5 +217,5 @@ echo "========================================" echo " Build Complete!" echo "========================================" echo "" -echo " Output: $OUTPUT_DIR/kernel-$TARGET_ARCH" -ls -lh "$OUTPUT_DIR/kernel-$TARGET_ARCH" +echo " Output: $OUTPUT_DIR/$OUTPUT_NAME" +ls -lh "$OUTPUT_DIR/$OUTPUT_NAME" diff --git a/scripts/package-release.sh b/scripts/package-release.sh index 4f64d83..a4ffadc 100755 --- a/scripts/package-release.sh +++ b/scripts/package-release.sh @@ -30,18 +30,18 @@ echo "" rm -rf "$RELEASE_DIR" mkdir -p "$RELEASE_DIR" -for ARCH in arm64 x86_64; do - KERNEL="$OUTPUT_DIR/kernel-$ARCH" +for NAME in kernel-arm64 kernel-x86_64 microvm-kernel-arm64; do + KERNEL="$OUTPUT_DIR/$NAME" if [ ! -f "$KERNEL" ]; then - echo "Warning: kernel-$ARCH not found, skipping" + echo "Warning: $NAME not found, skipping" continue fi - echo "Packaging $ARCH..." - cp "$KERNEL" "$RELEASE_DIR/kernel-$ARCH" - sha256sum "$RELEASE_DIR/kernel-$ARCH" > "$RELEASE_DIR/kernel-$ARCH.sha256" - echo " Created: kernel-$ARCH + kernel-$ARCH.sha256" + echo "Packaging $NAME..." + cp "$KERNEL" "$RELEASE_DIR/$NAME" + sha256sum "$RELEASE_DIR/$NAME" > "$RELEASE_DIR/$NAME.sha256" + echo " Created: $NAME + $NAME.sha256" done echo "" @@ -50,4 +50,4 @@ echo " Packaging Complete!" echo "========================================" echo "" echo "Release files:" -ls -lh "$RELEASE_DIR"/kernel-* 2>/dev/null || echo " (none)" +ls -lh "$RELEASE_DIR"/*kernel-* 2>/dev/null || echo " (none)"