diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md new file mode 100644 index 000000000..43c994c2d --- /dev/null +++ b/.claude/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..53217d287 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,149 @@ +# AGENTS.md + +This file provides guidance to Agents when working with code in this repository. + +## What this project is + +**libkrun** is a Rust dynamic library that provides virtualization-based process isolation via KVM (Linux) and HVF (macOS). It exposes a C API (`include/libkrun.h`) that lets callers run a process inside a lightweight VM with configurable vCPUs, RAM, virtio devices, and an embedded init binary. + +## Build commands + +All builds go through the Makefile, which handles feature flags, platform detection, and sysroot management for cross-compilation. Direct `cargo build` skips that plumbing. + +```bash +# Release build (minimal — no optional devices) +make + +# Release build with common optional devices +make BLK=1 NET=1 GPU=1 SND=1 INPUT=1 + +# Debug build +make debug + +# TEE variants (mutually exclusive with each other and GPU/SND/INPUT) +make SEV=1 # AMD SEV — produces libkrun-sev.so +make TDX=1 # Intel TDX — produces libkrun-tdx.so + +# Other optional features +make VHOST_USER=1 +make VIRGL_RESOURCE_MAP2=1 + +# Install to /usr/local (or PREFIX=...) +make install +make PREFIX=$HOME/.local install +``` + +The Makefile exports `CC_LINUX` for Rust build scripts that compile C code targeting Linux. On macOS it auto-downloads a Debian sysroot; on Linux it uses the host toolchain. + +## Lint and format + +Clippy is run with `-D warnings` — zero warnings are allowed. The CI checks several feature combinations; you should too when touching device or feature-gated code: + +```bash +# Required before every PR — same as CI +cargo clippy --locked -- -D warnings +cargo clippy --locked --features amd-sev -- -D warnings +cargo clippy --locked --features tdx -- -D warnings +cargo clippy --locked --features net,blk,gpu,snd,input -- -D warnings + +# Format check +cargo fmt -- --check +``` + +## Tests + +```bash +# Unit tests (requires init/init to exist and KVM access on Linux) +touch init/init +cargo test + +# Integration tests (builds and installs the library first) +make test +make test TEST=test_name # run a single integration test +make test BLK=1 # integration tests with blk feature +``` + +Integration tests live in `tests/` as a separate Cargo workspace. They require the library to be installed to a local prefix (`test-prefix/`) which `make test` handles automatically. + +## Crate architecture + +The workspace (`Cargo.toml`) contains these crates under `src/`: + +| Crate | Role | +|---|---| +| **libkrun** | C API surface. Manages `KrunContext` instances (one per VM), translates API calls into VMM configuration, and drives startup via `krun_start_enter()`. | +| **vmm** (krun-vmm) | VMM core: builds and runs the VM, owns the vCPU threads, wires devices to memory and IRQs. | +| **devices** (krun-devices) | All virtio device implementations: console, block, fs (virtiofs passthrough + read-only wrapper), net, gpu, sound, input, vsock. | +| **arch** (krun-arch) | Platform-specific VM setup: GDT/IDT (x86_64), FDT (aarch64/riscv), boot protocol. | +| **kernel** | Loads the kernel image and sets up the boot parameters passed to the VMM. | +| **hvf** | macOS HVF hypervisor bindings (Linux uses kvm-ioctls directly in vmm). | +| **cpuid** | x86_64 CPUID leaf manipulation for vCPU feature exposure. | +| **rutabaga_gfx** | Wraps virglrenderer for virtio-gpu. | +| **display** / **input** | Host-side display and input backends (used by the gpu feature). | +| **utils**, **polly**, **smbios**, **arch_gen** | Shared utilities, event loop, SMBIOS table generation, architecture codegen. | +| **aws_nitro** | AWS Nitro Enclave support. | + +### How a VM starts + +1. Caller invokes `krun_create_ctx()` → allocates a `KrunContext` +2. Caller configures it (vCPUs, RAM, disks, network, exec path, etc.) +3. `krun_start_enter()` calls into **vmm**, which: + - Loads the kernel via **kernel** + - Instantiates virtio devices from **devices** + - Starts vCPU threads (KVM ioctls on Linux, HVF on macOS) + - The guest boots, the C init binary runs as PID 1, reads `.krun_config.json` from the virtiofs overlay, and execs the workload + +### The init binary (`init/init.c`) + +The guest PID-1 is a statically-linked C binary (`init/init.c`) compiled by `src/devices/build.rs` via `CC_LINUX`. The compiled binary path is set in the `KRUN_INIT_BINARY_PATH` env var at build time and embedded into the devices crate via `include_bytes!`. The passthrough fs backend exposes it as a virtual read-only file named `init.krun` (inode defined in `src/devices/src/virtio/fs/linux/passthrough.rs`) — the real host filesystem never sees it. + +AWS Nitro uses a separate C init (`init/aws-nitro/`) built by the Makefile when `AWS_NITRO=1`. + +### Feature flags + +Features are additive and controlled at the `libkrun` crate level. Each device feature (`blk`, `net`, `gpu`, `snd`, `input`) enables the corresponding code in both `devices` and `vmm`. The TEE variants (`amd-sev`, `tdx`) imply `blk` + `tee` and affect the soname of the output library. + +## Pull Request expectations +- New tests are added when necessary. +- Documentation is added or updated when necessary. +- Linting and formatting has been done. +- All of the tests pass. +- The commit structure follows what's described in [Commit structure](### Commit structure). + +## Code Quality + +### Commit structure + +- Format: `: ` — e.g., `virtio/blk: add print_text() function` +- Commits must be self-contained, compile, and pass tests independently +- Sign all commits with `git commit -s` (DCO requirement) +- Agent attribution: `Claude Code: <model-name>` +- Commit messages should be concise and written in the imperative mood. Small, focused commits are preferred. + +### Rust coding style +- No error handling for impossible scenarios. +- Avoid checking for empty input when calling a function if the function already handles the base case well (e.g. empty input is noop). +- Use `use` imports instead of inline full paths. One level of qualitifation is fine when it clarifies what something is (e.g., `log::trace!`, `fs::read_to_string()`), but don't use longer paths like `std::process::Command::new(...)` or `crate::foo::bar::baz()` -- import with `use` instead. + +Creating stubs to make code compile causes silent runtime failures: +- **EventFd**: Don't create new `EventFd::new()` - propagate existing ones (via `Arc<EventFd>` or `.try_clone()`). New `EventFd`s are never signaled -> deadlock. +- **Queues**: Don't create empty queues - pass existing ones through. Empty queues -> nothing received. +- **Files**: Don't create dummy files for `include_bytes!()`. Ask the user how to build/obtain them. + +**Principle**: When something is wired into the system, propagate it. Don't create disconnected instances. If a build fails due to missing dependencies, ask the user rather than stubbing. + +## Platform support + +### Host platforms (where libkrun runs as a library) + +- **Linux x86_64 / aarch64**: primary targets, full feature support (KVM) +- **Linux riscv64**: experimental (KVM) +- **macOS aarch64**: supported (HVF), GPU works +- **FreeBSD**: experimental cross-compilation target (`make BUILD_BSD_INIT=1`) + +### Guest platforms (what runs inside the VM) + +The guest ISA always matches the host ISA — KVM and HVF use hardware virtualization, not emulation. + +- **Linux** (x86_64, aarch64, riscv64): primary guest OS; the default init binary (`init/init.c`) is Linux-specific +- **FreeBSD** (same arch as host): experimental; requires building the FreeBSD init with `make BUILD_BSD_INIT=1`