Skip to content

Commit c2b6211

Browse files
MatiasVaratylerfanelli
authored andcommitted
Add support for KVM_EXIT_MEMORY_FAULT
The KVM_EXIT_MEMORY_FAULT vmexit is triggered when guest wants to switch a region of memory from private to shared and viceversa. To support this when tee is enabled, add an extra thread named sender_io that gets the parameters from the vcpu thread and triggers the set_memory_properties(). The vcpu fd is owned only by this thread. Signed-off-by: Matias Ezequiel Vara Larsen <[email protected]>
1 parent e2d88fa commit c2b6211

File tree

2 files changed

+70
-11
lines changed

2 files changed

+70
-11
lines changed

src/vmm/src/builder.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
//! Enables pre-boot setup, instantiation and booting of a Firecracker VMM.
55
6+
#[cfg(feature = "tee")]
7+
use crate::vstate::MemProperties;
68
#[cfg(target_os = "macos")]
79
use crossbeam_channel::unbounded;
810

@@ -697,6 +699,8 @@ pub fn build_microvm(
697699
&guest_memory,
698700
payload_config.entry_addr,
699701
&exit_evt,
702+
#[cfg(feature = "tee")]
703+
io_sender,
700704
)
701705
.map_err(StartMicrovmError::Internal)?;
702706

