Skip to content

Commit d4362d6

Browse files
committed
Add CCA feature
This is WIP Signed-off-by: Matias Ezequiel Vara Larsen <[email protected]>
1 parent 86f75cd commit d4362d6

File tree

8 files changed

+155
-21
lines changed

8 files changed

+155
-21
lines changed

Makefile

+3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ ifeq ($(SEV),1)
2727
INIT_SRC += $(SNP_INIT_SRC)
2828
BUILD_INIT = 0
2929
endif
30+
ifeq ($(CCA), 1)
31+
FEATURE_FLAGS := --features cca
32+
endif
3033
ifeq ($(GPU),1)
3134
FEATURE_FLAGS += --features gpu
3235
endif

src/arch/src/aarch64/fdt.rs

+3
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,10 @@ fn create_psci_node(fdt: &mut FdtWriter) -> Result<()> {
285285
// Two methods available: hvc and smc.
286286
// As per documentation, PSCI calls between a guest and hypervisor may use the HVC conduit instead of SMC.
287287
// So, since we are using kvm, we need to use hvc.
288+
#[cfg(not(feature = "cca"))]
288289
fdt.property_string("method", "hvc")?;
290+
#[cfg(feature = "cca")]
291+
fdt.property_string("method", "smc")?;
289292
fdt.end_node(node)?;
290293

291294
Ok(())

src/arch/src/aarch64/linux/regs.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,10 @@ arm64_sys_reg!(MPIDR_EL1, 3, 0, 0, 0, 5);
125125
/// * `boot_ip` - Starting instruction pointer.
126126
/// * `mem` - Reserved DRAM for current VM.
127127
pub fn setup_regs(vcpu: &VcpuFd, cpu_id: u8, boot_ip: u64, mem: &GuestMemoryMmap) -> Result<()> {
128-
// Get the register index of the PSTATE (Processor State) register.
128+
// PSTATE cannot be accesed from the host in CCA
129+
#[cfg(not(feature = "cca"))]
129130
#[allow(deref_nullptr)]
131+
// Get the register index of the PSTATE (Processor State) register.
130132
vcpu.set_one_reg(arm64_core_reg!(pstate), &PSTATE_FAULT_BITS_64.to_le_bytes())
131133
.map_err(Error::SetCoreRegister)?;
132134

src/arch/src/aarch64/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ pub fn arch_memory_regions(size: usize) -> (ArchMemoryInfo, Vec<(GuestAddress, u
6969
} else {
7070
vec![
7171
(GuestAddress(layout::DRAM_MEM_START), dram_size),
72-
(GuestAddress(shm_start_addr), MMIO_SHM_SIZE as usize),
72+
//(GuestAddress(shm_start_addr), MMIO_SHM_SIZE as usize),
7373
]
7474
};
7575

src/vmm/src/builder.rs

+40-11
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33

44
//! Enables pre-boot setup, instantiation and booting of a Firecracker VMM.
55
6+
use cca::Algo;
67
#[cfg(target_os = "macos")]
78
use crossbeam_channel::{unbounded, Sender};
9+
use std::cmp::max;
810
use std::fmt::{Display, Formatter};
911
use std::fs::File;
1012
use std::io;
@@ -68,7 +70,9 @@ use vm_memory::mmap::MmapRegion;
6870
#[cfg(any(target_arch = "aarch64", feature = "tee"))]
6971
use vm_memory::Bytes;
7072
use vm_memory::GuestMemory;
71-
use vm_memory::{GuestAddress, GuestMemoryMmap};
73+
use vm_memory::{Address, GuestAddress, GuestMemoryMmap, GuestMemoryRegion};
74+
75+
use kvm_bindings::KVM_ARM_VCPU_REC;
7276

7377
#[cfg(feature = "efi")]
7478
static EDK2_BINARY: &[u8] = include_bytes!("../../../edk2/KRUN_EFI.silent.fd");
@@ -435,17 +439,18 @@ pub fn build_microvm(
435439

436440
// On x86_64 always create a serial device,
437441
// while on aarch64 only create it if 'console=' is specified in the boot args.
438-
let serial_device = if cfg!(feature = "efi") {
442+
// TODO: to comment this
443+
let serial_device = //if cfg!(feature = "efi") {
439444
Some(setup_serial_device(
440445
event_manager,
441446
None,
442-
None,
447+
//None,
443448
// Uncomment this to get EFI output when debugging EDK2.
444-
// Some(Box::new(io::stdout())),
445-
)?)
446-
} else {
447-
None
448-
};
449+
Some(Box::new(io::stdout())),
450+
)?);
451+
//} else {
452+
// None
453+
//};
449454

450455
let exit_evt = EventFd::new(utils::eventfd::EFD_NONBLOCK)
451456
.map_err(Error::EventFd)
@@ -559,7 +564,7 @@ pub fn build_microvm(
559564
)?;
560565
}
561566

562-
#[cfg(not(feature = "tee"))]
567+
#[cfg(all(not(feature = "tee"), not(feature = "cca")))]
563568
let _shm_region = Some(VirtioShmRegion {
564569
host_addr: guest_memory
565570
.get_host_address(GuestAddress(arch_memory_info.shm_start_addr))
@@ -647,6 +652,7 @@ pub fn build_microvm(
647652
#[cfg(not(feature = "tee"))]
648653
let initrd_config = None;
649654

655+
// after this point guest memory and regs are not accesible anymore
650656
vmm.configure_system(
651657
vcpus.as_slice(),
652658
&initrd_config,
@@ -809,7 +815,7 @@ fn load_cmdline(vmm: &Vmm) -> std::result::Result<(), StartMicrovmError> {
809815
.map_err(StartMicrovmError::LoadCommandline)
810816
}
811817

812-
#[cfg(all(target_os = "linux", not(feature = "tee")))]
818+
#[cfg(all(target_os = "linux", not(feature = "tee"), not(feature = "cca")))]
813819
pub(crate) fn setup_vm(
814820
guest_memory: &GuestMemoryMmap,
815821
) -> std::result::Result<Vm, StartMicrovmError> {
@@ -824,6 +830,29 @@ pub(crate) fn setup_vm(
824830
.map_err(StartMicrovmError::Internal)?;
825831
Ok(vm)
826832
}
833+
#[cfg(all(target_os = "linux", feature = "cca"))]
834+
pub(crate) fn setup_vm(
835+
guest_memory: &GuestMemoryMmap,
836+
) -> std::result::Result<Vm, StartMicrovmError> {
837+
let kvm = KvmContext::new()
838+
.map_err(Error::KvmContext)
839+
.map_err(StartMicrovmError::Internal)?;
840+
841+
// calculate max_addr for max_ipa
842+
let mut max_addr = 0;
843+
for (_index, region) in guest_memory.iter().enumerate() {
844+
max_addr = max(max_addr, region.start_addr().raw_value() + region.len() - 1);
845+
}
846+
847+
let mut vm = Vm::new(kvm.fd(), max_addr as usize)
848+
.map_err(Error::Vm)
849+
.map_err(StartMicrovmError::Internal)?;
850+
851+
vm.memory_init(guest_memory, kvm.max_memslots(), true)
852+
.map_err(Error::Vm)
853+
.map_err(StartMicrovmError::Internal)?;
854+
Ok(vm)
855+
}
827856
#[cfg(all(target_os = "linux", feature = "tee"))]
828857
pub(crate) fn setup_vm(
829858
kvm: &KvmContext,
@@ -1021,7 +1050,7 @@ fn create_vcpus_aarch64(
10211050
) -> super::Result<Vec<Vcpu>> {
10221051
let mut vcpus = Vec::with_capacity(vcpu_config.vcpu_count as usize);
10231052
for cpu_index in 0..vcpu_config.vcpu_count {
1024-
let mut vcpu = Vcpu::new_aarch64(
1053+
let mut vcpu: Vcpu = Vcpu::new_aarch64(
10251054
cpu_index,
10261055
vm.fd(),
10271056
exit_evt.try_clone().map_err(Error::EventFd)?,

src/vmm/src/lib.rs

+30
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,20 @@ use crate::vstate::{Vcpu, VcpuHandle, VcpuResponse, Vm};
5555
use arch::ArchMemoryInfo;
5656
use arch::DeviceType;
5757
use arch::InitrdConfig;
58+
use cca::Algo;
5859
#[cfg(target_os = "macos")]
5960
use crossbeam_channel::Sender;
6061
use devices::virtio::VmmExitObserver;
6162
use devices::BusDevice;
6263
use kernel::cmdline::Cmdline as KernelCmdline;
64+
use kvm_bindings::KVM_ARM_VCPU_REC;
6365
use polly::event_manager::{self, EventManager, Subscriber};
6466
use utils::epoll::{EpollEvent, EventSet};
6567
use utils::eventfd::EventFd;
68+
use vm_memory::Address;
69+
use vm_memory::GuestMemory;
6670
use vm_memory::GuestMemoryMmap;
71+
use vm_memory::GuestMemoryRegion;
6772

6873
/// Success exit code.
6974
pub const FC_EXIT_CODE_OK: u8 = 0;
@@ -299,6 +304,31 @@ impl Vmm {
299304
_smbios_oem_strings,
300305
)
301306
.map_err(Error::ConfigureSystem)?;
307+
308+
// after activation guest is not accesible anymore
309+
#[cfg(feature = "cca")]
310+
{
311+
let _ = self
312+
.vm
313+
.realm
314+
.configure_measurement(self.vm.fd(), Algo::AlgoSha256);
315+
self.vm.realm.create_realm_descriptor(self.vm.fd()).unwrap();
316+
317+
for (_index, region) in self.guest_memory.iter().enumerate() {
318+
self.vm
319+
.realm
320+
.populate(self.vm.fd(), region.start_addr().raw_value(), region.len())
321+
.unwrap();
322+
}
323+
let feature = KVM_ARM_VCPU_REC as i32;
324+
325+
// not really sure if the finalize and the activate should go here
326+
for vcpu in vcpus.iter() {
327+
vcpu.fd.vcpu_finalize(&feature).unwrap();
328+
}
329+
330+
self.vm.realm.activate(self.vm.fd()).unwrap();
331+
}
302332
}
303333

304334
#[cfg(all(target_arch = "aarch64", target_os = "macos"))]

src/vmm/src/linux/vstate.rs

+72-7
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88
use crossbeam_channel::{unbounded, Receiver, Sender, TryRecvError};
99
use libc::{c_int, c_void, siginfo_t};
1010
use std::cell::Cell;
11+
use std::cmp::max;
1112
use std::fmt::{Display, Formatter};
1213
use std::io;
1314
use std::os::fd::RawFd;
1415

1516
#[cfg(feature = "tee")]
1617
use std::os::unix::io::RawFd;
1718

19+
use kvm_ioctls::VcpuExit::Unsupported;
1820
use std::result;
1921
use std::sync::atomic::{fence, Ordering};
2022
#[cfg(not(test))]
@@ -48,8 +50,10 @@ use kvm_bindings::{
4850
KVM_MAX_CPUID_ENTRIES, KVM_PIT_SPEAKER_DUMMY,
4951
};
5052
use kvm_bindings::{
51-
kvm_create_guest_memfd, kvm_userspace_memory_region, kvm_userspace_memory_region2,
52-
KVM_API_VERSION, KVM_MEM_GUEST_MEMFD,
53+
kvm_create_guest_memfd, kvm_memory_attributes, kvm_userspace_memory_region,
54+
kvm_userspace_memory_region2, KVM_API_VERSION, KVM_MEMORY_ATTRIBUTE_PRIVATE,
55+
KVM_MEMORY_EXIT_FLAG_PRIVATE, KVM_MEM_GUEST_MEMFD, KVM_VM_TYPE_ARM_IPA_SIZE_MASK,
56+
KVM_VM_TYPE_ARM_REALM,
5357
};
5458
use kvm_ioctls::*;
5559
use utils::eventfd::EventFd;
@@ -65,6 +69,9 @@ use sev::launch::sev as sev_launch;
6569
#[cfg(feature = "amd-sev")]
6670
use sev::launch::snp;
6771

72+
#[cfg(feature = "cca")]
73+
use cca::Realm;
74+
6875
/// Signal number (SIGRTMIN) used to kick Vcpus.
6976
pub(crate) const VCPU_RTSIG_OFFSET: i32 = 0;
7077

@@ -483,11 +490,14 @@ pub struct Vm {
483490

484491
#[cfg(feature = "amd-sev")]
485492
pub tee: Tee,
493+
494+
#[cfg(feature = "cca")]
495+
pub realm: Realm,
486496
}
487497

488498
impl Vm {
489499
/// Constructs a new `Vm` using the given `Kvm` instance.
490-
#[cfg(not(feature = "tee"))]
500+
#[cfg(all(not(feature = "tee"), not(feature = "cca")))]
491501
pub fn new(kvm: &Kvm) -> Result<Self> {
492502
//create fd for interacting with kvm-vm specific functions
493503
let vm_fd = kvm.create_vm().map_err(Error::VmFd)?;
@@ -511,6 +521,26 @@ impl Vm {
511521
})
512522
}
513523

524+
#[cfg(feature = "cca")]
525+
pub fn new(kvm: &Kvm, max_ipa: usize) -> Result<Self> {
526+
//create fd for interacting with kvm-vm specific functions
527+
let ipa_bits = max(64u32 - max_ipa.leading_zeros() - 1, 32) + 1;
528+
let vm_fd = kvm
529+
.create_vm_with_type(
530+
(KVM_VM_TYPE_ARM_REALM | (ipa_bits & KVM_VM_TYPE_ARM_IPA_SIZE_MASK)).into(),
531+
)
532+
.map_err(Error::VmFd)?;
533+
534+
let realm = Realm::new().unwrap();
535+
536+
Ok(Vm {
537+
fd: vm_fd,
538+
#[cfg(target_arch = "aarch64")]
539+
irqchip_handle: None,
540+
realm,
541+
})
542+
}
543+
514544
#[cfg(feature = "amd-sev")]
515545
pub fn new(kvm: &Kvm, tee_config: &TeeConfig) -> Result<Self> {
516546
//create fd for interacting with kvm-vm specific functions
@@ -581,7 +611,7 @@ impl Vm {
581611
.create_guest_memfd(gmem)
582612
.map_err(Error::CreateGuestMemfd)?;
583613

584-
let memory_region = kvm_userspace_memory_region2 {
614+
let memory_region: kvm_userspace_memory_region2 = kvm_userspace_memory_region2 {
585615
slot: index as u32,
586616
flags: KVM_MEM_GUEST_MEMFD,
587617
guest_phys_addr: region.start_addr().raw_value(),
@@ -600,6 +630,17 @@ impl Vm {
600630
.set_user_memory_region2(memory_region)
601631
.map_err(Error::SetUserMemoryRegion2)?;
602632
};
633+
634+
// set private by default when using guestmemfd
635+
// this imitates QEMU behavior
636+
let attr = kvm_memory_attributes {
637+
address: region.start_addr().raw_value(),
638+
size: region.len(),
639+
attributes: KVM_MEMORY_ATTRIBUTE_PRIVATE as u64,
640+
flags: 0,
641+
};
642+
643+
self.fd.set_memory_attributes(attr).unwrap();
603644
} else {
604645
let memory_region = kvm_userspace_memory_region {
605646
slot: index as u32,
@@ -808,7 +849,7 @@ type VcpuCell = Cell<Option<*mut Vcpu>>;
808849

809850
/// A wrapper around creating and using a kvm-based VCPU.
810851
pub struct Vcpu {
811-
fd: VcpuFd,
852+
pub fd: VcpuFd,
812853
id: u8,
813854
mmio_bus: Option<devices::Bus>,
814855
#[allow(dead_code)]
@@ -1267,19 +1308,39 @@ impl Vcpu {
12671308
info!("Received KVM_EXIT_SHUTDOWN signal");
12681309
Ok(VcpuEmulation::Stopped)
12691310
}
1311+
VcpuExit::MemoryFault {
1312+
flags,
1313+
gpa: _,
1314+
size: _,
1315+
} => {
1316+
// TODO: flags can be private or shared
1317+
if flags & !KVM_MEMORY_EXIT_FLAG_PRIVATE as u64 != 0 {
1318+
error!("KVM_EXIT_MEMORY_FAULT: Unknown flag {}", flags);
1319+
Err(Error::VcpuUnhandledKvmExit)
1320+
} else {
1321+
// TODO: to transition from shared to private
1322+
Ok(VcpuEmulation::Handled)
1323+
}
1324+
}
12701325
// Documentation specifies that below kvm exits are considered
12711326
// errors.
12721327
VcpuExit::FailEntry(reason, vcpu) => {
12731328
error!("Received KVM_EXIT_FAIL_ENTRY signal: reason={reason}, vcpu={vcpu}");
12741329
Err(Error::VcpuUnhandledKvmExit)
12751330
}
1331+
// TODO: to remove this
1332+
Unsupported(39) => {
1333+
println!("memory fault!");
1334+
Ok(VcpuEmulation::Handled)
1335+
}
12761336
VcpuExit::InternalError => {
12771337
error!("Received KVM_EXIT_INTERNAL_ERROR signal");
12781338
Err(Error::VcpuUnhandledKvmExit)
12791339
}
12801340
r => {
12811341
// TODO: Are we sure we want to finish running a vcpu upon
12821342
// receiving a vm exit that is not necessarily an error?
1343+
println!("error! {:?}", r);
12831344
error!("Unexpected exit reason on vcpu run: {:?}", r);
12841345
Err(Error::VcpuUnhandledKvmExit)
12851346
}
@@ -1605,7 +1666,9 @@ mod tests {
16051666

16061667
// Create valid memory region and test that the initialization is successful.
16071668
let gm = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap();
1608-
assert!(vm.memory_init(&gm, kvm_context.max_memslots(), false).is_ok());
1669+
assert!(vm
1670+
.memory_init(&gm, kvm_context.max_memslots(), false)
1671+
.is_ok());
16091672

16101673
// Set the maximum number of memory slots to 1 in KvmContext to check the error
16111674
// path of memory_init. Create 2 non-overlapping memory slots.
@@ -1615,7 +1678,9 @@ mod tests {
16151678
(GuestAddress(0x1001), 0x2000),
16161679
])
16171680
.unwrap();
1618-
assert!(vm.memory_init(&gm, kvm_context.max_memslots(), false).is_err());
1681+
assert!(vm
1682+
.memory_init(&gm, kvm_context.max_memslots(), false)
1683+
.is_err());
16191684
}
16201685

16211686
#[cfg(target_arch = "x86_64")]

src/vmm/src/vmm_config/boot_source.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ use std::fmt::{Display, Formatter, Result};
1616
//pub const DEFAULT_KERNEL_CMDLINE: &str = "reboot=k panic=1 pci=off nomodule 8250.nr_uarts=0 \
1717
// i8042.noaux i8042.nomux i8042.nopnp i8042.dumbkbd";
1818

19+
// TODO: to unchange this
1920
#[cfg(all(target_os = "linux", not(feature = "tee")))]
20-
pub const DEFAULT_KERNEL_CMDLINE: &str = "reboot=k panic=-1 panic_print=0 nomodule console=hvc0 \
21+
pub const DEFAULT_KERNEL_CMDLINE: &str =
22+
"reboot=k panic=-1 panic_print=0 nomodule console=pl011,mmio,0x40001000 \
2123
rootfstype=virtiofs rw quiet no-kvmapf";
2224

2325
#[cfg(feature = "amd-sev")]

0 commit comments

Comments
 (0)