1mod tlb_flush;
7
8use super::BackingPrivate;
9use super::BackingSharedParams;
10use super::HardwareIsolatedBacking;
11use super::UhEmulationState;
12use super::UhHypercallHandler;
13use super::hardware_cvm;
14use super::vp_state;
15use super::vp_state::UhVpStateAccess;
16use crate::BackingShared;
17use crate::GuestVtl;
18use crate::IsolationType;
19use crate::TlbFlushLockAccess;
20use crate::UhCvmPartitionState;
21use crate::UhCvmVpState;
22use crate::UhPartitionInner;
23use crate::UhPartitionNewParams;
24use crate::UhProcessor;
25use crate::WakeReason;
26use crate::get_tsc_frequency;
27use cvm_tracing::CVM_ALLOWED;
28use cvm_tracing::CVM_CONFIDENTIAL;
29use guestmem::GuestMemory;
30use hcl::ioctl::ProcessorRunner;
31use hcl::ioctl::tdx::Tdx;
32use hcl::ioctl::tdx::TdxPrivateRegs;
33use hcl::protocol::hcl_intr_offload_flags;
34use hcl::protocol::tdx_tdg_vp_enter_exit_info;
35use hv1_emulator::hv::ProcessorVtlHv;
36use hv1_emulator::synic::GlobalSynic;
37use hv1_emulator::synic::ProcessorSynic;
38use hv1_hypercall::AsHandler;
39use hv1_hypercall::HvRepResult;
40use hv1_hypercall::HypercallIo;
41use hv1_structs::ProcessorSet;
42use hv1_structs::VtlArray;
43use hvdef::HV_PAGE_SIZE;
44use hvdef::HvError;
45use hvdef::HvSynicSimpSiefp;
46use hvdef::HvX64PendingExceptionEvent;
47use hvdef::HvX64RegisterName;
48use hvdef::Vtl;
49use hvdef::hypercall::HvFlushFlags;
50use hvdef::hypercall::HvGvaRange;
51use inspect::Inspect;
52use inspect::InspectMut;
53use inspect_counters::Counter;
54use std::sync::atomic::AtomicU8;
55use std::sync::atomic::Ordering;
56use thiserror::Error;
57use tlb_flush::FLUSH_GVA_LIST_SIZE;
58use tlb_flush::TdxFlushState;
59use tlb_flush::TdxPartitionFlushState;
60use virt::EmulatorMonitorSupport;
61use virt::Processor;
62use virt::VpHaltReason;
63use virt::VpIndex;
64use virt::io::CpuIo;
65use virt::state::StateElement;
66use virt::vp;
67use virt::vp::AccessVpState;
68use virt::vp::MpState;
69use virt::vp::Registers;
70use virt::x86::MsrError;
71use virt::x86::MsrErrorExt;
72use virt::x86::SegmentRegister;
73use virt::x86::TableRegister;
74use virt_support_apic::ApicClient;
75use virt_support_apic::OffloadNotSupported;
76use virt_support_x86emu::emulate::EmulatedMemoryOperation;
77use virt_support_x86emu::emulate::EmulatorSupport as X86EmulatorSupport;
78use virt_support_x86emu::emulate::TranslateMode;
79use virt_support_x86emu::emulate::emulate_insn_memory_op;
80use virt_support_x86emu::emulate::emulate_io;
81use virt_support_x86emu::emulate::emulate_translate_gva;
82use virt_support_x86emu::translate::TranslationRegisters;
83use vmcore::vmtime::VmTimeAccess;
84use x86defs::ApicRegisterValue;
85use x86defs::RFlags;
86use x86defs::X64_CR0_ET;
87use x86defs::X64_CR0_NE;
88use x86defs::X64_CR0_PE;
89use x86defs::X64_CR0_PG;
90use x86defs::X64_CR4_MCE;
91use x86defs::X64_CR4_UMIP;
92use x86defs::X64_CR4_VMXE;
93use x86defs::X64_EFER_FFXSR;
94use x86defs::X64_EFER_LMA;
95use x86defs::X64_EFER_LME;
96use x86defs::X64_EFER_NXE;
97use x86defs::X64_EFER_SVME;
98use x86defs::X86X_MSR_EFER;
99use x86defs::apic::X2APIC_MSR_BASE;
100use x86defs::tdx::TdCallResultCode;
101use x86defs::tdx::TdVmCallR10Result;
102use x86defs::tdx::TdxGp;
103use x86defs::tdx::TdxInstructionInfo;
104use x86defs::tdx::TdxL2Ctls;
105use x86defs::tdx::TdxVpEnterRaxResult;
106use x86defs::vmx::CR_ACCESS_TYPE_LMSW;
107use x86defs::vmx::CR_ACCESS_TYPE_MOV_TO_CR;
108use x86defs::vmx::CrAccessQualification;
109use x86defs::vmx::ExitQualificationIo;
110use x86defs::vmx::GdtrOrIdtrInstruction;
111use x86defs::vmx::GdtrOrIdtrInstructionInfo;
112use x86defs::vmx::INTERRUPT_TYPE_EXTERNAL;
113use x86defs::vmx::INTERRUPT_TYPE_HARDWARE_EXCEPTION;
114use x86defs::vmx::INTERRUPT_TYPE_NMI;
115use x86defs::vmx::IO_SIZE_8_BIT;
116use x86defs::vmx::IO_SIZE_16_BIT;
117use x86defs::vmx::IO_SIZE_32_BIT;
118use x86defs::vmx::Ia32FeatureControl;
119use x86defs::vmx::Interruptibility;
120use x86defs::vmx::InterruptionInformation;
121use x86defs::vmx::LdtrOrTrInstruction;
122use x86defs::vmx::LdtrOrTrInstructionInfo;
123use x86defs::vmx::ProcessorControls;
124use x86defs::vmx::SecondaryProcessorControls;
125use x86defs::vmx::VMX_ENTRY_CONTROL_LONG_MODE_GUEST;
126use x86defs::vmx::VmcsField;
127use x86defs::vmx::VmxApicPage;
128use x86defs::vmx::VmxEptExitQualification;
129use x86defs::vmx::VmxExit;
130use x86defs::vmx::VmxExitBasic;
131use x86emu::Gp;
132use x86emu::Segment;
133
134const MSR_ALLOWED_READ: &[u32] = &[
136 x86defs::X86X_MSR_TSC,
137 x86defs::X86X_MSR_TSC_AUX,
138 X86X_MSR_EFER,
139 x86defs::X86X_MSR_STAR,
140 x86defs::X86X_MSR_LSTAR,
141 x86defs::X86X_MSR_SFMASK,
142 x86defs::X86X_MSR_SYSENTER_CS,
143 x86defs::X86X_MSR_SYSENTER_ESP,
144 x86defs::X86X_MSR_SYSENTER_EIP,
145];
146
147const MSR_ALLOWED_READ_WRITE: &[u32] = &[
149 x86defs::X64_MSR_FS_BASE,
150 x86defs::X64_MSR_GS_BASE,
151 x86defs::X64_MSR_KERNEL_GS_BASE,
152 x86defs::X86X_MSR_SPEC_CTRL,
153 x86defs::X86X_MSR_U_CET,
154 x86defs::X86X_MSR_S_CET,
155 x86defs::X86X_MSR_PL0_SSP,
156 x86defs::X86X_MSR_PL1_SSP,
157 x86defs::X86X_MSR_PL2_SSP,
158 x86defs::X86X_MSR_PL3_SSP,
159 x86defs::X86X_MSR_INTERRUPT_SSP_TABLE_ADDR,
160 x86defs::X86X_IA32_MSR_XFD,
161 x86defs::X86X_IA32_MSR_XFD_ERR,
162];
163
164#[derive(Debug, Error)]
165#[error("unknown exit {0:#x?}")]
166struct UnknownVmxExit(VmxExit);
167
168#[derive(Debug, Error)]
169#[error("bad guest state on VP.ENTER")]
170struct VmxBadGuestState;
171
172#[derive(Debug, Error)]
173#[error("failed to run")]
174struct TdxRunVpError(#[source] hcl::ioctl::Error);
175
176#[derive(Debug)]
177struct TdxExit<'a>(&'a tdx_tdg_vp_enter_exit_info);
178
179impl TdxExit<'_> {
180 fn code(&self) -> TdxVpEnterRaxResult {
181 self.0.rax.into()
182 }
183 fn qualification(&self) -> u64 {
184 self.0.rcx
185 }
186 fn gla(&self) -> Option<u64> {
187 if self.code().vmx_exit().basic_reason() == VmxExitBasic::EPT_VIOLATION {
189 Some(self.0.rdx)
190 } else {
191 None
192 }
193 }
194 fn gpa(&self) -> Option<u64> {
195 if self.code().vmx_exit().basic_reason() == VmxExitBasic::EPT_VIOLATION {
197 Some(self.0.r8)
198 } else {
199 None
200 }
201 }
202 fn _exit_interruption_info(&self) -> InterruptionInformation {
203 (self.0.r9 as u32).into()
204 }
205 fn _exit_interruption_error_code(&self) -> u32 {
206 (self.0.r9 >> 32) as u32
207 }
208 fn idt_vectoring_info(&self) -> InterruptionInformation {
209 (self.0.r10 as u32).into()
210 }
211 fn idt_vectoring_error_code(&self) -> u32 {
212 (self.0.r10 >> 32) as u32
213 }
214 fn instr_info(&self) -> TdxInstructionInfo {
215 self.0.r11.into()
216 }
217 fn cs(&self) -> SegmentRegister {
218 SegmentRegister {
219 selector: self.0.rsi as u16,
220 base: self.0.rdi,
221 limit: (self.0.rsi >> 32) as u32,
222 attributes: (self.0.rsi >> 16) as u16,
223 }
224 }
225 fn cpl(&self) -> u8 {
226 self.0.r12 as u8 & 3
227 }
228}
229
230#[derive(Debug, Inspect)]
232enum ShadowedRegister {
233 Cr0,
234 Cr4,
235}
236
237impl ShadowedRegister {
238 fn name(&self) -> &'static str {
239 match self {
240 Self::Cr0 => "cr0",
241 Self::Cr4 => "cr4",
242 }
243 }
244
245 fn physical_vmcs_field(&self) -> VmcsField {
246 match self {
247 Self::Cr0 => VmcsField::VMX_VMCS_GUEST_CR0,
248 Self::Cr4 => VmcsField::VMX_VMCS_GUEST_CR4,
249 }
250 }
251
252 fn shadow_vmcs_field(&self) -> VmcsField {
253 match self {
254 Self::Cr0 => VmcsField::VMX_VMCS_CR0_READ_SHADOW,
255 Self::Cr4 => VmcsField::VMX_VMCS_CR4_READ_SHADOW,
256 }
257 }
258
259 fn guest_owned_mask(&self) -> u64 {
260 match self {
264 Self::Cr0 => {
265 X64_CR0_ET
266 | x86defs::X64_CR0_MP
267 | x86defs::X64_CR0_EM
268 | x86defs::X64_CR0_TS
269 | x86defs::X64_CR0_WP
270 | x86defs::X64_CR0_AM
271 | X64_CR0_PE
272 | X64_CR0_PG
273 }
274 Self::Cr4 => {
275 x86defs::X64_CR4_VME
276 | x86defs::X64_CR4_PVI
277 | x86defs::X64_CR4_TSD
278 | x86defs::X64_CR4_DE
279 | x86defs::X64_CR4_PSE
280 | x86defs::X64_CR4_PAE
281 | x86defs::X64_CR4_PGE
282 | x86defs::X64_CR4_PCE
283 | x86defs::X64_CR4_FXSR
284 | x86defs::X64_CR4_XMMEXCPT
285 | X64_CR4_UMIP
286 | x86defs::X64_CR4_LA57
287 | x86defs::X64_CR4_RWFSGS
288 | x86defs::X64_CR4_PCIDE
289 | x86defs::X64_CR4_OSXSAVE
290 | x86defs::X64_CR4_SMEP
291 | x86defs::X64_CR4_SMAP
292 | x86defs::X64_CR4_CET
293 }
294 }
295 }
296}
297
298#[derive(Inspect)]
303struct VirtualRegister {
304 register: ShadowedRegister,
306 vtl: GuestVtl,
308 shadow_value: u64,
310 allowed_bits: u64,
312}
313
314impl VirtualRegister {
315 fn new(reg: ShadowedRegister, vtl: GuestVtl, initial_value: u64, allowed_bits: u64) -> Self {
316 Self {
317 register: reg,
318 vtl,
319 shadow_value: initial_value,
320 allowed_bits,
321 }
322 }
323
324 fn write<'a>(
328 &mut self,
329 value: u64,
330 runner: &mut ProcessorRunner<'a, Tdx<'a>>,
331 ) -> Result<(), vp_state::Error> {
332 tracing::trace!(?self.register, value, "write virtual register");
333
334 if value & !self.allowed_bits != 0 {
335 return Err(vp_state::Error::InvalidValue(
336 value,
337 self.register.name(),
338 "disallowed bit set",
339 ));
340 }
341
342 let old_physical_reg = runner.read_vmcs64(self.vtl, self.register.physical_vmcs_field());
345
346 tracing::trace!(old_physical_reg, "old_physical_reg");
347
348 let guest_owned_mask = self.register.guest_owned_mask();
349 if (old_physical_reg ^ value) & guest_owned_mask != 0 {
350 let new_physical_reg =
351 (old_physical_reg & !guest_owned_mask) | (value & guest_owned_mask);
352
353 tracing::trace!(new_physical_reg, "new_physical_reg");
354
355 runner.write_vmcs64(
356 self.vtl,
357 self.register.physical_vmcs_field(),
358 !0,
359 new_physical_reg,
360 );
361 }
362
363 self.shadow_value = value;
364 runner.write_vmcs64(self.vtl, self.register.shadow_vmcs_field(), !0, value);
365 Ok(())
366 }
367
368 fn read<'a>(&self, runner: &ProcessorRunner<'a, Tdx<'a>>) -> u64 {
369 let physical_reg = runner.read_vmcs64(self.vtl, self.register.physical_vmcs_field());
370
371 let guest_owned_mask = self.register.guest_owned_mask();
374 (self.shadow_value & !self.register.guest_owned_mask()) | (physical_reg & guest_owned_mask)
375 }
376}
377
378struct TdxTscDeadlineService {
392 tsc_scale_100ns: u128,
394}
395
396impl TdxTscDeadlineService {
397 fn ref_time_to_tsc(&self, ref_time: u64) -> u64 {
399 ((ref_time as u128 * self.tsc_scale_100ns) >> 64) as u64
402 }
403
404 fn is_before(ref_time: u64, ref_time_last: u64) -> bool {
410 let delta = ref_time.wrapping_sub(ref_time_last);
411 (delta as i64) < 0
412 }
413}
414
415impl hardware_cvm::HardwareIsolatedGuestTimer<TdxBacked> for TdxTscDeadlineService {
416 fn is_hardware_virtualized(&self) -> bool {
417 true
418 }
419
420 fn update_deadline(
424 &self,
425 vp: &mut UhProcessor<'_, TdxBacked>,
426 ref_time_now: u64,
427 ref_time_next: u64,
428 ) {
429 let vp_state = vp
430 .backing
431 .tsc_deadline_state
432 .as_mut()
433 .expect("TdxTscDeadlineService requires tsc_deadline_state");
434
435 if vp_state
437 .deadline_100ns
438 .is_none_or(|last| Self::is_before(ref_time_next, last))
439 {
440 vp_state.deadline_100ns = Some(ref_time_next);
442
443 let state = vp.runner.tdx_l2_tsc_deadline_state_mut();
444 if vp_state
445 .last_deadline_100ns
446 .is_none_or(|last| last != ref_time_next)
447 {
448 let ref_time_from_now = ref_time_next.saturating_sub(ref_time_now);
449 let tsc_delta = self.ref_time_to_tsc(ref_time_from_now);
450 let deadline = safe_intrinsics::rdtsc().wrapping_add(tsc_delta);
451
452 state.deadline = deadline;
453 state.update_deadline = 1;
454
455 tracing::trace!(
456 ref_time_from_now,
457 tsc_delta,
458 deadline,
459 "updating deadline for TDX L2-VM TSC deadline timer"
460 );
461 } else {
462 state.update_deadline = 0;
463 }
464 }
465 }
466
467 fn clear_deadline(&self, vp: &mut UhProcessor<'_, TdxBacked>) {
469 let vp_state = vp
470 .backing
471 .tsc_deadline_state
472 .as_mut()
473 .expect("TdxTscDeadlineService requires tsc_deadline_state");
474
475 vp_state.deadline_100ns = None;
476
477 let state = vp.runner.tdx_l2_tsc_deadline_state_mut();
478 state.update_deadline = 0;
479 }
480
481 fn begin_vtl_transition(&self, _vp: &mut UhProcessor<'_, TdxBacked>, _vtl: GuestVtl) {}
482
483 fn end_vtl_transition(&self, vp: &mut UhProcessor<'_, TdxBacked>, _vtl: GuestVtl) {
484 let vp_state = vp
485 .backing
486 .tsc_deadline_state
487 .as_mut()
488 .expect("TdxTscDeadlineService requires tsc_deadline_state");
489
490 vp_state.last_deadline_100ns = vp_state.deadline_100ns;
491 }
492}
493
494#[derive(Inspect, Default)]
496struct TdxTscDeadline {
497 #[inspect(hex)]
499 deadline_100ns: Option<u64>,
500 #[inspect(hex)]
503 last_deadline_100ns: Option<u64>,
504}
505
506#[derive(InspectMut)]
508pub struct TdxBacked {
509 #[inspect(mut)]
510 vtls: VtlArray<TdxVtl, 2>,
511
512 untrusted_synic: Option<ProcessorSynic>,
513 #[inspect(hex, iter_by_index)]
514 eoi_exit_bitmap: [u64; 4],
515
516 #[inspect(skip)]
518 flush_page: user_driver::memory::MemoryBlock,
519
520 #[inspect(flatten)]
521 cvm: UhCvmVpState,
522
523 #[inspect(flatten)]
525 tsc_deadline_state: Option<TdxTscDeadline>,
526}
527
528#[derive(InspectMut)]
529struct TdxVtl {
530 efer: u64,
532 cr0: VirtualRegister,
534 cr4: VirtualRegister,
536
537 msr_cstar: u64,
539
540 tpr_threshold: u8,
541 #[inspect(skip)]
542 processor_controls: ProcessorControls,
543 #[inspect(skip)]
544 interruption_information: InterruptionInformation,
545 exception_error_code: u32,
546 interruption_set: bool,
547
548 #[inspect(mut)]
549 private_regs: TdxPrivateRegs,
550
551 flush_state: TdxFlushState,
553
554 enter_stats: EnterStats,
555 exit_stats: ExitStats,
556}
557
558#[derive(Default)]
559pub struct TdxEmulationCache {
560 segs: [Option<SegmentRegister>; 6],
561 cr0: Option<u64>,
562}
563
564#[derive(Inspect, Default)]
565struct EnterStats {
566 success: Counter,
567 host_routed_async: Counter,
568 l2_exit_pending_intr: Counter,
569 pending_intr: Counter,
570 host_routed_td_vmcall: Counter,
571}
572
573#[derive(Inspect, Default)]
574struct ExitStats {
575 io: Counter,
576 msr_read: Counter,
577 msr_write: Counter,
578 ept_violation: Counter,
579 cpuid: Counter,
580 cr_access: Counter,
581 xsetbv: Counter,
582 tpr_below_threshold: Counter,
583 interrupt_window: Counter,
584 nmi_window: Counter,
585 vmcall: Counter,
586 smi_intr: Counter,
587 wbinvd: Counter,
588 hw_interrupt: Counter,
589 tdcall: Counter,
590 hlt: Counter,
591 pause: Counter,
592 needs_interrupt_reinject: Counter,
593 exception: Counter,
594 descriptor_table: Counter,
595 timer_expired: Counter,
596}
597
598enum UhDirectOverlay {
599 Sipp,
600 Sifp,
601 Count,
602}
603
604impl HardwareIsolatedBacking for TdxBacked {
605 fn cvm_state(&self) -> &UhCvmVpState {
606 &self.cvm
607 }
608
609 fn cvm_state_mut(&mut self) -> &mut UhCvmVpState {
610 &mut self.cvm
611 }
612
613 fn cvm_partition_state(shared: &Self::Shared) -> &UhCvmPartitionState {
614 &shared.cvm
615 }
616
617 fn switch_vtl(this: &mut UhProcessor<'_, Self>, _source_vtl: GuestVtl, target_vtl: GuestVtl) {
618 this.backing.cvm_state_mut().exit_vtl = target_vtl;
622 }
623
624 fn translation_registers(
625 &self,
626 this: &UhProcessor<'_, Self>,
627 vtl: GuestVtl,
628 ) -> TranslationRegisters {
629 let cr0 = this.backing.vtls[vtl].cr0.read(&this.runner);
630 let cr4 = this.backing.vtls[vtl].cr4.read(&this.runner);
631 let efer = this.backing.vtls[vtl].efer;
632 let cr3 = this.runner.read_vmcs64(vtl, VmcsField::VMX_VMCS_GUEST_CR3);
633 let ss = this.read_segment(vtl, TdxSegmentReg::Ss).into();
634 let rflags = this.backing.vtls[vtl].private_regs.rflags;
635
636 TranslationRegisters {
637 cr0,
638 cr4,
639 efer,
640 cr3,
641 ss,
642 rflags,
643 encryption_mode: this.partition.caps.vtom.map_or(
644 virt_support_x86emu::translate::EncryptionMode::None,
645 virt_support_x86emu::translate::EncryptionMode::Vtom,
646 ),
647 }
648 }
649
650 fn tlb_flush_lock_access<'a>(
651 vp_index: Option<VpIndex>,
652 partition: &'a UhPartitionInner,
653 shared: &'a Self::Shared,
654 ) -> impl TlbFlushLockAccess + 'a {
655 TdxTlbLockFlushAccess {
656 vp_index,
657 partition,
658 shared,
659 }
660 }
661
662 fn pending_event_vector(this: &UhProcessor<'_, Self>, vtl: GuestVtl) -> Option<u8> {
663 let event_inject = this.backing.vtls[vtl].interruption_information;
664 if event_inject.valid() {
665 Some(event_inject.vector())
666 } else {
667 None
668 }
669 }
670
671 fn set_pending_exception(
672 this: &mut UhProcessor<'_, Self>,
673 vtl: GuestVtl,
674 event: HvX64PendingExceptionEvent,
675 ) {
676 let new_intr = InterruptionInformation::new()
677 .with_valid(true)
678 .with_deliver_error_code(event.deliver_error_code())
679 .with_vector(event.vector().try_into().unwrap())
680 .with_interruption_type(INTERRUPT_TYPE_HARDWARE_EXCEPTION);
681
682 this.backing.vtls[vtl].interruption_information = new_intr;
683 this.backing.vtls[vtl].exception_error_code = event.error_code();
684 }
685
686 fn cr0(this: &UhProcessor<'_, Self>, vtl: GuestVtl) -> u64 {
687 this.read_cr0(vtl)
688 }
689
690 fn cr4(this: &UhProcessor<'_, Self>, vtl: GuestVtl) -> u64 {
691 this.read_cr4(vtl)
692 }
693
694 fn intercept_message_state(
695 this: &UhProcessor<'_, Self>,
696 vtl: GuestVtl,
697 include_optional_state: bool,
698 ) -> super::InterceptMessageState {
699 let exit = TdxExit(this.runner.tdx_vp_enter_exit_info());
700 let backing_vtl = &this.backing.vtls[vtl];
701 let shared_gps = this.runner.tdx_enter_guest_gps();
702
703 super::InterceptMessageState {
704 instruction_length_and_cr8: exit.instr_info().length() as u8,
705 cpl: exit.cpl(),
706 efer_lma: backing_vtl.efer & X64_EFER_LMA != 0,
707 cs: exit.cs().into(),
708 rip: backing_vtl.private_regs.rip,
709 rflags: backing_vtl.private_regs.rflags,
710 rax: shared_gps[TdxGp::RAX],
711 rdx: shared_gps[TdxGp::RDX],
712 optional: if include_optional_state {
713 Some(super::InterceptMessageOptionalState {
714 ds: this.read_segment(vtl, TdxSegmentReg::Ds).into(),
715 es: this.read_segment(vtl, TdxSegmentReg::Es).into(),
716 })
717 } else {
718 None
719 },
720 rcx: shared_gps[TdxGp::RCX],
721 rsi: shared_gps[TdxGp::RSI],
722 rdi: shared_gps[TdxGp::RDI],
723 }
724 }
725
726 fn cr_intercept_registration(
727 this: &mut UhProcessor<'_, Self>,
728 intercept_control: hvdef::HvRegisterCrInterceptControl,
729 ) {
730 let vtl = GuestVtl::Vtl0;
732 let intercept_masks = &this
733 .backing
734 .cvm_state()
735 .vtl1
736 .as_ref()
737 .unwrap()
738 .reg_intercept;
739
740 this.runner.write_vmcs64(
742 vtl,
743 VmcsField::VMX_VMCS_CR0_GUEST_HOST_MASK,
744 !0,
745 this.shared.cr_guest_host_mask(ShadowedRegister::Cr0)
746 | if intercept_control.cr0_write() {
747 intercept_masks.cr0_mask
748 } else {
749 0
750 },
751 );
752 this.runner.write_vmcs64(
753 vtl,
754 VmcsField::VMX_VMCS_CR4_GUEST_HOST_MASK,
755 !0,
756 this.shared.cr_guest_host_mask(ShadowedRegister::Cr4)
757 | if intercept_control.cr4_write() {
758 intercept_masks.cr4_mask
759 } else {
760 0
761 },
762 );
763
764 let intercept_tables = intercept_control.gdtr_write()
766 | intercept_control.idtr_write()
767 | intercept_control.ldtr_write()
768 | intercept_control.tr_write();
769 this.runner.write_vmcs32(
770 vtl,
771 VmcsField::VMX_VMCS_SECONDARY_PROCESSOR_CONTROLS,
772 SecondaryProcessorControls::new()
773 .with_descriptor_table_exiting(true)
774 .into_bits(),
775 SecondaryProcessorControls::new()
776 .with_descriptor_table_exiting(intercept_tables)
777 .into_bits(),
778 );
779
780 this.runner.set_msr_bit(
784 vtl,
785 x86defs::X86X_MSR_S_CET,
786 true,
787 intercept_control.msr_scet_write(),
788 );
789 this.runner.set_msr_bit(
790 vtl,
791 x86defs::X86X_MSR_PL0_SSP,
792 true,
793 intercept_control.msr_pls_ssp_write(),
794 );
795 this.runner.set_msr_bit(
796 vtl,
797 x86defs::X86X_MSR_PL1_SSP,
798 true,
799 intercept_control.msr_pls_ssp_write(),
800 );
801 this.runner.set_msr_bit(
802 vtl,
803 x86defs::X86X_MSR_PL2_SSP,
804 true,
805 intercept_control.msr_pls_ssp_write(),
806 );
807 this.runner.set_msr_bit(
808 vtl,
809 x86defs::X86X_MSR_PL3_SSP,
810 true,
811 intercept_control.msr_pls_ssp_write(),
812 );
813 this.runner.set_msr_bit(
814 vtl,
815 x86defs::X86X_MSR_INTERRUPT_SSP_TABLE_ADDR,
816 true,
817 intercept_control.msr_pls_ssp_write(),
818 );
819 }
820
821 fn is_interrupt_pending(
822 this: &mut UhProcessor<'_, Self>,
823 vtl: GuestVtl,
824 check_rflags: bool,
825 dev: &impl CpuIo,
826 ) -> bool {
827 let backing_vtl = &this.backing.vtls[vtl];
828 if backing_vtl.interruption_information.valid()
829 && backing_vtl.interruption_information.interruption_type() == INTERRUPT_TYPE_NMI
830 {
831 return true;
832 }
833
834 let (vector, ppr) = if this.backing.cvm.lapics[vtl].lapic.is_offloaded() {
835 let vector = backing_vtl.private_regs.rvi;
836 let ppr = std::cmp::max(
837 backing_vtl.private_regs.svi.into(),
838 this.runner.tdx_apic_page(vtl).tpr.value,
839 );
840 (vector, ppr)
841 } else {
842 let lapic = &mut this.backing.cvm.lapics[vtl].lapic;
843 let vector = lapic.next_irr().unwrap_or(0);
844 let ppr = lapic
845 .access(&mut TdxApicClient {
846 partition: this.partition,
847 apic_page: this.runner.tdx_apic_page_mut(vtl),
848 dev,
849 vmtime: &this.vmtime,
850 vtl,
851 })
852 .get_ppr();
853 (vector, ppr)
854 };
855 let vector_priority = (vector as u32) >> 4;
856 let ppr_priority = ppr >> 4;
857
858 if vector_priority <= ppr_priority {
859 return false;
860 }
861
862 if check_rflags && !RFlags::from_bits(backing_vtl.private_regs.rflags).interrupt_enable() {
863 return false;
864 }
865
866 let interruptibility: Interruptibility = this
867 .runner
868 .read_vmcs32(vtl, VmcsField::VMX_VMCS_GUEST_INTERRUPTIBILITY)
869 .into();
870
871 if interruptibility.blocked_by_sti() || interruptibility.blocked_by_movss() {
872 return false;
873 }
874
875 true
876 }
877
878 fn untrusted_synic_mut(&mut self) -> Option<&mut ProcessorSynic> {
879 self.untrusted_synic.as_mut()
880 }
881
882 fn update_deadline(this: &mut UhProcessor<'_, Self>, ref_time_now: u64, next_ref_time: u64) {
883 this.shared
884 .guest_timer
885 .update_deadline(this, ref_time_now, next_ref_time);
886 }
887
888 fn clear_deadline(this: &mut UhProcessor<'_, Self>) {
889 this.shared.guest_timer.clear_deadline(this);
890 }
891}
892
893#[derive(Inspect)]
895pub struct TdxBackedShared {
896 #[inspect(flatten)]
897 pub(crate) cvm: UhCvmPartitionState,
898 pub(crate) untrusted_synic: Option<GlobalSynic>,
902 flush_state: VtlArray<TdxPartitionFlushState, 2>,
903 #[inspect(iter_by_index)]
904 active_vtl: Vec<AtomicU8>,
905 cr4_allowed_bits: u64,
907 #[inspect(skip)]
909 guest_timer: Box<dyn hardware_cvm::HardwareIsolatedGuestTimer<TdxBacked>>,
910}
911
912impl TdxBackedShared {
913 pub(crate) fn new(
914 partition_params: &UhPartitionNewParams<'_>,
915 params: BackingSharedParams<'_>,
916 ) -> Result<Self, crate::Error> {
917 let untrusted_synic = (partition_params.handle_synic && !partition_params.hide_isolation)
923 .then(|| GlobalSynic::new(partition_params.topology.vp_count()));
924
925 let cr4_fixed1 = params.hcl.read_vmx_cr4_fixed1();
927 let cr4_allowed_bits =
928 (ShadowedRegister::Cr4.guest_owned_mask() | X64_CR4_MCE) & cr4_fixed1;
929
930 let cvm = params.cvm_state.unwrap();
931
932 let guest_timer: Box<dyn hardware_cvm::HardwareIsolatedGuestTimer<TdxBacked>> =
934 match params.lower_vtl_timer_virt_available {
935 true => {
936 let tsc_frequency = get_tsc_frequency(IsolationType::Tdx).unwrap();
939 const NUM_100NS_IN_SEC: u128 = 10_000_000;
940 let tsc_scale_100ns = ((tsc_frequency as u128) << 64) / NUM_100NS_IN_SEC;
941
942 tracing::info!(CVM_ALLOWED, "enabling TDX L2-VM TSC deadline timer service");
943
944 Box::new(TdxTscDeadlineService { tsc_scale_100ns })
945 }
946 false => {
947 Box::new(hardware_cvm::VmTimeGuestTimer)
949 }
950 };
951
952 Ok(Self {
953 untrusted_synic,
954 flush_state: VtlArray::from_fn(|_| TdxPartitionFlushState::new()),
955 cvm,
956 active_vtl: std::iter::repeat_n(2, partition_params.topology.vp_count() as usize)
958 .map(AtomicU8::new)
959 .collect(),
960 cr4_allowed_bits,
961 guest_timer,
962 })
963 }
964
965 fn cr_guest_host_mask(&self, reg: ShadowedRegister) -> u64 {
967 match reg {
968 ShadowedRegister::Cr0 => {
969 !ShadowedRegister::Cr0.guest_owned_mask() | X64_CR0_PE | X64_CR0_PG
970 }
971 ShadowedRegister::Cr4 => {
972 !(ShadowedRegister::Cr4.guest_owned_mask() & self.cr4_allowed_bits)
973 }
974 }
975 }
976}
977
978impl TdxBacked {
979 pub fn shared_pages_required_per_cpu() -> u64 {
982 UhDirectOverlay::Count as u64
983 }
984}
985
986struct UntrustedSynicVtlProts<'a>(&'a GuestMemory);
990
991impl hv1_emulator::VtlProtectAccess for UntrustedSynicVtlProts<'_> {
992 fn check_modify_and_lock_overlay_page(
993 &mut self,
994 gpn: u64,
995 _check_perms: hvdef::HvMapGpaFlags,
996 _new_perms: Option<hvdef::HvMapGpaFlags>,
997 ) -> Result<guestmem::LockedPages, HvError> {
998 self.0
1001 .lock_gpns(guestmem::AccessType::Write, false, &[gpn])
1002 .map_err(|_| HvError::OperationFailed)
1003 }
1004
1005 fn unlock_overlay_page(&mut self, _gpn: u64) -> Result<(), HvError> {
1006 Ok(())
1007 }
1008}
1009
1010#[expect(private_interfaces)]
1011impl BackingPrivate for TdxBacked {
1012 type HclBacking<'tdx> = Tdx<'tdx>;
1013 type Shared = TdxBackedShared;
1014 type EmulationCache = TdxEmulationCache;
1015
1016 fn shared(shared: &BackingShared) -> &Self::Shared {
1017 let BackingShared::Tdx(shared) = shared else {
1018 unreachable!()
1019 };
1020 shared
1021 }
1022
1023 fn new(
1024 params: super::BackingParams<'_, '_, Self>,
1025 shared: &TdxBackedShared,
1026 ) -> Result<Self, crate::Error> {
1027 params.runner.write_vmcs32(
1035 GuestVtl::Vtl0,
1036 VmcsField::VMX_VMCS_SECONDARY_PROCESSOR_CONTROLS,
1037 SecondaryProcessorControls::new()
1038 .with_mode_based_execute_control(true)
1039 .into(),
1040 SecondaryProcessorControls::new()
1041 .with_mode_based_execute_control(true)
1042 .into(),
1043 );
1044
1045 let controls = TdxL2Ctls::new()
1046 .with_enable_shared_ept(!shared.cvm.hide_isolation)
1048 .with_enable_tdvmcall(shared.untrusted_synic.is_none() && !shared.cvm.hide_isolation);
1050
1051 params
1052 .runner
1053 .set_l2_ctls(GuestVtl::Vtl0, controls)
1054 .map_err(crate::Error::FailedToSetL2Ctls)?;
1055
1056 for vtl in [GuestVtl::Vtl0, GuestVtl::Vtl1] {
1057 let initial_cr0 = params
1060 .runner
1061 .read_vmcs64(vtl, VmcsField::VMX_VMCS_GUEST_CR0);
1062 assert_eq!(initial_cr0, X64_CR0_PE | X64_CR0_NE);
1063
1064 params.runner.write_vmcs64(
1068 vtl,
1069 VmcsField::VMX_VMCS_CR0_READ_SHADOW,
1070 !0,
1071 X64_CR0_PE | X64_CR0_NE,
1072 );
1073 params.runner.write_vmcs64(
1074 vtl,
1075 VmcsField::VMX_VMCS_CR0_GUEST_HOST_MASK,
1076 !0,
1077 shared.cr_guest_host_mask(ShadowedRegister::Cr0),
1078 );
1079
1080 let initial_cr4 = params
1081 .runner
1082 .read_vmcs64(vtl, VmcsField::VMX_VMCS_GUEST_CR4);
1083 assert_eq!(initial_cr4, X64_CR4_MCE | X64_CR4_VMXE);
1084
1085 params
1086 .runner
1087 .write_vmcs64(vtl, VmcsField::VMX_VMCS_CR4_READ_SHADOW, !0, 0);
1088 params.runner.write_vmcs64(
1089 vtl,
1090 VmcsField::VMX_VMCS_CR4_GUEST_HOST_MASK,
1091 !0,
1092 shared.cr_guest_host_mask(ShadowedRegister::Cr4),
1093 );
1094
1095 for msr in MSR_ALLOWED_READ {
1099 params.runner.set_msr_bit(vtl, *msr, false, false);
1100 }
1101 for msr in MSR_ALLOWED_READ_WRITE {
1102 params.runner.set_msr_bit(vtl, *msr, false, false);
1103 params.runner.set_msr_bit(vtl, *msr, true, false);
1104 }
1105
1106 if params.partition.intercept_debug_exceptions {
1108 if cfg!(feature = "gdb") {
1109 let initial_exception_bitmap = params
1110 .runner
1111 .read_vmcs32(vtl, VmcsField::VMX_VMCS_EXCEPTION_BITMAP);
1112
1113 let exception_bitmap =
1114 initial_exception_bitmap | (1 << x86defs::Exception::DEBUG.0);
1115
1116 params.runner.write_vmcs32(
1117 vtl,
1118 VmcsField::VMX_VMCS_EXCEPTION_BITMAP,
1119 !0,
1120 exception_bitmap,
1121 );
1122 } else {
1123 return Err(super::Error::InvalidDebugConfiguration);
1124 }
1125 }
1126 }
1127
1128 let flush_page = shared
1129 .cvm
1130 .private_dma_client
1131 .allocate_dma_buffer(HV_PAGE_SIZE as usize)
1132 .map_err(crate::Error::AllocateTlbFlushPage)?;
1133
1134 let untrusted_synic = shared
1135 .untrusted_synic
1136 .as_ref()
1137 .map(|synic| synic.add_vp(params.vp_info.base.vp_index));
1138
1139 Ok(Self {
1140 vtls: VtlArray::from_fn(|vtl| {
1141 let vtl: GuestVtl = vtl.try_into().unwrap();
1142 TdxVtl {
1143 efer: params
1144 .runner
1145 .read_vmcs64(vtl, VmcsField::VMX_VMCS_GUEST_EFER),
1146 cr0: VirtualRegister::new(
1147 ShadowedRegister::Cr0,
1148 vtl,
1149 params
1150 .runner
1151 .read_vmcs64(vtl, VmcsField::VMX_VMCS_GUEST_CR0),
1152 !0,
1153 ),
1154 cr4: VirtualRegister::new(
1155 ShadowedRegister::Cr4,
1156 vtl,
1157 params
1158 .runner
1159 .read_vmcs64(vtl, VmcsField::VMX_VMCS_GUEST_CR4),
1160 shared.cr4_allowed_bits,
1161 ),
1162 msr_cstar: 0,
1163 tpr_threshold: 0,
1164 processor_controls: params
1165 .runner
1166 .read_vmcs32(vtl, VmcsField::VMX_VMCS_PROCESSOR_CONTROLS)
1167 .into(),
1168 interruption_information: Default::default(),
1169 exception_error_code: 0,
1170 interruption_set: false,
1171 flush_state: TdxFlushState::new(),
1172 private_regs: TdxPrivateRegs::new(vtl),
1173 enter_stats: Default::default(),
1174 exit_stats: Default::default(),
1175 }
1176 }),
1177 untrusted_synic,
1178 eoi_exit_bitmap: [0; 4],
1179 flush_page,
1180 cvm: UhCvmVpState::new(
1181 &shared.cvm,
1182 params.partition,
1183 params.vp_info,
1184 UhDirectOverlay::Count as usize,
1185 )?,
1186 tsc_deadline_state: shared
1187 .guest_timer
1188 .is_hardware_virtualized()
1189 .then(TdxTscDeadline::default),
1190 })
1191 }
1192
1193 type StateAccess<'p, 'a>
1194 = UhVpStateAccess<'a, 'p, Self>
1195 where
1196 Self: 'a + 'p,
1197 'p: 'a;
1198
1199 fn access_vp_state<'a, 'p>(
1200 this: &'a mut UhProcessor<'p, Self>,
1201 vtl: GuestVtl,
1202 ) -> Self::StateAccess<'p, 'a> {
1203 UhVpStateAccess::new(this, vtl)
1204 }
1205
1206 fn init(this: &mut UhProcessor<'_, Self>) {
1207 let pfns = &this.backing.cvm.direct_overlay_handle.pfns();
1210 let reg = |gpn| {
1211 u64::from(
1212 HvSynicSimpSiefp::new()
1213 .with_base_gpn(gpn)
1214 .with_enabled(true),
1215 )
1216 };
1217
1218 let values: &[(HvX64RegisterName, u64); 2] = &[
1219 (
1220 HvX64RegisterName::Sifp,
1221 reg(pfns[UhDirectOverlay::Sifp as usize]),
1222 ),
1223 (
1224 HvX64RegisterName::Sipp,
1225 reg(pfns[UhDirectOverlay::Sipp as usize]),
1226 ),
1227 ];
1228
1229 let reg_count = if let Some(synic) = &mut this.backing.untrusted_synic {
1230 let prot_access = &mut UntrustedSynicVtlProts(&this.partition.gm[GuestVtl::Vtl0]);
1231
1232 synic
1233 .set_simp(reg(pfns[UhDirectOverlay::Sipp as usize]), prot_access)
1234 .unwrap();
1235 synic
1236 .set_siefp(reg(pfns[UhDirectOverlay::Sifp as usize]), prot_access)
1237 .unwrap();
1238 1
1242 } else {
1243 2
1244 };
1245
1246 this.runner
1247 .set_vp_registers_hvcall(Vtl::Vtl0, &values[..reg_count])
1248 .expect("set_vp_registers hypercall for direct overlays should succeed");
1249
1250 this.set_apic_offload(GuestVtl::Vtl0, true);
1252 this.backing.cvm.lapics[GuestVtl::Vtl0]
1253 .lapic
1254 .enable_offload();
1255
1256 this.set_apic_offload(GuestVtl::Vtl1, false);
1258
1259 for vtl in [GuestVtl::Vtl0, GuestVtl::Vtl1] {
1264 let registers = Registers::at_reset(&this.partition.caps, &this.inner.vp_info);
1265
1266 let mut state = this.access_state(vtl.into());
1267 state
1268 .set_registers(®isters)
1269 .expect("Resetting to architectural state should succeed");
1270
1271 state.commit().expect("committing state should succeed");
1272 }
1273
1274 *this.runner.fx_state_mut() =
1277 vp::Xsave::at_reset(&this.partition.caps, &this.inner.vp_info).fxsave();
1278 }
1279
1280 async fn run_vp(
1281 this: &mut UhProcessor<'_, Self>,
1282 dev: &impl CpuIo,
1283 _stop: &mut virt::StopVp<'_>,
1284 ) -> Result<(), VpHaltReason> {
1285 this.run_vp_tdx(dev).await
1286 }
1287
1288 fn poll_apic(this: &mut UhProcessor<'_, Self>, vtl: GuestVtl, scan_irr: bool) {
1289 if !this.try_poll_apic(vtl, scan_irr) {
1290 tracing::info!(CVM_ALLOWED, "disabling APIC offload due to auto EOI");
1291 let page = this.runner.tdx_apic_page_mut(vtl);
1292 let (irr, isr) = pull_apic_offload(page);
1293
1294 this.backing.cvm.lapics[vtl]
1295 .lapic
1296 .disable_offload(&irr, &isr);
1297 this.set_apic_offload(vtl, false);
1298 this.try_poll_apic(vtl, false);
1299 }
1300 }
1301
1302 fn request_extint_readiness(_this: &mut UhProcessor<'_, Self>) {
1303 unreachable!("extint managed through software apic")
1304 }
1305
1306 fn request_untrusted_sint_readiness(this: &mut UhProcessor<'_, Self>, sints: u16) {
1307 if let Some(synic) = &mut this.backing.untrusted_synic {
1308 synic.request_sint_readiness(sints);
1309 } else {
1310 tracelimit::error_ratelimited!(CVM_ALLOWED, "untrusted synic is not configured");
1311 }
1312 }
1313
1314 fn hv(&self, vtl: GuestVtl) -> Option<&ProcessorVtlHv> {
1315 Some(&self.cvm.hv[vtl])
1316 }
1317
1318 fn hv_mut(&mut self, vtl: GuestVtl) -> Option<&mut ProcessorVtlHv> {
1319 Some(&mut self.cvm.hv[vtl])
1320 }
1321
1322 fn handle_vp_start_enable_vtl_wake(this: &mut UhProcessor<'_, Self>, vtl: GuestVtl) {
1323 this.hcvm_handle_vp_start_enable_vtl(vtl)
1324 }
1325
1326 fn vtl1_inspectable(this: &UhProcessor<'_, Self>) -> bool {
1327 this.hcvm_vtl1_inspectable()
1328 }
1329
1330 fn process_interrupts(
1331 this: &mut UhProcessor<'_, Self>,
1332 scan_irr: VtlArray<bool, 2>,
1333 first_scan_irr: &mut bool,
1334 dev: &impl CpuIo,
1335 ) -> bool {
1336 this.cvm_process_interrupts(scan_irr, first_scan_irr, dev)
1337 }
1338}
1339
1340impl UhProcessor<'_, TdxBacked> {
1341 fn try_poll_apic(&mut self, vtl: GuestVtl, scan_irr: bool) -> bool {
1344 let mut scan = TdxApicScanner {
1345 processor_controls: self.backing.vtls[vtl]
1346 .processor_controls
1347 .with_nmi_window_exiting(false)
1348 .with_interrupt_window_exiting(false),
1349 vp: self,
1350 tpr_threshold: 0,
1351 };
1352
1353 hardware_cvm::apic::poll_apic_core(&mut scan, vtl, scan_irr);
1355
1356 let TdxApicScanner {
1357 vp: _,
1358 processor_controls: new_processor_controls,
1359 tpr_threshold: new_tpr_threshold,
1360 } = scan;
1361
1362 if self.backing.cvm.lapics[vtl].activity != MpState::WaitForSipi
1364 && self.backing.vtls[vtl].tpr_threshold != new_tpr_threshold
1365 {
1366 tracing::trace!(new_tpr_threshold, ?vtl, "setting tpr threshold");
1367 self.runner.write_vmcs32(
1368 vtl,
1369 VmcsField::VMX_VMCS_TPR_THRESHOLD,
1370 !0,
1371 new_tpr_threshold.into(),
1372 );
1373 self.backing.vtls[vtl].tpr_threshold = new_tpr_threshold;
1374 }
1375
1376 if self.backing.vtls[vtl].processor_controls != new_processor_controls {
1377 tracing::trace!(?new_processor_controls, ?vtl, "requesting window change");
1378 self.runner.write_vmcs32(
1379 vtl,
1380 VmcsField::VMX_VMCS_PROCESSOR_CONTROLS,
1381 !0,
1382 new_processor_controls.into(),
1383 );
1384 self.backing.vtls[vtl].processor_controls = new_processor_controls;
1385 }
1386
1387 if vtl == GuestVtl::Vtl0 {
1389 let mut update_rvi = false;
1390 let r: Result<(), OffloadNotSupported> = self.backing.cvm.lapics[vtl]
1391 .lapic
1392 .push_to_offload(|irr, isr, tmr| {
1393 let apic_page = self.runner.tdx_apic_page_mut(vtl);
1394
1395 for (((irr, page_irr), isr), page_isr) in irr
1396 .iter()
1397 .zip(&mut apic_page.irr)
1398 .zip(isr)
1399 .zip(&mut apic_page.isr)
1400 {
1401 page_irr.value |= *irr;
1402 page_isr.value |= *isr;
1403 }
1404
1405 let svi = top_vector(&apic_page.isr);
1407 self.backing.vtls[vtl].private_regs.svi = svi;
1408 update_rvi = true;
1409
1410 let fields = [
1412 VmcsField::VMX_VMCS_EOI_EXIT_0,
1413 VmcsField::VMX_VMCS_EOI_EXIT_1,
1414 VmcsField::VMX_VMCS_EOI_EXIT_2,
1415 VmcsField::VMX_VMCS_EOI_EXIT_3,
1416 ];
1417 for ((&field, eoi_exit), (i, tmr)) in fields
1418 .iter()
1419 .zip(&mut self.backing.eoi_exit_bitmap)
1420 .zip(tmr.chunks_exact(2).enumerate())
1421 {
1422 let tmr = tmr[0] as u64 | ((tmr[1] as u64) << 32);
1423 if *eoi_exit != tmr {
1424 self.runner.write_vmcs64(vtl, field, !0, tmr);
1425 *eoi_exit = tmr;
1426 self.runner.proxy_irr_exit_mut_vtl0()[i * 2] = tmr as u32;
1432 self.runner.proxy_irr_exit_mut_vtl0()[i * 2 + 1] = (tmr >> 32) as u32;
1433 }
1434 }
1435 });
1436
1437 if let Err(OffloadNotSupported) = r {
1438 return false;
1441 }
1442
1443 if update_rvi {
1444 let page = self.runner.tdx_apic_page_mut(vtl);
1445 let rvi = top_vector(&page.irr);
1446 self.backing.vtls[vtl].private_regs.rvi = rvi;
1447 }
1448 }
1449
1450 if (self.backing.cvm.lapics[vtl].activity != MpState::Running)
1452 && self.backing.cvm.lapics[vtl].lapic.is_offloaded()
1453 && self.backing.vtls[vtl].private_regs.rvi != 0
1454 {
1455 self.backing.cvm.lapics[vtl].activity = MpState::Running;
1468 }
1469
1470 true
1471 }
1472
1473 fn access_apic_without_offload<R>(
1474 &mut self,
1475 vtl: GuestVtl,
1476 f: impl FnOnce(&mut Self) -> R,
1477 ) -> R {
1478 let offloaded = self.backing.cvm.lapics[vtl].lapic.is_offloaded();
1479 if offloaded {
1480 let (irr, isr) = pull_apic_offload(self.runner.tdx_apic_page_mut(vtl));
1481 self.backing.cvm.lapics[vtl]
1482 .lapic
1483 .disable_offload(&irr, &isr);
1484 }
1485 let r = f(self);
1486 if offloaded {
1487 self.backing.cvm.lapics[vtl].lapic.enable_offload();
1488 }
1489 r
1490 }
1491
1492 fn set_apic_offload(&mut self, vtl: GuestVtl, offload: bool) {
1493 let offload_bitmap = if offload {
1495 (1 << x86defs::apic::ApicRegister::TPR.0)
1496 | (1 << x86defs::apic::ApicRegister::EOI.0)
1497 | (1 << x86defs::apic::ApicRegister::SELF_IPI.0)
1498 } else {
1499 0
1500 };
1501 for offset in [0, 0x100] {
1503 self.runner
1504 .write_msr_bitmap(vtl, offset + X2APIC_MSR_BASE / 64, !0, !offload_bitmap);
1505 }
1506
1507 self.runner.write_vmcs32(
1509 vtl,
1510 VmcsField::VMX_VMCS_SECONDARY_PROCESSOR_CONTROLS,
1511 SecondaryProcessorControls::new()
1512 .with_virtual_interrupt_delivery(true)
1513 .into(),
1514 SecondaryProcessorControls::new()
1515 .with_virtual_interrupt_delivery(offload)
1516 .into(),
1517 );
1518
1519 if offload
1521 && self.backing.vtls[vtl]
1522 .interruption_information
1523 .interruption_type()
1524 == INTERRUPT_TYPE_EXTERNAL
1525 {
1526 self.backing.vtls[vtl]
1527 .interruption_information
1528 .set_valid(false);
1529 }
1530 }
1531}
1532
1533struct TdxApicScanner<'a, 'b> {
1534 vp: &'a mut UhProcessor<'b, TdxBacked>,
1535 processor_controls: ProcessorControls,
1536 tpr_threshold: u8,
1537}
1538
1539impl<'b> hardware_cvm::apic::ApicBacking<'b, TdxBacked> for TdxApicScanner<'_, 'b> {
1540 fn vp(&mut self) -> &mut UhProcessor<'b, TdxBacked> {
1541 self.vp
1542 }
1543
1544 fn handle_interrupt(&mut self, vtl: GuestVtl, vector: u8) {
1545 if self.vp.backing.cvm.lapics[vtl].activity == MpState::Idle {
1547 self.vp.backing.cvm.lapics[vtl].activity = MpState::Running;
1548 }
1549 if self.vp.backing.vtls[vtl].interruption_information.valid()
1553 && self.vp.backing.vtls[vtl]
1554 .interruption_information
1555 .interruption_type()
1556 != INTERRUPT_TYPE_EXTERNAL
1557 {
1558 self.processor_controls.set_interrupt_window_exiting(true);
1559 return;
1560 }
1561
1562 let interruptibility: Interruptibility = self
1564 .vp
1565 .runner
1566 .read_vmcs32(vtl, VmcsField::VMX_VMCS_GUEST_INTERRUPTIBILITY)
1567 .into();
1568
1569 let rflags = RFlags::from(self.vp.backing.vtls[vtl].private_regs.rflags);
1570 if !rflags.interrupt_enable()
1571 || interruptibility.blocked_by_sti()
1572 || interruptibility.blocked_by_movss()
1573 {
1574 self.processor_controls.set_interrupt_window_exiting(true);
1575 return;
1576 }
1577
1578 let priority = vector >> 4;
1579 let apic = self.vp.runner.tdx_apic_page(vtl);
1580 if (apic.tpr.value as u8 >> 4) >= priority {
1581 self.tpr_threshold = priority;
1582 return;
1583 }
1584
1585 self.vp.backing.vtls[vtl].interruption_information = InterruptionInformation::new()
1586 .with_valid(true)
1587 .with_vector(vector)
1588 .with_interruption_type(INTERRUPT_TYPE_EXTERNAL);
1589
1590 self.vp.backing.cvm.lapics[vtl].activity = MpState::Running;
1591 }
1592
1593 fn handle_nmi(&mut self, vtl: GuestVtl) {
1594 if self.vp.backing.cvm.lapics[vtl].activity == MpState::Idle {
1597 self.vp.backing.cvm.lapics[vtl].activity = MpState::Running;
1598 }
1599 if self.vp.backing.vtls[vtl].interruption_information.valid()
1603 && self.vp.backing.vtls[vtl]
1604 .interruption_information
1605 .interruption_type()
1606 != INTERRUPT_TYPE_EXTERNAL
1607 {
1608 self.processor_controls.set_nmi_window_exiting(true);
1609 return;
1610 }
1611
1612 let interruptibility: Interruptibility = self
1613 .vp
1614 .runner
1615 .read_vmcs32(vtl, VmcsField::VMX_VMCS_GUEST_INTERRUPTIBILITY)
1616 .into();
1617
1618 if interruptibility.blocked_by_nmi()
1619 || interruptibility.blocked_by_sti()
1620 || interruptibility.blocked_by_movss()
1621 {
1622 self.processor_controls.set_nmi_window_exiting(true);
1623 return;
1624 }
1625
1626 self.vp.backing.vtls[vtl].interruption_information = InterruptionInformation::new()
1627 .with_valid(true)
1628 .with_vector(2)
1629 .with_interruption_type(INTERRUPT_TYPE_NMI);
1630
1631 self.vp.backing.cvm.lapics[vtl].activity = MpState::Running;
1632 }
1633
1634 fn handle_sipi(&mut self, vtl: GuestVtl, cs: SegmentRegister) {
1635 self.vp.write_segment(vtl, TdxSegmentReg::Cs, cs).unwrap();
1636 self.vp.backing.vtls[vtl].private_regs.rip = 0;
1637 self.vp.backing.cvm.lapics[vtl].activity = MpState::Running;
1638 }
1639}
1640
1641impl UhProcessor<'_, TdxBacked> {
1642 async fn run_vp_tdx(&mut self, dev: &impl CpuIo) -> Result<(), VpHaltReason> {
1643 let next_vtl = self.backing.cvm.exit_vtl;
1644
1645 if self.backing.vtls[next_vtl].interruption_information.valid() {
1646 tracing::trace!(
1647 vector = self.backing.vtls[next_vtl]
1648 .interruption_information
1649 .vector(),
1650 vp_index = self.vp_index().index(),
1651 ?next_vtl,
1652 "injecting interrupt"
1653 );
1654
1655 self.runner.write_vmcs32(
1656 next_vtl,
1657 VmcsField::VMX_VMCS_ENTRY_INTERRUPT_INFO,
1658 !0,
1659 self.backing.vtls[next_vtl].interruption_information.into(),
1660 );
1661 if self.backing.vtls[next_vtl]
1662 .interruption_information
1663 .deliver_error_code()
1664 {
1665 self.runner.write_vmcs32(
1666 next_vtl,
1667 VmcsField::VMX_VMCS_ENTRY_EXCEPTION_ERROR_CODE,
1668 !0,
1669 self.backing.vtls[next_vtl].exception_error_code,
1670 );
1671 }
1672 self.backing.vtls[next_vtl].interruption_set = true;
1673 } else if self.backing.vtls[next_vtl].interruption_set {
1674 self.runner
1675 .write_vmcs32(next_vtl, VmcsField::VMX_VMCS_ENTRY_INTERRUPT_INFO, !0, 0);
1676 self.backing.vtls[next_vtl].interruption_set = false;
1677 }
1678
1679 self.shared.active_vtl[self.vp_index().index() as usize]
1693 .store(next_vtl as u8, Ordering::SeqCst);
1694
1695 self.do_tlb_flush(next_vtl);
1696 self.unlock_tlb_lock(Vtl::Vtl2);
1697 let tlb_halt = self.should_halt_for_tlb_unlock(next_vtl);
1698
1699 let activity = self.backing.cvm.lapics[next_vtl].activity;
1703 let kernel_known_state =
1704 matches!(activity, MpState::Running | MpState::Halted | MpState::Idle);
1705 let halted_other = tlb_halt || !kernel_known_state;
1706
1707 self.runner
1708 .set_halted(activity != MpState::Running || tlb_halt);
1709
1710 let offload_enabled = self.backing.cvm.lapics[next_vtl].lapic.can_offload_irr()
1722 && !self.backing.vtls[next_vtl].interruption_information.valid()
1723 && self.backing.vtls[next_vtl]
1724 .private_regs
1725 .vp_entry_flags
1726 .invd_translations()
1727 == 0;
1728 let x2apic_enabled = self.backing.cvm.lapics[next_vtl].lapic.x2apic_enabled();
1729
1730 let offload_flags = hcl_intr_offload_flags::new()
1731 .with_offload_intr_inject(offload_enabled)
1732 .with_offload_x2apic(offload_enabled && x2apic_enabled)
1733 .with_halted_other(halted_other)
1734 .with_halted_hlt(activity == MpState::Halted)
1735 .with_halted_idle(activity == MpState::Idle);
1736
1737 *self.runner.offload_flags_mut() = offload_flags;
1738
1739 self.shared.guest_timer.begin_vtl_transition(self, next_vtl);
1740
1741 self.runner
1742 .write_private_regs(&self.backing.vtls[next_vtl].private_regs);
1743
1744 let has_intercept = self
1745 .runner
1746 .run()
1747 .map_err(|e| dev.fatal_error(TdxRunVpError(e).into()))?;
1748
1749 self.shared.active_vtl[self.vp_index().index() as usize].store(2, Ordering::Relaxed);
1753
1754 let entered_from_vtl = next_vtl;
1755 self.runner
1756 .read_private_regs(&mut self.backing.vtls[entered_from_vtl].private_regs);
1757
1758 self.shared
1759 .guest_timer
1760 .end_vtl_transition(self, entered_from_vtl);
1761
1762 if offload_enabled && kernel_known_state {
1764 let offload_flags = self.runner.offload_flags_mut();
1765
1766 self.backing.cvm.lapics[entered_from_vtl].activity =
1767 match (offload_flags.halted_hlt(), offload_flags.halted_idle()) {
1768 (false, false) => MpState::Running,
1769 (true, false) => MpState::Halted,
1770 (false, true) => MpState::Idle,
1771 (true, true) => {
1772 tracelimit::warn_ratelimited!(
1773 CVM_ALLOWED,
1774 "Kernel indicates VP is both halted and idle!"
1775 );
1776 activity
1777 }
1778 };
1779 }
1780
1781 if !has_intercept {
1782 return Ok(());
1783 }
1784
1785 let exit_info = TdxExit(self.runner.tdx_vp_enter_exit_info());
1786
1787 if exit_info.code().tdx_exit() >= TdCallResultCode::PENDING_INTERRUPT {
1789 self.backing.vtls[entered_from_vtl]
1790 .enter_stats
1791 .pending_intr
1792 .increment();
1793 return Ok(());
1794 }
1795
1796 self.backing.vtls[entered_from_vtl]
1798 .private_regs
1799 .vp_entry_flags
1800 .set_invd_translations(0);
1801
1802 let stat = match exit_info.code().tdx_exit() {
1804 TdCallResultCode::SUCCESS => {
1805 &mut self.backing.vtls[entered_from_vtl].enter_stats.success
1806 }
1807 TdCallResultCode::L2_EXIT_HOST_ROUTED_ASYNC => {
1808 &mut self.backing.vtls[entered_from_vtl]
1809 .enter_stats
1810 .host_routed_async
1811 }
1812 TdCallResultCode::L2_EXIT_PENDING_INTERRUPT => {
1813 &mut self.backing.vtls[entered_from_vtl]
1814 .enter_stats
1815 .l2_exit_pending_intr
1816 }
1817 TdCallResultCode::L2_EXIT_HOST_ROUTED_TDVMCALL => {
1818 assert_eq!(
1824 exit_info.code().vmx_exit(),
1825 VmxExit::new().with_basic_reason(VmxExitBasic::TDCALL)
1826 );
1827 &mut self.backing.vtls[entered_from_vtl]
1828 .enter_stats
1829 .host_routed_td_vmcall
1830 }
1831 _ => panic!("unexpected tdx exit code {:?}", exit_info.code()),
1832 };
1833
1834 stat.increment();
1835 self.handle_vmx_exit(dev, entered_from_vtl).await?;
1836 Ok(())
1837 }
1838
1839 async fn handle_vmx_exit(
1840 &mut self,
1841 dev: &impl CpuIo,
1842 intercepted_vtl: GuestVtl,
1843 ) -> Result<(), VpHaltReason> {
1844 let exit_info = TdxExit(self.runner.tdx_vp_enter_exit_info());
1845
1846 let vmx_exit = exit_info.code().vmx_exit();
1848 if vmx_exit.vm_enter_failed() {
1849 return Err(self.handle_vm_enter_failed(dev, intercepted_vtl, vmx_exit));
1850 }
1851
1852 let next_interruption = exit_info.idt_vectoring_info();
1853
1854 if self.backing.vtls[intercepted_vtl]
1856 .interruption_information
1857 .valid()
1858 && (!next_interruption.valid()
1859 || self.backing.vtls[intercepted_vtl]
1860 .interruption_information
1861 .interruption_type()
1862 != next_interruption.interruption_type())
1863 {
1864 match self.backing.vtls[intercepted_vtl]
1865 .interruption_information
1866 .interruption_type()
1867 {
1868 INTERRUPT_TYPE_EXTERNAL
1869 if !self.backing.cvm.lapics[intercepted_vtl]
1870 .lapic
1871 .is_offloaded() =>
1872 {
1873 tracing::trace!(
1875 vector = self.backing.vtls[intercepted_vtl]
1876 .interruption_information
1877 .vector(),
1878 "acknowledging interrupt"
1879 );
1880 self.backing.cvm.lapics[intercepted_vtl]
1881 .lapic
1882 .acknowledge_interrupt(
1883 self.backing.vtls[intercepted_vtl]
1884 .interruption_information
1885 .vector(),
1886 );
1887 }
1888 INTERRUPT_TYPE_NMI => {
1889 tracing::debug!("acknowledging NMI");
1891 self.backing.cvm.lapics[intercepted_vtl].nmi_pending = false;
1892 }
1893 _ => {}
1894 }
1895 }
1896
1897 if self.backing.cvm.lapics[intercepted_vtl]
1898 .lapic
1899 .is_offloaded()
1900 {
1901 if next_interruption.valid() {
1914 tracing::debug!(
1915 ?next_interruption,
1916 vp_index = self.vp_index().index(),
1917 "exit requires reinjecting interrupt"
1918 );
1919 self.backing.vtls[intercepted_vtl].interruption_information = next_interruption;
1920 self.backing.vtls[intercepted_vtl].exception_error_code =
1921 exit_info.idt_vectoring_error_code();
1922 self.backing.vtls[intercepted_vtl]
1923 .exit_stats
1924 .needs_interrupt_reinject
1925 .increment();
1926 } else {
1927 self.backing.vtls[intercepted_vtl].interruption_information = Default::default();
1928 }
1929 } else {
1930 if next_interruption.valid()
1934 && !matches!(
1935 next_interruption.interruption_type(),
1936 INTERRUPT_TYPE_EXTERNAL | INTERRUPT_TYPE_NMI
1937 )
1938 {
1939 self.backing.vtls[intercepted_vtl].interruption_information = next_interruption;
1940 self.backing.vtls[intercepted_vtl].exception_error_code =
1941 exit_info.idt_vectoring_error_code();
1942 } else {
1943 self.backing.vtls[intercepted_vtl].interruption_information = Default::default();
1944 }
1945 }
1946
1947 let mut breakpoint_debug_exception = false;
1948 let stat = match vmx_exit.basic_reason() {
1949 VmxExitBasic::IO_INSTRUCTION => {
1950 let io_qual = ExitQualificationIo::from(exit_info.qualification() as u32);
1951
1952 let len = match io_qual.access_size() {
1953 IO_SIZE_8_BIT => 1,
1954 IO_SIZE_16_BIT => 2,
1955 IO_SIZE_32_BIT => 4,
1956 _ => panic!(
1957 "tdx module returned invalid io instr size {}",
1958 io_qual.access_size()
1959 ),
1960 };
1961
1962 let port_access_protected = self.cvm_try_protect_io_port_access(
1963 intercepted_vtl,
1964 io_qual.port(),
1965 io_qual.is_in(),
1966 len,
1967 io_qual.is_string(),
1968 io_qual.rep_prefix(),
1969 );
1970
1971 if !port_access_protected {
1972 if io_qual.is_string() || io_qual.rep_prefix() {
1973 self.emulate(
1978 dev,
1979 self.backing.vtls[intercepted_vtl]
1980 .interruption_information
1981 .valid(),
1982 intercepted_vtl,
1983 TdxEmulationCache::default(),
1984 )
1985 .await?;
1986 } else {
1987 let mut rax = self.runner.tdx_enter_guest_gps()[TdxGp::RAX];
1988 emulate_io(
1989 self.inner.vp_info.base.vp_index,
1990 !io_qual.is_in(),
1991 io_qual.port(),
1992 &mut rax,
1993 len,
1994 dev,
1995 )
1996 .await;
1997 self.runner.tdx_enter_guest_gps_mut()[TdxGp::RAX] = rax;
1998
1999 self.advance_to_next_instruction(intercepted_vtl);
2000 }
2001 }
2002
2003 &mut self.backing.vtls[intercepted_vtl].exit_stats.io
2004 }
2005 VmxExitBasic::MSR_READ => {
2006 let msr = self.runner.tdx_enter_guest_gps()[TdxGp::RCX] as u32;
2007
2008 let result = self.backing.cvm.lapics[intercepted_vtl]
2009 .lapic
2010 .access(&mut TdxApicClient {
2011 partition: self.partition,
2012 vmtime: &self.vmtime,
2013 apic_page: self.runner.tdx_apic_page_mut(intercepted_vtl),
2014 dev,
2015 vtl: intercepted_vtl,
2016 })
2017 .msr_read(msr)
2018 .or_else_if_unknown(|| self.read_msr_cvm(msr, intercepted_vtl))
2019 .or_else_if_unknown(|| self.read_msr_tdx(msr, intercepted_vtl));
2020
2021 let value = match result {
2022 Ok(v) => Some(v),
2023 Err(MsrError::Unknown) => {
2024 tracelimit::warn_ratelimited!(CVM_ALLOWED, msr, "unknown tdx vm msr read");
2025 Some(0)
2026 }
2027 Err(MsrError::InvalidAccess) => None,
2028 };
2029
2030 let inject_gp = if let Some(value) = value {
2031 let gps = self.runner.tdx_enter_guest_gps_mut();
2032 gps[TdxGp::RAX] = (value as u32).into();
2033 gps[TdxGp::RDX] = ((value >> 32) as u32).into();
2034 false
2035 } else {
2036 true
2037 };
2038
2039 if inject_gp {
2040 self.inject_gpf(intercepted_vtl);
2041 } else {
2042 self.advance_to_next_instruction(intercepted_vtl);
2043 }
2044 &mut self.backing.vtls[intercepted_vtl].exit_stats.msr_read
2045 }
2046 VmxExitBasic::MSR_WRITE => {
2047 let gps = self.runner.tdx_enter_guest_gps();
2048 let msr = gps[TdxGp::RCX] as u32;
2049 let value =
2050 (gps[TdxGp::RAX] as u32 as u64) | ((gps[TdxGp::RDX] as u32 as u64) << 32);
2051
2052 if !self.cvm_try_protect_msr_write(intercepted_vtl, msr) {
2053 let result = self.backing.cvm.lapics[intercepted_vtl]
2054 .lapic
2055 .access(&mut TdxApicClient {
2056 partition: self.partition,
2057 vmtime: &self.vmtime,
2058 apic_page: self.runner.tdx_apic_page_mut(intercepted_vtl),
2059 dev,
2060 vtl: intercepted_vtl,
2061 })
2062 .msr_write(msr, value)
2063 .or_else_if_unknown(|| self.write_msr_cvm(msr, value, intercepted_vtl))
2064 .or_else_if_unknown(|| self.write_msr_tdx(msr, value, intercepted_vtl))
2065 .or_else_if_unknown(|| {
2066 if MSR_ALLOWED_READ_WRITE.contains(&msr) {
2068 unreachable!("intercepted a write to MSR {msr}, configured for passthrough by default, that wasn't registered for intercepts by a higher VTL");
2069 }
2070 Err(MsrError::Unknown)
2071 });
2072
2073 let inject_gp = match result {
2074 Ok(()) => false,
2075 Err(MsrError::Unknown) => {
2076 tracelimit::warn_ratelimited!(
2077 CVM_ALLOWED,
2078 msr,
2079 "unknown tdx vm msr write"
2080 );
2081 tracelimit::warn_ratelimited!(
2082 CVM_CONFIDENTIAL,
2083 value,
2084 "unknown tdx vm msr write"
2085 );
2086 false
2087 }
2088 Err(MsrError::InvalidAccess) => true,
2089 };
2090
2091 if inject_gp {
2092 self.inject_gpf(intercepted_vtl);
2093 } else {
2094 self.advance_to_next_instruction(intercepted_vtl);
2095 }
2096 }
2097 &mut self.backing.vtls[intercepted_vtl].exit_stats.msr_write
2098 }
2099 VmxExitBasic::CPUID => {
2100 let gps = self.runner.tdx_enter_guest_gps();
2101 let leaf = gps[TdxGp::RAX] as u32;
2102 let subleaf = gps[TdxGp::RCX] as u32;
2103 let [eax, ebx, ecx, edx] = self.cvm_cpuid_result(intercepted_vtl, leaf, subleaf);
2104 let gps = self.runner.tdx_enter_guest_gps_mut();
2105 gps[TdxGp::RAX] = eax.into();
2106 gps[TdxGp::RBX] = ebx.into();
2107 gps[TdxGp::RCX] = ecx.into();
2108 gps[TdxGp::RDX] = edx.into();
2109 self.advance_to_next_instruction(intercepted_vtl);
2110 &mut self.backing.vtls[intercepted_vtl].exit_stats.cpuid
2111 }
2112 VmxExitBasic::VMCALL_INSTRUCTION => {
2113 if exit_info.cpl() != 0 {
2114 self.inject_gpf(intercepted_vtl);
2115 } else {
2116 let is_64bit = self.long_mode(intercepted_vtl);
2117 let guest_memory = &self.partition.gm[intercepted_vtl];
2118 let handler = UhHypercallHandler {
2119 trusted: !self.cvm_partition().hide_isolation,
2120 vp: &mut *self,
2121 intercepted_vtl,
2122 };
2123
2124 UhHypercallHandler::TDX_DISPATCHER.dispatch(
2125 guest_memory,
2126 hv1_hypercall::X64RegisterIo::new(handler, is_64bit, true),
2127 );
2128 }
2129 &mut self.backing.vtls[intercepted_vtl].exit_stats.vmcall
2130 }
2131 VmxExitBasic::HLT_INSTRUCTION => {
2132 self.backing.cvm.lapics[intercepted_vtl].activity = MpState::Halted;
2133 self.clear_interrupt_shadow(intercepted_vtl);
2134 self.advance_to_next_instruction(intercepted_vtl);
2135 &mut self.backing.vtls[intercepted_vtl].exit_stats.hlt
2136 }
2137 VmxExitBasic::CR_ACCESS => {
2138 let qual = CrAccessQualification::from(exit_info.qualification());
2139 let cr;
2140 let value;
2141 match qual.access_type() {
2142 CR_ACCESS_TYPE_MOV_TO_CR => {
2143 cr = qual.cr();
2144 value = self.runner.tdx_enter_guest_gps()[qual.gp_register() as usize];
2145 }
2146 CR_ACCESS_TYPE_LMSW => {
2147 cr = 0;
2148 let cr0 = self.backing.vtls[intercepted_vtl].cr0.read(&self.runner);
2149 value = (qual.lmsw_source_data() as u64 & 0xf) | (cr0 & !0xf);
2151 }
2152 access_type => unreachable!("not registered for cr access type {access_type}"),
2153 }
2154
2155 let cr = match cr {
2156 0 => HvX64RegisterName::Cr0,
2157 4 => HvX64RegisterName::Cr4,
2158 _ => unreachable!("not registered for cr{cr} accesses"),
2159 };
2160
2161 if !self.cvm_try_protect_secure_register_write(intercepted_vtl, cr, value) {
2162 let r = match cr {
2163 HvX64RegisterName::Cr0 => self.backing.vtls[intercepted_vtl]
2164 .cr0
2165 .write(value, &mut self.runner),
2166 HvX64RegisterName::Cr4 => self.backing.vtls[intercepted_vtl]
2167 .cr4
2168 .write(value, &mut self.runner),
2169 _ => unreachable!(),
2170 };
2171 if r.is_ok() {
2172 self.update_execution_mode(intercepted_vtl);
2173 self.advance_to_next_instruction(intercepted_vtl);
2174 } else {
2175 tracelimit::warn_ratelimited!(
2176 CVM_ALLOWED,
2177 ?cr,
2178 value,
2179 "failed to write cr"
2180 );
2181 self.inject_gpf(intercepted_vtl);
2182 }
2183 }
2184 &mut self.backing.vtls[intercepted_vtl].exit_stats.cr_access
2185 }
2186 VmxExitBasic::XSETBV => {
2187 let gps = self.runner.tdx_enter_guest_gps();
2188 if let Some(value) =
2189 hardware_cvm::validate_xsetbv_exit(hardware_cvm::XsetbvExitInput {
2190 rax: gps[TdxGp::RAX],
2191 rcx: gps[TdxGp::RCX],
2192 rdx: gps[TdxGp::RDX],
2193 cr4: self.backing.vtls[intercepted_vtl].cr4.read(&self.runner),
2194 cpl: exit_info.cpl(),
2195 })
2196 {
2197 if !self.cvm_try_protect_secure_register_write(
2198 intercepted_vtl,
2199 HvX64RegisterName::Xfem,
2200 value,
2201 ) {
2202 self.runner
2203 .set_vp_register(intercepted_vtl, HvX64RegisterName::Xfem, value.into())
2204 .unwrap();
2205 self.advance_to_next_instruction(intercepted_vtl);
2206 }
2207 } else {
2208 self.inject_gpf(intercepted_vtl);
2209 }
2210 &mut self.backing.vtls[intercepted_vtl].exit_stats.xsetbv
2211 }
2212 VmxExitBasic::WBINVD_INSTRUCTION => {
2213 let no_invalidate = exit_info.qualification() != 0;
2215 if no_invalidate {
2216 self.runner.tdx_vp_state_flags_mut().set_wbnoinvd(true);
2217 } else {
2218 self.runner.tdx_vp_state_flags_mut().set_wbinvd(true);
2219 }
2220
2221 self.advance_to_next_instruction(intercepted_vtl);
2222 &mut self.backing.vtls[intercepted_vtl].exit_stats.wbinvd
2223 }
2224 VmxExitBasic::EPT_VIOLATION => {
2225 let gpa = exit_info.gpa().expect("is EPT exit");
2226 let ept_info = VmxEptExitQualification::from(exit_info.qualification());
2227 if !next_interruption.valid() && ept_info.nmi_unmasking_due_to_iret() {
2230 let mask = Interruptibility::new().with_blocked_by_nmi(true);
2231 let value = Interruptibility::new().with_blocked_by_nmi(true);
2232 let old_interruptibility: Interruptibility = self
2233 .runner
2234 .write_vmcs32(
2235 intercepted_vtl,
2236 VmcsField::VMX_VMCS_GUEST_INTERRUPTIBILITY,
2237 mask.into(),
2238 value.into(),
2239 )
2240 .into();
2241 assert!(!old_interruptibility.blocked_by_nmi());
2242 } else {
2243 let is_write = ept_info.access_mask() & 0b10 != 0;
2244 if self.check_mem_fault(intercepted_vtl, gpa, is_write, ept_info) {
2245 self.emulate(
2246 dev,
2247 self.backing.vtls[intercepted_vtl]
2248 .interruption_information
2249 .valid(),
2250 intercepted_vtl,
2251 TdxEmulationCache::default(),
2252 )
2253 .await?;
2254 }
2255 }
2256
2257 &mut self.backing.vtls[intercepted_vtl].exit_stats.ept_violation
2258 }
2259 VmxExitBasic::TPR_BELOW_THRESHOLD => {
2260 &mut self.backing.vtls[intercepted_vtl]
2262 .exit_stats
2263 .tpr_below_threshold
2264 }
2265 VmxExitBasic::INTERRUPT_WINDOW => {
2266 &mut self.backing.vtls[intercepted_vtl]
2268 .exit_stats
2269 .interrupt_window
2270 }
2271 VmxExitBasic::NMI_WINDOW => {
2272 &mut self.backing.vtls[intercepted_vtl].exit_stats.nmi_window
2274 }
2275 VmxExitBasic::HW_INTERRUPT => {
2276 if cfg!(feature = "gdb") {
2277 let debug_regs = self
2279 .access_state(intercepted_vtl.into())
2280 .debug_regs()
2281 .expect("register query should not fail");
2282 breakpoint_debug_exception = debug_regs.dr6.trailing_zeros() < 4;
2285 }
2286 &mut self.backing.vtls[intercepted_vtl].exit_stats.hw_interrupt
2287 }
2288 VmxExitBasic::SMI_INTR => &mut self.backing.vtls[intercepted_vtl].exit_stats.smi_intr,
2289 VmxExitBasic::PAUSE_INSTRUCTION => {
2290 &mut self.backing.vtls[intercepted_vtl].exit_stats.pause
2291 }
2292 VmxExitBasic::TDCALL => {
2293 if self.backing.untrusted_synic.is_some() {
2296 assert_eq!(intercepted_vtl, GuestVtl::Vtl0);
2297 self.handle_tdvmcall(dev, intercepted_vtl);
2298 } else if self.cvm_partition().hide_isolation {
2299 self.backing.vtls[intercepted_vtl].interruption_information =
2301 InterruptionInformation::new()
2302 .with_valid(true)
2303 .with_vector(x86defs::Exception::INVALID_OPCODE.0)
2304 .with_interruption_type(INTERRUPT_TYPE_HARDWARE_EXCEPTION);
2305 }
2306 &mut self.backing.vtls[intercepted_vtl].exit_stats.tdcall
2307 }
2308 VmxExitBasic::EXCEPTION => {
2309 tracing::trace!(
2310 "Caught Exception: {:?}",
2311 exit_info._exit_interruption_info()
2312 );
2313 if cfg!(feature = "gdb") {
2314 breakpoint_debug_exception = true;
2315 }
2316 &mut self.backing.vtls[intercepted_vtl].exit_stats.exception
2317 }
2318 VmxExitBasic::TRIPLE_FAULT => {
2319 return Err(VpHaltReason::TripleFault {
2320 vtl: intercepted_vtl.into(),
2321 });
2322 }
2323 VmxExitBasic::GDTR_OR_IDTR => {
2324 let info = GdtrOrIdtrInstructionInfo::from(exit_info.instr_info().info());
2325 tracing::trace!("Intercepted GDT or IDT instruction: {:?}", info);
2326 let reg = match info.instruction() {
2327 GdtrOrIdtrInstruction::Sidt | GdtrOrIdtrInstruction::Lidt => {
2328 HvX64RegisterName::Idtr
2329 }
2330 GdtrOrIdtrInstruction::Sgdt | GdtrOrIdtrInstruction::Lgdt => {
2331 HvX64RegisterName::Gdtr
2332 }
2333 };
2334 if (info.instruction().is_load()
2336 && !self.cvm_try_protect_secure_register_write(intercepted_vtl, reg, 0))
2337 || !info.instruction().is_load()
2338 {
2339 self.emulate_gdtr_or_idtr(intercepted_vtl, dev).await?;
2340 }
2341 &mut self.backing.vtls[intercepted_vtl]
2342 .exit_stats
2343 .descriptor_table
2344 }
2345 VmxExitBasic::LDTR_OR_TR => {
2346 let info = LdtrOrTrInstructionInfo::from(exit_info.instr_info().info());
2347 tracing::trace!("Intercepted LDT or TR instruction: {:?}", info);
2348 let reg = match info.instruction() {
2349 LdtrOrTrInstruction::Sldt | LdtrOrTrInstruction::Lldt => {
2350 HvX64RegisterName::Ldtr
2351 }
2352 LdtrOrTrInstruction::Str | LdtrOrTrInstruction::Ltr => HvX64RegisterName::Tr,
2353 };
2354 if (info.instruction().is_load()
2356 && !self.cvm_try_protect_secure_register_write(intercepted_vtl, reg, 0))
2357 || !info.instruction().is_load()
2358 {
2359 self.emulate_ldtr_or_tr(intercepted_vtl, dev).await?;
2360 }
2361 &mut self.backing.vtls[intercepted_vtl]
2362 .exit_stats
2363 .descriptor_table
2364 }
2365 VmxExitBasic::TIMER_EXPIRED => {
2366 &mut self.backing.vtls[intercepted_vtl].exit_stats.timer_expired
2368 }
2369 _ => {
2370 return Err(dev.fatal_error(UnknownVmxExit(exit_info.code().vmx_exit()).into()));
2371 }
2372 };
2373 stat.increment();
2374
2375 if cfg!(feature = "gdb") && breakpoint_debug_exception {
2378 self.handle_debug_exception(dev, intercepted_vtl)?;
2379 }
2380
2381 Ok(())
2382 }
2383
2384 fn trace_processor_state(&self, vtl: GuestVtl) {
2386 let raw_exit = self.runner.tdx_vp_enter_exit_info();
2387 tracing::error!(CVM_CONFIDENTIAL, ?raw_exit, "raw tdx vp enter exit info");
2388
2389 let gprs = self.runner.tdx_enter_guest_gps();
2390 tracing::error!(CVM_CONFIDENTIAL, ?gprs, "guest gpr list");
2391
2392 let TdxPrivateRegs {
2393 rflags,
2394 rip,
2395 rsp,
2396 ssp,
2397 rvi,
2398 svi,
2399 msr_kernel_gs_base,
2400 msr_star,
2401 msr_lstar,
2402 msr_sfmask,
2403 msr_xss,
2404 msr_tsc_aux,
2405 vp_entry_flags,
2406 } = self.backing.vtls[vtl].private_regs;
2407 tracing::error!(
2408 CVM_CONFIDENTIAL,
2409 rflags,
2410 rip,
2411 rsp,
2412 ssp,
2413 rvi,
2414 svi,
2415 msr_kernel_gs_base,
2416 msr_star,
2417 msr_lstar,
2418 msr_sfmask,
2419 msr_xss,
2420 msr_tsc_aux,
2421 ?vp_entry_flags,
2422 "private registers"
2423 );
2424
2425 let physical_cr0 = self.runner.read_vmcs64(vtl, VmcsField::VMX_VMCS_GUEST_CR0);
2426 let shadow_cr0 = self
2427 .runner
2428 .read_vmcs64(vtl, VmcsField::VMX_VMCS_CR0_READ_SHADOW);
2429 let cr0_guest_host_mask: u64 = self
2430 .runner
2431 .read_vmcs64(vtl, VmcsField::VMX_VMCS_CR0_GUEST_HOST_MASK);
2432 tracing::error!(
2433 CVM_CONFIDENTIAL,
2434 physical_cr0,
2435 shadow_cr0,
2436 cr0_guest_host_mask,
2437 "cr0 values"
2438 );
2439
2440 let physical_cr4 = self.runner.read_vmcs64(vtl, VmcsField::VMX_VMCS_GUEST_CR4);
2441 let shadow_cr4 = self
2442 .runner
2443 .read_vmcs64(vtl, VmcsField::VMX_VMCS_CR4_READ_SHADOW);
2444 let cr4_guest_host_mask = self
2445 .runner
2446 .read_vmcs64(vtl, VmcsField::VMX_VMCS_CR4_GUEST_HOST_MASK);
2447 tracing::error!(
2448 CVM_CONFIDENTIAL,
2449 physical_cr4,
2450 shadow_cr4,
2451 cr4_guest_host_mask,
2452 "cr4 values"
2453 );
2454
2455 let cr3 = self.runner.read_vmcs64(vtl, VmcsField::VMX_VMCS_GUEST_CR3);
2456 tracing::error!(CVM_CONFIDENTIAL, cr3, "cr3");
2457
2458 let cached_efer = self.backing.vtls[vtl].efer;
2459 let vmcs_efer = self.runner.read_vmcs64(vtl, VmcsField::VMX_VMCS_GUEST_EFER);
2460 let entry_controls = self
2461 .runner
2462 .read_vmcs32(vtl, VmcsField::VMX_VMCS_ENTRY_CONTROLS);
2463 tracing::error!(CVM_CONFIDENTIAL, cached_efer, vmcs_efer, "efer");
2464 tracing::error!(CVM_CONFIDENTIAL, entry_controls, "entry controls");
2465
2466 let cs = self.read_segment(vtl, TdxSegmentReg::Cs);
2467 let ds = self.read_segment(vtl, TdxSegmentReg::Ds);
2468 let es = self.read_segment(vtl, TdxSegmentReg::Es);
2469 let fs = self.read_segment(vtl, TdxSegmentReg::Fs);
2470 let gs = self.read_segment(vtl, TdxSegmentReg::Gs);
2471 let ss = self.read_segment(vtl, TdxSegmentReg::Ss);
2472 let tr = self.read_segment(vtl, TdxSegmentReg::Tr);
2473 let ldtr = self.read_segment(vtl, TdxSegmentReg::Ldtr);
2474
2475 tracing::error!(
2476 CVM_CONFIDENTIAL,
2477 ?cs,
2478 ?ds,
2479 ?es,
2480 ?fs,
2481 ?gs,
2482 ?ss,
2483 ?tr,
2484 ?ldtr,
2485 "segment values"
2486 );
2487
2488 let exception_bitmap = self
2489 .runner
2490 .read_vmcs32(vtl, VmcsField::VMX_VMCS_EXCEPTION_BITMAP);
2491 tracing::error!(CVM_CONFIDENTIAL, exception_bitmap, "exception bitmap");
2492
2493 let cached_processor_controls = self.backing.vtls[vtl].processor_controls;
2494 let vmcs_processor_controls = ProcessorControls::from(
2495 self.runner
2496 .read_vmcs32(vtl, VmcsField::VMX_VMCS_PROCESSOR_CONTROLS),
2497 );
2498 let vmcs_secondary_processor_controls = SecondaryProcessorControls::from(
2499 self.runner
2500 .read_vmcs32(vtl, VmcsField::VMX_VMCS_SECONDARY_PROCESSOR_CONTROLS),
2501 );
2502 tracing::error!(
2503 CVM_CONFIDENTIAL,
2504 ?cached_processor_controls,
2505 ?vmcs_processor_controls,
2506 ?vmcs_secondary_processor_controls,
2507 "processor controls"
2508 );
2509
2510 if cached_processor_controls != vmcs_processor_controls {
2511 tracing::error!(CVM_ALLOWED, "BUGBUG: processor controls mismatch");
2512 }
2513
2514 let cached_tpr_threshold = self.backing.vtls[vtl].tpr_threshold;
2515 let vmcs_tpr_threshold = self
2516 .runner
2517 .read_vmcs32(vtl, VmcsField::VMX_VMCS_TPR_THRESHOLD);
2518 tracing::error!(
2519 CVM_CONFIDENTIAL,
2520 cached_tpr_threshold,
2521 vmcs_tpr_threshold,
2522 "tpr threshold"
2523 );
2524
2525 let cached_eoi_exit_bitmap = self.backing.eoi_exit_bitmap;
2526 let vmcs_eoi_exit_bitmap = {
2527 let fields = [
2528 VmcsField::VMX_VMCS_EOI_EXIT_0,
2529 VmcsField::VMX_VMCS_EOI_EXIT_1,
2530 VmcsField::VMX_VMCS_EOI_EXIT_2,
2531 VmcsField::VMX_VMCS_EOI_EXIT_3,
2532 ];
2533 fields
2534 .iter()
2535 .map(|field| self.runner.read_vmcs64(vtl, *field))
2536 .collect::<Vec<_>>()
2537 };
2538 tracing::error!(
2539 CVM_CONFIDENTIAL,
2540 ?cached_eoi_exit_bitmap,
2541 ?vmcs_eoi_exit_bitmap,
2542 "eoi exit bitmap"
2543 );
2544
2545 let cached_interrupt_information = self.backing.vtls[vtl].interruption_information;
2546 let cached_interruption_set = self.backing.vtls[vtl].interruption_set;
2547 let vmcs_interrupt_information = self
2548 .runner
2549 .read_vmcs32(vtl, VmcsField::VMX_VMCS_ENTRY_INTERRUPT_INFO);
2550 let vmcs_entry_exception_code = self
2551 .runner
2552 .read_vmcs32(vtl, VmcsField::VMX_VMCS_ENTRY_EXCEPTION_ERROR_CODE);
2553 tracing::error!(
2554 CVM_CONFIDENTIAL,
2555 ?cached_interrupt_information,
2556 cached_interruption_set,
2557 vmcs_interrupt_information,
2558 vmcs_entry_exception_code,
2559 "interrupt information"
2560 );
2561
2562 let guest_interruptibility = self
2563 .runner
2564 .read_vmcs32(vtl, VmcsField::VMX_VMCS_GUEST_INTERRUPTIBILITY);
2565 tracing::error!(
2566 CVM_CONFIDENTIAL,
2567 guest_interruptibility,
2568 "guest interruptibility"
2569 );
2570
2571 let vmcs_sysenter_cs = self
2572 .runner
2573 .read_vmcs32(vtl, VmcsField::VMX_VMCS_GUEST_SYSENTER_CS_MSR);
2574 let vmcs_sysenter_esp = self
2575 .runner
2576 .read_vmcs64(vtl, VmcsField::VMX_VMCS_GUEST_SYSENTER_ESP_MSR);
2577 let vmcs_sysenter_eip = self
2578 .runner
2579 .read_vmcs64(vtl, VmcsField::VMX_VMCS_GUEST_SYSENTER_EIP_MSR);
2580 tracing::error!(
2581 CVM_CONFIDENTIAL,
2582 vmcs_sysenter_cs,
2583 vmcs_sysenter_esp,
2584 vmcs_sysenter_eip,
2585 "sysenter values"
2586 );
2587
2588 let vmcs_pat = self.runner.read_vmcs64(vtl, VmcsField::VMX_VMCS_GUEST_PAT);
2589 tracing::error!(CVM_CONFIDENTIAL, vmcs_pat, "guest PAT");
2590 }
2591
2592 fn handle_vm_enter_failed(
2593 &self,
2594 dev: &impl CpuIo,
2595 vtl: GuestVtl,
2596 vmx_exit: VmxExit,
2597 ) -> VpHaltReason {
2598 assert!(vmx_exit.vm_enter_failed());
2599 match vmx_exit.basic_reason() {
2600 VmxExitBasic::BAD_GUEST_STATE => {
2601 tracing::error!(CVM_ALLOWED, "VP.ENTER failed with bad guest state");
2604 self.trace_processor_state(vtl);
2605
2606 dev.fatal_error(VmxBadGuestState.into())
2607 }
2608 _ => dev.fatal_error(UnknownVmxExit(vmx_exit).into()),
2609 }
2610 }
2611
2612 fn advance_to_next_instruction(&mut self, vtl: GuestVtl) {
2613 let instr_info = TdxExit(self.runner.tdx_vp_enter_exit_info()).instr_info();
2614 let rip = &mut self.backing.vtls[vtl].private_regs.rip;
2615 *rip = rip.wrapping_add(instr_info.length().into());
2616 }
2617
2618 fn clear_interrupt_shadow(&mut self, vtl: GuestVtl) {
2619 let mask = Interruptibility::new().with_blocked_by_sti(true);
2620 let value = Interruptibility::new().with_blocked_by_sti(false);
2621 self.runner.write_vmcs32(
2622 vtl,
2623 VmcsField::VMX_VMCS_GUEST_INTERRUPTIBILITY,
2624 mask.into(),
2625 value.into(),
2626 );
2627 }
2628
2629 fn inject_gpf(&mut self, vtl: GuestVtl) {
2630 self.backing.vtls[vtl].interruption_information = InterruptionInformation::new()
2631 .with_valid(true)
2632 .with_vector(x86defs::Exception::GENERAL_PROTECTION_FAULT.0)
2633 .with_interruption_type(INTERRUPT_TYPE_HARDWARE_EXCEPTION)
2634 .with_deliver_error_code(true);
2635 self.backing.vtls[vtl].exception_error_code = 0;
2636 }
2637
2638 fn handle_tdvmcall(&mut self, _dev: &impl CpuIo, intercepted_vtl: GuestVtl) {
2639 let regs = self.runner.tdx_enter_guest_gps();
2640 if regs[TdxGp::R10] == 0 {
2641 let result = match VmxExitBasic(regs[TdxGp::R11] as u16) {
2643 VmxExitBasic::MSR_WRITE => {
2644 let msr = regs[TdxGp::R12] as u32;
2645 let value = regs[TdxGp::R13];
2646 match self.write_tdvmcall_msr(msr, value, intercepted_vtl) {
2647 Ok(()) => {
2648 tracing::debug!(msr, value, "tdvmcall msr write");
2649 TdVmCallR10Result::SUCCESS
2650 }
2651 Err(err) => {
2652 tracelimit::warn_ratelimited!(
2653 CVM_ALLOWED,
2654 msr,
2655 ?err,
2656 "failed tdvmcall msr write"
2657 );
2658 tracelimit::warn_ratelimited!(
2659 CVM_CONFIDENTIAL,
2660 value,
2661 "failed tdvmcall msr write"
2662 );
2663 TdVmCallR10Result::OPERAND_INVALID
2664 }
2665 }
2666 }
2667 VmxExitBasic::MSR_READ => {
2668 let msr = regs[TdxGp::R12] as u32;
2669 match self.read_tdvmcall_msr(msr, intercepted_vtl) {
2670 Ok(value) => {
2671 tracing::debug!(msr, value, "tdvmcall msr read");
2672 self.runner.tdx_enter_guest_gps_mut()[TdxGp::R11] = value;
2673 TdVmCallR10Result::SUCCESS
2674 }
2675 Err(err) => {
2676 tracelimit::warn_ratelimited!(
2677 CVM_ALLOWED,
2678 msr,
2679 ?err,
2680 "failed tdvmcall msr read"
2681 );
2682 TdVmCallR10Result::OPERAND_INVALID
2683 }
2684 }
2685 }
2686 subfunction => {
2687 tracelimit::warn_ratelimited!(
2688 CVM_ALLOWED,
2689 ?subfunction,
2690 "architectural vmcall not supported"
2691 );
2692 TdVmCallR10Result::OPERAND_INVALID
2693 }
2694 };
2695 self.runner.tdx_enter_guest_gps_mut()[TdxGp::R10] = result.0;
2696 self.backing.vtls[intercepted_vtl].private_regs.rip = self.backing.vtls
2697 [intercepted_vtl]
2698 .private_regs
2699 .rip
2700 .wrapping_add(4);
2701 } else {
2702 let guest_memory = &self.shared.cvm.shared_memory;
2709 let handler = UhHypercallHandler {
2710 vp: &mut *self,
2711 trusted: false,
2712 intercepted_vtl,
2713 };
2714
2715 UhHypercallHandler::TDCALL_DISPATCHER.dispatch(guest_memory, TdHypercall(handler));
2716 }
2717 }
2718
2719 fn read_tdvmcall_msr(&mut self, msr: u32, intercepted_vtl: GuestVtl) -> Result<u64, MsrError> {
2720 match msr {
2721 msr @ (hvdef::HV_X64_MSR_GUEST_OS_ID | hvdef::HV_X64_MSR_VP_INDEX) => {
2722 self.backing.cvm.hv[intercepted_vtl].msr_read(msr)
2723 }
2724 _ => self
2725 .backing
2726 .untrusted_synic
2727 .as_mut()
2728 .unwrap()
2729 .read_nontimer_msr(msr),
2730 }
2731 }
2732
2733 fn write_tdvmcall_msr(
2734 &mut self,
2735 msr: u32,
2736 value: u64,
2737 intercepted_vtl: GuestVtl,
2738 ) -> Result<(), MsrError> {
2739 match msr {
2740 hvdef::HV_X64_MSR_GUEST_OS_ID => {
2741 self.backing.cvm.hv[intercepted_vtl].msr_write_guest_os_id(value)
2742 }
2743 _ => {
2744 self.backing
2748 .untrusted_synic
2749 .as_mut()
2750 .unwrap()
2751 .write_nontimer_msr(
2752 msr,
2753 value,
2754 &mut UntrustedSynicVtlProts(&self.partition.gm[GuestVtl::Vtl0]),
2755 )?;
2756 if matches!(msr, hvdef::HV_X64_MSR_SINT0..=hvdef::HV_X64_MSR_SINT15) {
2759 if let Err(err) = self.runner.set_vp_register(
2760 intercepted_vtl,
2761 HvX64RegisterName(
2762 HvX64RegisterName::Sint0.0 + (msr - hvdef::HV_X64_MSR_SINT0),
2763 ),
2764 value.into(),
2765 ) {
2766 tracelimit::warn_ratelimited!(
2767 CVM_ALLOWED,
2768 error = &err as &dyn std::error::Error,
2769 "failed to set sint register"
2770 );
2771 }
2772 }
2773 }
2774 }
2775
2776 Ok(())
2777 }
2778
2779 fn read_msr_tdx(&mut self, msr: u32, vtl: GuestVtl) -> Result<u64, MsrError> {
2780 match msr {
2787 x86defs::X86X_IA32_MSR_PLATFORM_ID => {
2789 Ok(0)
2797 }
2798
2799 x86defs::X86X_MSR_MTRR_CAP => {
2800 Ok(0x400)
2803 }
2804 x86defs::X86X_MSR_MTRR_DEF_TYPE => {
2805 Ok(0)
2809 }
2810 x86defs::X86X_MSR_CSTAR => Ok(self.backing.vtls[vtl].msr_cstar),
2811 x86defs::X86X_MSR_MCG_CAP => Ok(0),
2812 x86defs::X86X_MSR_MCG_STATUS => Ok(0),
2813 x86defs::X86X_MSR_MC_UPDATE_PATCH_LEVEL => Ok(0xFFFFFFFF),
2814 x86defs::X86X_MSR_XSS => Ok(self.backing.vtls[vtl].private_regs.msr_xss),
2815 x86defs::X86X_IA32_MSR_MISC_ENABLE => Ok(hv1_emulator::x86::MISC_ENABLE.into()),
2816 x86defs::X86X_IA32_MSR_FEATURE_CONTROL => {
2817 Ok(u64::from(Ia32FeatureControl::new().with_locked(true)))
2818 }
2819 x86defs::X86X_MSR_CR_PAT => {
2820 let pat = self.runner.read_vmcs64(vtl, VmcsField::VMX_VMCS_GUEST_PAT);
2821 Ok(pat)
2822 }
2823
2824 x86defs::X86X_MSR_MISC_FEATURE_ENABLES
2827 | x86defs::X86X_MSR_PLATFORM_INFO
2828 | x86defs::X86X_MSR_PPIN_CTL
2829 | x86defs::X86X_IA32_MSR_SMI_COUNT
2830 | x86defs::X86X_MSR_UMWAIT_CONTROL
2831 | x86defs::X86X_AMD_MSR_DE_CFG
2832 | x86defs::X86X_IA32_MSR_RAPL_POWER_UNIT
2833 | x86defs::X86X_IA32_MSR_PKG_ENERGY_STATUS
2834 | x86defs::X86X_IA32_MSR_DRAM_ENERGY_STATUS
2835 | x86defs::X86X_IA32_MSR_PP0_ENERGY_STATUS => Ok(0),
2836
2837 hvdef::HV_X64_MSR_GUEST_IDLE => {
2838 self.backing.cvm.lapics[vtl].activity = MpState::Idle;
2839 self.clear_interrupt_shadow(vtl);
2840 Ok(0)
2841 }
2842 X86X_MSR_EFER => Ok(self.backing.vtls[vtl].efer),
2843
2844 _ => Err(MsrError::Unknown),
2845 }
2846 }
2847
2848 fn write_msr_tdx(&mut self, msr: u32, value: u64, vtl: GuestVtl) -> Result<(), MsrError> {
2849 hardware_cvm::validate_cvm_msr_write(msr, value, &self.partition.caps.xsave)?;
2850
2851 let state = &mut self.backing.vtls[vtl].private_regs;
2852
2853 match msr {
2854 X86X_MSR_EFER => {
2855 self.write_efer(vtl, value)
2856 .map_err(|_| MsrError::InvalidAccess)?;
2857 self.update_execution_mode(vtl);
2858 }
2859 x86defs::X86X_MSR_STAR => state.msr_star = value,
2860 x86defs::X86X_MSR_CSTAR => self.backing.vtls[vtl].msr_cstar = value,
2861 x86defs::X86X_MSR_LSTAR => state.msr_lstar = value,
2862 x86defs::X86X_MSR_SFMASK => state.msr_sfmask = value,
2863 x86defs::X86X_MSR_TSC_AUX => state.msr_tsc_aux = value,
2864 x86defs::X86X_MSR_SYSENTER_CS => {
2865 self.runner.write_vmcs32(
2866 vtl,
2867 VmcsField::VMX_VMCS_GUEST_SYSENTER_CS_MSR,
2868 !0,
2869 value as u32,
2870 );
2871 }
2872 x86defs::X86X_MSR_SYSENTER_EIP => {
2873 self.runner.write_vmcs64(
2874 vtl,
2875 VmcsField::VMX_VMCS_GUEST_SYSENTER_EIP_MSR,
2876 !0,
2877 value,
2878 );
2879 }
2880 x86defs::X86X_MSR_SYSENTER_ESP => {
2881 self.runner.write_vmcs64(
2882 vtl,
2883 VmcsField::VMX_VMCS_GUEST_SYSENTER_ESP_MSR,
2884 !0,
2885 value,
2886 );
2887 }
2888 x86defs::X86X_MSR_XSS => state.msr_xss = value,
2889 x86defs::X86X_MSR_MC_UPDATE_PATCH_LEVEL => {
2890 if value != 0 {
2892 return Err(MsrError::InvalidAccess);
2893 }
2894 }
2895 x86defs::X86X_IA32_MSR_MISC_ENABLE => {}
2896 x86defs::X86X_MSR_CR_PAT => {
2897 self.runner
2898 .write_vmcs64(vtl, VmcsField::VMX_VMCS_GUEST_PAT, !0, value);
2899 }
2900
2901 x86defs::X86X_MSR_MCG_STATUS => {
2902 if x86defs::X86xMcgStatusRegister::from(value).reserved0() != 0 {
2904 return Err(MsrError::InvalidAccess);
2905 }
2906 }
2907
2908 x86defs::X86X_MSR_MTRR_DEF_TYPE => {}
2910
2911 x86defs::X86X_MSR_BIOS_UPDT_TRIG => {}
2914
2915 x86defs::X86X_MSR_MISC_FEATURE_ENABLES
2918 | x86defs::X86X_MSR_PLATFORM_INFO
2919 | x86defs::X86X_MSR_PPIN_CTL
2920 | x86defs::X86X_IA32_MSR_SMI_COUNT
2921 | x86defs::X86X_MSR_UMWAIT_CONTROL
2922 | x86defs::X86X_AMD_MSR_DE_CFG
2923 | x86defs::X86X_IA32_MSR_RAPL_POWER_UNIT
2924 | x86defs::X86X_IA32_MSR_PKG_ENERGY_STATUS
2925 | x86defs::X86X_IA32_MSR_DRAM_ENERGY_STATUS
2926 | x86defs::X86X_IA32_MSR_PP0_ENERGY_STATUS => {}
2927
2928 _ => return Err(MsrError::Unknown),
2929 }
2930
2931 Ok(())
2932 }
2933
2934 fn write_segment(
2935 &mut self,
2936 vtl: GuestVtl,
2937 seg: TdxSegmentReg,
2938 reg: SegmentRegister,
2939 ) -> Result<(), vp_state::Error> {
2940 self.runner
2942 .write_vmcs16(vtl, seg.selector(), !0, reg.selector);
2943 self.runner.write_vmcs64(vtl, seg.base(), !0, reg.base);
2944 self.runner.write_vmcs32(vtl, seg.limit(), !0, reg.limit);
2945
2946 let mut attributes = x86defs::vmx::VmxSegmentAttributes::from(reg.attributes as u32);
2948 attributes.set_null(!attributes.present());
2949
2950 self.runner
2951 .write_vmcs32(vtl, seg.attributes(), !0, attributes.into());
2952
2953 Ok(())
2954 }
2955
2956 fn read_segment(&self, vtl: GuestVtl, seg: TdxSegmentReg) -> SegmentRegister {
2957 let selector = self.runner.read_vmcs16(vtl, seg.selector());
2958 let base = self.runner.read_vmcs64(vtl, seg.base());
2959 let limit = self.runner.read_vmcs32(vtl, seg.limit());
2960 let attributes = self.runner.read_vmcs32(vtl, seg.attributes());
2961
2962 SegmentRegister {
2963 selector,
2964 base,
2965 limit,
2966 attributes: attributes as u16,
2967 }
2968 }
2969
2970 fn long_mode(&self, vtl: GuestVtl) -> bool {
2971 let backing = &self.backing.vtls[vtl];
2972 backing.cr0.read(&self.runner) & X64_CR0_PE != 0 && backing.efer & X64_EFER_LMA != 0
2973 }
2974}
2975
2976impl<T: CpuIo> X86EmulatorSupport for UhEmulationState<'_, '_, T, TdxBacked> {
2977 fn vp_index(&self) -> VpIndex {
2978 self.vp.vp_index()
2979 }
2980
2981 fn flush(&mut self) {
2982 }
2984
2985 fn vendor(&self) -> x86defs::cpuid::Vendor {
2986 self.vp.partition.caps.vendor
2987 }
2988
2989 fn gp(&mut self, reg: Gp) -> u64 {
2990 self.vp.runner.tdx_enter_guest_gps()[reg as usize]
2991 }
2992
2993 fn set_gp(&mut self, reg: Gp, v: u64) {
2994 self.vp.runner.tdx_enter_guest_gps_mut()[reg as usize] = v;
2995 }
2996
2997 fn xmm(&mut self, index: usize) -> u128 {
2998 u128::from_ne_bytes(self.vp.runner.fx_state().xmm[index])
2999 }
3000
3001 fn set_xmm(&mut self, index: usize, v: u128) {
3002 self.vp.runner.fx_state_mut().xmm[index] = v.to_ne_bytes();
3003 }
3004
3005 fn rip(&mut self) -> u64 {
3006 self.vp.backing.vtls[self.vtl].private_regs.rip
3007 }
3008
3009 fn set_rip(&mut self, v: u64) {
3010 self.vp.backing.vtls[self.vtl].private_regs.rip = v;
3011 }
3012
3013 fn segment(&mut self, index: Segment) -> x86defs::SegmentRegister {
3014 let tdx_segment_index = match index {
3015 Segment::CS => TdxSegmentReg::Cs,
3016 Segment::ES => TdxSegmentReg::Es,
3017 Segment::SS => TdxSegmentReg::Ss,
3018 Segment::DS => TdxSegmentReg::Ds,
3019 Segment::FS => TdxSegmentReg::Fs,
3020 Segment::GS => TdxSegmentReg::Gs,
3021 };
3022 let reg = match tdx_segment_index {
3023 TdxSegmentReg::Cs => self.cache.segs[index as usize]
3024 .get_or_insert_with(|| TdxExit(self.vp.runner.tdx_vp_enter_exit_info()).cs()),
3025 _ => self.cache.segs[index as usize]
3026 .get_or_insert_with(|| self.vp.read_segment(self.vtl, tdx_segment_index)),
3027 };
3028 (*reg).into()
3029 }
3030
3031 fn efer(&mut self) -> u64 {
3032 self.vp.backing.vtls[self.vtl].efer
3033 }
3034
3035 fn cr0(&mut self) -> u64 {
3036 let reg = self
3037 .cache
3038 .cr0
3039 .get_or_insert_with(|| self.vp.backing.vtls[self.vtl].cr0.read(&self.vp.runner));
3040 *reg
3041 }
3042
3043 fn rflags(&mut self) -> RFlags {
3044 self.vp.backing.vtls[self.vtl].private_regs.rflags.into()
3045 }
3046
3047 fn set_rflags(&mut self, v: RFlags) {
3048 self.vp.backing.vtls[self.vtl].private_regs.rflags = v.into();
3049 }
3050
3051 fn instruction_bytes(&self) -> &[u8] {
3052 &[]
3053 }
3054
3055 fn physical_address(&self) -> Option<u64> {
3056 TdxExit(self.vp.runner.tdx_vp_enter_exit_info()).gpa()
3057 }
3058
3059 fn initial_gva_translation(
3060 &mut self,
3061 ) -> Option<virt_support_x86emu::emulate::InitialTranslation> {
3062 let exit_info = TdxExit(self.vp.runner.tdx_vp_enter_exit_info());
3063 let ept_info = VmxEptExitQualification::from(exit_info.qualification());
3064
3065 if exit_info.code().vmx_exit().basic_reason() == VmxExitBasic::EPT_VIOLATION
3066 && ept_info.gva_valid()
3067 {
3068 Some(virt_support_x86emu::emulate::InitialTranslation {
3069 gva: exit_info.gla().expect("already validated EPT exit"),
3070 gpa: exit_info.gpa().expect("already validated EPT exit"),
3071 translate_mode: match ept_info.access_mask() {
3072 0x1 => TranslateMode::Read,
3073 0x2 | 0x3 => TranslateMode::Write,
3086 0x4 => TranslateMode::Execute,
3087 _ => panic!("unexpected ept access mask 0x{:x}", ept_info.access_mask()),
3088 },
3089 })
3090 } else {
3091 None
3092 }
3093 }
3094
3095 fn interruption_pending(&self) -> bool {
3096 self.interruption_pending
3097 }
3098
3099 fn check_vtl_access(
3100 &mut self,
3101 _gpa: u64,
3102 _mode: TranslateMode,
3103 ) -> Result<(), virt_support_x86emu::emulate::EmuCheckVtlAccessError> {
3104 Ok(())
3106 }
3107
3108 fn translate_gva(
3109 &mut self,
3110 gva: u64,
3111 mode: TranslateMode,
3112 ) -> Result<
3113 virt_support_x86emu::emulate::EmuTranslateResult,
3114 virt_support_x86emu::emulate::EmuTranslateError,
3115 > {
3116 emulate_translate_gva(self, gva, mode)
3117 }
3118
3119 fn inject_pending_event(&mut self, event_info: hvdef::HvX64PendingEvent) {
3120 assert!(event_info.reg_0.event_pending());
3121 assert_eq!(
3122 event_info.reg_0.event_type(),
3123 hvdef::HV_X64_PENDING_EVENT_EXCEPTION
3124 );
3125 assert!(!self.interruption_pending);
3126
3127 TdxBacked::set_pending_exception(
3130 self.vp,
3131 self.vtl,
3132 HvX64PendingExceptionEvent::from(event_info.reg_0.into_bits()),
3133 );
3134 }
3135
3136 fn is_gpa_mapped(&self, gpa: u64, write: bool) -> bool {
3137 let vtom = self.vp.partition.caps.vtom.unwrap_or(0);
3140 debug_assert!(vtom == 0 || vtom.is_power_of_two());
3141 self.vp.partition.is_gpa_mapped(gpa & !vtom, write)
3142 }
3143
3144 fn lapic_base_address(&self) -> Option<u64> {
3145 self.vp.backing.cvm.lapics[self.vtl].lapic.base_address()
3146 }
3147
3148 fn lapic_read(&mut self, address: u64, data: &mut [u8]) {
3149 self.vp.backing.cvm.lapics[self.vtl]
3150 .lapic
3151 .access(&mut TdxApicClient {
3152 partition: self.vp.partition,
3153 dev: self.devices,
3154 vmtime: &self.vp.vmtime,
3155 apic_page: self.vp.runner.tdx_apic_page_mut(self.vtl),
3156 vtl: self.vtl,
3157 })
3158 .mmio_read(address, data);
3159 }
3160
3161 fn lapic_write(&mut self, address: u64, data: &[u8]) {
3162 self.vp.backing.cvm.lapics[self.vtl]
3163 .lapic
3164 .access(&mut TdxApicClient {
3165 partition: self.vp.partition,
3166 dev: self.devices,
3167 vmtime: &self.vp.vmtime,
3168 apic_page: self.vp.runner.tdx_apic_page_mut(self.vtl),
3169 vtl: self.vtl,
3170 })
3171 .mmio_write(address, data);
3172 }
3173
3174 fn monitor_support(&self) -> Option<&dyn EmulatorMonitorSupport> {
3175 Some(self)
3176 }
3177}
3178
3179#[derive(Debug)]
3180enum TdxSegmentReg {
3181 Es,
3182 Cs,
3183 Ss,
3184 Ds,
3185 Fs,
3186 Gs,
3187 Ldtr,
3188 Tr,
3189}
3190
3191impl TdxSegmentReg {
3192 fn selector(&self) -> VmcsField {
3194 match self {
3195 Self::Es => VmcsField::VMX_VMCS_GUEST_ES_SELECTOR,
3196 Self::Cs => VmcsField::VMX_VMCS_GUEST_CS_SELECTOR,
3197 Self::Ss => VmcsField::VMX_VMCS_GUEST_SS_SELECTOR,
3198 Self::Ds => VmcsField::VMX_VMCS_GUEST_DS_SELECTOR,
3199 Self::Fs => VmcsField::VMX_VMCS_GUEST_FS_SELECTOR,
3200 Self::Gs => VmcsField::VMX_VMCS_GUEST_GS_SELECTOR,
3201 Self::Ldtr => VmcsField::VMX_VMCS_GUEST_LDTR_SELECTOR,
3202 Self::Tr => VmcsField::VMX_VMCS_GUEST_TR_SELECTOR,
3203 }
3204 }
3205
3206 fn base(&self) -> VmcsField {
3208 match self {
3209 Self::Es => VmcsField::VMX_VMCS_GUEST_ES_BASE,
3210 Self::Cs => VmcsField::VMX_VMCS_GUEST_CS_BASE,
3211 Self::Ss => VmcsField::VMX_VMCS_GUEST_SS_BASE,
3212 Self::Ds => VmcsField::VMX_VMCS_GUEST_DS_BASE,
3213 Self::Fs => VmcsField::VMX_VMCS_GUEST_FS_BASE,
3214 Self::Gs => VmcsField::VMX_VMCS_GUEST_GS_BASE,
3215 Self::Ldtr => VmcsField::VMX_VMCS_GUEST_LDTR_BASE,
3216 Self::Tr => VmcsField::VMX_VMCS_GUEST_TR_BASE,
3217 }
3218 }
3219
3220 fn limit(&self) -> VmcsField {
3222 match self {
3223 Self::Es => VmcsField::VMX_VMCS_GUEST_ES_LIMIT,
3224 Self::Cs => VmcsField::VMX_VMCS_GUEST_CS_LIMIT,
3225 Self::Ss => VmcsField::VMX_VMCS_GUEST_SS_LIMIT,
3226 Self::Ds => VmcsField::VMX_VMCS_GUEST_DS_LIMIT,
3227 Self::Fs => VmcsField::VMX_VMCS_GUEST_FS_LIMIT,
3228 Self::Gs => VmcsField::VMX_VMCS_GUEST_GS_LIMIT,
3229 Self::Ldtr => VmcsField::VMX_VMCS_GUEST_LDTR_LIMIT,
3230 Self::Tr => VmcsField::VMX_VMCS_GUEST_TR_LIMIT,
3231 }
3232 }
3233
3234 fn attributes(&self) -> VmcsField {
3236 match self {
3237 Self::Es => VmcsField::VMX_VMCS_GUEST_ES_AR,
3238 Self::Cs => VmcsField::VMX_VMCS_GUEST_CS_AR,
3239 Self::Ss => VmcsField::VMX_VMCS_GUEST_SS_AR,
3240 Self::Ds => VmcsField::VMX_VMCS_GUEST_DS_AR,
3241 Self::Fs => VmcsField::VMX_VMCS_GUEST_FS_AR,
3242 Self::Gs => VmcsField::VMX_VMCS_GUEST_GS_AR,
3243 Self::Ldtr => VmcsField::VMX_VMCS_GUEST_LDTR_AR,
3244 Self::Tr => VmcsField::VMX_VMCS_GUEST_TR_AR,
3245 }
3246 }
3247}
3248
3249#[derive(Debug)]
3250enum TdxTableReg {
3251 Idtr,
3252 Gdtr,
3253}
3254
3255impl TdxTableReg {
3256 fn base_code(&self) -> VmcsField {
3257 match self {
3258 Self::Idtr => VmcsField::VMX_VMCS_GUEST_IDTR_BASE,
3259 Self::Gdtr => VmcsField::VMX_VMCS_GUEST_GDTR_BASE,
3260 }
3261 }
3262
3263 fn limit_code(&self) -> VmcsField {
3264 match self {
3265 Self::Idtr => VmcsField::VMX_VMCS_GUEST_IDTR_LIMIT,
3266 Self::Gdtr => VmcsField::VMX_VMCS_GUEST_GDTR_LIMIT,
3267 }
3268 }
3269}
3270
3271impl UhProcessor<'_, TdxBacked> {
3272 fn write_efer(&mut self, vtl: GuestVtl, efer: u64) -> Result<(), vp_state::Error> {
3278 if efer & (X64_EFER_SVME | X64_EFER_FFXSR) != 0 {
3279 return Err(vp_state::Error::InvalidValue(
3280 efer,
3281 "EFER",
3282 "SVME or FFXSR set",
3283 ));
3284 }
3285
3286 if efer & X64_EFER_NXE == 0 {
3288 return Err(vp_state::Error::InvalidValue(efer, "EFER", "NXE not set"));
3289 }
3290
3291 if self.backing.vtls[vtl].efer != efer {
3293 self.backing.vtls[vtl].efer = efer;
3294 self.runner
3295 .write_vmcs64(vtl, VmcsField::VMX_VMCS_GUEST_EFER, !0, efer);
3296 }
3297
3298 Ok(())
3299 }
3300
3301 fn read_cr0(&self, vtl: GuestVtl) -> u64 {
3304 self.backing.vtls[vtl].cr0.read(&self.runner)
3305 }
3306
3307 fn write_cr0(&mut self, vtl: GuestVtl, value: u64) -> Result<(), vp_state::Error> {
3309 self.backing.vtls[vtl]
3310 .cr0
3311 .write(value | X64_CR0_ET, &mut self.runner)
3312 }
3313
3314 fn read_cr4(&self, vtl: GuestVtl) -> u64 {
3315 self.backing.vtls[vtl].cr4.read(&self.runner)
3316 }
3317
3318 fn write_cr4(&mut self, vtl: GuestVtl, value: u64) -> Result<(), vp_state::Error> {
3319 self.backing.vtls[vtl].cr4.write(value, &mut self.runner)
3320 }
3321
3322 fn write_table_register(&mut self, vtl: GuestVtl, table: TdxTableReg, reg: TableRegister) {
3323 self.runner
3324 .write_vmcs64(vtl, table.base_code(), !0, reg.base);
3325 self.runner
3326 .write_vmcs32(vtl, table.limit_code(), !0, reg.limit.into());
3327 }
3328
3329 fn read_table_register(&self, vtl: GuestVtl, table: TdxTableReg) -> TableRegister {
3330 let base = self.runner.read_vmcs64(vtl, table.base_code());
3331 let limit = self.runner.read_vmcs32(vtl, table.limit_code());
3332
3333 TableRegister {
3334 base,
3335 limit: limit as u16,
3336 }
3337 }
3338
3339 fn update_execution_mode(&mut self, vtl: GuestVtl) {
3341 let lme = self.backing.vtls[vtl].efer & X64_EFER_LME == X64_EFER_LME;
3342 let pg = self.read_cr0(vtl) & X64_CR0_PG == X64_CR0_PG;
3343 let efer_lma = self.backing.vtls[vtl].efer & X64_EFER_LMA == X64_EFER_LMA;
3344 let lma = lme && pg;
3345
3346 if lma != efer_lma {
3347 let new_efer = self.backing.vtls[vtl].efer ^ X64_EFER_LMA;
3349 self.write_efer(vtl, new_efer)
3350 .expect("EFER was valid before, it should still be valid");
3351 }
3352
3353 self.runner.write_vmcs32(
3354 vtl,
3355 VmcsField::VMX_VMCS_ENTRY_CONTROLS,
3356 VMX_ENTRY_CONTROL_LONG_MODE_GUEST,
3357 if lma {
3358 VMX_ENTRY_CONTROL_LONG_MODE_GUEST
3359 } else {
3360 0
3361 },
3362 );
3363 }
3364
3365 async fn emulate_gdtr_or_idtr(
3366 &mut self,
3367 vtl: GuestVtl,
3368 dev: &impl CpuIo,
3369 ) -> Result<(), VpHaltReason> {
3370 let exit_info = TdxExit(self.runner.tdx_vp_enter_exit_info());
3371 assert_eq!(
3372 exit_info.code().vmx_exit().basic_reason(),
3373 VmxExitBasic::GDTR_OR_IDTR
3374 );
3375 let instr_info = GdtrOrIdtrInstructionInfo::from(exit_info.instr_info().info());
3376
3377 if (instr_info.instruction().is_load() && exit_info.cpl() != 0)
3380 || (!instr_info.instruction().is_load()
3381 && exit_info.cpl() > 0
3382 && self.read_cr4(vtl) & X64_CR4_UMIP != 0)
3383 {
3384 self.inject_gpf(vtl);
3385 return Ok(());
3386 }
3387
3388 let (gva, segment) = self.compute_gva_for_table_access_emulation(
3389 exit_info.qualification(),
3390 (!instr_info.base_register_invalid()).then_some(instr_info.base_register()),
3391 (!instr_info.index_register_invalid()).then_some(instr_info.index_register()),
3392 instr_info.scaling(),
3393 instr_info.address_size(),
3394 instr_info.segment_register(),
3395 );
3396
3397 let gm = &self.partition.gm[vtl];
3398 let interruption_pending = self.backing.vtls[vtl].interruption_information.valid();
3399 let len = 2 + if self.long_mode(vtl) { 8 } else { 4 };
3400 let mut buf = [0u8; 10];
3401
3402 match instr_info.instruction() {
3403 GdtrOrIdtrInstruction::Sidt | GdtrOrIdtrInstruction::Sgdt => {
3404 let table = self.read_table_register(
3405 vtl,
3406 if matches!(instr_info.instruction(), GdtrOrIdtrInstruction::Sidt) {
3407 TdxTableReg::Idtr
3408 } else {
3409 TdxTableReg::Gdtr
3410 },
3411 );
3412 buf[..2].copy_from_slice(&table.limit.to_le_bytes());
3413 buf[2..].copy_from_slice(&table.base.to_le_bytes());
3414 let mut emulation_state = UhEmulationState {
3415 vp: &mut *self,
3416 interruption_pending,
3417 devices: dev,
3418 vtl,
3419 cache: TdxEmulationCache::default(),
3420 };
3421 emulate_insn_memory_op(
3422 &mut emulation_state,
3423 gm,
3424 dev,
3425 gva,
3426 segment,
3427 x86emu::AlignmentMode::Unaligned,
3428 EmulatedMemoryOperation::Write(&buf[..len]),
3429 )
3430 .await?;
3431 }
3432
3433 GdtrOrIdtrInstruction::Lgdt | GdtrOrIdtrInstruction::Lidt => {
3434 let mut emulation_state = UhEmulationState {
3435 vp: &mut *self,
3436 interruption_pending,
3437 devices: dev,
3438 vtl,
3439 cache: TdxEmulationCache::default(),
3440 };
3441 emulate_insn_memory_op(
3442 &mut emulation_state,
3443 gm,
3444 dev,
3445 gva,
3446 segment,
3447 x86emu::AlignmentMode::Unaligned,
3448 EmulatedMemoryOperation::Read(&mut buf[..len]),
3449 )
3450 .await?;
3451 let table = TableRegister {
3452 limit: u16::from_le_bytes(buf[..2].try_into().unwrap()),
3453 base: u64::from_le_bytes(buf[2..len].try_into().unwrap()),
3454 };
3455 self.write_table_register(
3456 vtl,
3457 if matches!(instr_info.instruction(), GdtrOrIdtrInstruction::Lidt) {
3458 TdxTableReg::Idtr
3459 } else {
3460 TdxTableReg::Gdtr
3461 },
3462 table,
3463 );
3464 }
3465 }
3466
3467 self.advance_to_next_instruction(vtl);
3468 Ok(())
3469 }
3470
3471 async fn emulate_ldtr_or_tr(
3472 &mut self,
3473 vtl: GuestVtl,
3474 dev: &impl CpuIo,
3475 ) -> Result<(), VpHaltReason> {
3476 let exit_info = TdxExit(self.runner.tdx_vp_enter_exit_info());
3477 assert_eq!(
3478 exit_info.code().vmx_exit().basic_reason(),
3479 VmxExitBasic::LDTR_OR_TR
3480 );
3481 let instr_info = LdtrOrTrInstructionInfo::from(exit_info.instr_info().info());
3482
3483 if (instr_info.instruction().is_load() && exit_info.cpl() != 0)
3486 || (!instr_info.instruction().is_load()
3487 && exit_info.cpl() > 0
3488 && self.read_cr4(vtl) & X64_CR4_UMIP != 0)
3489 {
3490 self.inject_gpf(vtl);
3491 return Ok(());
3492 }
3493
3494 let gm = &self.partition.gm[vtl];
3495 let interruption_pending = self.backing.vtls[vtl].interruption_information.valid();
3496
3497 match instr_info.instruction() {
3498 LdtrOrTrInstruction::Sldt | LdtrOrTrInstruction::Str => {
3499 let value = self.runner.read_vmcs16(
3500 vtl,
3501 if matches!(instr_info.instruction(), LdtrOrTrInstruction::Sldt) {
3502 TdxSegmentReg::Ldtr
3503 } else {
3504 TdxSegmentReg::Tr
3505 }
3506 .selector(),
3507 );
3508
3509 if instr_info.memory_or_register() {
3510 let gps = self.runner.tdx_enter_guest_gps_mut();
3511 gps[instr_info.register_1() as usize] = value.into();
3512 } else {
3513 let (gva, segment) = self.compute_gva_for_table_access_emulation(
3514 exit_info.qualification(),
3515 (!instr_info.base_register_invalid()).then_some(instr_info.base_register()),
3516 (!instr_info.index_register_invalid())
3517 .then_some(instr_info.index_register()),
3518 instr_info.scaling(),
3519 instr_info.address_size(),
3520 instr_info.segment_register(),
3521 );
3522 let mut emulation_state = UhEmulationState {
3523 vp: &mut *self,
3524 interruption_pending,
3525 devices: dev,
3526 vtl,
3527 cache: TdxEmulationCache::default(),
3528 };
3529 emulate_insn_memory_op(
3530 &mut emulation_state,
3531 gm,
3532 dev,
3533 gva,
3534 segment,
3535 x86emu::AlignmentMode::Standard,
3536 EmulatedMemoryOperation::Write(&value.to_le_bytes()),
3537 )
3538 .await?;
3539 }
3540 }
3541
3542 LdtrOrTrInstruction::Lldt | LdtrOrTrInstruction::Ltr => {
3543 let value = if instr_info.memory_or_register() {
3544 let gps = self.runner.tdx_enter_guest_gps();
3545 gps[instr_info.register_1() as usize] as u16
3546 } else {
3547 let (gva, segment) = self.compute_gva_for_table_access_emulation(
3548 exit_info.qualification(),
3549 (!instr_info.base_register_invalid()).then_some(instr_info.base_register()),
3550 (!instr_info.index_register_invalid())
3551 .then_some(instr_info.index_register()),
3552 instr_info.scaling(),
3553 instr_info.address_size(),
3554 instr_info.segment_register(),
3555 );
3556 let mut emulation_state = UhEmulationState {
3557 vp: &mut *self,
3558 interruption_pending,
3559 devices: dev,
3560 vtl,
3561 cache: TdxEmulationCache::default(),
3562 };
3563 let mut buf = [0u8; 2];
3564 emulate_insn_memory_op(
3565 &mut emulation_state,
3566 gm,
3567 dev,
3568 gva,
3569 segment,
3570 x86emu::AlignmentMode::Standard,
3571 EmulatedMemoryOperation::Read(&mut buf),
3572 )
3573 .await?;
3574 u16::from_le_bytes(buf)
3575 };
3576 self.runner.write_vmcs16(
3577 vtl,
3578 if matches!(instr_info.instruction(), LdtrOrTrInstruction::Lldt) {
3579 TdxSegmentReg::Ldtr
3580 } else {
3581 TdxSegmentReg::Tr
3582 }
3583 .selector(),
3584 !0,
3585 value,
3586 );
3587 }
3588 }
3589
3590 self.advance_to_next_instruction(vtl);
3591 Ok(())
3592 }
3593
3594 fn compute_gva_for_table_access_emulation(
3595 &self,
3596 qualification: u64,
3597 base_reg: Option<u8>,
3598 index_reg: Option<u8>,
3599 scaling: u8,
3600 address_size: u8,
3601 segment_register: u8,
3602 ) -> (u64, Segment) {
3603 let gps = self.runner.tdx_enter_guest_gps();
3604
3605 let mut gva = qualification;
3607 if let Some(base_register) = base_reg {
3608 gva += gps[base_register as usize];
3609 }
3610 if let Some(index_register) = index_reg {
3611 gva += gps[index_register as usize] << scaling;
3612 }
3613 match address_size {
3614 0 => gva &= 0xFFFF,
3616 1 => gva &= 0xFFFFFFFF,
3618 2 => {}
3620 _ => unreachable!(),
3621 }
3622
3623 let segment = match segment_register {
3624 0 => Segment::ES,
3625 1 => Segment::CS,
3626 2 => Segment::SS,
3627 3 => Segment::DS,
3628 4 => Segment::FS,
3629 5 => Segment::GS,
3630 _ => unreachable!(),
3631 };
3632
3633 (gva, segment)
3634 }
3635}
3636
3637struct TdxApicClient<'a, T> {
3638 partition: &'a UhPartitionInner,
3639 apic_page: &'a mut VmxApicPage,
3640 dev: &'a T,
3641 vmtime: &'a VmTimeAccess,
3642 vtl: GuestVtl,
3643}
3644
3645impl<T: CpuIo> ApicClient for TdxApicClient<'_, T> {
3646 fn cr8(&mut self) -> u32 {
3647 self.apic_page.tpr.value >> 4
3648 }
3649
3650 fn set_cr8(&mut self, value: u32) {
3651 self.apic_page.tpr.value = value << 4;
3652 }
3653
3654 fn set_apic_base(&mut self, _value: u64) {
3655 }
3657
3658 fn wake(&mut self, vp_index: VpIndex) {
3659 self.partition.vps[vp_index.index() as usize].wake(self.vtl, WakeReason::INTCON);
3660 }
3661
3662 fn eoi(&mut self, vector: u8) {
3663 self.dev.handle_eoi(vector.into())
3664 }
3665
3666 fn now(&mut self) -> vmcore::vmtime::VmTime {
3667 self.vmtime.now()
3668 }
3669
3670 fn pull_offload(&mut self) -> ([u32; 8], [u32; 8]) {
3671 pull_apic_offload(self.apic_page)
3672 }
3673}
3674
3675fn pull_apic_offload(page: &mut VmxApicPage) -> ([u32; 8], [u32; 8]) {
3676 let mut irr = [0; 8];
3677 let mut isr = [0; 8];
3678 for (((irr, page_irr), isr), page_isr) in irr
3679 .iter_mut()
3680 .zip(page.irr.iter_mut())
3681 .zip(isr.iter_mut())
3682 .zip(page.isr.iter_mut())
3683 {
3684 *irr = std::mem::take(&mut page_irr.value);
3685 *isr = std::mem::take(&mut page_isr.value);
3686 }
3687 (irr, isr)
3688}
3689
3690impl hv1_hypercall::X64RegisterState for UhHypercallHandler<'_, '_, TdxBacked> {
3691 fn rip(&mut self) -> u64 {
3692 self.vp.backing.vtls[self.intercepted_vtl].private_regs.rip
3693 }
3694
3695 fn set_rip(&mut self, rip: u64) {
3696 self.vp.backing.vtls[self.intercepted_vtl].private_regs.rip = rip;
3697 }
3698
3699 fn gp(&mut self, n: hv1_hypercall::X64HypercallRegister) -> u64 {
3700 self.vp.runner.tdx_enter_guest_gps()[n as usize]
3701 }
3702
3703 fn set_gp(&mut self, n: hv1_hypercall::X64HypercallRegister, value: u64) {
3704 let gps = self.vp.runner.tdx_enter_guest_gps_mut();
3705 gps[n as usize] = value;
3706 }
3707
3708 fn xmm(&mut self, n: usize) -> u128 {
3710 u128::from_ne_bytes(self.vp.runner.fx_state().xmm[n])
3711 }
3712
3713 fn set_xmm(&mut self, n: usize, value: u128) {
3714 self.vp.runner.fx_state_mut().xmm[n] = value.to_ne_bytes();
3715 }
3716}
3717
3718impl UhHypercallHandler<'_, '_, TdxBacked> {
3719 const TDX_DISPATCHER: hv1_hypercall::Dispatcher<Self> = hv1_hypercall::dispatcher!(
3720 Self,
3721 [
3722 hv1_hypercall::HvModifySparseGpaPageHostVisibility,
3723 hv1_hypercall::HvQuerySparseGpaPageHostVisibility,
3724 hv1_hypercall::HvX64StartVirtualProcessor,
3725 hv1_hypercall::HvGetVpIndexFromApicId,
3726 hv1_hypercall::HvRetargetDeviceInterrupt,
3727 hv1_hypercall::HvFlushVirtualAddressList,
3728 hv1_hypercall::HvFlushVirtualAddressListEx,
3729 hv1_hypercall::HvFlushVirtualAddressSpace,
3730 hv1_hypercall::HvFlushVirtualAddressSpaceEx,
3731 hv1_hypercall::HvPostMessage,
3732 hv1_hypercall::HvSignalEvent,
3733 hv1_hypercall::HvExtQueryCapabilities,
3734 hv1_hypercall::HvGetVpRegisters,
3735 hv1_hypercall::HvSetVpRegisters,
3736 hv1_hypercall::HvEnablePartitionVtl,
3737 hv1_hypercall::HvX64EnableVpVtl,
3738 hv1_hypercall::HvVtlCall,
3739 hv1_hypercall::HvVtlReturn,
3740 hv1_hypercall::HvModifyVtlProtectionMask,
3741 hv1_hypercall::HvX64TranslateVirtualAddress,
3742 hv1_hypercall::HvSendSyntheticClusterIpi,
3743 hv1_hypercall::HvSendSyntheticClusterIpiEx,
3744 hv1_hypercall::HvInstallIntercept,
3745 hv1_hypercall::HvAssertVirtualInterrupt,
3746 ]
3747 );
3748
3749 const TDCALL_DISPATCHER: hv1_hypercall::Dispatcher<Self> = hv1_hypercall::dispatcher!(
3753 Self,
3754 [hv1_hypercall::HvPostMessage, hv1_hypercall::HvSignalEvent],
3755 );
3756}
3757
3758impl AccessVpState for UhVpStateAccess<'_, '_, TdxBacked> {
3759 type Error = vp_state::Error;
3760
3761 fn caps(&self) -> &virt::x86::X86PartitionCapabilities {
3762 &self.vp.partition.caps
3763 }
3764
3765 fn commit(&mut self) -> Result<(), Self::Error> {
3766 Ok(())
3767 }
3768
3769 fn registers(&mut self) -> Result<Registers, Self::Error> {
3770 let gps = self.vp.runner.tdx_enter_guest_gps();
3771
3772 let cs = self.vp.read_segment(self.vtl, TdxSegmentReg::Cs);
3773 let ds = self.vp.read_segment(self.vtl, TdxSegmentReg::Ds);
3774 let es = self.vp.read_segment(self.vtl, TdxSegmentReg::Es);
3775 let fs = self.vp.read_segment(self.vtl, TdxSegmentReg::Fs);
3776 let gs = self.vp.read_segment(self.vtl, TdxSegmentReg::Gs);
3777 let ss = self.vp.read_segment(self.vtl, TdxSegmentReg::Ss);
3778 let tr = self.vp.read_segment(self.vtl, TdxSegmentReg::Tr);
3779 let ldtr = self.vp.read_segment(self.vtl, TdxSegmentReg::Ldtr);
3780
3781 let gdtr = self.vp.read_table_register(self.vtl, TdxTableReg::Gdtr);
3782 let idtr = self.vp.read_table_register(self.vtl, TdxTableReg::Idtr);
3783
3784 let cr0 = self.vp.read_cr0(self.vtl);
3785 let cr2 = self.vp.runner.cr2();
3786 let cr3 = self
3787 .vp
3788 .runner
3789 .read_vmcs64(self.vtl, VmcsField::VMX_VMCS_GUEST_CR3);
3790 let cr4 = self.vp.read_cr4(self.vtl);
3791
3792 let cr8 = self.vp.runner.tdx_apic_page(self.vtl).tpr.value >> 4;
3793
3794 let efer = self.vp.backing.vtls[self.vtl].efer;
3795
3796 Ok(Registers {
3797 rax: gps[TdxGp::RAX],
3798 rcx: gps[TdxGp::RCX],
3799 rdx: gps[TdxGp::RDX],
3800 rbx: gps[TdxGp::RBX],
3801 rsp: self.vp.backing.vtls[self.vtl].private_regs.rsp,
3802 rbp: gps[TdxGp::RBP],
3803 rsi: gps[TdxGp::RSI],
3804 rdi: gps[TdxGp::RDI],
3805 r8: gps[TdxGp::R8],
3806 r9: gps[TdxGp::R9],
3807 r10: gps[TdxGp::R10],
3808 r11: gps[TdxGp::R11],
3809 r12: gps[TdxGp::R12],
3810 r13: gps[TdxGp::R13],
3811 r14: gps[TdxGp::R14],
3812 r15: gps[TdxGp::R15],
3813 rip: self.vp.backing.vtls[self.vtl].private_regs.rip,
3814 rflags: self.vp.backing.vtls[self.vtl].private_regs.rflags,
3815 cs,
3816 ds,
3817 es,
3818 fs,
3819 gs,
3820 ss,
3821 tr,
3822 ldtr,
3823 gdtr,
3824 idtr,
3825 cr0,
3826 cr2,
3827 cr3,
3828 cr4,
3829 cr8: cr8.into(),
3830 efer,
3831 })
3832 }
3833
3834 fn set_registers(&mut self, value: &Registers) -> Result<(), Self::Error> {
3835 let Registers {
3836 rax,
3837 rcx,
3838 rdx,
3839 rbx,
3840 rsp,
3841 rbp,
3842 rsi,
3843 rdi,
3844 r8,
3845 r9,
3846 r10,
3847 r11,
3848 r12,
3849 r13,
3850 r14,
3851 r15,
3852 rip,
3853 rflags,
3854 cs,
3855 ds,
3856 es,
3857 fs,
3858 gs,
3859 ss,
3860 tr,
3861 ldtr,
3862 gdtr,
3863 idtr,
3864 cr0,
3865 cr2,
3866 cr3,
3867 cr4,
3868 cr8,
3869 efer,
3870 } = value;
3871
3872 let gps = self.vp.runner.tdx_enter_guest_gps_mut();
3873 gps[TdxGp::RAX] = *rax;
3874 gps[TdxGp::RCX] = *rcx;
3875 gps[TdxGp::RDX] = *rdx;
3876 gps[TdxGp::RBX] = *rbx;
3877 self.vp.backing.vtls[self.vtl].private_regs.rsp = *rsp;
3878 gps[TdxGp::RBP] = *rbp;
3879 gps[TdxGp::RSI] = *rsi;
3880 gps[TdxGp::RDI] = *rdi;
3881 gps[TdxGp::R8] = *r8;
3882 gps[TdxGp::R9] = *r9;
3883 gps[TdxGp::R10] = *r10;
3884 gps[TdxGp::R11] = *r11;
3885 gps[TdxGp::R12] = *r12;
3886 gps[TdxGp::R13] = *r13;
3887 gps[TdxGp::R14] = *r14;
3888 gps[TdxGp::R15] = *r15;
3889 self.vp.backing.vtls[self.vtl].private_regs.rip = *rip;
3890 self.vp.backing.vtls[self.vtl].private_regs.rflags = *rflags;
3892
3893 self.vp.write_segment(self.vtl, TdxSegmentReg::Cs, *cs)?;
3895 self.vp.write_segment(self.vtl, TdxSegmentReg::Ds, *ds)?;
3896 self.vp.write_segment(self.vtl, TdxSegmentReg::Es, *es)?;
3897 self.vp.write_segment(self.vtl, TdxSegmentReg::Fs, *fs)?;
3898 self.vp.write_segment(self.vtl, TdxSegmentReg::Gs, *gs)?;
3899 self.vp.write_segment(self.vtl, TdxSegmentReg::Ss, *ss)?;
3900 self.vp.write_segment(self.vtl, TdxSegmentReg::Tr, *tr)?;
3901 self.vp
3902 .write_segment(self.vtl, TdxSegmentReg::Ldtr, *ldtr)?;
3903
3904 self.vp
3906 .write_table_register(self.vtl, TdxTableReg::Gdtr, *gdtr);
3907 self.vp
3908 .write_table_register(self.vtl, TdxTableReg::Idtr, *idtr);
3909
3910 self.vp.write_cr0(self.vtl, *cr0)?;
3911
3912 self.vp.runner.set_cr2(*cr2);
3915
3916 self.vp
3917 .runner
3918 .write_vmcs64(self.vtl, VmcsField::VMX_VMCS_GUEST_CR3, !0, *cr3);
3919
3920 self.vp.write_cr4(self.vtl, *cr4)?;
3921
3922 self.vp.runner.tdx_apic_page_mut(self.vtl).tpr.value = (*cr8 << 4) as u32;
3923
3924 self.vp.write_efer(self.vtl, *efer)?;
3925
3926 self.vp.update_execution_mode(self.vtl);
3928
3929 Ok(())
3930 }
3931
3932 fn activity(&mut self) -> Result<vp::Activity, Self::Error> {
3933 let lapic = &self.vp.backing.cvm.lapics[self.vtl];
3934 let interruptibility: Interruptibility = self
3935 .vp
3936 .runner
3937 .read_vmcs32(self.vtl, VmcsField::VMX_VMCS_GUEST_INTERRUPTIBILITY)
3938 .into();
3939 Ok(vp::Activity {
3940 mp_state: lapic.activity,
3941 nmi_pending: lapic.nmi_pending,
3942 nmi_masked: interruptibility.blocked_by_nmi(),
3943 interrupt_shadow: interruptibility.blocked_by_sti()
3944 || interruptibility.blocked_by_movss(),
3945 pending_event: None, pending_interruption: None, })
3948 }
3949
3950 fn set_activity(&mut self, value: &vp::Activity) -> Result<(), Self::Error> {
3951 let &vp::Activity {
3952 mp_state,
3953 nmi_pending,
3954 nmi_masked,
3955 interrupt_shadow,
3956 pending_event: _, pending_interruption: _, } = value;
3959 self.vp.backing.cvm.lapics[self.vtl].activity = mp_state;
3960 self.vp.backing.cvm.lapics[self.vtl].nmi_pending = nmi_pending;
3961 let interruptibility = Interruptibility::new()
3962 .with_blocked_by_movss(interrupt_shadow)
3963 .with_blocked_by_nmi(nmi_masked);
3964 self.vp.runner.write_vmcs32(
3965 self.vtl,
3966 VmcsField::VMX_VMCS_GUEST_INTERRUPTIBILITY,
3967 !0,
3968 interruptibility.into(),
3969 );
3970 Ok(())
3971 }
3972
3973 fn xsave(&mut self) -> Result<vp::Xsave, Self::Error> {
3974 Err(vp_state::Error::Unimplemented("xsave"))
3976 }
3977
3978 fn set_xsave(&mut self, _value: &vp::Xsave) -> Result<(), Self::Error> {
3979 Err(vp_state::Error::Unimplemented("xsave"))
3981 }
3982
3983 fn apic(&mut self) -> Result<vp::Apic, Self::Error> {
3984 self.vp.access_apic_without_offload(self.vtl, |vp| {
3985 Ok(vp.backing.cvm.lapics[self.vtl].lapic.save())
3986 })
3987 }
3988
3989 fn set_apic(&mut self, value: &vp::Apic) -> Result<(), Self::Error> {
3990 self.vp.access_apic_without_offload(self.vtl, |vp| {
3991 vp.backing.cvm.lapics[self.vtl]
3992 .lapic
3993 .restore(value)
3994 .map_err(vp_state::Error::InvalidApicBase)?;
3995
3996 Ok(())
3997 })
3998 }
3999
4000 fn xcr(&mut self) -> Result<vp::Xcr0, Self::Error> {
4001 Ok(vp::Xcr0 {
4002 value: self
4003 .vp
4004 .runner
4005 .get_vp_register(self.vtl, HvX64RegisterName::Xfem)
4006 .unwrap()
4007 .as_u64(),
4008 })
4009 }
4010
4011 fn set_xcr(&mut self, _value: &vp::Xcr0) -> Result<(), Self::Error> {
4012 Err(vp_state::Error::Unimplemented("xcr"))
4013 }
4014
4015 fn xss(&mut self) -> Result<vp::Xss, Self::Error> {
4016 Ok(vp::Xss {
4017 value: self.vp.backing.vtls[self.vtl].private_regs.msr_xss,
4018 })
4019 }
4020
4021 fn set_xss(&mut self, value: &vp::Xss) -> Result<(), Self::Error> {
4022 self.vp.backing.vtls[self.vtl].private_regs.msr_xss = value.value;
4023 Ok(())
4024 }
4025
4026 fn mtrrs(&mut self) -> Result<vp::Mtrrs, Self::Error> {
4027 Ok(vp::Mtrrs {
4028 msr_mtrr_def_type: 0, fixed: [0; 11], variable: [0; 16], })
4032 }
4033
4034 fn set_mtrrs(&mut self, _value: &vp::Mtrrs) -> Result<(), Self::Error> {
4035 Ok(())
4037 }
4038
4039 fn pat(&mut self) -> Result<vp::Pat, Self::Error> {
4040 let msr_cr_pat = self
4041 .vp
4042 .runner
4043 .read_vmcs64(self.vtl, VmcsField::VMX_VMCS_GUEST_PAT);
4044 Ok(vp::Pat { value: msr_cr_pat })
4045 }
4046
4047 fn set_pat(&mut self, value: &vp::Pat) -> Result<(), Self::Error> {
4048 self.vp
4049 .runner
4050 .write_vmcs64(self.vtl, VmcsField::VMX_VMCS_GUEST_PAT, !0, value.value);
4051 Ok(())
4052 }
4053
4054 fn virtual_msrs(&mut self) -> Result<vp::VirtualMsrs, Self::Error> {
4055 let state = &self.vp.backing.vtls[self.vtl].private_regs;
4056
4057 let sysenter_cs = self
4058 .vp
4059 .runner
4060 .read_vmcs32(self.vtl, VmcsField::VMX_VMCS_GUEST_SYSENTER_CS_MSR)
4061 .into();
4062 let sysenter_eip = self
4063 .vp
4064 .runner
4065 .read_vmcs64(self.vtl, VmcsField::VMX_VMCS_GUEST_SYSENTER_EIP_MSR);
4066 let sysenter_esp = self
4067 .vp
4068 .runner
4069 .read_vmcs64(self.vtl, VmcsField::VMX_VMCS_GUEST_SYSENTER_ESP_MSR);
4070
4071 Ok(vp::VirtualMsrs {
4072 kernel_gs_base: state.msr_kernel_gs_base,
4073 sysenter_cs,
4074 sysenter_eip,
4075 sysenter_esp,
4076 star: state.msr_star,
4077 lstar: state.msr_lstar,
4078 cstar: self.vp.backing.vtls[self.vtl].msr_cstar,
4079 sfmask: state.msr_sfmask,
4080 })
4081 }
4082
4083 fn set_virtual_msrs(&mut self, value: &vp::VirtualMsrs) -> Result<(), Self::Error> {
4084 let &vp::VirtualMsrs {
4085 kernel_gs_base,
4086 sysenter_cs,
4087 sysenter_eip,
4088 sysenter_esp,
4089 star,
4090 lstar,
4091 cstar,
4092 sfmask,
4093 } = value;
4094
4095 let state = &mut self.vp.backing.vtls[self.vtl].private_regs;
4096 state.msr_kernel_gs_base = kernel_gs_base;
4097 state.msr_star = star;
4098 state.msr_lstar = lstar;
4099 state.msr_sfmask = sfmask;
4100
4101 self.vp.runner.write_vmcs32(
4102 self.vtl,
4103 VmcsField::VMX_VMCS_GUEST_SYSENTER_CS_MSR,
4104 !0,
4105 sysenter_cs as u32,
4106 );
4107 self.vp.runner.write_vmcs64(
4108 self.vtl,
4109 VmcsField::VMX_VMCS_GUEST_SYSENTER_EIP_MSR,
4110 !0,
4111 sysenter_eip,
4112 );
4113 self.vp.runner.write_vmcs64(
4114 self.vtl,
4115 VmcsField::VMX_VMCS_GUEST_SYSENTER_ESP_MSR,
4116 !0,
4117 sysenter_esp,
4118 );
4119
4120 self.vp.backing.vtls[self.vtl].msr_cstar = cstar;
4121
4122 Ok(())
4123 }
4124
4125 fn debug_regs(&mut self) -> Result<vp::DebugRegisters, Self::Error> {
4126 let mut values = [0u64.into(); 5];
4127 self.vp
4128 .runner
4129 .get_vp_registers(
4130 self.vtl,
4131 &[
4132 HvX64RegisterName::Dr0,
4133 HvX64RegisterName::Dr1,
4134 HvX64RegisterName::Dr2,
4135 HvX64RegisterName::Dr3,
4136 HvX64RegisterName::Dr6,
4137 ],
4138 &mut values,
4139 )
4140 .map_err(vp_state::Error::GetRegisters)?;
4141
4142 let dr7 = self
4143 .vp
4144 .runner
4145 .read_vmcs64(self.vtl, VmcsField::VMX_VMCS_GUEST_DR7);
4146
4147 Ok(vp::DebugRegisters {
4148 dr0: values[0].as_u64(),
4149 dr1: values[1].as_u64(),
4150 dr2: values[2].as_u64(),
4151 dr3: values[3].as_u64(),
4152 dr6: values[4].as_u64(),
4153 dr7,
4154 })
4155 }
4156
4157 fn set_debug_regs(&mut self, value: &vp::DebugRegisters) -> Result<(), Self::Error> {
4158 let &vp::DebugRegisters {
4159 dr0,
4160 dr1,
4161 dr2,
4162 dr3,
4163 dr6,
4164 dr7,
4165 } = value;
4166 self.vp
4167 .runner
4168 .set_vp_registers(
4169 self.vtl,
4170 [
4171 (HvX64RegisterName::Dr0, dr0),
4172 (HvX64RegisterName::Dr1, dr1),
4173 (HvX64RegisterName::Dr2, dr2),
4174 (HvX64RegisterName::Dr3, dr3),
4175 (HvX64RegisterName::Dr6, dr6),
4176 ],
4177 )
4178 .map_err(vp_state::Error::SetRegisters)?;
4179
4180 self.vp
4181 .runner
4182 .write_vmcs64(self.vtl, VmcsField::VMX_VMCS_GUEST_DR7, !0, dr7);
4183
4184 Ok(())
4185 }
4186
4187 fn tsc(&mut self) -> Result<vp::Tsc, Self::Error> {
4188 Err(vp_state::Error::Unimplemented("tsc"))
4189 }
4190
4191 fn set_tsc(&mut self, _value: &vp::Tsc) -> Result<(), Self::Error> {
4192 Err(vp_state::Error::Unimplemented("tsc"))
4193 }
4194
4195 fn tsc_aux(&mut self) -> Result<vp::TscAux, Self::Error> {
4196 Ok(vp::TscAux {
4197 value: self.vp.backing.vtls[self.vtl].private_regs.msr_tsc_aux,
4198 })
4199 }
4200
4201 fn set_tsc_aux(&mut self, value: &vp::TscAux) -> Result<(), Self::Error> {
4202 self.vp.backing.vtls[self.vtl].private_regs.msr_tsc_aux = value.value;
4203 Ok(())
4204 }
4205
4206 fn cet(&mut self) -> Result<vp::Cet, Self::Error> {
4207 Err(vp_state::Error::Unimplemented("cet"))
4208 }
4209
4210 fn set_cet(&mut self, _value: &vp::Cet) -> Result<(), Self::Error> {
4211 Err(vp_state::Error::Unimplemented("cet"))
4212 }
4213
4214 fn cet_ss(&mut self) -> Result<vp::CetSs, Self::Error> {
4215 Err(vp_state::Error::Unimplemented("cet_ss"))
4216 }
4217
4218 fn set_cet_ss(&mut self, _value: &vp::CetSs) -> Result<(), Self::Error> {
4219 Err(vp_state::Error::Unimplemented("cet_ss"))
4220 }
4221
4222 fn synic_msrs(&mut self) -> Result<vp::SyntheticMsrs, Self::Error> {
4223 Err(vp_state::Error::Unimplemented("synic_msrs"))
4224 }
4225
4226 fn set_synic_msrs(&mut self, _value: &vp::SyntheticMsrs) -> Result<(), Self::Error> {
4227 Err(vp_state::Error::Unimplemented("synic_msrs"))
4228 }
4229
4230 fn synic_message_page(&mut self) -> Result<vp::SynicMessagePage, Self::Error> {
4231 Err(vp_state::Error::Unimplemented("synic_message_page"))
4232 }
4233
4234 fn set_synic_message_page(&mut self, _value: &vp::SynicMessagePage) -> Result<(), Self::Error> {
4235 Err(vp_state::Error::Unimplemented("synic_message_page"))
4236 }
4237
4238 fn synic_event_flags_page(&mut self) -> Result<vp::SynicEventFlagsPage, Self::Error> {
4239 Err(vp_state::Error::Unimplemented("synic_event_flags_page"))
4240 }
4241
4242 fn set_synic_event_flags_page(
4243 &mut self,
4244 _value: &vp::SynicEventFlagsPage,
4245 ) -> Result<(), Self::Error> {
4246 Err(vp_state::Error::Unimplemented("synic_event_flags_page"))
4247 }
4248
4249 fn synic_message_queues(&mut self) -> Result<vp::SynicMessageQueues, Self::Error> {
4250 Err(vp_state::Error::Unimplemented("synic_message_queues"))
4251 }
4252
4253 fn set_synic_message_queues(
4254 &mut self,
4255 _value: &vp::SynicMessageQueues,
4256 ) -> Result<(), Self::Error> {
4257 Err(vp_state::Error::Unimplemented("synic_message_queues"))
4258 }
4259
4260 fn synic_timers(&mut self) -> Result<vp::SynicTimers, Self::Error> {
4261 Err(vp_state::Error::Unimplemented("synic_timers"))
4262 }
4263
4264 fn set_synic_timers(&mut self, _value: &vp::SynicTimers) -> Result<(), Self::Error> {
4265 Err(vp_state::Error::Unimplemented("synic_timers"))
4266 }
4267
4268 fn nested_state(&mut self) -> Result<vp::NestedState, Self::Error> {
4269 Err(vp_state::Error::Unimplemented("nested_state"))
4270 }
4271
4272 fn set_nested_state(&mut self, _value: &vp::NestedState) -> Result<(), Self::Error> {
4273 Err(vp_state::Error::Unimplemented("nested_state"))
4274 }
4275}
4276
4277fn top_vector(reg: &[ApicRegisterValue; 8]) -> u8 {
4281 reg.iter()
4282 .enumerate()
4283 .rev()
4284 .find_map(|(i, r)| {
4285 (r.value != 0).then(|| (i as u32 * 32 + (31 - r.value.leading_zeros())) as u8)
4286 })
4287 .unwrap_or(0)
4288}
4289
4290struct TdHypercall<'a, 'b>(UhHypercallHandler<'a, 'b, TdxBacked>);
4291
4292impl<'a, 'b> AsHandler<UhHypercallHandler<'a, 'b, TdxBacked>> for TdHypercall<'a, 'b> {
4293 fn as_handler(&mut self) -> &mut UhHypercallHandler<'a, 'b, TdxBacked> {
4294 &mut self.0
4295 }
4296}
4297
4298impl HypercallIo for TdHypercall<'_, '_> {
4299 fn advance_ip(&mut self) {
4300 self.0.vp.runner.tdx_enter_guest_gps_mut()[TdxGp::R10] = 0;
4301 self.0.vp.backing.vtls[self.0.intercepted_vtl]
4302 .private_regs
4303 .rip = self.0.vp.backing.vtls[self.0.intercepted_vtl]
4304 .private_regs
4305 .rip
4306 .wrapping_add(4);
4307 }
4308
4309 fn retry(&mut self, control: u64) {
4310 self.0.vp.runner.tdx_enter_guest_gps_mut()[TdxGp::R10] = control;
4311 self.set_result(hvdef::hypercall::HypercallOutput::from(HvError::Timeout).into());
4312 }
4313
4314 fn control(&mut self) -> u64 {
4315 self.0.vp.runner.tdx_enter_guest_gps()[TdxGp::R10]
4316 }
4317
4318 fn input_gpa(&mut self) -> u64 {
4319 self.0.vp.runner.tdx_enter_guest_gps()[TdxGp::RDX]
4320 }
4321
4322 fn output_gpa(&mut self) -> u64 {
4323 self.0.vp.runner.tdx_enter_guest_gps()[TdxGp::R8]
4324 }
4325
4326 fn fast_register_pair_count(&mut self) -> usize {
4327 7
4328 }
4329
4330 fn extended_fast_hypercalls_ok(&mut self) -> bool {
4331 false
4332 }
4333
4334 fn fast_input(&mut self, buf: &mut [[u64; 2]], _output_register_pairs: usize) -> usize {
4335 self.fast_regs(0, buf);
4336 buf.len()
4337 }
4338
4339 fn fast_output(&mut self, _starting_pair_index: usize, buf: &[[u64; 2]]) {
4340 assert!(buf.is_empty());
4341 }
4342
4343 fn vtl_input(&mut self) -> u64 {
4344 unreachable!()
4345 }
4346
4347 fn set_result(&mut self, n: u64) {
4348 self.0.vp.runner.tdx_enter_guest_gps_mut()[TdxGp::R11] = n;
4349 }
4350
4351 fn fast_regs(&mut self, starting_pair_index: usize, buf: &mut [[u64; 2]]) {
4352 let regs = self.0.vp.runner.tdx_enter_guest_gps();
4353 let fx_state = self.0.vp.runner.fx_state();
4354 for (i, [low, high]) in buf.iter_mut().enumerate() {
4355 let index = i + starting_pair_index;
4356 if index == 0 {
4357 *low = regs[TdxGp::RDX];
4358 *high = regs[TdxGp::R8];
4359 } else {
4360 let value = u128::from_ne_bytes(fx_state.xmm[index - 1]);
4361 *low = value as u64;
4362 *high = (value >> 64) as u64;
4363 }
4364 }
4365 }
4366}
4367
4368impl hv1_hypercall::VtlSwitchOps for UhHypercallHandler<'_, '_, TdxBacked> {
4369 fn advance_ip(&mut self) {
4370 let long_mode = self.vp.long_mode(self.intercepted_vtl);
4371 let mut io = hv1_hypercall::X64RegisterIo::new(self, long_mode, true);
4372 io.advance_ip();
4373 }
4374
4375 fn inject_invalid_opcode_fault(&mut self) {
4376 self.vp.backing.vtls[self.intercepted_vtl].interruption_information =
4377 InterruptionInformation::new()
4378 .with_valid(true)
4379 .with_interruption_type(INTERRUPT_TYPE_HARDWARE_EXCEPTION)
4380 .with_vector(x86defs::Exception::INVALID_OPCODE.0);
4381 }
4382}
4383
4384impl hv1_hypercall::FlushVirtualAddressList for UhHypercallHandler<'_, '_, TdxBacked> {
4385 fn flush_virtual_address_list(
4386 &mut self,
4387 processor_set: ProcessorSet<'_>,
4388 flags: HvFlushFlags,
4389 gva_ranges: &[HvGvaRange],
4390 ) -> HvRepResult {
4391 hv1_hypercall::FlushVirtualAddressListEx::flush_virtual_address_list_ex(
4392 self,
4393 processor_set,
4394 flags,
4395 gva_ranges,
4396 )
4397 }
4398}
4399
4400impl hv1_hypercall::FlushVirtualAddressListEx for UhHypercallHandler<'_, '_, TdxBacked> {
4401 fn flush_virtual_address_list_ex(
4402 &mut self,
4403 processor_set: ProcessorSet<'_>,
4404 flags: HvFlushFlags,
4405 gva_ranges: &[HvGvaRange],
4406 ) -> HvRepResult {
4407 self.hcvm_validate_flush_inputs(processor_set, flags, true)
4408 .map_err(|e| (e, 0))?;
4409
4410 let vtl = self.intercepted_vtl;
4411 let flush_state = &self.vp.shared.flush_state[vtl];
4412
4413 if let Err(()) = Self::add_ranges_to_tlb_flush_list(
4415 flush_state,
4416 gva_ranges,
4417 flags.use_extended_range_format(),
4418 ) {
4419 if flags.non_global_mappings_only() {
4420 flush_state
4421 .flush_entire_non_global_counter
4422 .fetch_add(1, Ordering::Relaxed);
4423 } else {
4424 flush_state
4425 .flush_entire_counter
4426 .fetch_add(1, Ordering::Relaxed);
4427 }
4428 }
4429
4430 TdxTlbLockFlushAccess {
4432 vp_index: Some(self.vp.vp_index()),
4433 partition: self.vp.partition,
4434 shared: self.vp.shared,
4435 }
4436 .wake_processors_for_tlb_flush(vtl, (!flags.all_processors()).then_some(processor_set));
4437
4438 self.vp.set_wait_for_tlb_locks(vtl);
4440
4441 Ok(())
4442 }
4443}
4444
4445impl hv1_hypercall::FlushVirtualAddressSpace for UhHypercallHandler<'_, '_, TdxBacked> {
4446 fn flush_virtual_address_space(
4447 &mut self,
4448 processor_set: ProcessorSet<'_>,
4449 flags: HvFlushFlags,
4450 ) -> hvdef::HvResult<()> {
4451 hv1_hypercall::FlushVirtualAddressSpaceEx::flush_virtual_address_space_ex(
4452 self,
4453 processor_set,
4454 flags,
4455 )
4456 }
4457}
4458
4459impl hv1_hypercall::FlushVirtualAddressSpaceEx for UhHypercallHandler<'_, '_, TdxBacked> {
4460 fn flush_virtual_address_space_ex(
4461 &mut self,
4462 processor_set: ProcessorSet<'_>,
4463 flags: HvFlushFlags,
4464 ) -> hvdef::HvResult<()> {
4465 self.hcvm_validate_flush_inputs(processor_set, flags, false)?;
4466 let vtl = self.intercepted_vtl;
4467
4468 let flush_state = &self.vp.shared.flush_state[vtl];
4469
4470 if flags.non_global_mappings_only() {
4472 flush_state
4473 .flush_entire_non_global_counter
4474 .fetch_add(1, Ordering::Relaxed);
4475 } else {
4476 flush_state
4477 .flush_entire_counter
4478 .fetch_add(1, Ordering::Relaxed);
4479 }
4480
4481 TdxTlbLockFlushAccess {
4483 vp_index: Some(self.vp.vp_index()),
4484 partition: self.vp.partition,
4485 shared: self.vp.shared,
4486 }
4487 .wake_processors_for_tlb_flush(vtl, (!flags.all_processors()).then_some(processor_set));
4488
4489 self.vp.set_wait_for_tlb_locks(vtl);
4491
4492 Ok(())
4493 }
4494}
4495
4496impl UhHypercallHandler<'_, '_, TdxBacked> {
4497 fn add_ranges_to_tlb_flush_list(
4498 flush_state: &TdxPartitionFlushState,
4499 gva_ranges: &[HvGvaRange],
4500 use_extended_range_format: bool,
4501 ) -> Result<(), ()> {
4502 if gva_ranges.len() > FLUSH_GVA_LIST_SIZE {
4504 return Err(());
4505 }
4506
4507 if use_extended_range_format
4508 && gva_ranges
4509 .iter()
4510 .any(|range| range.as_extended().large_page())
4511 {
4512 return Err(());
4515 }
4516
4517 flush_state
4518 .gva_list
4519 .write()
4520 .extend(gva_ranges.iter().copied());
4521
4522 Ok(())
4523 }
4524}
4525
4526impl TdxTlbLockFlushAccess<'_> {
4527 fn wake_processors_for_tlb_flush(
4528 &mut self,
4529 target_vtl: GuestVtl,
4530 processor_set: Option<ProcessorSet<'_>>,
4531 ) {
4532 match processor_set {
4533 Some(processors) => {
4534 self.wake_processors_for_tlb_flush_inner(target_vtl, processors);
4535 }
4536 None => self.wake_processors_for_tlb_flush_inner(
4537 target_vtl,
4538 0..(self.partition.vps.len() as u32),
4539 ),
4540 }
4541 }
4542
4543 fn wake_processors_for_tlb_flush_inner(
4544 &mut self,
4545 target_vtl: GuestVtl,
4546 processors: impl IntoIterator<Item = u32>,
4547 ) {
4548 std::sync::atomic::fence(Ordering::SeqCst);
4556 self.partition.hcl.kick_cpus(
4557 processors.into_iter().filter(|&vp| {
4558 self.shared.active_vtl[vp as usize].load(Ordering::Relaxed) == target_vtl as u8
4559 }),
4560 true,
4561 true,
4562 );
4563 }
4564}
4565
4566struct TdxTlbLockFlushAccess<'a> {
4567 vp_index: Option<VpIndex>,
4568 partition: &'a UhPartitionInner,
4569 shared: &'a TdxBackedShared,
4570}
4571
4572impl TlbFlushLockAccess for TdxTlbLockFlushAccess<'_> {
4573 fn flush(&mut self, vtl: GuestVtl) {
4574 self.shared.flush_state[vtl]
4575 .flush_entire_counter
4576 .fetch_add(1, Ordering::Relaxed);
4577
4578 self.wake_processors_for_tlb_flush(vtl, None);
4579 self.set_wait_for_tlb_locks(vtl);
4580 }
4581
4582 fn flush_entire(&mut self) {
4583 for vtl in [GuestVtl::Vtl0, GuestVtl::Vtl1] {
4584 self.shared.flush_state[vtl]
4585 .flush_entire_counter
4586 .fetch_add(1, Ordering::Relaxed);
4587 }
4588 for vtl in [GuestVtl::Vtl0, GuestVtl::Vtl1] {
4589 self.wake_processors_for_tlb_flush(vtl, None);
4590 self.set_wait_for_tlb_locks(vtl);
4591 }
4592 }
4593
4594 fn set_wait_for_tlb_locks(&mut self, vtl: GuestVtl) {
4595 if let Some(vp_index) = self.vp_index {
4596 hardware_cvm::tlb_lock::TlbLockAccess {
4597 vp_index,
4598 cvm_partition: &self.shared.cvm,
4599 }
4600 .set_wait_for_tlb_locks(vtl);
4601 }
4602 }
4603}
4604
4605mod save_restore {
4606 use super::TdxBacked;
4607 use super::UhProcessor;
4608 use vmcore::save_restore::RestoreError;
4609 use vmcore::save_restore::SaveError;
4610 use vmcore::save_restore::SaveRestore;
4611 use vmcore::save_restore::SavedStateNotSupported;
4612
4613 impl SaveRestore for UhProcessor<'_, TdxBacked> {
4614 type SavedState = SavedStateNotSupported;
4615
4616 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
4617 Err(SaveError::NotSupported)
4618 }
4619
4620 fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
4621 match state {}
4622 }
4623 }
4624}