diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9f8a794..eb034ea 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,8 +25,9 @@ jobs: # ========================================================================== # 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). + # Firecracker sandbox microVMs (arm64 nested on macOS, x86_64 bare-metal + # Linux hosts — the x86_64 artifact is the ELF vmlinux Firecracker boots + # directly, and it is KVM boot-smoked in CI below). # ========================================================================== build-kernel: name: Build Kernel (${{ matrix.arch }}, ${{ matrix.flavor }}) @@ -46,6 +47,10 @@ jobs: flavor: microvm artifact: microvm-kernel-arm64 runner: ubuntu-24.04-arm + - arch: x86_64 + flavor: microvm + artifact: microvm-kernel-x86_64 + runner: ubuntu-24.04 steps: - name: Checkout @@ -72,6 +77,55 @@ jobs: OUTPUT_DIR="$(pwd)/output" \ ./scripts/build-kernel.sh + # x86_64 hosted runners expose /dev/kvm, so the one kernel we cannot + # boot on developer hardware (Apple Silicon) is the one we CAN boot + # in CI: bring up the freshly built ELF vmlinux under the pinned + # Firecracker with a busybox init that prints a marker. This + # exercises the exact risk set of this flavor — ACPI boot + ACPI + # virtio-mmio discovery, virtio-blk, ext4 root, ttyS0 console, and + # init exec. arm64 runners have no KVM; that flavor is validated by + # the sandbox e2e suite on real hardware instead. + - name: Boot-smoke under Firecracker (KVM) + if: matrix.artifact == 'microvm-kernel-x86_64' + run: | + set -eux + test -e /dev/kvm + sudo chmod a+rw /dev/kvm + FC_VER=v1.16.1 + FC_SHA256=382a02a869e4d6d5cb14c40577f9545e8458021ea8b0b2d3fc10ec14d9c242e6 + curl -sfL "https://github.com/firecracker-microvm/firecracker/releases/download/${FC_VER}/firecracker-${FC_VER}-x86_64.tgz" -o fc.tgz + echo "${FC_SHA256} fc.tgz" | sha256sum -c - + tar xzf fc.tgz + FC="release-${FC_VER}-x86_64/firecracker-${FC_VER}-x86_64" + sudo apt-get install -y busybox-static + dd if=/dev/zero of=rootfs.ext4 bs=1M count=16 + mkfs.ext4 -q rootfs.ext4 + mkdir mnt && sudo mount -o loop rootfs.ext4 mnt + sudo mkdir -p mnt/bin mnt/dev mnt/proc mnt/sys + sudo cp "$(command -v busybox)" mnt/bin/busybox + printf '#!/bin/busybox sh\n/bin/busybox echo ARCBOX-X86-MICROVM-BOOT-OK\n/bin/busybox reboot -f\n' | sudo tee mnt/init >/dev/null + sudo chmod +x mnt/init + sudo umount mnt + cat > fc.json <<'CFG' + { + "boot-source": { + "kernel_image_path": "output/microvm-kernel-x86_64", + "boot_args": "console=ttyS0 reboot=k panic=-1 pci=off root=/dev/vda rw init=/init" + }, + "drives": [ + { + "drive_id": "rootfs", + "path_on_host": "rootfs.ext4", + "is_root_device": true, + "is_read_only": false + } + ], + "machine-config": { "vcpu_count": 1, "mem_size_mib": 128 } + } + CFG + timeout 60 "$FC" --no-api --config-file fc.json | tee console.log || true + grep -q ARCBOX-X86-MICROVM-BOOT-OK console.log + - name: Generate checksum run: | cd output @@ -104,7 +158,7 @@ jobs: - name: Prepare release files run: | mkdir -p release - for NAME in kernel-arm64 kernel-x86_64 microvm-kernel-arm64; do + for NAME in kernel-arm64 kernel-x86_64 microvm-kernel-arm64 microvm-kernel-x86_64; do DIR="artifacts/$NAME" if [ -f "$DIR/$NAME" ]; then cp "$DIR/$NAME" "release/$NAME" @@ -126,7 +180,8 @@ jobs: ### Files - `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 + - `microvm-kernel-arm64` — ARM64 Image, Firecracker sandbox microVMs (nested, macOS hosts) + - `microvm-kernel-x86_64` — x86_64 ELF vmlinux, Firecracker sandbox microVMs (bare-metal Linux hosts / platform fleet) files: release/* draft: false prerelease: ${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') }} diff --git a/CLAUDE.md b/CLAUDE.md index 7749879..4b52a3d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -12,12 +12,17 @@ Two kernel **flavors** build from the same source — do not conflate them: 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"`). + (`configs/arcbox-microvm-{arch}.config`, artifact `microvm-kernel-{arch}`). + Optimized for kernel entry → PID 1 in the 200–300 ms class; virtio-mmio + only, no PCI/EFI/netfilter/BPF, HZ=100/PREEMPT_NONE. The arches differ + deliberately: arm64 runs NESTED inside the macOS System VM (DT + discovery, PL031 RTC, no ACPI; consumed by boot-assets `upstream.toml` + as the `vmlinux` binary, `install_dir = "kernel"`); x86_64 runs on + bare-metal Linux KVM (hardware-reduced ACPI: DSDT-enumerated + virtio-mmio, PCI config option required by ACPI init, kvmclock, ELF + vmlinux artifact, zstd initramfs + xz squashfs for the platform PaaS + fleet; KVM boot-smoked in CI). Keep the per-arch assertion sets in + build-kernel.sh in lockstep with any config edit. A flavor's load-bearing symbols are asserted post-`olddefconfig` in `scripts/build-kernel.sh` — extend the flavor's assertion list when adding a diff --git a/README.md b/README.md index 372354c..e408527 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,22 @@ 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. +| `microvm` | `configs/arcbox-microvm-{arch}.config` | `microvm-kernel-{arch}` | Firecracker sandbox microVMs | + +The microvm flavor targets kernel entry → PID 1 in the 200–300 ms class: +virtio-mmio device model only, no PCI/EFI/netfilter, everything built in. +The two arches serve different hosts and differ deliberately: arm64 runs +NESTED inside the macOS System VM (DT device discovery, PL031 RTC, Image +artifact, no ACPI), while x86_64 runs on bare-metal Linux KVM hosts — +ArcBox-on-Linux sandboxes and the platform PaaS fleet — where +Firecracker presents a hardware-reduced ACPI platform (DSDT-enumerated +virtio-mmio, `CONFIG_PCI` required by ACPI init per FC's kernel policy +despite zero PCI devices), kvmclock replaces the missing RTC, the +artifact is the ELF `vmlinux` Firecracker boots directly, and the +initramfs (zstd) + squashfs (xz) pair carries the platform boot +contract. +CI boot-smokes the x86_64 kernel under Firecracker on a KVM-capable +runner. ```bash FLAVOR=microvm ./scripts/build-kernel.sh diff --git a/configs/arcbox-microvm-x86_64.config b/configs/arcbox-microvm-x86_64.config new file mode 100644 index 0000000..2dc110a --- /dev/null +++ b/configs/arcbox-microvm-x86_64.config @@ -0,0 +1,302 @@ +# ArcBox microVM (sandbox) kernel configuration for x86_64 +# +# Guest kernel for Firecracker sandbox microVMs on x86_64 Linux hosts — +# bare-metal KVM, not nested. Serves both consumers of the sandbox path: +# ArcBox-on-Linux sandboxes (vm-agent over vsock, ext4 template rootfs) +# and the platform PaaS fleet (arcbox-bootkit initramfs owning the mounts: +# zstd cpio rdinit, ext4 template on /dev/vda, xz squashfs run-env on +# /dev/vdb). +# +# The Firecracker x86_64 device model differs from aarch64 in ways this +# config encodes deliberately (each verified by the CI KVM boot smoke, +# and matching FC's own docs/kernel-policy.md): +# - Firecracker x86_64 is a HARDWARE-REDUCED ACPI platform: the FADT +# sets HW_REDUCED_ACPI (so the kernel nulls the legacy PIC by design +# — "preallocated irqs: 0" is normal), MADT carries SMP config, and +# the DSDT carries the virtio-mmio devices as LNRO0005 nodes, IRQs +# mapped through ACPI onto the IOAPIC. The deprecated fallbacks are +# explicitly off per FC's kernel policy: no MPTable parsing and no +# cmdline device discovery (FC still auto-appends virtio_mmio.device= +# entries; with the option off they are inert, and with it on they +# spawn duplicate devices with raw ISA IRQs that cannot work in +# hardware-reduced mode). +# - CONFIG_PCI stays ON despite zero PCI devices: FC's kernel policy is +# explicit that ACPI initialization inside the guest needs it — the +# smoke measured the failure shape as "AE_BAD_PARAMETER, During +# Region initialization" + "Unable to load the System Description +# Tables", killing all ACPI enumeration. The fleet boots with pci=off +# so nothing scans. EFI stays off. +# - The bootable artifact is the uncompressed ELF vmlinux at the source +# root, not arch/x86/boot/bzImage (build-kernel.sh overrides +# KERNEL_IMAGE for this flavor). +# - There is no RTC device: cold-boot wall time comes from kvmclock +# (KVM_GUEST reads the host wall clock at boot), post-restore resync +# from ptp_kvm (/dev/ptp0, KVM_HC_CLOCK_PAIRING) — so no RTC_CLASS, +# where the arm64 flavor carries PL031. +# - The serial console is the legacy COM1 16550 at 0x3f8 (ttyS0), probed +# by the static 8250 table — no PNP/DT enumeration needed. +# +# Everything built in; CONFIG_MODULES stays off. Fragment style matches +# configs/arcbox-microvm-arm64.config: copied to .config, resolved by +# olddefconfig, then asserted by scripts/build-kernel.sh (microvm x86_64 +# assertion set). EXPERT is required to expose the VT/INPUT/... disables. + +# 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_64BIT=y +CONFIG_SMP=y +CONFIG_NR_CPUS=32 +# (No HOTPLUG_CPU disable here, unlike arm64: x86 SMP def_bool-selects it.) +# 64-bit-only guests: templates are baked from amd64 OCI images +# (oci2rootfs), and dropping the compat syscall surface mirrors the arm64 +# flavor's COMPAT cut. +# CONFIG_IA32_EMULATION is not set +# CONFIG_X86_16BIT is not set +# The sandbox never hosts further guests; KVM init has no business here. +# CONFIG_VIRTUALIZATION is not set + +# KVM paravirt guest: kvmclock is the boot-time wall-clock source (there +# is no RTC device on Firecracker x86_64) and the clocksource; ptp_kvm +# rides the same interface for post-restore resync. Steal-time accounting +# is real on a shared bare-metal fleet node. +CONFIG_HYPERVISOR_GUEST=y +CONFIG_PARAVIRT=y +CONFIG_KVM_GUEST=y +CONFIG_PARAVIRT_TIME_ACCOUNTING=y + +# 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, same call as the +# arm64 flavor — a sandbox runs a single workload, so rare ticks and no +# preemption churn win even without the nested-virt tick tax. +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 + +# ACPI is load-bearing on x86 Firecracker (hardware-reduced boot, MADT +# SMP tables, LNRO0005 virtio-mmio enumeration, VMGenID), and PCI is +# load-bearing for ACPI itself (FC kernel policy; no PCI device ever +# appears — the fleet boots pci=off). Cut the default-on ACPI drivers +# for hardware Firecracker never presents. CPU-side mitigations for +# untrusted workloads stay at kernel defaults on purpose: do not add +# mitigations=off-style toggles to this config. +CONFIG_ACPI=y +CONFIG_PCI=y +# CONFIG_X86_MPPARSE is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_BATTERY is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_THERMAL is not set +# CONFIG_ACPI_TABLE_UPGRADE is not set + +# 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_NUMA is not set +# CONFIG_SWAP is not set +# CONFIG_SUSPEND is not set +# CONFIG_HIBERNATION is not set +# CONFIG_CPU_FREQ is not set +# KASLR is inert under Firecracker's direct ELF load: x86 randomization +# lives in the bzImage decompression stub, which loading vmlinux bypasses +# — stating it off documents reality rather than trading security away. +# 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. The platform +# fleet configures networking from its initramfs instead — both ride the +# same INET stack. NAT/firewalling happens on the host side; 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 +# Discovery is ACPI (LNRO0005 in the DSDT — see header); the cmdline +# mechanism is deprecated by FC and actively harmful here, so it stays +# off and the build asserts it stayed off. +# CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set +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_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_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 + +# initramfs: the platform fleet boots rdinit=/init from a zstd cpio built +# by arcbox-bootkit; only the zstd decompressor is carried (the archive +# format is ours, not user input). ArcBox-on-Linux sandboxes boot +# root=/dev/vda directly and never load one — an absent initrd costs +# nothing. This is the one boot-path divergence from the arm64 flavor. +CONFIG_BLK_DEV_INITRD=y +CONFIG_RD_ZSTD=y +# CONFIG_RD_GZIP is not set +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set + +# Time: cold-boot wall clock + post-restore resync (CORE-75). Firecracker +# x86_64 exposes NO RTC device, so RTC_CLASS stays out entirely: kvmclock +# (KVM_GUEST above) sets CLOCK_REALTIME from the host wall clock at boot, +# and ptp_kvm exposes the host CLOCK_REALTIME at ns granularity via +# KVM_HC_CLOCK_PAIRING (/dev/ptp0) for vm-agent's accept-path resync. +# ptp_kvm being the only PTP driver also keeps /dev/ptp0 unambiguous. +CONFIG_PTP_1588_CLOCK=y +CONFIG_PTP_1588_CLOCK_KVM=y +# ACPI-based VMGenID: 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 for template rootfs images (oci2rootfs); squashfs for +# the platform run-env image (backhand-written, xz by default — zlib and +# zstd decompressors kept so a compressor change in bootkit is not a +# kernel event). Still no overlayfs: the platform initramfs mounts the +# template and run-env side by side (verified against arcbox-bootkit's +# initramfs sources), and the ArcBox CoW layer lives host-side. +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_ZLIB=y +CONFIG_SQUASHFS_XZ=y +CONFIG_SQUASHFS_ZSTD=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; squashfs decompressors pull their +# libraries via select) +CONFIG_CRYPTO=y +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRC32=y diff --git a/scripts/build-kernel.sh b/scripts/build-kernel.sh index 73346dc..8d6f2a6 100755 --- a/scripts/build-kernel.sh +++ b/scripts/build-kernel.sh @@ -10,9 +10,9 @@ # Flavors: # system (default) — System VM guest kernel (VZ/HV backends), # configs/arcbox-{arch}.config, output kernel-{arch} -# microvm — Firecracker sandbox guest kernel (arm64 only), +# microvm — Firecracker sandbox guest kernel, # configs/arcbox-microvm-{arch}.config, -# output microvm-kernel-{arch} +# output microvm-kernel-{arch} (x86_64: ELF vmlinux) set -e @@ -56,22 +56,40 @@ if [ "$FLAVOR" = "system" ]; then 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 + # devtmpfs automount over the empty template /dev, static ip=, ptp_kvm + # restore resync, 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" + CONFIG_PTP_1588_CLOCK_KVM CONFIG_VMGENID" + ASSERT_N="CONFIG_NETFILTER CONFIG_MODULES CONFIG_EFI" + if [ "$TARGET_ARCH" = "arm64" ]; then + # aarch64 Firecracker: DT device discovery, PL031 RTC; ACPI and + # PCI are cut and must stay cut. + ASSERT_Y="$ASSERT_Y CONFIG_RTC_DRV_PL031" + ASSERT_N="$ASSERT_N CONFIG_ACPI CONFIG_PCI" + else + # x86_64 Firecracker is a hardware-reduced ACPI platform: the + # DSDT enumerates virtio-mmio (LNRO0005), and per FC's kernel + # policy ACPI initialization needs CONFIG_PCI even though no PCI + # device ever appears. The deprecated fallbacks (MPTable, cmdline + # virtio-mmio) must stay off — the cmdline path spawns duplicate + # devices with raw ISA IRQs that cannot work without a legacy + # PIC. kvmclock replaces the missing RTC; the bootable artifact + # is the ELF vmlinux at the source root — not bzImage. The + # initramfs/squashfs pair is the platform PaaS boot contract + # (arcbox-bootkit: zstd cpio + xz run-env). + ASSERT_Y="$ASSERT_Y CONFIG_ACPI CONFIG_PCI CONFIG_KVM_GUEST + CONFIG_BLK_DEV_INITRD CONFIG_RD_ZSTD + CONFIG_SQUASHFS CONFIG_SQUASHFS_XZ" + ASSERT_N="$ASSERT_N CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES CONFIG_X86_MPPARSE" + KERNEL_IMAGE="vmlinux" + fi else echo "Error: Unsupported flavor: $FLAVOR (expected 'system' or 'microvm')" exit 1 @@ -83,6 +101,15 @@ fi ASSERT_Y=$(echo $ASSERT_Y) ASSERT_N=$(echo $ASSERT_N) +# Where the bootable artifact lands in the source tree. vmlinux is the ELF +# at the root (Firecracker x86_64 boots it directly); everything else is a +# packaged image under arch/*/boot. +if [ "$KERNEL_IMAGE" = "vmlinux" ]; then + KERNEL_IMAGE_SRC="vmlinux" +else + KERNEL_IMAGE_SRC="arch/$TARGET_ARCH/boot/$KERNEL_IMAGE" +fi + echo "========================================" echo " ArcBox Kernel Build" echo "========================================" @@ -140,7 +167,7 @@ do_build() { make ARCH=$TARGET_ARCH ${CROSS_COMPILE:+CROSS_COMPILE=$CROSS_COMPILE} -j"$(nproc)" $KERNEL_IMAGE # Copy output. - cp "arch/$TARGET_ARCH/boot/$KERNEL_IMAGE" "$OUTPUT_PATH" + cp "$KERNEL_IMAGE_SRC" "$OUTPUT_PATH" echo "" echo "Build complete!" ls -lh "$OUTPUT_PATH" @@ -191,7 +218,7 @@ for sym in $ASSERT_N; do done echo 'Building kernel...' make ARCH=$TARGET_ARCH -j\$(nproc) $KERNEL_IMAGE -cp arch/$TARGET_ARCH/boot/$KERNEL_IMAGE /output/$OUTPUT_NAME +cp $KERNEL_IMAGE_SRC /output/$OUTPUT_NAME echo 'Build complete!' ls -lh /output/$OUTPUT_NAME "