Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for arm cca #211

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 ($(GPU),1)
FEATURE_FLAGS += --features gpu
endif
Expand Down
6 changes: 4 additions & 2 deletions src/arch/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ authors = ["The Chromium OS Authors"]
edition = "2021"

[features]
default = ["cca"]
cca = []
Comment on lines +8 to +9
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't make cca the default here. IMO, it should follow suit with the others

Suggested change
default = ["cca"]
cca = []
cca = ["tee"]

Copy link
Collaborator Author

@MatiasVara MatiasVara Mar 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, when I compile with cca flag:

cargo build --release --features cca

The tee feature would be enabled. However, most of the code for tee is not required and I ended up doing this everywhere:

-    #[cfg(feature = "tee")]
+    #[cfg(all(feature = "tee", not(feature = "cca")))]
     let qboot_bundle = vm_resources
         .qboot_bundle()
         .ok_or(StartMicrovmError::MissingKernelConfig)?;

Can't cca be just a different feature?

tee = []
amd-sev = [ "tee" ]
efi = []
Expand All @@ -18,8 +20,8 @@ smbios = { path = "../smbios" }
utils = { path = "../utils" }

[target.'cfg(target_os = "linux")'.dependencies]
kvm-bindings = { version = ">=0.8", features = ["fam-wrappers"] }
kvm-ioctls = ">=0.17"
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" }
Comment on lines +23 to +24
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make a PR once these branches are ready? I'd like to have the deps be on the main branch

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean to use the main branch rather than the cca?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly. I'm going to have to make some changes for my TDX work, so I think we'll need to merge your CCA work and my TDX work into the main branch and then use that here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tylerfanelli Do you think we can merge the cca branches into main for kvm-ioctl/bindings repos? Or, shall we have one branch per flavor? Bear in mind that those repo are temporal until changes are upstreamed.


[target.'cfg(target_arch = "aarch64")'.dependencies]
vm-fdt = ">= 0.2.0"
Expand Down
3 changes: 3 additions & 0 deletions src/arch/src/aarch64/fdt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,10 @@ 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(not(feature = "cca"))]
fdt.property_string("method", "hvc")?;
#[cfg(feature = "cca")]
fdt.property_string("method", "smc")?;
fdt.end_node(node)?;

Ok(())
Expand Down
4 changes: 3 additions & 1 deletion src/arch/src/aarch64/linux/regs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,10 @@ 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<()> {
// Get the register index of the PSTATE (Processor State) register.
// 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)?;

Expand Down
4 changes: 2 additions & 2 deletions src/cpuid/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ edition = "2021"
vmm-sys-util = ">=0.11"

[target.'cfg(target_os = "linux")'.dependencies]
kvm-bindings = { version = ">=0.8", features = ["fam-wrappers"] }
kvm-ioctls = ">=0.17"
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" }
Comment on lines +11 to +12
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment here

2 changes: 2 additions & 0 deletions src/devices/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ authors = ["The Chromium OS Authors"]
edition = "2021"

[features]
default = ["cca"]
tee = []
cca = []
Comment on lines +8 to +10
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
default = ["cca"]
tee = []
cca = []
cca = ["tee"]

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I not leave tee =[] here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should. I think that was a suggestion error. I was trying to suggest just getting rid of default = ...

amd-sev = ["blk", "tee"]
net = []
blk = []
Expand Down
15 changes: 12 additions & 3 deletions src/devices/src/virtio/console/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,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 << uapi::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)]
Expand Down
1 change: 1 addition & 0 deletions src/devices/src/virtio/console/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ mod defs {
pub const VIRTIO_CONSOLE_F_MULTIPORT: u32 = 1;
pub const VIRTIO_F_VERSION_1: u32 = 32;
pub const VIRTIO_ID_CONSOLE: u32 = 3;
pub const VIRTIO_F_ACCESS_PLATFORM: u32 = 33;
}

#[allow(dead_code)]
Expand Down
13 changes: 11 additions & 2 deletions src/devices/src/virtio/fs/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ use std::thread::JoinHandle;
#[cfg(target_os = "macos")]
use hvf::MemoryMapping;
use utils::eventfd::{EventFd, EFD_NONBLOCK};
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::{
Expand Down Expand Up @@ -70,7 +73,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();
Expand Down
7 changes: 6 additions & 1 deletion src/devices/src/virtio/rng/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,17 @@ use super::super::{
use super::{defs, defs::uapi};
use crate::legacy::GicV3;
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)]
Expand Down
2 changes: 2 additions & 0 deletions src/libkrun/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ snd = []
virgl_resource_map2 = []

[dependencies]
vm-memory = { version = ">=0.13", features = ["backend-mmap"] }
crossbeam-channel = "0.5"
env_logger = "0.9.0"
libc = ">=0.2.39"
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" }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment here

devices = { path = "../devices" }
polly = { path = "../polly" }
utils = { path = "../utils" }
Expand Down
68 changes: 68 additions & 0 deletions src/libkrun/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
#[macro_use]
extern crate log;

use crossbeam_channel::unbounded;
use kvm_bindings::kvm_memory_attributes;
use libc::fallocate;
use libc::madvise;
use libc::FALLOC_FL_KEEP_SIZE;
use libc::FALLOC_FL_PUNCH_HOLE;
use libc::MADV_DONTNEED;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::convert::TryInto;
Expand All @@ -11,10 +18,13 @@ use std::ffi::CString;
#[cfg(target_os = "linux")]
use std::os::fd::AsRawFd;
use std::os::fd::RawFd;
use std::os::raw::c_void;
use std::path::PathBuf;
use std::slice;
use std::sync::atomic::{AtomicI32, Ordering};
use std::sync::Mutex;
use vm_memory::GuestMemoryRegion;
use vm_memory::{Address, GuestMemory};