@@ -1464,13 +1468,16 @@ fn create_vcpus_aarch64(
14641468
guest_mem: &GuestMemoryMmap,
14651469
entry_addr: GuestAddress,
14661470
exit_evt: &EventFd,
1471+
#[cfg(feature = "tee")] sender_io: Sender<MemProperties>,
14671472
) -> super::Result<Vec<Vcpu>> {
14681473
let mut vcpus = Vec::with_capacity(vcpu_config.vcpu_count as usize);
14691474
for cpu_index in 0..vcpu_config.vcpu_count {
14701475
let mut vcpu = Vcpu::new_aarch64(
14711476
cpu_index,
14721477
vm.fd(),
14731478
exit_evt.try_clone().map_err(Error::EventFd)?,
1479+
#[cfg(feature = "tee")]
1480+
sender_io.clone(),
14741481
)
14751482
.map_err(Error::Vcpu)?;
14761483

src/vmm/src/linux/vstate.rs

Lines changed: 63 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ use std::io;
1313

1414
use std::os::unix::io::RawFd;
1515

16+
#[cfg(feature = "tee")]
17+
use kvm_ioctls::VcpuExit::Unsupported;
18+
19+
use std::sync::Arc;
20+
use std::sync::Mutex;
21+
1622
use std::result;
1723
use std::sync::atomic::{fence, Ordering};
1824
#[cfg(not(test))]
@@ -39,14 +45,14 @@ use kvm_bindings::{
3945
KVM_CLOCK_TSC_STABLE, KVM_IRQCHIP_IOAPIC, KVM_IRQCHIP_PIC_MASTER, KVM_IRQCHIP_PIC_SLAVE,
4046
KVM_MAX_CPUID_ENTRIES,
4147
};
48+
#[cfg(feature = "tee")]
4249
use kvm_bindings::{
43-
kvm_create_guest_memfd, kvm_memory_attributes, kvm_userspace_memory_region,
44-
kvm_userspace_memory_region2, KVM_API_VERSION, KVM_MEMORY_ATTRIBUTE_PRIVATE,
45-
KVM_MEM_GUEST_MEMFD,
50+
kvm_create_guest_memfd, kvm_memory_attributes, kvm_userspace_memory_region2, KVM_API_VERSION,
51+
KVM_MEMORY_ATTRIBUTE_PRIVATE, KVM_MEMORY_EXIT_FLAG_PRIVATE, KVM_MEM_GUEST_MEMFD, KVM_EXIT_MEMORY_FAULT
4652
};
47-
#[cfg(feature = "tee")]
48-
use kvm_bindings::{kvm_enable_cap, KVM_CAP_EXIT_HYPERCALL};
49-
use kvm_ioctls::{Cap::*, *};
53+
#[cfg(not(feature = "tee"))]
54+
use kvm_bindings::{kvm_userspace_memory_region, KVM_API_VERSION};
55+
use kvm_ioctls::*;
5056
use utils::eventfd::EventFd;
5157
use utils::signal::{register_signal_handler, sigrtmin, Killable};
5258
use utils::sm::StateMachine;
@@ -771,6 +777,13 @@ pub struct VcpuConfig {
771777
pub cpu_template: Option<CpuFeaturesTemplate>,
772778
}
773779

780+
#[cfg(feature = "tee")]
781+
pub struct MemProperties {
782+
pub addr: u64,
783+
pub size: u64,
784+
pub attributes: u32,
785+
}
786+
774787
// Using this for easier explicit type-casting to help IDEs interpret the code.
775788
type VcpuCell = Cell<Option<*mut Vcpu>>;
776789

@@ -793,6 +806,10 @@ pub struct Vcpu {
793806
#[cfg(target_arch = "aarch64")]
794807
mpidr: u64,
795808

809+
// The transmitting end of the events channel which will be given to the vcpu side
810+
#[cfg(feature = "tee")]
811+
sender_io: Sender<MemProperties>,
812+
796813
// The receiving end of events channel owned by the vcpu side.
797814
event_receiver: Receiver<VcpuEvent>,
798815
// The transmitting end of the events channel which will be given to the handler.
@@ -940,7 +957,12 @@ impl Vcpu {
940957
/// * `exit_evt` - An `EventFd` that will be written into when this vcpu exits.
941958
/// * `create_ts` - A timestamp used by the vcpu to calculate its lifetime.
942959
#[cfg(target_arch = "aarch64")]
943-
pub fn new_aarch64(id: u8, vm_fd: &VmFd, exit_evt: EventFd) -> Result<Self> {
960+
pub fn new_aarch64(
961+
id: u8,
962+
vm_fd: &VmFd,
963+
exit_evt: EventFd,
964+
#[cfg(feature = "tee")] sender_io: Sender<MemProperties>,
965+
) -> Result<Self> {
944966
let kvm_vcpu = vm_fd.create_vcpu(id as u64).map_err(Error::VcpuFd)?;
945967
let (event_sender, event_receiver) = unbounded();
946968
let (response_sender, response_receiver) = unbounded();
@@ -955,6 +977,8 @@ impl Vcpu {
955977
event_sender: Some(event_sender),
956978
response_receiver: Some(response_receiver),
957979
response_sender,
980+
#[cfg(feature = "tee")]
981+
sender_io,
958982
})
959983
}
960984

@@ -1266,16 +1290,44 @@ impl Vcpu {
12661290
info!("Received KVM_EXIT_SHUTDOWN signal");
12671291
Ok(VcpuEmulation::Stopped)
12681292
}
1293+
#[cfg(feature = "tee")]
1294+
VcpuExit::MemoryFault { flags, gpa, size } => {
1295+
if flags & !KVM_MEMORY_EXIT_FLAG_PRIVATE as u64 != 0 {
1296+
error!("KVM_EXIT_MEMORY_FAULT: Unknown flag {}", flags);
1297+
Err(Error::VcpuUnhandledKvmExit)
1298+
} else {
1299+
// from private to shared
1300+
let mut attr = 0;
1301+
// from shared to private
1302+
if flags & KVM_MEMORY_EXIT_FLAG_PRIVATE as u64
1303+
== KVM_MEMORY_EXIT_FLAG_PRIVATE as u64
1304+
{
1305+
attr = KVM_MEMORY_ATTRIBUTE_PRIVATE;
1306+
};
1307+
1308+
let _ = self.sender_io.try_send(MemProperties {
1309+
addr: gpa,
1310+
size,
1311+
attributes: attr,
1312+
});
1313+
Ok(VcpuEmulation::Handled)
1314+
}
1315+
}
1316+
// Documentation specifices that when KVM exists with KVM_EXIT_MEMORY_FAULT,
1317+
// userspace should assume kvm_run.exit_reason is stale/undefined for error numbers
1318+
// different than EFAULT or EHWPOISON
1319+
#[cfg(feature = "tee")]
1320+
Unsupported(KVM_EXIT_MEMORY_FAULT) => Ok(VcpuEmulation::Handled),
1321+
VcpuExit::InternalError => {
1322+
error!("Received KVM_EXIT_INTERNAL_ERROR signal");
1323+
Err(Error::VcpuUnhandledKvmExit)
1324+
}
12691325
// Documentation specifies that below kvm exits are considered
12701326
// errors.
12711327
VcpuExit::FailEntry(reason, vcpu) => {
12721328
error!("Received KVM_EXIT_FAIL_ENTRY signal: reason={reason}, vcpu={vcpu}");
12731329
Err(Error::VcpuUnhandledKvmExit)
12741330
}
1275-
VcpuExit::InternalError => {
1276-
error!("Received KVM_EXIT_INTERNAL_ERROR signal");
1277-
Err(Error::VcpuUnhandledKvmExit)
1278-
}
12791331
r => {
12801332
// TODO: Are we sure we want to finish running a vcpu upon
12811333
// receiving a vm exit that is not necessarily an error?

0 commit comments

Comments
 (0)