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

TDX: Support VTL0 IOMMU posted interrupts + interrupt relay #384

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
21 changes: 21 additions & 0 deletions openhcl/hcl/src/ioctl.rs
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ mod ioctls {
const MSHV_VTL_RMPQUERY: u16 = 0x35;
const MSHV_INVLPGB: u16 = 0x36;
const MSHV_TLBSYNC: u16 = 0x37;
const MSHV_REMAP_GUEST_INTERRUPT: u16 = 0x38;

#[repr(C)]
#[derive(Copy, Clone)]
Expand Down Expand Up @@ -595,6 +596,14 @@ mod ioctls {
MSHV_IOCTL,
MSHV_TLBSYNC
);

ioctl_readwrite!(
/// Remap VTL0 device interrupt in VTL2.
hcl_remap_guest_interrupt,
MSHV_IOCTL,
MSHV_REMAP_GUEST_INTERRUPT,
u32
);
}

/// The `/dev/mshv_vtl_low` device for accessing VTL0 memory.
Expand Down Expand Up @@ -3228,4 +3237,16 @@ impl Hcl {
hcl_tlbsync(self.mshv_vtl.file.as_raw_fd()).expect("should always succeed");
}
}

/// Remap guest device interrupt vector in VTL2 kernel
pub fn remap_guest_interrupt(&self, vector: u32) -> u32 {
let mut vector = vector; // Input VTL0 guest vector, output VTL2 vector

unsafe {
hcl_remap_guest_interrupt(self.mshv_vtl.file.as_raw_fd(), &mut vector)
.expect("should always succeed");
}

vector
}
}
73 changes: 33 additions & 40 deletions openhcl/virt_mshv_vtl/src/processor/hardware_cvm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,39 @@ impl<T: CpuIo, B: HardwareIsolatedBacking> UhHypercallHandler<'_, '_, T, B> {
)
}

pub fn hcvm_retarget_interrupt(
&mut self,
device_id: u64,
address: u64,
data: u32,
vector: u32,
multicast: bool,
target_processors: ProcessorSet<'_>,
) -> HvResult<()> {
// It is unknown whether the interrupt is physical or virtual, so try both. Note that the
// actual response from the hypervisor can't really be trusted so:
// 1. Always invoke the virtual interrupt retargeting.
// 2. A failure from the physical interrupt retargeting is not necessarily a sign of a
// malicious hypervisor or a buggy guest, since the target could simply be a virtual one.
let hv_result = self.retarget_physical_interrupt(
device_id,
address,
data,
vector,
multicast,
target_processors,
);
let virtual_result = self.retarget_virtual_interrupt(
device_id,
address,
data,
vector,
multicast,
target_processors,
);
hv_result.or(virtual_result)
}

pub fn hcvm_validate_flush_inputs(
&mut self,
processor_set: ProcessorSet<'_>,
Expand Down Expand Up @@ -757,46 +790,6 @@ impl<T, B: HardwareIsolatedBacking> hv1_hypercall::GetVpRegisters
}
}

impl<T: CpuIo, B: HardwareIsolatedBacking> hv1_hypercall::RetargetDeviceInterrupt
for UhHypercallHandler<'_, '_, T, B>
{
fn retarget_interrupt(
&mut self,
device_id: u64,
address: u64,
data: u32,
params: hv1_hypercall::HvInterruptParameters<'_>,
) -> HvResult<()> {
let hv1_hypercall::HvInterruptParameters {
vector,
multicast,
target_processors,
} = params;
// It is unknown whether the interrupt is physical or virtual, so try both. Note that the
// actual response from the hypervisor can't really be trusted so:
// 1. Always invoke the virtual interrupt retargeting.
// 2. A failure from the physical interrupt retargeting is not necessarily a sign of a
// malicious hypervisor or a buggy guest, since the target could simply be a virtual one.
let hv_result = self.retarget_physical_interrupt(
device_id,
address,
data,
vector,
multicast,
target_processors,
);
let virtual_result = self.retarget_virtual_interrupt(
device_id,
address,
data,
vector,
multicast,
target_processors,
);
hv_result.or(virtual_result)
}
}

impl<'b, T, B: HardwareIsolatedBacking> hv1_hypercall::SetVpRegisters
for UhHypercallHandler<'_, 'b, T, B>
where
Expand Down
24 changes: 24 additions & 0 deletions openhcl/virt_mshv_vtl/src/processor/snp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2179,6 +2179,30 @@ impl<T: CpuIo> hv1_hypercall::EnablePartitionVtl for UhHypercallHandler<'_, '_,
}
}

impl<T: CpuIo> hv1_hypercall::RetargetDeviceInterrupt for UhHypercallHandler<'_, '_, T, SnpBacked> {
fn retarget_interrupt(
&mut self,
device_id: u64,
address: u64,
data: u32,
params: hv1_hypercall::HvInterruptParameters<'_>,
) -> hvdef::HvResult<()> {
let hv1_hypercall::HvInterruptParameters {
vector,
multicast,
target_processors,
} = params;
self.hcvm_retarget_interrupt(
device_id,
address,
data,
vector,
multicast,
target_processors,
)
}
}

impl<T: CpuIo> hv1_hypercall::VtlSwitchOps for UhHypercallHandler<'_, '_, T, SnpBacked> {
fn advance_ip(&mut self) {
let is_64bit = self.vp.long_mode(self.intercepted_vtl);
Expand Down
28 changes: 28 additions & 0 deletions openhcl/virt_mshv_vtl/src/processor/tdx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3344,6 +3344,34 @@ impl<T> HypercallIo for TdHypercall<'_, '_, T> {
}
}

impl<T: CpuIo> hv1_hypercall::RetargetDeviceInterrupt for UhHypercallHandler<'_, '_, T, TdxBacked> {
fn retarget_interrupt(
&mut self,
device_id: u64,
address: u64,
data: u32,
params: hv1_hypercall::HvInterruptParameters<'_>,
) -> hvdef::HvResult<()> {
let hv1_hypercall::HvInterruptParameters {
vector,
multicast,
target_processors,
} = params;

// Request a remapping in vtl2 for the guest device interrupt vector
let remapped_vector = self.vp.partition.hcl.remap_guest_interrupt(vector);

self.hcvm_retarget_interrupt(
device_id,
address,
data,
remapped_vector,
multicast,
target_processors,
)
}
}

impl<T: CpuIo> hv1_hypercall::FlushVirtualAddressList for UhHypercallHandler<'_, '_, T, TdxBacked> {
fn flush_virtual_address_list(
&mut self,
Expand Down