#[cfg(target_os = "macos")]
use crossbeam_channel::unbounded;
Expand Down Expand Up @@ -1225,9 +1235,12 @@ pub extern "C" fn krun_start_enter(ctx_id: u32) -> i32 {
#[cfg(target_os = "macos")]
let (sender, receiver) = unbounded();

let (io_sender, receiver) = unbounded();

let _vmm = match vmm::builder::build_microvm(
&ctx_cfg.vmr,
&mut event_manager,
io_sender,
ctx_cfg.shutdown_efd,
Comment on lines +1238 to 1244
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm struggling with the design of this. As is, this would be forcing all flavors of libkrun to have a separate thread waiting to convert memory regions. This should be conditional upon the cca feature.

I need to do something similar for the TDX implementation, and I couldn't have a function signature like

vmm::builder::build_microvm(
    &ctx_cfg.vmr,
    &mut event_manager
    #[cfg(feature = "cca")]
    io_sender,
    ctx_cfg.shutdown_efd,
    #[cfg(target_os = "macos")]
    sender,
)

I'm not sure what the best way to do this is. Maybe make sender something along the lines of Option<Sender<T>>? Maybe there's something more "rusty" that would work too...

Copy link
Collaborator Author

@MatiasVara MatiasVara Feb 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure about the design either. I do not like that all flavors spawn an extra thread so I will change that. Why couldn't you have a function signature as you proposed?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC cargo complained about it. I don't remember the exact reason. It very well could have been user error

#[cfg(target_os = "macos")]
sender,
Expand All @@ -1242,6 +1255,61 @@ pub extern "C" fn krun_start_enter(ctx_id: u32) -> i32 {
#[cfg(target_os = "macos")]
let mapper_vmm = _vmm.clone();

let vm = _vmm.lock().unwrap().kvm_vm().fd.clone();
let guest_mem = _vmm.lock().unwrap().guest_memory().clone();
let guest_memfd = _vmm.lock().unwrap().guest_memfd_vec.clone();

std::thread::spawn(move || loop {
match receiver.recv() {
Err(e) => error!("Error in receiver: {:?}", e),
Ok(m) => {
let _ret = vm
.lock()
.unwrap()
.set_memory_attributes(kvm_memory_attributes {
address: m.addr,
size: m.size,
attributes: m.attributes as u64,
flags: 0,
});

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we do this instead of looping through the regions?

Suggested change
let region = guest_mem.find_region(GuestAddress(m.addr));
if let None = region {
// error because we couldn't find the associated region
}
let offset = ...
if m.attributes == 0 {
fallocate()
} else {
let host_start = ...
madvise()
}

// from private to shared
if m.attributes == 0 {
for (index, region) in guest_mem.iter().enumerate() {
// this supposes that m.addr + m.size < region.start + region.size
// which may be false
if (region.start_addr().raw_value() + region.size() as u64) > m.addr {
let offset = m.addr - region.start_addr().raw_value();
unsafe {
let _ret = fallocate(
*guest_memfd.get(index).unwrap(),
Comment on lines +1284 to +1285
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should check the return value of _ret

FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
offset as i64,
m.size as i64,
);
}
}
}
// from shared to private
} else {
for (_index, region) in guest_mem.iter().enumerate() {
if (region.start_addr().raw_value() + region.size() as u64) > m.addr {
let offset = m.addr - region.start_addr().raw_value();
let host_startaddr = m.addr + offset;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this based on QEMU's ram_block_discard_range? In QEMU I think this uses the actual host address, if I'm not mistaken. Should this be region.get_host_address(MemoryRegionAddress(m.addr + offset))?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is based on ram_block_discard_range(). You are right, it should use actual host address. Thanks.

unsafe {
let _ret = madvise(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should check the return value of _ret here too

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. How do I handle the error in this case?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know how to handle this off the top of my head, but at the very least I think we should probably check if the ret value is < 0 and then log the error

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I will check for that condition.

host_startaddr as *mut c_void,
m.size.try_into().unwrap(),
MADV_DONTNEED,
);
}
}
}
}
}
}
});

#[cfg(target_os = "macos")]
std::thread::Builder::new()
.name("mapping worker".into())
Expand Down
8 changes: 6 additions & 2 deletions src/vmm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ authors = ["Amazon Firecracker team <[email protected]>"]
edition = "2021"

[features]
default = ["cca"]
tee = []
amd-sev = [ "blk", "tee", "codicon", "kbs-types", "procfs", "rdrand", "serde", "serde_json", "sev", "curl" ]
cca = []
Comment on lines +8 to +11
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
default = ["cca"]
tee = []
amd-sev = [ "blk", "tee", "codicon", "kbs-types", "procfs", "rdrand", "serde", "serde_json", "sev", "curl" ]
cca = []
tee = []
amd-sev = [ "blk", "tee", "codicon", "kbs-types", "procfs", "rdrand", "serde", "serde_json", "sev", "curl" ]
cca = [ "tee" ]

net = []
blk = []
efi = [ "blk", "net" ]
Expand Down Expand Up @@ -37,12 +39,14 @@ sev = { version = "4.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]
cpuid = { path = "../cpuid" }

[target.'cfg(target_os = "linux")'.dependencies]
kvm-bindings = { version = ">=0.10", features = ["fam-wrappers"] }
kvm-ioctls = ">=0.17"
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" }
Comment on lines +48 to +49
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same branch comment


[target.'cfg(target_os = "macos")'.dependencies]
hvf = { path = "../hvf" }
Expand Down
Loading
Loading