Skip to main content

supermachine_kernel/
lib.rs

1//! Pre-built runtime assets for supermachine, packaged as a Rust
2//! crate so embedders can `cargo add supermachine-kernel` instead
3//! of fetching binaries out-of-band.
4//!
5//! Two assets are bundled:
6//!
7//! 1. **Linux kernel image** ([`KERNEL_BYTES`]) — ~29 MiB aarch64
8//!    `Image` format with the AF_TSI patch series applied.
9//! 2. **`init-oci` shim** ([`INIT_OCI_BYTES`]) — ~1.6 MiB statically
10//!    linked aarch64-musl binary. PID 1 inside each microVM. Sets
11//!    up overlayfs, mounts /proc + /dev, exec's the customer's
12//!    image entrypoint. Only needed if you bake images at runtime
13//!    (i.e. via the future `Image::from_oci(...)` API); restoring
14//!    a snapshot doesn't need it.
15//!
16//! Versioned in lockstep with the [`supermachine`] library — pin
17//! both to the same version.
18//!
19//! ## Use cases
20//!
21//! ### From a `build.rs` (recommended for `.app` bundles)
22//!
23//! Pre-stage the assets into your bundle's Resources at build time
24//! so the resulting `.app` is self-contained:
25//!
26//! ```no_run
27//! // build.rs
28//! fn main() {
29//!     let resources = std::path::PathBuf::from(
30//!         std::env::var("OUT_DIR").unwrap()
31//!     ).join("../../../bundle-resources");
32//!     std::fs::create_dir_all(&resources).unwrap();
33//!     supermachine_kernel::extract_kernel_to(&resources.join("kernel")).unwrap();
34//!     supermachine_kernel::extract_init_oci_to(&resources.join("init-oci")).unwrap();
35//! }
36//! ```
37//!
38//! ### From runtime code
39//!
40//! Extract once on first start to a writable scratch dir:
41//!
42//! ```no_run
43//! use std::path::PathBuf;
44//!
45//! fn ensure_assets() -> std::io::Result<PathBuf> {
46//!     let dir = std::env::temp_dir().join("supermachine-assets");
47//!     std::fs::create_dir_all(&dir)?;
48//!     supermachine_kernel::extract_kernel_to(&dir.join("kernel"))?;
49//!     supermachine_kernel::extract_init_oci_to(&dir.join("init-oci"))?;
50//!     Ok(dir)
51//! }
52//! ```
53//!
54//! Then point [`supermachine::AssetPaths::from_dir`] at the result.
55//!
56//! [`supermachine`]: https://crates.io/crates/supermachine
57//! [`supermachine::AssetPaths::from_dir`]: https://docs.rs/supermachine/latest/supermachine/assets/struct.AssetPaths.html#method.from_dir
58
59/// Raw bytes of the kernel image — an aarch64 Linux `Image` format
60/// binary (raw kernel, no ELF wrapper). About 29 MiB.
61///
62/// The supermachine VMM expects the bytes loaded into guest RAM at
63/// the boot offset (0x80000 from RAM start) and PC pointed at the
64/// load address. The library handles that wiring internally; you
65/// just need the path on disk.
66///
67/// The bytes are staged into `OUT_DIR` by `build.rs`, which
68/// resolves them from one of three sources (env override, dev tree,
69/// or download from the matching GitHub release). See `build.rs`
70/// for the full discovery order.
71pub const KERNEL_BYTES: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/kernel"));
72
73/// Length of the kernel image in bytes — equivalent to
74/// `KERNEL_BYTES.len()` but evaluable in `const` contexts.
75pub const KERNEL_LEN: usize = KERNEL_BYTES.len();
76
77/// Raw bytes of the in-VM init shim (statically-linked aarch64-musl
78/// ELF executable, ~1.6 MiB). The CLI's bake step copies this into
79/// the guest's initramfs as PID 1; it sets up overlayfs, mounts
80/// /proc + /dev, then exec's the OCI image's entrypoint.
81///
82/// Embedders that only restore snapshots don't need to extract this
83/// — restoring brings back the post-init state directly. It's only
84/// needed if you bake fresh images at runtime, which today still
85/// goes through the `supermachine` CLI (the future
86/// `Image::from_oci(...)` library API will use this constant).
87pub const INIT_OCI_BYTES: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/init-oci"));
88
89/// Length of the init-oci binary in bytes.
90pub const INIT_OCI_LEN: usize = INIT_OCI_BYTES.len();
91
92/// Write the bundled kernel image to `dest`. Overwrites any
93/// existing file. Caller is responsible for the parent dir
94/// existing — use [`extract_kernel_to_with_parents`] if you'd
95/// rather mkdir -p.
96///
97/// ```no_run
98/// supermachine_kernel::extract_kernel_to(
99///     std::path::Path::new("/tmp/supermachine/kernel"),
100/// ).unwrap();
101/// ```
102pub fn extract_kernel_to(dest: &std::path::Path) -> std::io::Result<()> {
103    std::fs::write(dest, KERNEL_BYTES)
104}
105
106/// Like [`extract_kernel_to`] but `mkdir -p`'s the parent dir first.
107pub fn extract_kernel_to_with_parents(dest: &std::path::Path) -> std::io::Result<()> {
108    if let Some(parent) = dest.parent() {
109        std::fs::create_dir_all(parent)?;
110    }
111    extract_kernel_to(dest)
112}
113
114/// Write the bundled init-oci binary to `dest`. Sets it executable
115/// (mode 0o755) on Unix.
116pub fn extract_init_oci_to(dest: &std::path::Path) -> std::io::Result<()> {
117    std::fs::write(dest, INIT_OCI_BYTES)?;
118    #[cfg(unix)]
119    {
120        use std::os::unix::fs::PermissionsExt;
121        let mut perms = std::fs::metadata(dest)?.permissions();
122        perms.set_mode(0o755);
123        std::fs::set_permissions(dest, perms)?;
124    }
125    Ok(())
126}
127
128/// Like [`extract_init_oci_to`] but `mkdir -p`'s the parent dir first.
129pub fn extract_init_oci_to_with_parents(dest: &std::path::Path) -> std::io::Result<()> {
130    if let Some(parent) = dest.parent() {
131        std::fs::create_dir_all(parent)?;
132    }
133    extract_init_oci_to(dest)
134}
135
136// ---------- backward compat ----------
137// The earlier 0.1.0-pre layout shipped only the kernel. Keep these
138// names available for one minor so anyone who tracked HEAD doesn't
139// break.
140
141/// Deprecated alias for [`extract_kernel_to`]. Will be removed in 0.2.
142#[deprecated(since = "0.1.0", note = "use extract_kernel_to")]
143pub fn extract_to(dest: &std::path::Path) -> std::io::Result<()> {
144    extract_kernel_to(dest)
145}
146
147/// Deprecated alias for [`extract_kernel_to_with_parents`].
148#[deprecated(since = "0.1.0", note = "use extract_kernel_to_with_parents")]
149pub fn extract_to_with_parents(dest: &std::path::Path) -> std::io::Result<()> {
150    extract_kernel_to_with_parents(dest)
151}