diff --git a/Cargo.lock b/Cargo.lock index bcd8042e1..0148f1ca7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -123,6 +123,7 @@ dependencies = [ "libc", "smbios", "utils", + "vm-fdt", "vm-memory", "vmm-sys-util", ] @@ -283,6 +284,16 @@ dependencies = [ "shlex", ] +[[package]] +name = "cca" +version = "0.0.1" +dependencies = [ + "kvm-bindings", + "kvm-ioctls", + "libc", + "vmm-sys-util", +] + [[package]] name = "cexpr" version = "0.6.0" @@ -1897,6 +1908,7 @@ version = "0.1.0" dependencies = [ "arch", "bzip2", + "cca", "codicon", "cpuid", "crossbeam-channel", diff --git a/Makefile b/Makefile index ce70aee16..8856ca3b4 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,9 @@ ifeq ($(SEV),1) INIT_SRC += $(SNP_INIT_SRC) BUILD_INIT = 0 endif +ifeq ($(CCA), 1) + FEATURE_FLAGS := --features cca +endif ifeq ($(VIRGL_RESOURCE_MAP2),1) FEATURE_FLAGS += --features virgl_resource_map2 endif diff --git a/src/arch/Cargo.toml b/src/arch/Cargo.toml index 562f39dc2..f981afd32 100644 --- a/src/arch/Cargo.toml +++ b/src/arch/Cargo.toml @@ -5,6 +5,7 @@ authors = ["The Chromium OS Authors"] edition = "2021" [features] +cca = [ "tee" ] tee = [] amd-sev = [ "tee" ] efi = [] @@ -19,8 +20,12 @@ smbios = { path = "../smbios" } utils = { path = "../utils" } [target.'cfg(target_os = "linux")'.dependencies] -kvm-bindings = { version = ">=0.11", features = ["fam-wrappers"] } -kvm-ioctls = ">=0.21" +kvm-bindings = { version = ">=0.8", features = ["fam-wrappers"] , git = "https://github.com/virtee/kvm-bindings", branch = "add_bindings_for_realms" } +kvm-ioctls = { version = ">=0.17", git = "https://github.com/virtee/kvm-ioctls", branch = "cca" } + + +[target.'cfg(target_arch = "aarch64")'.dependencies] +vm-fdt = ">= 0.2.0" [dev-dependencies] utils = { path = "../utils" } diff --git a/src/arch/src/aarch64/linux/regs.rs b/src/arch/src/aarch64/linux/regs.rs index b932c9cc4..3f227a314 100644 --- a/src/arch/src/aarch64/linux/regs.rs +++ b/src/arch/src/aarch64/linux/regs.rs @@ -110,6 +110,9 @@ arm64_sys_reg!(MPIDR_EL1, 3, 0, 0, 0, 5); /// * `boot_ip` - Starting instruction pointer. /// * `mem` - Reserved DRAM for current VM. pub fn setup_regs(vcpu: &VcpuFd, cpu_id: u8, boot_ip: u64, mem: &GuestMemoryMmap) -> Result<()> { + // PSTATE cannot be accesed from the host in CCA + #[cfg(not(feature = "cca"))] + #[allow(deref_nullptr)] // Get the register index of the PSTATE (Processor State) register. vcpu.set_one_reg(arm64_core_reg!(pstate), &PSTATE_FAULT_BITS_64.to_le_bytes()) .map_err(Error::SetCoreRegister)?; diff --git a/src/cpuid/Cargo.toml b/src/cpuid/Cargo.toml index 8d9bbeeae..a7b5706df 100644 --- a/src/cpuid/Cargo.toml +++ b/src/cpuid/Cargo.toml @@ -8,5 +8,5 @@ edition = "2021" vmm-sys-util = ">= 0.14" [target.'cfg(target_os = "linux")'.dependencies] -kvm-bindings = { version = ">=0.11", features = ["fam-wrappers"] } -kvm-ioctls = ">=0.21" +kvm-bindings = { version = ">=0.8", features = ["fam-wrappers"] , git = "https://github.com/virtee/kvm-bindings", branch = "add_bindings_for_realms" } +kvm-ioctls = { version = ">=0.17", git = "https://github.com/virtee/kvm-ioctls", branch = "cca" } diff --git a/src/devices/Cargo.toml b/src/devices/Cargo.toml index ce1339758..4460a5995 100644 --- a/src/devices/Cargo.toml +++ b/src/devices/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [features] tee = [] +cca = [ "tee" ] amd-sev = ["blk", "tee"] net = [] blk = [] @@ -43,8 +44,8 @@ lru = ">=0.9" [target.'cfg(target_os = "linux")'.dependencies] rutabaga_gfx = { path = "../rutabaga_gfx", features = ["x"], optional = true } caps = "0.5.5" -kvm-bindings = { version = ">=0.11", features = ["fam-wrappers"] } -kvm-ioctls = ">=0.21" +kvm-bindings = { version = ">=0.8", features = ["fam-wrappers"] , git = "https://github.com/virtee/kvm-bindings", branch = "add_bindings_for_realms" } +kvm-ioctls = { version = ">=0.17", git = "https://github.com/virtee/kvm-ioctls", branch = "cca" } [target.'cfg(any(target_arch = "aarch64", target_arch = "riscv64"))'.dependencies] vm-fdt = ">= 0.2.0" diff --git a/src/devices/src/fdt/aarch64.rs b/src/devices/src/fdt/aarch64.rs index 8ef879fb7..b9fb77efe 100644 --- a/src/devices/src/fdt/aarch64.rs +++ b/src/devices/src/fdt/aarch64.rs @@ -286,10 +286,12 @@ fn create_psci_node(fdt: &mut FdtWriter) -> Result<()> { // Two methods available: hvc and smc. // As per documentation, PSCI calls between a guest and hypervisor may use the HVC conduit instead of SMC. // So, since we are using kvm, we need to use hvc. - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(feature = "cca")))] fdt.property_string("method", "hvc")?; #[cfg(target_os = "macos")] fdt.property_string("method", "smc")?; + #[cfg(feature = "cca")] + fdt.property_string("method", "smc")?; fdt.end_node(node)?; Ok(()) diff --git a/src/devices/src/virtio/block/device.rs b/src/devices/src/virtio/block/device.rs index d104fa742..2ae2f297f 100644 --- a/src/devices/src/virtio/block/device.rs +++ b/src/devices/src/virtio/block/device.rs @@ -27,6 +27,9 @@ use utils::eventfd::{EventFd, EFD_NONBLOCK}; use virtio_bindings::{ virtio_blk::*, virtio_config::VIRTIO_F_VERSION_1, virtio_ring::VIRTIO_RING_F_EVENT_IDX, }; +#[cfg(feature = "cca")] +use virtio_bindings::virtio_config::VIRTIO_F_ACCESS_PLATFORM; + use vm_memory::{ByteValued, GuestMemoryMmap}; use super::worker::BlockWorker; @@ -240,10 +243,19 @@ impl Block { let disk_properties = DiskProperties::new(Arc::clone(&disk_image), disk_image_id.clone(), cache_type)?; - let mut avail_features = (1u64 << VIRTIO_F_VERSION_1) + + let mut avail_features = if cfg!(feature = "cca") { + (1u64 << VIRTIO_F_VERSION_1) | (1u64 << VIRTIO_BLK_F_FLUSH) | (1u64 << VIRTIO_BLK_F_SEG_MAX) - | (1u64 << VIRTIO_RING_F_EVENT_IDX); + | (1u64 << VIRTIO_RING_F_EVENT_IDX) + | (1 << VIRTIO_F_ACCESS_PLATFORM as u64) + } else { + (1u64 << VIRTIO_F_VERSION_1) + | (1u64 << VIRTIO_BLK_F_FLUSH) + | (1u64 << VIRTIO_BLK_F_SEG_MAX) + | (1u64 << VIRTIO_RING_F_EVENT_IDX) + }; if is_disk_read_only { avail_features |= 1u64 << VIRTIO_BLK_F_RO; diff --git a/src/devices/src/virtio/console/device.rs b/src/devices/src/virtio/console/device.rs index e1d9e0da3..109c63f91 100644 --- a/src/devices/src/virtio/console/device.rs +++ b/src/devices/src/virtio/console/device.rs @@ -10,6 +10,8 @@ use libc::TIOCGWINSZ; use nix::ioctl_read_bad; use utils::eventfd::EventFd; use vm_memory::{ByteValued, Bytes, GuestMemoryMmap}; +#[cfg(feature = "cca")] +use virtio_bindings::virtio_config::VIRTIO_F_ACCESS_PLATFORM; use super::super::{ ActivateError, ActivateResult, ConsoleError, DeviceState, Queue as VirtQueue, VirtioDevice, @@ -30,9 +32,18 @@ use crate::virtio::{PortDescription, VmmExitObserver}; pub(crate) const CONTROL_RXQ_INDEX: usize = 2; pub(crate) const CONTROL_TXQ_INDEX: usize = 3; -pub(crate) const AVAIL_FEATURES: u64 = (1 << uapi::VIRTIO_CONSOLE_F_SIZE as u64) - | (1 << uapi::VIRTIO_CONSOLE_F_MULTIPORT as u64) - | (1 << uapi::VIRTIO_F_VERSION_1 as u64); +// CCA requires VIRTIO_F_ACCESS_PLATFORM to ensure DMA-APIs +// are triggered for virtio in Linux +pub(crate) const AVAIL_FEATURES: u64 = if cfg!(feature = "cca") { + (1 << uapi::VIRTIO_CONSOLE_F_SIZE as u64) + | (1 << uapi::VIRTIO_CONSOLE_F_MULTIPORT as u64) + | (1 << uapi::VIRTIO_F_VERSION_1 as u64) + | (1 << VIRTIO_F_ACCESS_PLATFORM as u64) +} else { + (1 << uapi::VIRTIO_CONSOLE_F_SIZE as u64) + | (1 << uapi::VIRTIO_CONSOLE_F_MULTIPORT as u64) + | (1 << uapi::VIRTIO_F_VERSION_1 as u64) +}; #[repr(C)] #[derive(Default)] diff --git a/src/devices/src/virtio/fs/device.rs b/src/devices/src/virtio/fs/device.rs index f5d6a8015..1372e47cf 100644 --- a/src/devices/src/virtio/fs/device.rs +++ b/src/devices/src/virtio/fs/device.rs @@ -9,7 +9,10 @@ use std::thread::JoinHandle; use utils::eventfd::{EventFd, EFD_NONBLOCK}; #[cfg(target_os = "macos")] use utils::worker_message::WorkerMessage; -use virtio_bindings::{virtio_config::VIRTIO_F_VERSION_1, virtio_ring::VIRTIO_RING_F_EVENT_IDX}; +use virtio_bindings::{ + virtio_config::VIRTIO_F_ACCESS_PLATFORM, virtio_config::VIRTIO_F_VERSION_1, + virtio_ring::VIRTIO_RING_F_EVENT_IDX, +}; use vm_memory::{ByteValued, GuestMemoryMmap}; use super::super::{ @@ -72,7 +75,13 @@ impl Fs { .push(EventFd::new(utils::eventfd::EFD_NONBLOCK).map_err(FsError::EventFd)?); } - let avail_features = (1u64 << VIRTIO_F_VERSION_1) | (1u64 << VIRTIO_RING_F_EVENT_IDX); + let avail_features = if cfg!(feature = "cca") { + (1u64 << VIRTIO_F_VERSION_1) + | (1u64 << VIRTIO_RING_F_EVENT_IDX) + | (1 << VIRTIO_F_ACCESS_PLATFORM as u64) + } else { + (1u64 << VIRTIO_F_VERSION_1) | (1u64 << VIRTIO_RING_F_EVENT_IDX) + }; let tag = fs_id.into_bytes(); let mut config = VirtioFsConfig::default(); diff --git a/src/devices/src/virtio/mod.rs b/src/devices/src/virtio/mod.rs index 791925700..dea3c160b 100644 --- a/src/devices/src/virtio/mod.rs +++ b/src/devices/src/virtio/mod.rs @@ -21,7 +21,7 @@ pub mod console; pub mod descriptor_utils; pub mod device; pub mod file_traits; -#[cfg(not(any(feature = "tee", feature = "nitro")))] +#[cfg(not(any(feature = "tee", feature = "nitro", feature = "cca")))] pub mod fs; #[cfg(feature = "gpu")] pub mod gpu; @@ -42,7 +42,7 @@ pub use self::balloon::*; pub use self::block::{Block, CacheType}; pub use self::console::*; pub use self::device::*; -#[cfg(not(any(feature = "tee", feature = "nitro")))] +#[cfg(not(any(feature = "tee", feature = "nitro", feature = "cca")))] pub use self::fs::*; #[cfg(feature = "gpu")] pub use self::gpu::*; diff --git a/src/devices/src/virtio/rng/device.rs b/src/devices/src/virtio/rng/device.rs index bc3721ade..1cf5b8b49 100644 --- a/src/devices/src/virtio/rng/device.rs +++ b/src/devices/src/virtio/rng/device.rs @@ -13,12 +13,17 @@ use super::super::{ use super::{defs, defs::uapi}; use crate::legacy::IrqChip; use crate::Error as DeviceError; +use virtio_bindings::virtio_config::VIRTIO_F_ACCESS_PLATFORM; // Request queue. pub(crate) const REQ_INDEX: usize = 0; // Supported features. -pub(crate) const AVAIL_FEATURES: u64 = 1 << uapi::VIRTIO_F_VERSION_1 as u64; +pub(crate) const AVAIL_FEATURES: u64 = if cfg!(feature = "cca") { + 1 << uapi::VIRTIO_F_VERSION_1 as u64 | 1 << VIRTIO_F_ACCESS_PLATFORM as u64 +} else { + 1 << uapi::VIRTIO_F_VERSION_1 as u64 +}; #[derive(Copy, Clone, Debug, Default)] #[repr(C, packed)] diff --git a/src/libkrun/Cargo.toml b/src/libkrun/Cargo.toml index 39eeddd9b..0aa91b2dd 100644 --- a/src/libkrun/Cargo.toml +++ b/src/libkrun/Cargo.toml @@ -7,6 +7,7 @@ build = "build.rs" [features] tee = [] +cca = [ "tee" ] amd-sev = [ "blk", "tee" ] net = [] blk = [] @@ -19,11 +20,14 @@ nitro = [ "dep:nitro", "dep:nitro-enclaves" ] [dependencies] crossbeam-channel = ">=0.5.15" env_logger = "0.11" +vm-memory = { version = ">=0.13", features = ["backend-mmap"] } libc = ">=0.2.39" libloading = "0.8" log = "0.4.0" once_cell = "1.4.1" +kvm-bindings = { version = ">=0.8", features = ["fam-wrappers"] , git = "https://github.com/virtee/kvm-bindings", branch = "add_bindings_for_realms" } + devices = { path = "../devices" } polly = { path = "../polly" } utils = { path = "../utils" } @@ -33,8 +37,8 @@ vmm = { path = "../vmm" } hvf = { path = "../hvf" } [target.'cfg(target_os = "linux")'.dependencies] -kvm-bindings = { version = ">=0.11", features = ["fam-wrappers"] } -kvm-ioctls = ">=0.21" +kvm-bindings = { version = ">=0.11", features = ["fam-wrappers"] , git = "https://github.com/virtee/kvm-bindings", branch = "add_bindings_for_realms" } +kvm-ioctls = { version = ">=0.21", git = "https://github.com/virtee/kvm-ioctls", branch = "cca" } nitro = { path = "../nitro", optional = true } nitro-enclaves = { version = "0.3.0", optional = true } vm-memory = ">=0.13" diff --git a/src/libkrun/build.rs b/src/libkrun/build.rs index efc4886db..d6febbefd 100644 --- a/src/libkrun/build.rs +++ b/src/libkrun/build.rs @@ -12,4 +12,6 @@ fn main() { ); #[cfg(target_os = "macos")] println!("cargo:rustc-link-lib=framework=Hypervisor"); + #[cfg(feature = "cca")] + println!("cargo:rustc-link-lib=krunfw"); } diff --git a/src/libkrun/src/lib.rs b/src/libkrun/src/lib.rs index 40f20eb77..8c49b91b5 100644 --- a/src/libkrun/src/lib.rs +++ b/src/libkrun/src/lib.rs @@ -41,7 +41,7 @@ use vmm::vmm_config::block::BlockDeviceConfig; use vmm::vmm_config::boot_source::{BootSourceConfig, DEFAULT_KERNEL_CMDLINE}; #[cfg(not(feature = "tee"))] use vmm::vmm_config::external_kernel::{ExternalKernel, KernelFormat}; -#[cfg(not(feature = "tee"))] +#[cfg(any(not(feature = "tee"), feature = "cca"))] use vmm::vmm_config::fs::FsDeviceConfig; #[cfg(not(feature = "efi"))] use vmm::vmm_config::kernel_bundle::KernelBundle; @@ -85,8 +85,10 @@ pub struct KrunfwBindings { unsafe extern "C" fn(*mut u64, *mut u64, *mut size_t) -> *mut c_char, >, #[cfg(feature = "tee")] + #[cfg(target_arch = "x86_64")] get_initrd: libloading::Symbol<'static, unsafe extern "C" fn(*mut size_t) -> *mut c_char>, #[cfg(feature = "tee")] + #[cfg(target_arch = "x86_64")] get_qboot: libloading::Symbol<'static, unsafe extern "C" fn(*mut size_t) -> *mut c_char>, } @@ -101,8 +103,10 @@ impl KrunfwBindings { KrunfwBindings { get_kernel: krunfw.get(b"krunfw_get_kernel")?, #[cfg(feature = "tee")] + #[cfg(target_arch = "x86_64")] get_initrd: krunfw.get(b"krunfw_get_initrd")?, #[cfg(feature = "tee")] + #[cfg(target_arch = "x86_64")] get_qboot: krunfw.get(b"krunfw_get_qboot")?, } }) @@ -255,6 +259,7 @@ impl ContextConfig { } #[cfg(feature = "tee")] + #[cfg(target_arch = "x86_64")] fn get_tee_config_file(&self) -> Option { self.tee_config_file.clone() } @@ -469,7 +474,7 @@ pub extern "C" fn krun_set_vm_config(ctx_id: u32, num_vcpus: u8, ram_mib: u32) - #[allow(clippy::missing_safety_doc)] #[no_mangle] -#[cfg(not(feature = "tee"))] +#[cfg(any(not(feature = "tee"), feature = "cca"))] pub unsafe extern "C" fn krun_set_root(ctx_id: u32, c_root_path: *const c_char) -> i32 { let root_path = match CStr::from_ptr(c_root_path).to_str() { Ok(root) => root, @@ -1591,6 +1596,7 @@ unsafe fn load_krunfw_payload( vmr.set_kernel_bundle(kernel_bundle).unwrap(); #[cfg(feature = "tee")] + #[cfg(target_arch = "x86_64")] { let mut qboot_size: usize = 0; let qboot_host_addr = unsafe { (krunfw.get_qboot)(&mut qboot_size as *mut usize) }; @@ -1738,6 +1744,7 @@ pub extern "C" fn krun_start_enter(ctx_id: u32) -> i32 { * fail. */ #[cfg(feature = "tee")] + #[cfg(target_arch = "x86_64")] if let Some(tee_config) = ctx_cfg.get_tee_config_file() { if let Err(e) = ctx_cfg.vmr.set_tee_config(tee_config) { error!("Error setting up TEE config: {e:?}"); @@ -1850,6 +1857,9 @@ pub extern "C" fn krun_start_enter(ctx_id: u32) -> i32 { #[cfg(feature = "amd-sev")] vmm::worker::start_worker_thread(_vmm.clone(), _receiver.clone()).unwrap(); + #[cfg(feature = "cca")] + vmm::worker::start_worker_thread(_vmm.clone(), _receiver.clone()).unwrap(); + loop { match event_manager.run() { Ok(_) => {} diff --git a/src/utils/Cargo.toml b/src/utils/Cargo.toml index 7f8b56c10..ebda07161 100644 --- a/src/utils/Cargo.toml +++ b/src/utils/Cargo.toml @@ -12,4 +12,4 @@ vmm-sys-util = ">= 0.14" crossbeam-channel = ">=0.5.15" [target.'cfg(target_os = "linux")'.dependencies] -kvm-bindings = { version = ">=0.10", features = ["fam-wrappers"] } +kvm-bindings = { version = ">=0.8", features = ["fam-wrappers"] , git = "https://github.com/virtee/kvm-bindings", branch = "add_bindings_for_realms" } diff --git a/src/vmm/Cargo.toml b/src/vmm/Cargo.toml index 231c79a2e..da0055032 100644 --- a/src/vmm/Cargo.toml +++ b/src/vmm/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" [features] tee = [] amd-sev = [ "blk", "tee", "codicon", "kbs-types", "procfs", "rdrand", "serde", "serde_json", "sev", "curl" ] +cca = [ "tee" ] net = [] blk = [] efi = [ "blk", "net" ] @@ -40,14 +41,16 @@ sev = { version = "6.0.0", features = ["openssl"], optional = true } curl = { version = "0.4", optional = true } nix = "0.24.1" +cca = { git = "https://github.com/virtee/cca" } + [target.'cfg(target_arch = "x86_64")'.dependencies] bzip2 = "0.5" cpuid = { path = "../cpuid" } zstd = "0.13" [target.'cfg(target_os = "linux")'.dependencies] -kvm-bindings = { version = ">=0.11", features = ["fam-wrappers"] } -kvm-ioctls = ">=0.21" +kvm-bindings = { version = ">=0.8", features = ["fam-wrappers"] , git = "https://github.com/virtee/kvm-bindings", branch = "add_bindings_for_realms" } +kvm-ioctls = { version = ">=0.17", git = "https://github.com/virtee/kvm-ioctls", branch = "cca" } [target.'cfg(target_os = "macos")'.dependencies] hvf = { path = "../hvf" } diff --git a/src/vmm/src/builder.rs b/src/vmm/src/builder.rs index cae59f0da..0472dd1fd 100644 --- a/src/vmm/src/builder.rs +++ b/src/vmm/src/builder.rs @@ -44,10 +44,12 @@ use devices::legacy::{IrqChip, IrqChipDevice}; use devices::virtio::{port_io, MmioTransport, PortDescription, Vsock}; #[cfg(feature = "tee")] +#[cfg(target_arch = "x86_64")] use kbs_types::Tee; use crate::device_manager; #[cfg(feature = "tee")] +#[cfg(target_arch = "x86_64")] use crate::resources::TeeConfig; #[cfg(target_os = "linux")] use crate::signal_handler::register_sigint_handler; @@ -57,7 +59,7 @@ use crate::terminal::term_set_raw_mode; #[cfg(feature = "blk")] use crate::vmm_config::block::BlockBuilder; use crate::vmm_config::boot_source::DEFAULT_KERNEL_CMDLINE; -#[cfg(not(any(feature = "tee", feature = "nitro")))] +#[cfg(not(any(feature = "tee", feature = "nitro", feature = "cca")))] use crate::vmm_config::fs::FsDeviceConfig; #[cfg(target_os = "linux")] use crate::vstate::KvmContext; @@ -66,10 +68,11 @@ use crate::vstate::MeasuredRegion; use crate::vstate::{Error as VstateError, Vcpu, VcpuConfig, Vm}; use arch::{ArchMemoryInfo, InitrdConfig}; use device_manager::shm::ShmManager; -#[cfg(not(any(feature = "tee", feature = "nitro")))] +#[cfg(not(any(feature = "tee", feature = "nitro", feature = "cca")))] use devices::virtio::{fs::ExportTable, VirtioShmRegion}; use flate2::read::GzDecoder; #[cfg(feature = "tee")] +#[cfg(target_arch = "x86_64")] use kvm_bindings::KVM_MAX_CPUID_ENTRIES; use libc::{STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO}; #[cfg(target_arch = "x86_64")] @@ -89,6 +92,15 @@ use vm_memory::GuestMemory; use vm_memory::GuestRegionMmap; use vm_memory::{GuestAddress, GuestMemoryMmap}; +#[cfg(feature = "cca")] +use kvm_bindings::KVM_ARM_VCPU_REC; + +#[cfg(feature = "cca")] +use vm_memory::Address; + +#[cfg(feature = "cca")] +use cca::Algo; + #[cfg(feature = "efi")] static EDK2_BINARY: &[u8] = include_bytes!("../../../edk2/KRUN_EFI.silent.fd"); @@ -475,17 +487,20 @@ enum Payload { Empty, Efi, #[cfg(feature = "tee")] + #[cfg(target_arch = "x86_64")] Tee, } fn choose_payload(vm_resources: &VmResources) -> Result { if let Some(_kernel_bundle) = &vm_resources.kernel_bundle { #[cfg(feature = "tee")] + #[cfg(target_arch = "x86_64")] if vm_resources.qboot_bundle.is_none() || vm_resources.initrd_bundle.is_none() { return Err(StartMicrovmError::MissingKernelConfig); } #[cfg(feature = "tee")] + #[cfg(target_arch = "x86_64")] return Ok(Payload::Tee); #[cfg(all(target_os = "linux", target_arch = "x86_64", not(feature = "tee")))] @@ -547,14 +562,19 @@ pub fn build_microvm( let kvm = KvmContext::new() .map_err(Error::KvmContext) .map_err(StartMicrovmError::Internal)?; + #[cfg(feature = "cca")] + let vm = setup_vm(&kvm, &guest_memory)?; + #[cfg(target_arch = "x86_64")] let vm = setup_vm(&kvm, &guest_memory, vm_resources.tee_config())?; (kvm, vm) }; #[cfg(feature = "tee")] + #[cfg(target_arch = "x86_64")] let tee = vm_resources.tee_config().tee; #[cfg(feature = "tee")] + #[cfg(target_arch = "x86_64")] let snp_launcher = match tee { Tee::Snp => Some( vm.snp_secure_virt_prepare(&guest_memory) @@ -564,6 +584,7 @@ pub fn build_microvm( }; #[cfg(feature = "tee")] + #[cfg(target_arch = "x86_64")] let measured_regions = { println!("Injecting and measuring memory regions. This may take a while."); @@ -615,6 +636,50 @@ pub fn build_microvm( ] }; + #[cfg(feature = "cca")] + let measured_regions = { + let (kernel_guest_addr, kernel_size) = + if let Some(kernel_bundle) = &vm_resources.kernel_bundle { + (kernel_bundle.guest_addr, kernel_bundle.size) + } else { + return Err(StartMicrovmError::MissingKernelConfig); + }; + + let m = vec![ + MeasuredRegion { + guest_addr: kernel_guest_addr, + host_addr: guest_memory + .get_host_address(GuestAddress(kernel_guest_addr)) + .unwrap() as u64, + size: kernel_size, + populate: true, + }, + MeasuredRegion { + guest_addr: kernel_guest_addr + kernel_size as u64, + host_addr: guest_memory + .get_host_address(GuestAddress(kernel_guest_addr + kernel_size as u64)) + .unwrap() as u64, + size: vm_resources.vm_config().mem_size_mib.unwrap() << 20 - kernel_size, + populate: false, + }, + // The region used for the FDT must be populated. However, we only know the addr and the size after + // configure_system() but at that point guest_memory is already shared. For the moment, hardcore the + // fdt addr and size. + // TODO: to correct this + MeasuredRegion { + guest_addr: 0x3BFE00000, + host_addr: guest_memory + .get_host_address(GuestAddress(0x3BFE00000)) + .unwrap() as u64, + // size must be page aligned + size: 0x1000, + populate: true, + }, + ]; + + m + }; + // On x86_64 always create a serial device, // while on aarch64 only create it if 'console=' is specified in the boot args. let serial_device = if cfg!(feature = "efi") { @@ -661,7 +726,7 @@ pub fn build_microvm( Arc::new(VcpuList::new(cpu_count as u64)) }; - let vcpus; + let mut vcpus; let intc: IrqChip; // For x86_64 we need to create the interrupt controller before calling `KVM_CREATE_VCPUS` // while on aarch64 we need to do it the other way around. @@ -710,6 +775,8 @@ pub fn build_microvm( &guest_memory, payload_config.entry_addr, &exit_evt, + #[cfg(feature = "tee")] + _sender, ) .map_err(StartMicrovmError::Internal)?; @@ -811,7 +878,7 @@ pub fn build_microvm( vm_resources.console_output.clone(), )?; - #[cfg(not(any(feature = "tee", feature = "nitro")))] + #[cfg(not(any(feature = "tee", feature = "nitro", feature = "cca")))] let export_table: Option = if cfg!(feature = "gpu") { Some(Default::default()) } else { @@ -832,12 +899,12 @@ pub fn build_microvm( _sender.clone(), )?; } - #[cfg(not(any(feature = "tee", feature = "nitro")))] + #[cfg(not(any(feature = "tee", feature = "nitro", feature = "cca")))] attach_fs_devices( &mut vmm, &vm_resources.fs, &mut _shm_manager, - #[cfg(not(feature = "tee"))] + #[cfg(any(not(feature = "tee"), feature = "cca"))] export_table, intc.clone(), exit_code, @@ -881,6 +948,7 @@ pub fn build_microvm( .map_err(StartMicrovmError::Internal)?; #[cfg(feature = "tee")] + #[cfg(target_arch = "x86_64")] { match tee { Tee::Snp => { @@ -904,6 +972,52 @@ pub fn build_microvm( println!("Starting TEE/microVM."); } + // after this point guest memory and regs are not accesible anymore + #[cfg(feature = "cca")] + { + let _ = vmm + .kvm_vm() + .realm + .configure_measurement(&vmm.kvm_vm().fd(), Algo::AlgoSha256); + + vmm.kvm_vm() + .realm + .create_realm_descriptor(&vmm.kvm_vm().fd()) + .unwrap(); + + println!("Injecting and measuring memory regions. This may take a while."); + + for region in measured_regions.iter() { + if region.populate { + vmm.kvm_vm() + .realm + .populate( + &vmm.kvm_vm().fd(), + region.guest_addr, + region.size.try_into().unwrap(), + ) + .unwrap(); + } else { + vmm.kvm_vm() + .realm + .initiate( + &vmm.kvm_vm().fd(), + region.guest_addr, + region.size.try_into().unwrap(), + ) + .unwrap(); + } + } + + let features = KVM_ARM_VCPU_REC as i32; + + for vcpu in vcpus.iter_mut() { + vcpu.finalize(features).unwrap(); + } + + vmm.kvm_vm().realm.activate(&vmm.kvm_vm().fd()).unwrap(); + } + vmm.start_vcpus(vcpus) .map_err(StartMicrovmError::Internal)?; @@ -1139,6 +1253,7 @@ fn load_payload( #[cfg(test)] Payload::Empty => Ok((guest_mem, GuestAddress(0), None, None)), #[cfg(feature = "tee")] + #[cfg(target_arch = "x86_64")] Payload::Tee => { let (kernel_host_addr, kernel_guest_addr, kernel_size) = if let Some(kernel_bundle) = &_vm_resources.kernel_bundle { @@ -1319,7 +1434,28 @@ pub(crate) fn setup_vm( .map_err(StartMicrovmError::Internal)?; Ok(vm) } -#[cfg(all(target_os = "linux", feature = "tee"))] + +#[cfg(all(target_os = "linux", feature = "tee", target_arch = "aarch64"))] +pub(crate) fn setup_vm( + kvm: &KvmContext, + guest_memory: &GuestMemoryMmap, +) -> std::result::Result { + // calculate max_addr for max_ipa + // TODO: replace with QEMU way to do it + let mut vm = Vm::new( + kvm.fd(), + ((guest_memory.last_addr().raw_value()+ 1) * 2) as usize, + ) + .map_err(Error::Vm) + .map_err(StartMicrovmError::Internal)?; + + vm.memory_init(guest_memory, kvm.max_memslots()) + .map_err(Error::Vm) + .map_err(StartMicrovmError::Internal)?; + Ok(vm) +} + +#[cfg(all(target_os = "linux", feature = "tee", target_arch = "x86_64"))] pub(crate) fn setup_vm( kvm: &KvmContext, guest_memory: &GuestMemoryMmap, @@ -1512,13 +1648,16 @@ fn create_vcpus_aarch64( guest_mem: &GuestMemoryMmap, entry_addr: GuestAddress, exit_evt: &EventFd, + #[cfg(feature = "tee")] pm_sender: Sender, ) -> super::Result> { let mut vcpus = Vec::with_capacity(vcpu_config.vcpu_count as usize); for cpu_index in 0..vcpu_config.vcpu_count { - let mut vcpu = Vcpu::new_aarch64( + let mut vcpu: Vcpu = Vcpu::new_aarch64( cpu_index, vm.fd(), exit_evt.try_clone().map_err(Error::EventFd)?, + #[cfg(feature = "tee")] + pm_sender.clone(), ) .map_err(Error::Vcpu)?; @@ -1629,12 +1768,12 @@ fn attach_mmio_device( Ok(()) } -#[cfg(not(any(feature = "tee", feature = "nitro")))] +#[cfg(not(any(feature = "tee", feature = "nitro", feature = "cca")))] fn attach_fs_devices( vmm: &mut Vmm, fs_devs: &[FsDeviceConfig], shm_manager: &mut ShmManager, - #[cfg(not(feature = "tee"))] export_table: Option, + #[cfg(any(not(feature = "tee"), feature = "cca"))] export_table: Option, intc: IrqChip, exit_code: Arc, #[cfg(target_os = "macos")] map_sender: Sender, @@ -1666,7 +1805,7 @@ fn attach_fs_devices( }); } - #[cfg(not(feature = "tee"))] + #[cfg(any(not(feature = "tee"), feature = "cca"))] if let Some(export_table) = export_table.as_ref() { fs.lock().unwrap().set_export_table(export_table.clone()); } diff --git a/src/vmm/src/device_manager/shm.rs b/src/vmm/src/device_manager/shm.rs index ef26905c9..106fc457f 100644 --- a/src/vmm/src/device_manager/shm.rs +++ b/src/vmm/src/device_manager/shm.rs @@ -47,7 +47,7 @@ impl ShmManager { regions } - #[cfg(not(any(feature = "tee", feature = "nitro")))] + #[cfg(not(any(feature = "tee", feature = "nitro", feature = "cca")))] pub fn fs_region(&self, index: usize) -> Option<&ShmRegion> { self.fs_regions.get(&index) } diff --git a/src/vmm/src/linux/vstate.rs b/src/vmm/src/linux/vstate.rs index 1589deacf..929aab029 100644 --- a/src/vmm/src/linux/vstate.rs +++ b/src/vmm/src/linux/vstate.rs @@ -8,6 +8,8 @@ use crossbeam_channel::{unbounded, Receiver, Sender, TryRecvError}; use libc::{c_int, c_void, siginfo_t}; use std::cell::Cell; +#[cfg(feature = "cca")] +use std::cmp::max; use std::fmt::{Display, Formatter}; use std::io; use std::ops::Range; @@ -26,13 +28,17 @@ use super::super::{FC_EXIT_CODE_GENERIC_ERROR, FC_EXIT_CODE_OK}; use super::tee::amdsnp::{AmdSnp, Error as SnpError}; #[cfg(feature = "tee")] +#[cfg(target_arch = "x86_64")] use kbs_types::Tee; #[cfg(feature = "tee")] +#[cfg(target_arch = "x86_64")] use crate::resources::TeeConfig; use crate::vmm_config::machine_config::CpuFeaturesTemplate; #[cfg(target_arch = "x86_64")] use cpuid::{c3, filter_cpuid, t2, VmSpec}; +#[cfg(feature = "tee")] +use kvm_bindings::KVM_EXIT_MEMORY_FAULT; #[cfg(target_arch = "x86_64")] use kvm_bindings::{ kvm_clock_data, kvm_debugregs, kvm_irqchip, kvm_lapic_state, kvm_mp_state, kvm_pit_state2, @@ -49,6 +55,10 @@ use kvm_bindings::{kvm_enable_cap, KVM_CAP_EXIT_HYPERCALL, KVM_MEMORY_EXIT_FLAG_ #[cfg(not(target_arch = "riscv64"))] use kvm_bindings::{kvm_memory_attributes, KVM_MEMORY_ATTRIBUTE_PRIVATE}; use kvm_ioctls::{Cap::*, *}; + +#[cfg(feature = "cca")] +use kvm_bindings::{KVM_VM_TYPE_ARM_IPA_SIZE_MASK, KVM_VM_TYPE_ARM_REALM}; + use utils::eventfd::EventFd; use utils::signal::{register_signal_handler, sigrtmin, Killable}; use utils::sm::StateMachine; @@ -62,6 +72,9 @@ use vm_memory::{ #[cfg(feature = "amd-sev")] use sev::launch::snp; +#[cfg(feature = "cca")] +use cca::Realm; + /// Signal number (SIGRTMIN) used to kick Vcpus. pub(crate) const VCPU_RTSIG_OFFSET: i32 = 0; @@ -280,18 +293,21 @@ impl Display for Error { SetUserMemoryRegion(e) => write!(f, "Cannot set the memory regions: {e}"), ShmMmap(e) => write!(f, "Error creating memory map for SHM region: {e}"), #[cfg(feature = "tee")] + #[cfg(target_arch = "x86_64")] SnpSecVirtInit(e) => write!( f, "Error initializing the Secure Virtualization Backend (SEV): {e:?}" ), #[cfg(feature = "tee")] + #[cfg(target_arch = "x86_64")] SnpSecVirtPrepare(e) => write!( f, "Error preparing the VM for Secure Virtualization (SNP): {e:?}" ), #[cfg(feature = "tee")] + #[cfg(target_arch = "x86_64")] SnpSecVirtAttest(e) => write!(f, "Error attesting the Secure VM (SNP): {e:?}"), SignalVcpu(e) => write!(f, "Failed to signal Vcpu: {e}"), @@ -398,6 +414,8 @@ pub struct MeasuredRegion { pub guest_addr: u64, pub host_addr: u64, pub size: usize, + #[cfg(feature = "cca")] + pub populate: bool, } /// Describes a KVM context that gets attached to the microVM. @@ -469,6 +487,9 @@ pub struct Vm { pub tee_config: Tee, pub guest_memfds: Vec<(Range, RawFd)>, + + #[cfg(feature = "cca")] + pub realm: Realm, } impl Vm { @@ -497,6 +518,26 @@ impl Vm { }) } + #[cfg(feature = "cca")] + pub fn new(kvm: &Kvm, max_ipa: usize) -> Result { + //create fd for interacting with kvm-vm specific functions + let ipa_bits = max(64u32 - max_ipa.leading_zeros() - 1, 32) + 1; + let vm_fd = kvm + .create_vm_with_type( + (KVM_VM_TYPE_ARM_REALM | (ipa_bits & KVM_VM_TYPE_ARM_IPA_SIZE_MASK)).into(), + ) + .map_err(Error::VmFd)?; + + let realm = Realm::new(); + + Ok(Vm { + fd: vm_fd, + next_mem_slot: 0, + realm, + guest_memfds: Vec::new(), + }) + } + #[cfg(feature = "amd-sev")] pub fn new(kvm: &Kvm, tee_config: &TeeConfig) -> Result { //create fd for interacting with kvm-vm specific functions @@ -946,7 +987,12 @@ impl Vcpu { /// * `exit_evt` - An `EventFd` that will be written into when this vcpu exits. /// * `create_ts` - A timestamp used by the vcpu to calculate its lifetime. #[cfg(target_arch = "aarch64")] - pub fn new_aarch64(id: u8, vm_fd: &VmFd, exit_evt: EventFd) -> Result { + pub fn new_aarch64( + id: u8, + vm_fd: &VmFd, + exit_evt: EventFd, + #[cfg(feature = "tee")] pm_sender: Sender, + ) -> Result { let kvm_vcpu = vm_fd.create_vcpu(id as u64).map_err(Error::VcpuFd)?; let (event_sender, event_receiver) = unbounded(); let (response_sender, response_receiver) = unbounded(); @@ -961,6 +1007,8 @@ impl Vcpu { event_sender: Some(event_sender), response_receiver: Some(response_receiver), response_sender, + #[cfg(feature = "tee")] + pm_sender, }) } @@ -1076,6 +1124,11 @@ impl Vcpu { .map_err(Error::VcpuArmPreferredTarget)?; // We already checked that the capability is supported. kvi.features[0] |= 1 << kvm_bindings::KVM_ARM_VCPU_PSCI_0_2; + + if cfg!(feature = "cca") { + kvi.features[0] |= 1 << kvm_bindings::KVM_ARM_VCPU_REC; + } + // Non-boot cpus are powered off initially. if self.id > 0 { kvi.features[0] |= 1 << kvm_bindings::KVM_ARM_VCPU_POWER_OFF; @@ -1106,6 +1159,11 @@ impl Vcpu { ) -> Result<()> { arch::riscv64::regs::setup_regs(&self.fd, self.id, kernel_load_addr.raw_value(), guest_mem) .map_err(Error::REGSConfiguration)?; + } + + #[cfg(target_arch = "aarch64")] + pub fn finalize(&mut self, feature: i32) -> Result<()> { + let _ = self.fd.vcpu_finalize(&feature); Ok(()) } diff --git a/src/vmm/src/resources.rs b/src/vmm/src/resources.rs index 3bf32ce8d..1749f7f3e 100644 --- a/src/vmm/src/resources.rs +++ b/src/vmm/src/resources.rs @@ -4,22 +4,26 @@ //#![deny(warnings)] #[cfg(feature = "tee")] +#[cfg(target_arch = "x86_64")] use std::fs::File; #[cfg(feature = "tee")] +#[cfg(target_arch = "x86_64")] use std::io::BufReader; use std::path::PathBuf; #[cfg(feature = "tee")] +#[cfg(target_arch = "x86_64")] use serde::{Deserialize, Serialize}; #[cfg(feature = "tee")] +#[cfg(target_arch = "x86_64")] use kbs_types::Tee; #[cfg(feature = "blk")] use crate::vmm_config::block::{BlockBuilder, BlockConfigError, BlockDeviceConfig}; use crate::vmm_config::boot_source::{BootSourceConfig, BootSourceConfigError}; use crate::vmm_config::external_kernel::ExternalKernel; -#[cfg(not(feature = "tee"))] +#[cfg(any(not(feature = "tee"), feature = "cca"))] use crate::vmm_config::fs::*; #[cfg(feature = "tee")] use crate::vmm_config::kernel_bundle::{InitrdBundle, QbootBundle, QbootBundleError}; @@ -41,9 +45,11 @@ pub enum Error { BootSource(BootSourceConfigError), /// Error opening TEE config file. #[cfg(feature = "tee")] + #[cfg(target_arch = "x86_64")] OpenTeeConfig(std::io::Error), /// Error parsing TEE config file. #[cfg(feature = "tee")] + #[cfg(target_arch = "x86_64")] ParseTeeConfig(serde_json::Error), /// microVM vCpus or memory configuration error. VmConfig(VmConfigError), @@ -52,6 +58,7 @@ pub enum Error { } #[cfg(feature = "tee")] +#[cfg(target_arch = "x86_64")] #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TeeConfig { pub workload_id: String, @@ -63,6 +70,7 @@ pub struct TeeConfig { } #[cfg(feature = "tee")] +#[cfg(target_arch = "x86_64")] impl Default for TeeConfig { fn default() -> Self { Self { @@ -95,7 +103,7 @@ pub struct VmResources { #[cfg(feature = "tee")] pub initrd_bundle: Option, /// The fs device. - #[cfg(not(feature = "tee"))] + #[cfg(any(not(feature = "tee"), feature = "cca"))] pub fs: Vec, /// The vsock device. pub vsock: VsockBuilder, @@ -107,6 +115,7 @@ pub struct VmResources { pub net: NetBuilder, /// TEE configuration #[cfg(feature = "tee")] + #[cfg(target_arch = "x86_64")] pub tee_config: TeeConfig, /// Flags for the virtio-gpu device. pub gpu_virgl_flags: Option, @@ -244,7 +253,7 @@ impl VmResources { Ok(()) } - #[cfg(not(feature = "tee"))] + #[cfg(any(not(feature = "tee"), feature = "cca"))] pub fn add_fs_device(&mut self, config: FsDeviceConfig) { self.fs.push(config) } @@ -286,11 +295,13 @@ impl VmResources { } #[cfg(feature = "tee")] + #[cfg(target_arch = "x86_64")] pub fn tee_config(&self) -> &TeeConfig { &self.tee_config } #[cfg(feature = "tee")] + #[cfg(target_arch = "x86_64")] pub fn set_tee_config(&mut self, filepath: PathBuf) -> Result { let file = File::open(filepath.as_path()).map_err(Error::OpenTeeConfig)?; let reader = BufReader::new(file); diff --git a/src/vmm/src/vmm_config/mod.rs b/src/vmm/src/vmm_config/mod.rs index 9bd6dcf42..0e62308a8 100644 --- a/src/vmm/src/vmm_config/mod.rs +++ b/src/vmm/src/vmm_config/mod.rs @@ -12,7 +12,7 @@ pub mod boot_source; pub mod external_kernel; /// Wrapper for configuring the Fs devices attached to the microVM. -#[cfg(not(feature = "tee"))] +#[cfg(any(not(feature = "tee"), feature = "cca"))] pub mod fs; /// Wrapper over the microVM general information attached to the microVM.