Skip to content

Commit 4ead4cf

Browse files
committed
secure avic support
1 parent adfa49a commit 4ead4cf

File tree

19 files changed

+632
-51
lines changed

19 files changed

+632
-51
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9648,6 +9648,7 @@ dependencies = [
96489648
"arbitrary",
96499649
"bitfield-struct 0.10.1",
96509650
"open_enum",
9651+
"static_assertions",
96519652
"zerocopy 0.8.24",
96529653
]
96539654

openhcl/hcl/src/ioctl.rs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,10 @@ use std::sync::atomic::Ordering;
7878
use thiserror::Error;
7979
use user_driver::DmaClient;
8080
use user_driver::memory::MemoryBlock;
81+
use x86defs::snp::SevAvicPage;
8182
use x86defs::snp::SevVmsa;
8283
use x86defs::tdx::TdCallResultCode;
83-
use x86defs::vmx::ApicPage;
84+
use x86defs::vmx::VmxApicPage;
8485
use zerocopy::FromBytes;
8586
use zerocopy::FromZeros;
8687
use zerocopy::Immutable;
@@ -386,6 +387,7 @@ mod ioctls {
386387
const MSHV_VTL_RMPQUERY: u16 = 0x35;
387388
const MSHV_INVLPGB: u16 = 0x36;
388389
const MSHV_TLBSYNC: u16 = 0x37;
390+
const MSHV_VTL_SECURE_AVIC_VTL0_PFN: u16 = 0x38;
389391

390392
#[repr(C)]
391393
#[derive(Copy, Clone)]
@@ -563,6 +565,13 @@ mod ioctls {
563565
u64
564566
);
565567

568+
ioctl_readwrite!(
569+
hcl_read_secure_avic_vtl0_pfn,
570+
MSHV_IOCTL,
571+
MSHV_VTL_SECURE_AVIC_VTL0_PFN,
572+
u64
573+
);
574+
566575
pub const HCL_CAP_REGISTER_PAGE: u32 = 1;
567576
pub const HCL_CAP_VTL_RETURN_ACTION: u32 = 2;
568577
pub const HCL_CAP_DR6_SHARED: u32 = 3;
@@ -1556,9 +1565,12 @@ enum BackingState {
15561565
},
15571566
Snp {
15581567
vmsa: VtlArray<MappedPage<SevVmsa>, 2>,
1568+
vtl0_apic_page: MappedPage<SevAvicPage>,
1569+
/// VTL1 runs with the alternate interrupt injection.
1570+
vtl1_apic_page: MemoryBlock,
15591571
},
15601572
Tdx {
1561-
vtl0_apic_page: MappedPage<ApicPage>,
1573+
vtl0_apic_page: MappedPage<VmxApicPage>,
15621574
vtl1_apic_page: MemoryBlock,
15631575
},
15641576
}
@@ -1622,6 +1634,12 @@ impl HclVp {
16221634
.map_err(|e| Error::MmapVp(e, Some(Vtl::Vtl1)))?;
16231635
BackingState::Snp {
16241636
vmsa: [vmsa_vtl0, vmsa_vtl1].into(),
1637+
vtl0_apic_page: MappedPage::new(fd, MSHV_APIC_PAGE_OFFSET | vp as i64)
1638+
.map_err(|e| Error::MmapVp(e, Some(Vtl::Vtl0)))?,
1639+
vtl1_apic_page: private_dma_client
1640+
.ok_or(Error::MissingPrivateMemory)?
1641+
.allocate_dma_buffer(HV_PAGE_SIZE as usize)
1642+
.map_err(Error::AllocVp)?,
16251643
}
16261644
}
16271645
IsolationType::Tdx => BackingState::Tdx {
@@ -2134,6 +2152,8 @@ impl<'a, T: Backing<'a>> ProcessorRunner<'a, T> {
21342152
| HvX64RegisterName::VsmVpSecureConfigVtl0
21352153
| HvX64RegisterName::VsmVpSecureConfigVtl1
21362154
| HvX64RegisterName::CrInterceptControl
2155+
| HvX64RegisterName::SevAvicGpa
2156+
| HvX64RegisterName::GuestVsmPartitionConfig
21372157
)
21382158
));
21392159
self.set_vp_registers_hvcall_inner(vtl, &registers)
@@ -3059,6 +3079,21 @@ impl Hcl {
30593079
vp_pfn
30603080
}
30613081

