Skip to content

Commit 895e1f4

Browse files
committed
Secure AVIC draft
1 parent b7a2c8b commit 895e1f4

File tree

22 files changed

+170
-21
lines changed

22 files changed

+170
-21
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9520,6 +9520,7 @@ dependencies = [
95209520
"arbitrary",
95219521
"bitfield-struct 0.10.1",
95229522
"open_enum",
9523+
"static_assertions",
95239524
"zerocopy 0.8.23",
95249525
]
95259526

openhcl/hcl/src/ioctl.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,10 @@ use std::sync::atomic::Ordering;
7777
use thiserror::Error;
7878
use user_driver::DmaClient;
7979
use user_driver::memory::MemoryBlock;
80+
use x86defs::snp::SevAvicPage;
8081
use x86defs::snp::SevVmsa;
8182
use x86defs::tdx::TdCallResultCode;
82-
use x86defs::vmx::ApicPage;
83+
use x86defs::vmx::VmxApicPage;
8384
use zerocopy::FromBytes;
8485
use zerocopy::FromZeros;
8586
use zerocopy::Immutable;
@@ -1548,9 +1549,12 @@ enum BackingState {
15481549
},
15491550
Snp {
15501551
vmsa: VtlArray<MappedPage<SevVmsa>, 2>,
1552+
vtl0_apic_page: MappedPage<SevAvicPage>,
1553+
vtl1_apic_page: MemoryBlock,
15511554
},
15521555
Tdx {
1553-
vtl0_apic_page: MappedPage<ApicPage>,
1556+
vtl0_apic_page: MappedPage<VmxApicPage>,
1557+
// TODO: Once VTL0 works, add plumbing for VTL1.
15541558
vtl1_apic_page: MemoryBlock,
15551559
},
15561560
}
@@ -1602,6 +1606,12 @@ impl HclVp {
16021606
.map_err(|e| Error::MmapVp(e, Some(Vtl::Vtl1)))?;
16031607
BackingState::Snp {
16041608
vmsa: [vmsa_vtl0, vmsa_vtl1].into(),
1609+
vtl0_apic_page: MappedPage::new(fd, MSHV_APIC_PAGE_OFFSET | vp as i64)
1610+
.map_err(|e| Error::MmapVp(e, Some(Vtl::Vtl0)))?,
1611+
vtl1_apic_page: private_dma_client
1612+
.ok_or(Error::MissingPrivateMemory)?
1613+
.allocate_dma_buffer(HV_PAGE_SIZE as usize)
1614+
.map_err(Error::AllocVp)?,
16051615
}
16061616
}
16071617
IsolationType::Tdx => BackingState::Tdx {

openhcl/hcl/src/ioctl/snp.rs

Lines changed: 20 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+
apic_pages: VtlArray<&'a UnsafeCell<SevAvicPage>, 2>,
3436
}
3537

3638
/// Error returned by failing SNP operations.
@@ -176,11 +178,28 @@ 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+
// TODO: Register the VTL 1 AVIC page with the hypervisor.
191+
// Specification: "SEV-ES Guest-Hypervisor Communication Block Standartization",
192+
// 4.1.16.1 "Backing page support".
193+
//
194+
// The VTL 0 APIC page is registered by the kernel.
195+
let vtl1_apic_page_addr = vtl1_apic_page.pfns()[0] * user_driver::memory::PAGE_SIZE64;
196+
197+
// SAFETY: The mapping is held for the appropriate lifetime, and the
198+
// APIC page is never accessed as any other type, or by any other location.
199+
let vtl1_apic_page = unsafe { &*vtl1_apic_page.base().cast() };
200+
183201
Ok(Self {
202+
apic_pages: [vtl0_apic_page.as_ref(), vtl1_apic_page].into(),
184203
vmsa: vmsa.each_ref().map(|mp| mp.as_ref()),
185204
})
186205
}

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/protocol.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ pub struct hcl_hvcall {
175175

176176
pub const HCL_REG_PAGE_OFFSET: i64 = 1 << 16;
177177
pub const HCL_VMSA_PAGE_OFFSET: i64 = 2 << 16;
178+
// TODO: may need another constant if the kernel needs to allocate a page for
179+
// the VTL1 secure AVICs. Currently the kernel figures out the type of the
180+
// hardware isolation and allocates the page for VTL.
178181
pub const MSHV_APIC_PAGE_OFFSET: i64 = 3 << 16;
179182
pub const HCL_VMSA_GUEST_VSM_PAGE_OFFSET: i64 = 4 << 16;
180183

openhcl/openhcl_boot/src/host_params/shim_params.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ pub struct ShimParams {
107107
/// Memory used by the shim.
108108
pub used: MemoryRange,
109109
pub bounce_buffer: Option<MemoryRange>,
110+
/// Enable secure AVIC if supported.
111+
pub auto_enable_secure_avic: bool,
110112
}
111113

112114
impl ShimParams {
@@ -133,6 +135,7 @@ impl ShimParams {
133135
used_end,
134136
bounce_buffer_start,
135137
bounce_buffer_size,
138+
auto_enable_secure_avic,
136139
} = raw;
137140

138141
let isolation_type = get_isolation_type(supported_isolation_type);
@@ -166,6 +169,7 @@ impl ShimParams {
166169
..shim_base_address.wrapping_add_signed(used_end),
167170
),
168171
bounce_buffer,
172+
auto_enable_secure_avic: auto_enable_secure_avic != 0,
169173
}
170174
}
171175

