Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ BUILD_TYPE="release"
BUILD_SDK=true

WITH_HYPERLIGHT=false
WITH_MICROVM=false

while [[ $# -gt 0 ]]; do
case $1 in
Expand All @@ -29,13 +30,18 @@ while [[ $# -gt 0 ]]; do
WITH_HYPERLIGHT=true
shift
;;
--with-microvm)
WITH_MICROVM=true
shift
;;
--help|-h)
echo "Usage: build.sh [OPTIONS]"
echo ""
echo "Options:"
echo " --debug Build in debug mode (default: release)"
echo " --rust-only Only build Rust binaries, skip SDK/CLI"
echo " --with-hyperlight Build with Hyperlight (micro-VM) backend (x86_64 only)"
echo " --with-microvm Build with NanVix MicroVM backend (KVM required at runtime)"
echo " -h, --help Show this help message"
exit 0
;;
Expand Down Expand Up @@ -68,8 +74,15 @@ cd "$SRC_DIR"
LXC_PACKAGES=(-p lxc -p lxc_common -p wxc_common -p bwrap_common -p linux_test_proxy)

CARGO_FEATURES=()
FEATURES_LIST=()
if [ "$WITH_HYPERLIGHT" = true ]; then
CARGO_FEATURES=(--features hyperlight)
FEATURES_LIST+=(hyperlight)
fi
if [ "$WITH_MICROVM" = true ]; then
FEATURES_LIST+=(microvm)
fi
if [ ${#FEATURES_LIST[@]} -gt 0 ]; then
CARGO_FEATURES=(--features "$(IFS=,; echo "${FEATURES_LIST[*]}")")
fi

if [ "$BUILD_TYPE" = "release" ]; then
Expand Down
19 changes: 16 additions & 3 deletions docs/nanvix-microvm/nanvix.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,33 @@

Nanvix MicroVM is an experimental containment backend for MxC. It is powered by the
[Nanvix OS/VM](https://aka.ms/nanvix) and runs untrusted code with hardware-enforced isolation
via the Windows Hypervisor Platform (WHP).
via the Windows Hypervisor Platform (WHP) on Windows or KVM on Linux.

## Key Features

- **Fast cold-start** β€” ~100 ms from process spawn to guest code execution
- **Fast cold-start** β€” ~100 ms from process spawn to guest code execution (Windows warm-start via WHP snapshot; Linux uses cold boot via KVM every run)
- **Low Memory Footprint** β€” Resident memory size of ~100 MB
- **Hardware-Enforced Isolation** β€” Runs guest code inside a lightweight virtual machine (VM)

## Requirements

### Windows

- Windows with WHP enabled (`bcdedit /set hypervisorlaunchtype auto`)
- Nanvix runtime binaries (`nanvixd.exe`, `kernel.elf`, `python3.12`, `nanvix_rootfs.img`) placed next to `wxc-exec.exe`
- Nanvix runtime binaries (`nanvixd.exe`, `kernel.elf`, `python3.initrd`, `nanvix_rootfs.img`) placed next to `wxc-exec.exe`
- Build with `--with-microvm` (`build.bat --with-microvm` or `cargo build -p wxc --features microvm`)
- `--experimental` flag (Nanvix MicroVM is an experimental feature)

### Linux

- Linux with KVM available at `/dev/kvm` (and the invoking user has read/write access to it)
- Nanvix runtime binaries (`nanvixd.elf`, `kernel.elf`, `python3.initrd`, `nanvix_rootfs.img`) placed next to `lxc-exec` (the build script downloads and stages them automatically)
- Build with `--with-microvm` (`./build.sh --with-microvm` or `cargo build -p lxc --features microvm`)
- `--experimental` flag (Nanvix MicroVM is an experimental feature)

> **Note:** On Linux, WHP snapshots are not used. Each invocation cold-boots
> the VM via KVM. Snapshot-based warm-start is Windows-only.

## Quick Start

```json
Expand Down
2 changes: 2 additions & 0 deletions src/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/lxc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ path = "src/main.rs"

[features]
hyperlight = ["wxc_common/hyperlight"]
microvm = ["wxc_common/microvm", "dep:nanvix_binaries"]

[build-dependencies]
mxc_build_common.workspace = true
nanvix_common = { path = "../nanvix_common" }

[dependencies]
wxc_common = { workspace = true }
lxc_common = { workspace = true }
bwrap_common = { workspace = true }
anyhow = { workspace = true }
clap = { workspace = true }
nanvix_binaries = { path = "../nanvix_binaries", optional = true }
41 changes: 41 additions & 0 deletions src/lxc/build.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,47 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

//! Build script for lxc β€” embeds Windows VersionInfo (no-op on non-Windows)
//! and copies NanVix binaries next to the output executable when the
//! `microvm` feature is enabled.

fn main() {
mxc_build_common::embed_version_info("LXC container executor (Linux stub)", "lxc-exec.exe");

#[cfg(all(target_os = "linux", feature = "microvm"))]
copy_nanvix_binaries();

println!("cargo:rerun-if-changed=build.rs");
}

#[cfg(all(target_os = "linux", feature = "microvm"))]
fn copy_nanvix_binaries() {
use std::path::Path;

let nanvix_bin_dir = match std::env::var("DEP_NANVIX_BINARIES_BIN_DIR") {
Ok(dir) => dir,
Err(_) => {
eprintln!("lxc build.rs: DEP_NANVIX_BINARIES_BIN_DIR not set, skipping copy");
return;
}
};

// Cargo puts the output binary in OUT_DIR/../../.. (target/<profile>/)
let out_dir = std::env::var("OUT_DIR").unwrap();
let target_dir = Path::new(&out_dir)
.parent()
.and_then(|p| p.parent())
.and_then(|p| p.parent());

let target_dir = match target_dir {
Some(d) => d,
None => {
eprintln!("lxc build.rs: could not determine target dir from OUT_DIR");
return;
}
};

nanvix_common::copy_artifacts_to_target(Path::new(&nanvix_bin_dir), target_dir);

println!("cargo:rerun-if-env-changed=DEP_NANVIX_BINARIES_BIN_DIR");
}
17 changes: 17 additions & 0 deletions src/lxc/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ use lxc_common::lxc_runner::LxcScriptRunner;
use lxc_common::signal_cleanup;
#[cfg(all(feature = "hyperlight", target_arch = "x86_64"))]
use wxc_common::hyperlight_runner::HyperlightScriptRunner;
#[cfg(feature = "microvm")]
use wxc_common::nanvix_runner::NanVixScriptRunner;

#[derive(Parser)]
#[command(name = "lxc-exec", about = "Linux Container Executor")]
Expand Down Expand Up @@ -234,6 +236,21 @@ fn main() {
process::exit(1);
}
}
ContainmentBackend::MicroVm => {
if !request.experimental_enabled {
eprintln!("Error: MicroVM is an experimental feature. Use --experimental flag.");
process::exit(1);
}
#[cfg(feature = "microvm")]
{
Box::new(NanVixScriptRunner::new())
}
#[cfg(not(feature = "microvm"))]
{
eprintln!("Error: MicroVM backend not compiled in (build with --features microvm)");
process::exit(1);
}
}
ContainmentBackend::Bubblewrap => {
#[cfg(target_os = "linux")]
{
Expand Down
Loading
Loading