3082+
/// Gets the PFN for the VTL 0 secure AVIC
3083+
pub fn secure_avic_vtl0_pfn(&self, cpu_index: u32) -> u64 {
3084+
let mut savic_pfn = cpu_index as u64; // input vp, output pfn
3085+
3086+
// SAFETY: The ioctl requires no prerequisites other than the Secure AVIC VTL 0
3087+
// should be mapped. This ioctl should never fail as long as the VTL 0
3088+
// Secure AVIC was mapped.
3089+
unsafe {
3090+
hcl_read_secure_avic_vtl0_pfn(self.mshv_vtl.file.as_raw_fd(), &mut savic_pfn)
3091+
.expect("should always succeed");
3092+
}
3093+
3094+
savic_pfn
3095+
}
3096+
30623097
/// Returns the isolation type for the partition.
30633098
pub fn isolation(&self) -> IsolationType {
30643099
self.isolation

openhcl/hcl/src/ioctl/snp.rs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@ use sidecar_client::SidecarVp;
2525
use std::cell::UnsafeCell;
2626
use std::os::fd::AsRawFd;
2727
use thiserror::Error;
28+
use x86defs::snp::SevAvicPage;
2829
use x86defs::snp::SevRmpAdjust;
2930
use x86defs::snp::SevVmsa;
3031

3132
/// Runner backing for SNP partitions.
3233
pub struct Snp<'a> {
3334
vmsa: VtlArray<&'a UnsafeCell<SevVmsa>, 2>,
35+
avic_pages: VtlArray<&'a UnsafeCell<SevAvicPage>, 2>,
3436
}
3537

3638
/// Error returned by failing SNP operations.
@@ -176,11 +178,21 @@ impl MshvVtl {
176178
impl<'a> super::private::BackingPrivate<'a> for Snp<'a> {
177179
fn new(vp: &'a HclVp, sidecar: Option<&SidecarVp<'_>>, _hcl: &Hcl) -> Result<Self, NoRunner> {
178180
assert!(sidecar.is_none());
179-
let super::BackingState::Snp { vmsa } = &vp.backing else {
181+
let super::BackingState::Snp {
182+
vtl0_apic_page,
183+
vtl1_apic_page,
184+
vmsa,
185+
} = &vp.backing
186+
else {
180187
return Err(NoRunner::MismatchedIsolation);
181188
};
182189

190+
// SAFETY: The mapping is held for the appropriate lifetime, and the
191+
// APIC page is never accessed as any other type, or by any other location.
192+
let vtl1_apic_page = unsafe { &*vtl1_apic_page.base().cast() };
193+
183194
Ok(Self {
195+
avic_pages: [vtl0_apic_page.as_ref(), vtl1_apic_page].into(),
184196
vmsa: vmsa.each_ref().map(|mp| mp.as_ref()),
185197
})
186198
}
@@ -242,4 +254,37 @@ impl<'a> ProcessorRunner<'a, Snp<'a>> {
242254
})
243255
.into_inner()
244256
}
257+
258+
/// Gets a PFN of the VTL0 secure AVIC page.
259+
/// TODO: Maybe there is a better way other than passing `cpu_index`` here.
260+
pub fn secure_avic_vtl0_pfn(&self, cpu_index: u32) -> u64 {
261+
self.hcl.secure_avic_vtl0_pfn(cpu_index)
262+
}
263+
264+
/// Gets a reference to the secure AVIC page for the given VTL.
265+
pub fn secure_avic_page(&self, vtl: GuestVtl) -> &SevAvicPage {
266+
// SAFETY: the APIC pages will not be concurrently accessed by the processor
267+
// while this VP is in VTL2.
268+
unsafe { &*self.state.avic_pages[vtl].get() }
269+
}
270+
271+
/// Gets a mutable reference to the secure AVIC page for the given VTL.
272+
pub fn secure_avic_page_mut(&mut self, vtl: GuestVtl) -> &mut SevAvicPage {
273+
// SAFETY: the AVIC pages will not be concurrently accessed by the processor
274+
// while this VP is in VTL2.
275+
unsafe { &mut *self.state.avic_pages[vtl].get() }
276+
}
277+
278+
/// Gets a mutable reference to the secure AVIC page for the given VTL.
279+
pub fn secure_avic_page_vmsa_mut(
280+
&mut self,
281+
vtl: GuestVtl,
282+
) -> (&mut SevAvicPage, VmsaWrapper<'_, &mut SevVmsa>) {
283+
// SAFETY: the AVIC pages will not be concurrently accessed by the processor
284+
// while this VP is in VTL2.
285+
let avic_page = unsafe { &mut *self.state.avic_pages[vtl].get() };
286+
let vmsa = self.vmsa_mut(vtl);
287+
288+
(avic_page, vmsa)
289+
}
245290
}

