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/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 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)"