openhcl/openhcl_boot/src/main.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,9 @@ fn shim_main(shim_params_raw_offset: isize) -> ! {
720720
// Chain in the setup data.
721721
setup_data_tail.next = core::ptr::from_ref(&*cc_data) as u64;
722722
setup_data_tail = &mut cc_data.header;
723+
724+
// TODO: auto enable secure AVIC if CPUID indicates it is supported
725+
// and the guest interrupt control is supported.
723726
}
724727

725728
let reserved_memory = reserved_memory_regions(partition_info, sidecar.as_ref());

openhcl/virt_mshv_vtl/src/processor/tdx/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ use virt_support_x86emu::emulate::emulate_io;
7575
use virt_support_x86emu::emulate::emulate_translate_gva;
7676
use virt_support_x86emu::translate::TranslationRegisters;
7777
use vmcore::vmtime::VmTimeAccess;
78+
use x86defs::ApicRegister;
7879
use x86defs::RFlags;
7980
use x86defs::X64_CR0_ET;
8081
use x86defs::X64_CR0_NE;
@@ -95,8 +96,6 @@ use x86defs::tdx::TdxGp;
9596
use x86defs::tdx::TdxInstructionInfo;
9697
use x86defs::tdx::TdxL2Ctls;
9798
use x86defs::tdx::TdxVpEnterRaxResult;
98-
use x86defs::vmx::ApicPage;
99-
use x86defs::vmx::ApicRegister;
10099
use x86defs::vmx::CR_ACCESS_TYPE_LMSW;
101100
use x86defs::vmx::CR_ACCESS_TYPE_MOV_TO_CR;
102101
use x86defs::vmx::CrAccessQualification;
@@ -114,6 +113,7 @@ use x86defs::vmx::SecondaryProcessorControls;
114113
use x86defs::vmx::VMX_ENTRY_CONTROL_LONG_MODE_GUEST;
115114
use x86defs::vmx::VMX_FEATURE_CONTROL_LOCKED;
116115
use x86defs::vmx::VmcsField;
116+
use x86defs::vmx::VmxApicPage;
117117
use x86defs::vmx::VmxEptExitQualification;
118118
use x86defs::vmx::VmxExit;
119119
use x86defs::vmx::VmxExitBasic;
@@ -2917,7 +2917,7 @@ impl UhProcessor<'_, TdxBacked> {
29172917

29182918
struct TdxApicClient<'a, T> {
29192919
partition: &'a UhPartitionInner,
2920-
apic_page: &'a mut ApicPage,
2920+
apic_page: &'a mut VmxApicPage,
29212921
dev: &'a T,
29222922
vmtime: &'a VmTimeAccess,
29232923
vtl: GuestVtl,
@@ -2954,7 +2954,7 @@ impl<T: CpuIo> ApicClient for TdxApicClient<'_, T> {
29542954
}
29552955
}
29562956