openhcl/hcl/src/ioctl/tdx.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@ use x86defs::tdx::TdxGp;
3939
use x86defs::tdx::TdxL2Ctls;
4040
use x86defs::tdx::TdxL2EnterGuestState;
4141
use x86defs::tdx::TdxVmFlags;
42-
use x86defs::vmx::ApicPage;
4342
use x86defs::vmx::VmcsField;
43+
use x86defs::vmx::VmxApicPage;
4444

4545
/// Runner backing for TDX partitions.
4646
pub struct Tdx<'a> {
47-
apic_pages: VtlArray<&'a UnsafeCell<ApicPage>, 2>,
47+
apic_pages: VtlArray<&'a UnsafeCell<VmxApicPage>, 2>,
4848
}
4949

5050
impl MshvVtl {
@@ -123,14 +123,14 @@ impl<'a> ProcessorRunner<'a, Tdx<'a>> {
123123
}
124124

125125
/// Gets a reference to the tdx APIC page for the given VTL.
126-
pub fn tdx_apic_page(&self, vtl: GuestVtl) -> &ApicPage {
126+
pub fn tdx_apic_page(&self, vtl: GuestVtl) -> &VmxApicPage {
127127
// SAFETY: the APIC pages will not be concurrently accessed by the processor
128128
// while this VP is in VTL2.
129129
unsafe { &*self.state.apic_pages[vtl].get() }
130130
}
131131

132132
/// Gets a mutable reference to the tdx APIC page for the given VTL.
133-
pub fn tdx_apic_page_mut(&mut self, vtl: GuestVtl) -> &mut ApicPage {
133+
pub fn tdx_apic_page_mut(&mut self, vtl: GuestVtl) -> &mut VmxApicPage {
134134
// SAFETY: the APIC pages will not be concurrently accessed by the processor
135135
// while this VP is in VTL2.
136136
unsafe { &mut *self.state.apic_pages[vtl].get() }

openhcl/hcl/src/vmsa.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use std::array;
88
use std::ops::Deref;
99
use std::ops::DerefMut;
10+
use x86defs::snp::SecureAvicControl;
1011
use x86defs::snp::SevEventInjectInfo;
1112
use x86defs::snp::SevFeatures;
1213
use x86defs::snp::SevSelector;
@@ -267,6 +268,11 @@ reg_direct_mut!(v_intr_cntrl, v_intr_cntrl_mut, SevVirtualInterruptControl);
267268
reg_direct!(virtual_tom, set_virtual_tom, u64);
268269
reg_direct!(event_inject, set_event_inject, SevEventInjectInfo);
269270
reg_direct!(guest_error_code, set_guest_error_code, u64);
271+
reg_direct_mut!(
272+
secure_avic_control,
273+
secure_avic_control_mut,
274+
SecureAvicControl
275+
);
270276
regss!(es, set_es);
271277
regss!(cs, set_cs);
272278
regss!(ss, set_ss);

0 commit comments

Comments
 (0)