2957-
fn pull_apic_offload(page: &mut ApicPage) -> ([u32; 8], [u32; 8]) {
2957+
fn pull_apic_offload(page: &mut VmxApicPage) -> ([u32; 8], [u32; 8]) {
29582958
let mut irr = [0; 8];
29592959
let mut isr = [0; 8];
29602960
for (((irr, page_irr), isr), page_isr) in irr

vm/loader/igvmfilegen/src/file_loader.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::vp_context_builder::VpContextBuilder;
1414
use crate::vp_context_builder::VpContextPageState;
1515
use crate::vp_context_builder::VpContextState;
1616
use crate::vp_context_builder::snp::InjectionType;
17+
use crate::vp_context_builder::snp::SecureAvic;
1718
use crate::vp_context_builder::snp::SnpHardwareContext;
1819
use crate::vp_context_builder::tdx::TdxHardwareContext;
1920
use crate::vp_context_builder::vbs::VbsRegister;
@@ -149,6 +150,7 @@ pub enum LoaderIsolationType {
149150
shared_gpa_boundary_bits: Option<u8>,
150151
policy: SnpPolicy,
151152
injection_type: InjectionType,
153+
secure_avic: SecureAvic,
152154
// TODO SNP: SNP Keys? Other data?
153155
},
154156
Tdx {
@@ -201,6 +203,7 @@ impl IgvmLoaderRegister for X86Register {
201203
shared_gpa_boundary_bits,
202204
policy,
203205
injection_type,
206+
secure_avic,
204207
} => {
205208
// TODO SNP: assumed that shared_gpa_boundary is always available.
206209
let shared_gpa_boundary =
@@ -227,6 +230,7 @@ impl IgvmLoaderRegister for X86Register {
227230
!with_paravisor,
228231
shared_gpa_boundary,
229232
injection_type,
233+
secure_avic,
230234
));
231235

232236
(platform_header, vec![init_header], vp_context_builder)
@@ -890,25 +894,30 @@ impl<R: IgvmLoaderRegister + GuestArch + 'static> ImageLoad<R> for IgvmVtlLoader
890894
paravisor_present: self.loader.paravisor_present,
891895
isolation_type: IsolationType::None,
892896
shared_gpa_boundary_bits: None,
897+
auto_enable_secure_apic: false,
893898
},
894899
LoaderIsolationType::Vbs { .. } => IsolationConfig {
895900
paravisor_present: self.loader.paravisor_present,
896901
isolation_type: IsolationType::Vbs,
897902
shared_gpa_boundary_bits: None,
903+
auto_enable_secure_apic: false,
898904
},
899905
LoaderIsolationType::Snp {
900906
shared_gpa_boundary_bits,
901907
policy: _,
902908
injection_type: _,
909+
secure_avic,
903910
} => IsolationConfig {
904911
paravisor_present: self.loader.paravisor_present,
905912
isolation_type: IsolationType::Snp,
906913
shared_gpa_boundary_bits,
914+
auto_enable_secure_apic: matches!(secure_avic, SecureAvic::Auto),
907915
},
908916
LoaderIsolationType::Tdx { .. } => IsolationConfig {
909917
paravisor_present: self.loader.paravisor_present,
910918
isolation_type: IsolationType::Tdx,
911919
shared_gpa_boundary_bits: Some(TDX_SHARED_GPA_BOUNDARY_BITS),
920+
auto_enable_secure_apic: false,
912921
},
913922
}
914923
}
@@ -1260,6 +1269,7 @@ mod tests {
12601269
shared_gpa_boundary_bits: Some(39),
12611270
policy: SnpPolicy::from((0x1 << 17) | (0x1 << 16) | (0x1f)),
12621271
injection_type: InjectionType::Restricted,
1272+
secure_avic: SecureAvic::Enabled,
12631273
},
12641274
);
12651275
let data = vec![0, 5];

vm/loader/igvmfilegen/src/main.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use igvmfilegen_config::Image;
2525
use igvmfilegen_config::LinuxImage;
2626
use igvmfilegen_config::ResourceType;
2727
use igvmfilegen_config::Resources;
28+
use igvmfilegen_config::SecureAvicType;
2829
use igvmfilegen_config::SnpInjectionType;
2930
use igvmfilegen_config::UefiConfigType;
3031
use loader::importer::Aarch64Register;
@@ -182,6 +183,7 @@ fn create_igvm_file<R: IgvmfilegenRegister + GuestArch + 'static>(
182183
policy,
183184
enable_debug,
184185
injection_type,
186+
secure_avic,
185187
} => LoaderIsolationType::Snp {
186188
shared_gpa_boundary_bits,
187189
policy: SnpPolicy::from(policy).with_debug(enable_debug as u8),
@@ -191,6 +193,11 @@ fn create_igvm_file<R: IgvmfilegenRegister + GuestArch + 'static>(
191193
vp_context_builder::snp::InjectionType::Restricted
192194
}
193195
},
196+
secure_avic: match secure_avic {
197+
SecureAvicType::Auto => vp_context_builder::snp::SecureAvic::Auto,
198+
SecureAvicType::Enabled => vp_context_builder::snp::SecureAvic::Enabled,
199+
SecureAvicType::Disabled => vp_context_builder::snp::SecureAvic::Disabled,
200+
},
194201
},
195202
ConfigIsolationType::Tdx {
196203
enable_debug,

vm/loader/igvmfilegen/src/vp_context_builder/snp.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,17 @@ pub enum InjectionType {
2929
Restricted,
3030
}
3131

32+
/// The secure AVIC.
33+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
34+
pub enum SecureAvic {
35+
/// Offload AVIC to the hardware if available.
36+
Auto,
37+
/// Offload AVIC to the hardware.
38+
Enabled,
39+
/// The paravisor emulates APIC.
40+
Disabled,
41+
}
42+
3243
/// A hardware SNP VP context, that is imported as a VMSA.
3344
#[derive(Debug)]
3445
pub struct SnpHardwareContext {
@@ -59,6 +70,7 @@ impl SnpHardwareContext {
5970
enlightened_uefi: bool,
6071
shared_gpa_boundary: u64,
6172
injection_type: InjectionType,
73+
secure_avic: SecureAvic,
6274
) -> Self {
6375
let mut vmsa: SevVmsa = FromZeros::new_zeroed();
6476

@@ -92,6 +104,8 @@ impl SnpHardwareContext {
92104
vmsa.sev_features.set_prevent_host_ibs(true);
93105
vmsa.sev_features.set_vmsa_reg_prot(true);
94106
vmsa.sev_features.set_vtom(false);
107+
vmsa.sev_features
108+
.set_secure_avic(secure_avic == SecureAvic::Enabled);
95109
vmsa.virtual_tom = 0;
96110
}
97111
}

vm/loader/igvmfilegen_config/src/lib.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,18 @@ pub enum SnpInjectionType {
3232
Restricted,
3333
}
3434

35+
/// Secure AVIC type.
36+
#[derive(Serialize, Deserialize, Debug)]
37+
#[serde(rename_all = "snake_case")]
38+
pub enum SecureAvicType {
39+
/// Offload AVIC to the hardware if available.
40+
Auto,
41+
/// Offload AVIC to the hardware.
42+
Enabled,
43+
/// The paravisor emulates APIC.
44+
Disabled,
45+
}
46+
3547
/// The isolation type that should be used for the loader.
3648
#[derive(Serialize, Deserialize, Debug)]
3749
#[serde(rename_all = "snake_case")]
@@ -55,6 +67,8 @@ pub enum ConfigIsolationType {
5567
enable_debug: bool,
5668
/// The interrupt injection type to use for the highest vmpl.
5769
injection_type: SnpInjectionType,
70+
/// Secure AVIC
71+
secure_avic: SecureAvicType,
5872
},
5973
/// Intel TDX.
6074
Tdx {

vm/loader/loader_defs/src/shim.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ pub struct ShimParamsRaw {
5353
pub bounce_buffer_start: i64,
5454
/// The size of the bounce buffer range. This is 0 if unavailable.
5555
pub bounce_buffer_size: u64,
56+
/// Use the hardware APIC if available.
57+
pub auto_enable_secure_avic: u64,
5658
}
5759

5860
open_enum! {

vm/loader/manifests/openhcl-x64-cvm-dev.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
"shared_gpa_boundary_bits": 46,
1010
"policy": 196639,
1111
"enable_debug": true,
12-
"injection_type": "normal"
12+
"injection_type": "normal",
13+
"secure_avic": "auto"
1314
}
1415
},
1516
"image": {

0 commit comments

Comments
 (0)