1use super::BackingParams;
7use super::BackingPrivate;
8use super::BackingSharedParams;
9use super::HardwareIsolatedBacking;
10use super::InterceptMessageOptionalState;
11use super::InterceptMessageState;
12use super::UhEmulationState;
13use super::hardware_cvm;
14use super::hardware_cvm::HardwareIsolatedGuestTimer;
15use super::vp_state;
16use super::vp_state::UhVpStateAccess;
17use crate::BackingShared;
18use crate::Error;
19use crate::GuestVtl;
20use crate::TlbFlushLockAccess;
21use crate::UhCvmPartitionState;
22use crate::UhCvmVpState;
23use crate::UhPartitionInner;
24use crate::UhPartitionNewParams;
25use crate::WakeReason;
26use crate::devmsr;
27use crate::processor::UhHypercallHandler;
28use crate::processor::UhProcessor;
29use crate::processor::hardware_cvm::apic::ApicBacking;
30use cvm_tracing::CVM_ALLOWED;
31use cvm_tracing::CVM_CONFIDENTIAL;
32use hcl::protocol::hcl_intr_offload_flags;
33use hcl::vmsa::VmsaWrapper;
34use hv1_emulator::hv::ProcessorVtlHv;
35use hv1_emulator::synic::ProcessorSynic;
36use hv1_hypercall::HvRepResult;
37use hv1_hypercall::HypercallIo;
38use hv1_structs::ProcessorSet;
39use hv1_structs::VtlArray;
40use hvdef::HV_PAGE_SIZE;
41use hvdef::HvDeliverabilityNotificationsRegister;
42use hvdef::HvError;
43use hvdef::HvMessageType;
44use hvdef::HvX64PendingExceptionEvent;
45use hvdef::HvX64RegisterName;
46use hvdef::Vtl;
47use hvdef::hypercall::Control;
48use hvdef::hypercall::HvFlushFlags;
49use hvdef::hypercall::HvGvaRange;
50use hvdef::hypercall::HypercallOutput;
51use inspect::Inspect;
52use inspect::InspectMut;
53use inspect_counters::Counter;
54use virt::EmulatorMonitorSupport;
55use virt::Processor;
56use virt::VpHaltReason;
57use virt::VpIndex;
58use virt::io::CpuIo;
59use virt::state::StateElement;
60use virt::vp;
61use virt::vp::AccessVpState;
62use virt::vp::MpState;
63use virt::x86::MsrError;
64use virt::x86::MsrErrorExt;
65use virt::x86::SegmentRegister;
66use virt::x86::TableRegister;
67use virt_support_apic::ApicClient;
68use virt_support_x86emu::emulate::EmulatorSupport as X86EmulatorSupport;
69use virt_support_x86emu::emulate::emulate_io;
70use virt_support_x86emu::emulate::emulate_translate_gva;
71use virt_support_x86emu::translate::TranslationRegisters;
72use vmcore::vmtime::VmTime;
73use vmcore::vmtime::VmTimeAccess;
74use x86defs::RFlags;
75use x86defs::apic::X2APIC_MSR_BASE;
76use x86defs::cpuid::CpuidFunction;
77use x86defs::snp::SevAvicIncompleteIpiInfo1;
78use x86defs::snp::SevAvicIncompleteIpiInfo2;
79use x86defs::snp::SevAvicNoAccelInfo;
80use x86defs::snp::SevAvicPage;
81use x86defs::snp::SevAvicRegisterNumber;
82use x86defs::snp::SevEventInjectInfo;
83use x86defs::snp::SevExitCode;
84use x86defs::snp::SevInvlpgbEcx;
85use x86defs::snp::SevInvlpgbEdx;
86use x86defs::snp::SevInvlpgbRax;
87use x86defs::snp::SevIoAccessInfo;
88use x86defs::snp::SevNpfInfo;
89use x86defs::snp::SevSelector;
90use x86defs::snp::SevStatusMsr;
91use x86defs::snp::SevVmsa;
92use x86defs::snp::Vmpl;
93use zerocopy::FromZeros;
94use zerocopy::IntoBytes;
95
96#[derive(Debug, Error)]
97#[error("invalid vmcb")]
98struct InvalidVmcb;
99
100#[derive(Debug, Error)]
101enum SnpGhcbError {
102 #[error("failed to access GHCB page")]
103 GhcbPageAccess(#[source] guestmem::GuestMemoryError),
104 #[error("ghcb page used for vmgexit does not match overlay page")]
105 GhcbMisconfiguration,
106}
107
108#[derive(Debug, Error)]
109enum SnpRunVpError {
110 #[error("guest AVIC backing page is not validated or cannot be accessed")]
111 VpNotRestartableError,
112 #[error("failed to run")]
113 RunVpError(#[source] hcl::ioctl::Error),
114}
115
116#[derive(InspectMut)]
118pub struct SnpBacked {
119 #[inspect(hex)]
120 hv_sint_notifications: u16,
121 general_stats: VtlArray<GeneralStats, 2>,
122 exit_stats: VtlArray<ExitStats, 2>,
123 synic_timer_deadline: SnpSynicTimerDeadline,
124 #[inspect(flatten)]
125 cvm: UhCvmVpState,
126}
127
128#[derive(Inspect, Default)]
129struct GeneralStats {
130 guest_busy: Counter,
131 int_ack: Counter,
132 synth_int: Counter,
133}
134
135#[derive(Inspect, Default)]
136struct ExitStats {
137 automatic_exit: Counter,
138 bus_lock: Counter,
139 cpuid: Counter,
140 hlt: Counter,
141 intr: Counter,
142 invd: Counter,
143 invlpgb: Counter,
144 ioio: Counter,
145 msr_read: Counter,
146 msr_write: Counter,
147 npf: Counter,
148 npf_no_intercept: Counter,
149 npf_spurious: Counter,
150 rdpmc: Counter,
151 vmgexit: Counter,
152 vmmcall: Counter,
153 xsetbv: Counter,
154 excp_db: Counter,
155 secure_reg_write: Counter,
156 avic_no_accel: Counter,
157 avic_incomplete_ipi: Counter,
158}
159
160#[derive(Inspect, Default)]
161struct SnpSynicTimerDeadline {
162 #[inspect(hex)]
163 armed_ref_time: Option<u64>,
164 #[inspect(hex)]
165 armed_timeout: Option<VmTime>,
166 #[inspect(hex)]
167 next_ref_time: Option<u64>,
168 deadline_seen: bool,
169}
170
171impl SnpSynicTimerDeadline {
172 fn clear_scan_deadline(&mut self) {
173 if !self.deadline_seen {
176 self.armed_ref_time = None;
177 self.armed_timeout = None;
178 }
179
180 self.next_ref_time = None;
184 self.deadline_seen = false;
185 }
186
187 fn update_scan_deadline(&mut self, ref_time_next: u64) -> bool {
188 if self
191 .next_ref_time
192 .is_some_and(|next_ref_time| ref_time_next >= next_ref_time)
193 {
194 return false;
195 }
196
197 self.next_ref_time = Some(ref_time_next);
198 self.deadline_seen = true;
199 true
200 }
201}
202
203struct SnpKernelGuestTimer {
204 fallback: hardware_cvm::VmTimeGuestTimer,
205}
206
207impl SnpKernelGuestTimer {
208 fn timeout(&self, vmtime: &VmTimeAccess, ref_time_now: u64, ref_time_next: u64) -> VmTime {
209 self.fallback.timeout(vmtime, ref_time_now, ref_time_next)
210 }
211}
212
213impl HardwareIsolatedGuestTimer<SnpBacked> for SnpKernelGuestTimer {
214 fn is_hardware_virtualized(&self) -> bool {
215 false
216 }
217
218 fn update_deadline(
219 &self,
220 vp: &mut UhProcessor<'_, SnpBacked>,
221 ref_time_now: u64,
222 ref_time_next: u64,
223 ) {
224 self.fallback
225 .update_deadline(vp, ref_time_now, ref_time_next);
226 }
227
228 fn clear_deadline(&self, vp: &mut UhProcessor<'_, SnpBacked>) {
229 self.fallback.clear_deadline(vp);
230 }
231
232 fn begin_vtl_transition(&self, vp: &mut UhProcessor<'_, SnpBacked>, vtl: GuestVtl) {
233 vp.runner.set_stimer0_config(
234 (vtl == GuestVtl::Vtl0)
235 .then(|| vp.backing.cvm.hv[GuestVtl::Vtl0].synic.stimer_config(0)),
236 );
237 }
238
239 fn end_vtl_transition(&self, vp: &mut UhProcessor<'_, SnpBacked>, _vtl: GuestVtl) {
240 if let Some(update) = vp.runner.take_stimer0_update() {
241 assert_eq!(_vtl, GuestVtl::Vtl0);
242 tracing::trace!(
243 count = update.count,
244 programmed_ref_time = update.programmed_ref_time,
245 expired = update.expired,
246 "synchronizing kernel STIMER0 update"
247 );
248 vp.backing.cvm.hv[GuestVtl::Vtl0].synic.set_stimer_count_at(
251 0,
252 update.count,
253 update.programmed_ref_time,
254 );
255 }
256 }
257}
258
259enum UhDirectOverlay {
260 Sipp,
261 Sifp,
262 Ghcb,
263 Count,
264}
265
266impl SnpBacked {
267 fn calculate_efer(efer: u64, cr0: u64) -> u64 {
269 let new_efer = if efer & x86defs::X64_EFER_LME != 0 && cr0 & x86defs::X64_CR0_PG != 0 {
270 efer | x86defs::X64_EFER_LMA
271 } else {
272 efer & !x86defs::X64_EFER_LMA
273 };
274 new_efer | x86defs::X64_EFER_SVME
275 }
276
277 pub fn shared_pages_required_per_cpu() -> u64 {
280 UhDirectOverlay::Count as u64
281 }
282}
283
284impl HardwareIsolatedBacking for SnpBacked {
285 fn cvm_state(&self) -> &UhCvmVpState {
286 &self.cvm
287 }
288
289 fn cvm_state_mut(&mut self) -> &mut UhCvmVpState {
290 &mut self.cvm
291 }
292
293 fn cvm_partition_state(shared: &Self::Shared) -> &UhCvmPartitionState {
294 &shared.cvm
295 }
296
297 fn switch_vtl(this: &mut UhProcessor<'_, Self>, source_vtl: GuestVtl, target_vtl: GuestVtl) {
298 let [vmsa0, vmsa1] = this.runner.vmsas_mut();
299 let (current_vmsa, mut target_vmsa) = match (source_vtl, target_vtl) {
300 (GuestVtl::Vtl0, GuestVtl::Vtl1) => (vmsa0, vmsa1),
301 (GuestVtl::Vtl1, GuestVtl::Vtl0) => (vmsa1, vmsa0),
302 _ => unreachable!(),
303 };
304
305 target_vmsa.set_rax(current_vmsa.rax());
306 target_vmsa.set_rbx(current_vmsa.rbx());
307 target_vmsa.set_rcx(current_vmsa.rcx());
308 target_vmsa.set_rdx(current_vmsa.rdx());
309 target_vmsa.set_rbp(current_vmsa.rbp());
310 target_vmsa.set_rsi(current_vmsa.rsi());
311 target_vmsa.set_rdi(current_vmsa.rdi());
312 target_vmsa.set_r8(current_vmsa.r8());
313 target_vmsa.set_r9(current_vmsa.r9());
314 target_vmsa.set_r10(current_vmsa.r10());
315 target_vmsa.set_r11(current_vmsa.r11());
316 target_vmsa.set_r12(current_vmsa.r12());
317 target_vmsa.set_r13(current_vmsa.r13());
318 target_vmsa.set_r14(current_vmsa.r14());
319 target_vmsa.set_r15(current_vmsa.r15());
320 target_vmsa.set_xcr0(current_vmsa.xcr0());
321
322 target_vmsa.set_cr2(current_vmsa.cr2());
323
324 target_vmsa.set_dr0(current_vmsa.dr0());
326 target_vmsa.set_dr1(current_vmsa.dr1());
327 target_vmsa.set_dr2(current_vmsa.dr2());
328 target_vmsa.set_dr3(current_vmsa.dr3());
329
330 target_vmsa.set_pl0_ssp(current_vmsa.pl0_ssp());
331 target_vmsa.set_pl1_ssp(current_vmsa.pl1_ssp());
332 target_vmsa.set_pl2_ssp(current_vmsa.pl2_ssp());
333 target_vmsa.set_pl3_ssp(current_vmsa.pl3_ssp());
334 target_vmsa.set_u_cet(current_vmsa.u_cet());
335
336 target_vmsa.set_x87_registers(¤t_vmsa.x87_registers());
337
338 let vec_reg_count = 16;
339 for i in 0..vec_reg_count {
340 target_vmsa.set_xmm_registers(i, current_vmsa.xmm_registers(i));
341 target_vmsa.set_ymm_registers(i, current_vmsa.ymm_registers(i));
342 }
343
344 this.backing.cvm_state_mut().exit_vtl = target_vtl;
345 }
346
347 fn translation_registers(
348 &self,
349 this: &UhProcessor<'_, Self>,
350 vtl: GuestVtl,
351 ) -> TranslationRegisters {
352 let vmsa = this.runner.vmsa(vtl);
353 TranslationRegisters {
354 cr0: vmsa.cr0(),
355 cr4: vmsa.cr4(),
356 efer: vmsa.efer(),
357 cr3: vmsa.cr3(),
358 rflags: vmsa.rflags(),
359 ss: virt_seg_from_snp(vmsa.ss()).into(),
360 encryption_mode: virt_support_x86emu::translate::EncryptionMode::Vtom(
361 this.partition.caps.vtom.unwrap(),
362 ),
363 }
364 }
365
366 fn tlb_flush_lock_access<'a>(
367 vp_index: Option<VpIndex>,
368 partition: &'a UhPartitionInner,
369 shared: &'a Self::Shared,
370 ) -> impl TlbFlushLockAccess + 'a {
371 SnpTlbLockFlushAccess {
372 vp_index,
373 partition,
374 shared,
375 }
376 }
377
378 fn pending_event_vector(this: &UhProcessor<'_, Self>, vtl: GuestVtl) -> Option<u8> {
379 let event_inject = this.runner.vmsa(vtl).event_inject();
380 if event_inject.valid() {
381 Some(event_inject.vector())
382 } else {
383 None
384 }
385 }
386
387 fn set_pending_exception(
388 this: &mut UhProcessor<'_, Self>,
389 vtl: GuestVtl,
390 event: HvX64PendingExceptionEvent,
391 ) {
392 let inject_info = SevEventInjectInfo::new()
393 .with_valid(true)
394 .with_deliver_error_code(event.deliver_error_code())
395 .with_error_code(event.error_code())
396 .with_vector(event.vector().try_into().unwrap())
397 .with_interruption_type(x86defs::snp::SEV_INTR_TYPE_EXCEPT);
398
399 this.runner.vmsa_mut(vtl).set_event_inject(inject_info);
400 }
401
402 fn cr0(this: &UhProcessor<'_, Self>, vtl: GuestVtl) -> u64 {
403 this.runner.vmsa(vtl).cr0()
404 }
405
406 fn cr4(this: &UhProcessor<'_, Self>, vtl: GuestVtl) -> u64 {
407 this.runner.vmsa(vtl).cr4()
408 }
409
410 fn intercept_message_state(
411 this: &UhProcessor<'_, Self>,
412 vtl: GuestVtl,
413 include_optional_state: bool,
414 ) -> InterceptMessageState {
415 let vmsa = this.runner.vmsa(vtl);
416
417 let instr_len = if SevExitCode(vmsa.guest_error_code()) == SevExitCode::NPF {
419 0
420 } else {
421 (vmsa.next_rip() - vmsa.rip()) as u8
422 };
423
424 InterceptMessageState {
425 instruction_length_and_cr8: instr_len,
426 cpl: vmsa.cpl(),
427 efer_lma: vmsa.efer() & x86defs::X64_EFER_LMA != 0,
428 cs: virt_seg_from_snp(vmsa.cs()).into(),
429 rip: vmsa.rip(),
430 rflags: vmsa.rflags(),
431 rax: vmsa.rax(),
432 rdx: vmsa.rdx(),
433 optional: if include_optional_state {
434 Some(InterceptMessageOptionalState {
435 ds: virt_seg_from_snp(vmsa.ds()).into(),
436 es: virt_seg_from_snp(vmsa.es()).into(),
437 })
438 } else {
439 None
440 },
441 rcx: vmsa.rcx(),
442 rsi: vmsa.rsi(),
443 rdi: vmsa.rdi(),
444 }
445 }
446
447 fn cr_intercept_registration(
448 this: &mut UhProcessor<'_, Self>,
449 intercept_control: hvdef::HvRegisterCrInterceptControl,
450 ) {
451 this.runner
456 .set_vp_registers_hvcall(
457 Vtl::Vtl1,
458 [(
459 HvX64RegisterName::CrInterceptControl,
460 u64::from(intercept_control),
461 )],
462 )
463 .expect("setting intercept control succeeds");
464 }
465
466 fn is_interrupt_pending(
467 this: &mut UhProcessor<'_, Self>,
468 vtl: GuestVtl,
469 check_rflags: bool,
470 dev: &impl CpuIo,
471 ) -> bool {
472 let (avic_page, vmsa) = this.runner.secure_avic_page_vmsa_mut(vtl);
473 if vmsa.event_inject().valid()
474 && vmsa.event_inject().interruption_type() == x86defs::snp::SEV_INTR_TYPE_NMI
475 {
476 return true;
477 }
478 if vmsa.v_intr_cntrl().nmi() {
480 return true;
481 }
482
483 let vmsa_priority = vmsa.v_intr_cntrl().priority() as u32;
484 let lapic = &mut this.backing.cvm.lapics[vtl].lapic;
485 let ppr = lapic
486 .access(&mut SnpApicClient {
487 partition: this.partition,
488 vmsa,
489 avic_page,
490 dev,
491 vmtime: &this.vmtime,
492 vtl,
493 })
494 .get_ppr();
495 let ppr_priority = ppr >> 4;
496 if vmsa_priority <= ppr_priority {
497 return false;
498 }
499
500 let vmsa = this.runner.vmsa_mut(vtl);
501 if (check_rflags && !RFlags::from_bits(vmsa.rflags()).interrupt_enable())
502 || vmsa.v_intr_cntrl().intr_shadow()
503 || !vmsa.v_intr_cntrl().irq()
504 {
505 return false;
506 }
507
508 true
509 }
510
511 fn untrusted_synic_mut(&mut self) -> Option<&mut ProcessorSynic> {
512 None
513 }
514
515 fn update_deadline(this: &mut UhProcessor<'_, Self>, ref_time_now: u64, next_ref_time: u64) {
516 if !this
517 .backing
518 .synic_timer_deadline
519 .update_scan_deadline(next_ref_time)
520 {
521 return;
522 }
523
524 if this.backing.synic_timer_deadline.armed_ref_time == Some(next_ref_time) {
528 if let Some(timeout) = this.backing.synic_timer_deadline.armed_timeout {
529 this.vmtime.set_timeout_if_before(timeout);
530 }
531 return;
532 }
533
534 let timeout = this
535 .shared
536 .guest_timer
537 .timeout(&this.vmtime, ref_time_now, next_ref_time);
538
539 this.backing.synic_timer_deadline.armed_ref_time = Some(next_ref_time);
540 this.backing.synic_timer_deadline.armed_timeout = Some(timeout);
541 this.vmtime.set_timeout_if_before(timeout);
542 }
543
544 fn clear_deadline(this: &mut UhProcessor<'_, Self>) {
545 this.backing.synic_timer_deadline.clear_scan_deadline();
546 if this.backing.synic_timer_deadline.armed_ref_time.is_none() {
547 this.shared.guest_timer.clear_deadline(this);
548 }
549 }
550}
551
552#[derive(Inspect)]
554pub struct SnpBackedShared {
555 #[inspect(flatten)]
556 pub(crate) cvm: UhCvmPartitionState,
557 invlpgb_count_max: u16,
558 tsc_aux_virtualized: bool,
559 #[inspect(debug)]
560 sev_status: SevStatusMsr,
561 #[inspect(skip)]
563 guest_timer: SnpKernelGuestTimer,
564 secure_avic: bool,
565 pub(crate) vnmi: bool,
567}
568
569impl SnpBackedShared {
570 pub(crate) fn new(
571 _partition_params: &UhPartitionNewParams<'_>,
572 params: BackingSharedParams<'_>,
573 ) -> Result<Self, Error> {
574 let cvm = params.cvm_state.unwrap();
575 let invlpgb_count_max = x86defs::cpuid::ExtendedAddressSpaceSizesEdx::from(
576 params
577 .cpuid
578 .result(CpuidFunction::ExtendedAddressSpaceSizes.0, 0, &[0; 4])[3],
579 )
580 .invlpgb_count_max();
581 let extended_sev_features = x86defs::cpuid::ExtendedSevFeaturesEax::from(
582 params
583 .cpuid
584 .result(CpuidFunction::ExtendedSevFeatures.0, 0, &[0; 4])[0],
585 );
586 let tsc_aux_virtualized = extended_sev_features.tsc_aux_virtualization();
587
588 let svm_features_edx = x86defs::cpuid::ExtendedSvmVersionAndFeaturesEdx::from(
593 safe_intrinsics::cpuid(CpuidFunction::ExtendedSvmVersionAndFeatures.0, 0).edx,
594 );
595 let vnmi = svm_features_edx.vnmi();
596
597 let msr = devmsr::MsrDevice::new(0).expect("open msr");
601 let sev_status =
602 SevStatusMsr::from(msr.read_msr(x86defs::X86X_AMD_MSR_SEV).expect("read msr"));
603 tracing::info!(CVM_ALLOWED, ?sev_status, "SEV status");
604
605 #[cfg(feature = "disable_secure_avic")]
606 let secure_avic = false;
607 #[cfg(not(feature = "disable_secure_avic"))]
608 let secure_avic = sev_status.secure_avic();
609 tracing::info!(CVM_ALLOWED, ?secure_avic, "Secure AVIC status");
610
611 let guest_timer = SnpKernelGuestTimer {
613 fallback: hardware_cvm::VmTimeGuestTimer,
614 };
615
616 Ok(Self {
617 sev_status,
618 invlpgb_count_max,
619 tsc_aux_virtualized,
620 secure_avic,
621 cvm,
622 guest_timer,
623 vnmi,
624 })
625 }
626}
627
628#[expect(private_interfaces)]
629impl BackingPrivate for SnpBacked {
630 type HclBacking<'snp> = hcl::ioctl::snp::Snp<'snp>;
631 type Shared = SnpBackedShared;
632 type EmulationCache = ();
633
634 fn shared(shared: &BackingShared) -> &Self::Shared {
635 let BackingShared::Snp(shared) = shared else {
636 unreachable!()
637 };
638 shared
639 }
640
641 fn new(params: BackingParams<'_, '_, Self>, shared: &SnpBackedShared) -> Result<Self, Error> {
642 Ok(Self {
643 hv_sint_notifications: 0,
644 general_stats: VtlArray::from_fn(|_| Default::default()),
645 exit_stats: VtlArray::from_fn(|_| Default::default()),
646 synic_timer_deadline: Default::default(),
647 cvm: UhCvmVpState::new(
648 &shared.cvm,
649 params.partition,
650 params.vp_info,
651 UhDirectOverlay::Count as usize,
652 )?,
653 })
654 }
655
656 fn init(this: &mut UhProcessor<'_, Self>) {
657 let sev_status = this.vp().shared.sev_status;
658 let vnmi = this.vp().shared.vnmi;
659 for vtl in [GuestVtl::Vtl0, GuestVtl::Vtl1] {
660 init_vmsa(
661 &mut this.runner.vmsa_mut(vtl),
662 vtl,
663 this.partition.caps.vtom,
664 sev_status,
665 vnmi,
666 );
667
668 let registers = vp::Registers::at_reset(&this.partition.caps, &this.inner.vp_info);
670 this.access_state(vtl.into())
671 .set_registers(®isters)
672 .expect("Resetting to architectural state should succeed");
673
674 let debug_registers =
675 vp::DebugRegisters::at_reset(&this.partition.caps, &this.inner.vp_info);
676
677 this.access_state(vtl.into())
678 .set_debug_regs(&debug_registers)
679 .expect("Resetting to architectural state should succeed");
680
681 let xcr0 = vp::Xcr0::at_reset(&this.partition.caps, &this.inner.vp_info);
682 this.access_state(vtl.into())
683 .set_xcr(&xcr0)
684 .expect("Resetting to architectural state should succeed");
685
686 let cache_control = vp::Mtrrs::at_reset(&this.partition.caps, &this.inner.vp_info);
687 this.access_state(vtl.into())
688 .set_mtrrs(&cache_control)
689 .expect("Resetting to architectural state should succeed");
690 }
691
692 let pfns = &this.backing.cvm.direct_overlay_handle.pfns();
695 let values: &[(HvX64RegisterName, u64); 3] = &[
696 (
697 HvX64RegisterName::Sipp,
698 hvdef::HvSynicSimpSiefp::new()
699 .with_enabled(true)
700 .with_base_gpn(pfns[UhDirectOverlay::Sipp as usize])
701 .into(),
702 ),
703 (
704 HvX64RegisterName::Sifp,
705 hvdef::HvSynicSimpSiefp::new()
706 .with_enabled(true)
707 .with_base_gpn(pfns[UhDirectOverlay::Sifp as usize])
708 .into(),
709 ),
710 (
711 HvX64RegisterName::Ghcb,
712 x86defs::snp::GhcbMsr::new()
713 .with_info(x86defs::snp::GhcbInfo::REGISTER_REQUEST.0)
714 .with_pfn(pfns[UhDirectOverlay::Ghcb as usize])
715 .into(),
716 ),
717 ];
718
719 this.runner
720 .set_vp_registers_hvcall(Vtl::Vtl0, values)
721 .expect("set_vp_registers hypercall for direct overlays should succeed");
722
723 let using_secure_avic = this
724 .runner
725 .vmsa(GuestVtl::Vtl0)
726 .sev_features()
727 .secure_avic();
728 tracing::debug!(?using_secure_avic, "Using secure AVIC for VTL0");
729
730 if using_secure_avic {
731 let vtl0_avic_pfn = this.runner.secure_avic_vtl0_pfn(this.inner.cpu_index);
732 let mut vmsa = this.runner.vmsa_mut(GuestVtl::Vtl0);
733 let savic_ctrl = vmsa
734 .secure_avic_control()
735 .with_secure_avic_en(true)
736 .with_guest_apic_backing_page_ptr(vtl0_avic_pfn);
737 *(vmsa.secure_avic_control_mut()) = savic_ctrl;
738
739 this.set_apic_offload(GuestVtl::Vtl0, true);
740
741 this.runner
742 .set_vp_register(
743 GuestVtl::Vtl0,
744 HvX64RegisterName::SevAvicGpa,
745 savic_ctrl.into_bits().into(),
746 )
747 .expect("set_vp_register hypercall for SAVIC GPA should succeed");
748 }
749
750 assert!(
752 !this
753 .runner
754 .vmsa(GuestVtl::Vtl1)
755 .sev_features()
756 .secure_avic()
757 );
758 this.set_apic_offload(GuestVtl::Vtl1, false);
759 }
760
761 type StateAccess<'p, 'a>
762 = UhVpStateAccess<'a, 'p, Self>
763 where
764 Self: 'a + 'p,
765 'p: 'a;
766
767 fn access_vp_state<'a, 'p>(
768 this: &'a mut UhProcessor<'p, Self>,
769 vtl: GuestVtl,
770 ) -> Self::StateAccess<'p, 'a> {
771 UhVpStateAccess::new(this, vtl)
772 }
773
774 async fn run_vp(
775 this: &mut UhProcessor<'_, Self>,
776 dev: &impl CpuIo,
777 _stop: &mut virt::StopVp<'_>,
778 ) -> Result<(), VpHaltReason> {
779 this.run_vp_snp(dev).await
780 }
781
782 fn poll_apic(this: &mut UhProcessor<'_, Self>, vtl: GuestVtl, scan_irr: bool) {
783 this.runner.vmsa_mut(vtl).v_intr_cntrl_mut().set_irq(false);
788
789 hardware_cvm::apic::poll_apic_core(this, vtl, scan_irr);
790
791 if this.backing.cvm.lapics[vtl].lapic.is_offloaded() {
793 debug_assert!(vtl == GuestVtl::Vtl0);
794
795 let was_halted = matches!(
796 this.backing.cvm.lapics[vtl].activity,
797 MpState::Halted | MpState::Idle
798 );
799
800 let mut offloaded_interrupt = this
801 .runner
802 .secure_avic_page(vtl)
803 .irr
804 .iter()
805 .any(|irr| irr.value != 0);
806 let offload_supported =
807 match this.backing.cvm.lapics[vtl]
808 .lapic
809 .push_to_offload(|irr, isr, tmr| {
810 offloaded_interrupt |= irr.iter().any(|&irr| irr != 0);
811
812 let (apic_page, proxy_irr_vtl0) =
813 this.runner.secure_avic_page_proxy_irr_exit_vtl0_mut();
814
815 for (((((irr, page_irr), isr), page_isr), tmr), proxy_irr_vtl0) in irr
816 .iter()
817 .zip(&mut apic_page.irr)
818 .zip(isr)
819 .zip(&mut apic_page.isr)
820 .zip(tmr)
821 .zip(proxy_irr_vtl0)
822 {
823 page_irr.value |= *irr;
824 page_isr.value |= *isr;
825 *proxy_irr_vtl0 = *tmr;
826 }
827 }) {
828 Ok(_) => true,
829 Err(virt_support_apic::OffloadNotSupported) => false,
830 };
831
832 if !offload_supported {
833 tracing::info!(CVM_ALLOWED, "disabling APIC offload due to auto EOI");
834 this.set_apic_offload(vtl, false);
835 hardware_cvm::apic::poll_apic_core(this, vtl, false);
836 return;
837 }
838
839 if was_halted && offloaded_interrupt {
840 this.backing.cvm.lapics[vtl].activity = MpState::Running;
841 }
842 }
843 }
844
845 fn request_extint_readiness(_this: &mut UhProcessor<'_, Self>) {
846 unreachable!("extint managed through software apic")
847 }
848
849 fn request_untrusted_sint_readiness(this: &mut UhProcessor<'_, Self>, sints: u16) {
850 let sints = this.backing.hv_sint_notifications | sints;
851 if this.backing.hv_sint_notifications == sints {
852 return;
853 }
854 let notifications = HvDeliverabilityNotificationsRegister::new().with_sints(sints);
855 tracing::trace!(?notifications, "setting notifications");
856 this.runner
857 .set_vp_register(
858 GuestVtl::Vtl0,
859 HvX64RegisterName::DeliverabilityNotifications,
860 u64::from(notifications).into(),
861 )
862 .expect("requesting deliverability is not a fallable operation");
863
864 this.backing.hv_sint_notifications = sints;
865 }
866
867 fn inspect_extra(this: &mut UhProcessor<'_, Self>, resp: &mut inspect::Response<'_>) {
868 let vtl0_vmsa = this.runner.vmsa(GuestVtl::Vtl0);
869 let vtl1_vmsa = if this.backing.cvm_state().vtl1.is_some() {
870 Some(this.runner.vmsa(GuestVtl::Vtl1))
871 } else {
872 None
873 };
874
875 let add_vmsa_inspect = |req: inspect::Request<'_>, vmsa: VmsaWrapper<'_, &SevVmsa>| {
876 req.respond()
877 .hex("guest_error_code", vmsa.guest_error_code())
878 .hex("exit_info1", vmsa.exit_info1())
879 .hex("exit_info2", vmsa.exit_info2())
880 .hex("v_intr_cntrl", u64::from(vmsa.v_intr_cntrl()));
881 };
882
883 resp.child("vmsa_additional", |req| {
884 req.respond()
885 .child("vtl0", |inner_req| add_vmsa_inspect(inner_req, vtl0_vmsa))
886 .child("vtl1", |inner_req| {
887 if let Some(vtl1_vmsa) = vtl1_vmsa {
888 add_vmsa_inspect(inner_req, vtl1_vmsa);
889 }
890 });
891 });
892 }
893
894 fn hv(&self, vtl: GuestVtl) -> Option<&ProcessorVtlHv> {
895 Some(&self.cvm.hv[vtl])
896 }
897
898 fn hv_mut(&mut self, vtl: GuestVtl) -> Option<&mut ProcessorVtlHv> {
899 Some(&mut self.cvm.hv[vtl])
900 }
901
902 fn handle_vp_start_enable_vtl_wake(this: &mut UhProcessor<'_, Self>, vtl: GuestVtl) {
903 this.hcvm_handle_vp_start_enable_vtl(vtl)
904 }
905
906 fn vtl1_inspectable(this: &UhProcessor<'_, Self>) -> bool {
907 this.hcvm_vtl1_inspectable()
908 }
909
910 fn process_interrupts(
911 this: &mut UhProcessor<'_, Self>,
912 scan_irr: VtlArray<bool, 2>,
913 first_scan_irr: &mut bool,
914 dev: &impl CpuIo,
915 ) -> bool {
916 this.cvm_process_interrupts(scan_irr, first_scan_irr, dev)
917 }
918}
919
920impl UhProcessor<'_, SnpBacked> {
921 fn access_apic_without_offload<R>(
922 &mut self,
923 vtl: GuestVtl,
924 f: impl FnOnce(&mut Self) -> R,
925 ) -> R {
926 let offloaded = self.backing.cvm.lapics[vtl].lapic.is_offloaded();
927 self.set_apic_offload(vtl, false);
928 let r = f(self);
929 self.set_apic_offload(vtl, offloaded);
930 r
931 }
932
933 fn set_apic_offload(&mut self, vtl: GuestVtl, offload: bool) {
934 let offloaded = self.backing.cvm.lapics[vtl].lapic.is_offloaded();
935 if !offload {
936 if offloaded {
937 debug_assert!(vtl == GuestVtl::Vtl0);
938
939 let (irr, isr) = pull_apic_offload(self.runner.secure_avic_page_mut(vtl));
940 self.backing.cvm.lapics[vtl]
941 .lapic
942 .disable_offload(&irr, &isr);
943 }
944 } else {
945 debug_assert!(vtl == GuestVtl::Vtl0);
946 if !offloaded {
947 self.backing.cvm.lapics[vtl].lapic.enable_offload();
948 }
949 }
950 }
951}
952
953fn virt_seg_to_snp(val: SegmentRegister) -> SevSelector {
954 SevSelector {
955 selector: val.selector,
956 attrib: (val.attributes & 0xFF) | ((val.attributes >> 4) & 0xF00),
957 limit: val.limit,
958 base: val.base,
959 }
960}
961
962fn virt_table_to_snp(val: TableRegister) -> SevSelector {
963 SevSelector {
964 limit: val.limit as u32,
965 base: val.base,
966 ..FromZeros::new_zeroed()
967 }
968}
969
970fn virt_seg_from_snp(selector: SevSelector) -> SegmentRegister {
971 SegmentRegister {
972 base: selector.base,
973 limit: selector.limit,
974 selector: selector.selector,
975 attributes: (selector.attrib & 0xFF) | ((selector.attrib & 0xF00) << 4),
976 }
977}
978
979fn virt_table_from_snp(selector: SevSelector) -> TableRegister {
980 TableRegister {
981 limit: selector.limit as u16,
982 base: selector.base,
983 }
984}
985
986fn init_vmsa(
987 vmsa: &mut VmsaWrapper<'_, &mut SevVmsa>,
988 vtl: GuestVtl,
989 vtom: Option<u64>,
990 sev_status: SevStatusMsr,
991 vnmi: bool,
992) {
993 vmsa.reset(sev_status.vmsa_reg_prot());
997 vmsa.sev_features_mut()
998 .set_snp_btb_isolation(sev_status.snp_btb_isolation());
999 vmsa.sev_features_mut()
1000 .set_ibpb_on_entry(sev_status.ibpb_on_entry());
1001 vmsa.sev_features_mut()
1002 .set_prevent_host_ibs(sev_status.prevent_host_ibs());
1003 vmsa.sev_features_mut()
1004 .set_vmsa_reg_prot(sev_status.vmsa_reg_prot());
1005 vmsa.sev_features_mut().set_snp(true);
1006 vmsa.sev_features_mut().set_vtom(vtom.is_some());
1007 vmsa.set_virtual_tom(vtom.unwrap_or(0));
1008
1009 vmsa.sev_features_mut().set_reflect_vc(true);
1012 vmsa.sev_features_mut().set_debug_swap(true);
1013
1014 let use_secure_avic = cfg!(not(feature = "disable_secure_avic"))
1017 && vtl == GuestVtl::Vtl0
1018 && sev_status.secure_avic();
1019
1020 if use_secure_avic {
1021 vmsa.sev_features_mut().set_secure_avic(true);
1022 vmsa.sev_features_mut().set_guest_intercept_control(true);
1023 } else {
1024 vmsa.sev_features_mut().set_alternate_injection(true);
1025 }
1026
1027 vmsa.v_intr_cntrl_mut().set_guest_busy(true);
1028
1029 if vnmi && vtl == GuestVtl::Vtl0 {
1031 vmsa.v_intr_cntrl_mut().set_nmi_enable(true);
1032 }
1033
1034 let vmpl = match vtl {
1039 GuestVtl::Vtl0 => Vmpl::Vmpl2,
1040 GuestVtl::Vtl1 => Vmpl::Vmpl1,
1041 };
1042 vmsa.set_vmpl(vmpl.into());
1043
1044 vmsa.set_guest_error_code(SevExitCode::INTR.0);
1047
1048 vmsa.set_efer(x86defs::X64_EFER_SVME);
1051}
1052
1053struct SnpApicClient<'a, T> {
1054 partition: &'a UhPartitionInner,
1055 vmsa: VmsaWrapper<'a, &'a mut SevVmsa>,
1056 avic_page: &'a mut SevAvicPage,
1057 dev: &'a T,
1058 vmtime: &'a VmTimeAccess,
1059 vtl: GuestVtl,
1060}
1061
1062impl<T: CpuIo> ApicClient for SnpApicClient<'_, T> {
1063 fn cr8(&mut self) -> u32 {
1064 self.vmsa.v_intr_cntrl().tpr().into()
1065 }
1066
1067 fn set_cr8(&mut self, value: u32) {
1068 self.vmsa.v_intr_cntrl_mut().set_tpr(value as u8);
1069 }
1070
1071 fn set_apic_base(&mut self, _value: u64) {
1072 }
1074
1075 fn wake(&mut self, vp_index: VpIndex) {
1076 self.partition.vps[vp_index.index() as usize].wake(self.vtl, WakeReason::INTCON);
1077 }
1078
1079 fn eoi(&mut self, vector: u8) {
1080 debug_assert_eq!(self.vtl, GuestVtl::Vtl0);
1081 self.dev.handle_eoi(vector.into())
1082 }
1083
1084 fn now(&mut self) -> VmTime {
1085 self.vmtime.now()
1086 }
1087
1088 fn pull_offload(&mut self) -> ([u32; 8], [u32; 8]) {
1089 assert_eq!(self.vtl, GuestVtl::Vtl0);
1090 pull_apic_offload(self.avic_page)
1091 }
1092}
1093
1094fn pull_apic_offload(page: &mut SevAvicPage) -> ([u32; 8], [u32; 8]) {
1095 let mut irr = [0; 8];
1096 let mut isr = [0; 8];
1097 for (((irr, page_irr), isr), page_isr) in irr
1098 .iter_mut()
1099 .zip(page.irr.iter_mut())
1100 .zip(isr.iter_mut())
1101 .zip(page.isr.iter_mut())
1102 {
1103 *irr = std::mem::take(&mut page_irr.value);
1104 *isr = std::mem::take(&mut page_isr.value);
1105 }
1106 (irr, isr)
1107}
1108
1109impl UhHypercallHandler<'_, '_, SnpBacked> {
1110 const TRUSTED_DISPATCHER: hv1_hypercall::Dispatcher<Self> = hv1_hypercall::dispatcher!(
1112 Self,
1113 [
1114 hv1_hypercall::HvModifySparseGpaPageHostVisibility,
1115 hv1_hypercall::HvQuerySparseGpaPageHostVisibility,
1116 hv1_hypercall::HvX64StartVirtualProcessor,
1117 hv1_hypercall::HvGetVpIndexFromApicId,
1118 hv1_hypercall::HvGetVpRegisters,
1119 hv1_hypercall::HvEnablePartitionVtl,
1120 hv1_hypercall::HvRetargetDeviceInterrupt,
1121 hv1_hypercall::HvPostMessage,
1122 hv1_hypercall::HvSignalEvent,
1123 hv1_hypercall::HvX64EnableVpVtl,
1124 hv1_hypercall::HvExtQueryCapabilities,
1125 hv1_hypercall::HvVtlCall,
1126 hv1_hypercall::HvVtlReturn,
1127 hv1_hypercall::HvFlushVirtualAddressList,
1128 hv1_hypercall::HvFlushVirtualAddressListEx,
1129 hv1_hypercall::HvFlushVirtualAddressSpace,
1130 hv1_hypercall::HvFlushVirtualAddressSpaceEx,
1131 hv1_hypercall::HvSetVpRegisters,
1132 hv1_hypercall::HvModifyVtlProtectionMask,
1133 hv1_hypercall::HvX64TranslateVirtualAddress,
1134 hv1_hypercall::HvSendSyntheticClusterIpi,
1135 hv1_hypercall::HvSendSyntheticClusterIpiEx,
1136 hv1_hypercall::HvInstallIntercept,
1137 hv1_hypercall::HvAssertVirtualInterrupt,
1138 ],
1139 );
1140
1141 const UNTRUSTED_DISPATCHER: hv1_hypercall::Dispatcher<Self> = hv1_hypercall::dispatcher!(
1144 Self,
1145 [hv1_hypercall::HvPostMessage, hv1_hypercall::HvSignalEvent],
1146 );
1147}
1148
1149struct GhcbEnlightenedHypercall<'a, 'b> {
1150 handler: UhHypercallHandler<'a, 'b, SnpBacked>,
1151 control: u64,
1152 output_gpa: u64,
1153 input_gpa: u64,
1154 result: u64,
1155}
1156
1157impl<'a, 'b> hv1_hypercall::AsHandler<UhHypercallHandler<'a, 'b, SnpBacked>>
1158 for &mut GhcbEnlightenedHypercall<'a, 'b>
1159{
1160 fn as_handler(&mut self) -> &mut UhHypercallHandler<'a, 'b, SnpBacked> {
1161 &mut self.handler
1162 }
1163}
1164
1165impl HypercallIo for GhcbEnlightenedHypercall<'_, '_> {
1166 fn advance_ip(&mut self) {
1167 }
1169
1170 fn retry(&mut self, control: u64) {
1171 let control = Control::from(control);
1180 self.set_result(
1181 HypercallOutput::from(HvError::Timeout)
1182 .with_elements_processed(control.rep_start())
1183 .into(),
1184 );
1185 }
1186
1187 fn control(&mut self) -> u64 {
1188 self.control
1189 }
1190
1191 fn input_gpa(&mut self) -> u64 {
1192 self.input_gpa
1193 }
1194
1195 fn output_gpa(&mut self) -> u64 {
1196 self.output_gpa
1197 }
1198
1199 fn fast_register_pair_count(&mut self) -> usize {
1200 0
1201 }
1202
1203 fn extended_fast_hypercalls_ok(&mut self) -> bool {
1204 false
1205 }
1206
1207 fn fast_input(&mut self, _buf: &mut [[u64; 2]], _output_register_pairs: usize) -> usize {
1208 unimplemented!("not supported for secure enlightened abi")
1209 }
1210
1211 fn fast_output(&mut self, _starting_pair_index: usize, _buf: &[[u64; 2]]) {
1212 unimplemented!("not supported for secure enlightened abi")
1213 }
1214
1215 fn vtl_input(&mut self) -> u64 {
1216 unimplemented!("not supported for secure enlightened abi")
1217 }
1218
1219 fn set_result(&mut self, n: u64) {
1220 self.result = n;
1221 }
1222
1223 fn fast_regs(&mut self, _starting_pair_index: usize, _buf: &mut [[u64; 2]]) {
1224 unimplemented!("not supported for secure enlightened abi")
1225 }
1226}
1227
1228impl<'b> ApicBacking<'b, SnpBacked> for UhProcessor<'b, SnpBacked> {
1229 fn vp(&mut self) -> &mut UhProcessor<'b, SnpBacked> {
1230 self
1231 }
1232
1233 fn handle_interrupt(&mut self, vtl: GuestVtl, vector: u8) {
1234 let mut vmsa = self.runner.vmsa_mut(vtl);
1235 vmsa.v_intr_cntrl_mut().set_vector(vector);
1236 vmsa.v_intr_cntrl_mut().set_priority((vector >> 4).into());
1237 vmsa.v_intr_cntrl_mut().set_ignore_tpr(false);
1238 vmsa.v_intr_cntrl_mut().set_irq(true);
1239 self.backing.cvm.lapics[vtl].activity = MpState::Running;
1240 }
1241
1242 fn handle_nmi(&mut self, vtl: GuestVtl) {
1243 if self.shared.vnmi && vtl == GuestVtl::Vtl0 {
1246 {
1247 let mut vmsa = self.runner.vmsa_mut(vtl);
1248 vmsa.v_intr_cntrl_mut().set_nmi_enable(true);
1249 vmsa.v_intr_cntrl_mut().set_nmi(true);
1250 }
1251 } else {
1252 let mut vmsa = self.runner.vmsa_mut(vtl);
1253 vmsa.set_event_inject(
1256 SevEventInjectInfo::new()
1257 .with_interruption_type(x86defs::snp::SEV_INTR_TYPE_NMI)
1258 .with_vector(2)
1259 .with_valid(true),
1260 );
1261 }
1262 self.backing.cvm.lapics[vtl].nmi_pending = false;
1263 self.backing.cvm.lapics[vtl].activity = MpState::Running;
1264 }
1265
1266 fn handle_sipi(&mut self, vtl: GuestVtl, cs: SegmentRegister) {
1267 let mut vmsa = self.runner.vmsa_mut(vtl);
1268 vmsa.set_cs(virt_seg_to_snp(cs));
1269 vmsa.set_rip(0);
1270 self.backing.cvm.lapics[vtl].activity = MpState::Running;
1271 }
1272}
1273
1274impl UhProcessor<'_, SnpBacked> {
1275 fn handle_synic_deliverable_exit(&mut self) {
1276 let message = self
1277 .runner
1278 .exit_message()
1279 .as_message::<hvdef::HvX64SynicSintDeliverableMessage>();
1280
1281 tracing::trace!(
1282 deliverable_sints = message.deliverable_sints,
1283 "sint deliverable"
1284 );
1285
1286 self.backing.hv_sint_notifications &= !message.deliverable_sints;
1287
1288 self.deliver_synic_messages(GuestVtl::Vtl0, message.deliverable_sints);
1290 }
1291
1292 fn handle_vmgexit(
1293 &mut self,
1294 _dev: &impl CpuIo,
1295 intercepted_vtl: GuestVtl,
1296 ) -> Result<(), SnpGhcbError> {
1297 let message = self
1298 .runner
1299 .exit_message()
1300 .as_message::<hvdef::HvX64VmgexitInterceptMessage>();
1301
1302 let ghcb_msr = x86defs::snp::GhcbMsr::from(message.ghcb_msr);
1303 let flags = message.flags;
1304 let sw_exit_code = message.ghcb_page.standard.sw_exit_code;
1305 let sw_exit_info1 = message.ghcb_page.standard.sw_exit_info1;
1306 let sw_exit_info2 = message.ghcb_page.standard.sw_exit_info2;
1307 tracing::trace!(?ghcb_msr, "vmgexit intercept");
1308
1309 match x86defs::snp::GhcbInfo(ghcb_msr.info()) {
1310 x86defs::snp::GhcbInfo::NORMAL => {
1311 assert!(message.flags.ghcb_page_valid());
1312 let ghcb_pfn = ghcb_msr.pfn();
1313
1314 let ghcb_overlay =
1315 self.backing.cvm.direct_overlay_handle.pfns()[UhDirectOverlay::Ghcb as usize];
1316
1317 if ghcb_pfn != ghcb_overlay {
1319 tracelimit::warn_ratelimited!(
1320 CVM_ALLOWED,
1321 vmgexit_pfn = ghcb_pfn,
1322 overlay_pfn = ghcb_overlay,
1323 "ghcb page used for vmgexit does not match overlay page"
1324 );
1325
1326 return Err(SnpGhcbError::GhcbMisconfiguration);
1327 }
1328
1329 match x86defs::snp::GhcbUsage(message.ghcb_page.ghcb_usage) {
1330 x86defs::snp::GhcbUsage::HYPERCALL => {
1331 let guest_memory = &self.shared.cvm.shared_memory;
1332 let overlay_base = ghcb_overlay * HV_PAGE_SIZE;
1335 let x86defs::snp::GhcbHypercallParameters {
1336 output_gpa,
1337 input_control,
1338 } = guest_memory
1339 .read_plain(
1340 overlay_base
1341 + x86defs::snp::GHCB_PAGE_HYPERCALL_PARAMETERS_OFFSET as u64,
1342 )
1343 .map_err(SnpGhcbError::GhcbPageAccess)?;
1344
1345 let mut handler = GhcbEnlightenedHypercall {
1346 handler: UhHypercallHandler {
1347 vp: self,
1348 trusted: false,
1349 intercepted_vtl,
1350 },
1351 control: input_control,
1352 output_gpa,
1353 input_gpa: overlay_base,
1354 result: 0,
1355 };
1356
1357 UhHypercallHandler::UNTRUSTED_DISPATCHER
1358 .dispatch(guest_memory, &mut handler);
1359
1360 guest_memory
1368 .write_at(
1369 overlay_base
1370 + x86defs::snp::GHCB_PAGE_HYPERCALL_OUTPUT_OFFSET as u64,
1371 handler.result.as_bytes(),
1372 )
1373 .map_err(SnpGhcbError::GhcbPageAccess)?;
1374 }
1375 x86defs::snp::GhcbUsage::BASE => {
1376 match SevExitCode(sw_exit_code) {
1377 SevExitCode::VMMCALL => {
1379 let shared_memory = &self.shared.cvm.shared_memory;
1380 let overlay_base = ghcb_overlay * HV_PAGE_SIZE;
1381
1382 let input_control: u64 = shared_memory
1383 .read_plain(
1384 overlay_base + std::mem::offset_of!(SevVmsa, rcx) as u64,
1385 )
1386 .map_err(SnpGhcbError::GhcbPageAccess)?;
1387 let input_gpa: u64 = shared_memory
1388 .read_plain(
1389 overlay_base + std::mem::offset_of!(SevVmsa, rdx) as u64,
1390 )
1391 .map_err(SnpGhcbError::GhcbPageAccess)?;
1392 let output_gpa: u64 = shared_memory
1393 .read_plain(
1394 overlay_base + std::mem::offset_of!(SevVmsa, r8) as u64,
1395 )
1396 .map_err(SnpGhcbError::GhcbPageAccess)?;
1397
1398 let guest_memory = &self.shared.cvm.shared_memory;
1399 let mut handler = GhcbEnlightenedHypercall {
1400 handler: UhHypercallHandler {
1401 vp: self,
1402 trusted: false,
1403 intercepted_vtl,
1404 },
1405 control: input_control,
1406 output_gpa,
1407 input_gpa,
1408 result: 0,
1409 };
1410
1411 UhHypercallHandler::UNTRUSTED_DISPATCHER
1412 .dispatch(guest_memory, &mut handler);
1413
1414 shared_memory
1415 .write_at(
1416 overlay_base + std::mem::offset_of!(SevVmsa, rax) as u64,
1417 handler.result.as_bytes(),
1418 )
1419 .map_err(SnpGhcbError::GhcbPageAccess)?;
1420 }
1421 _ => {
1422 let exit_code = SevExitCode(sw_exit_code);
1423 unimplemented!("unhandled GHCB BASE sw_exit_code {exit_code:?}");
1424 }
1425 }
1426 }
1427 usage => unimplemented!(
1428 "Invalid ghcb message.\n\
1429 usage {usage:?}\n\
1430 flags {flags:?}\n\
1431 ghcb_msr {ghcb_msr:?}\n\
1432 sw_exit_code {sw_exit_code:?}\n\
1433 sw_exit_info1 {sw_exit_info1:?}\n\
1434 sw_exit_info2 {sw_exit_info2:?}"
1435 ),
1436 }
1437 }
1438 info => unimplemented!("ghcb info {info:?}"),
1439 }
1440
1441 Ok(())
1442 }
1443
1444 fn handle_msr_access(
1445 &mut self,
1446 dev: &impl CpuIo,
1447 entered_from_vtl: GuestVtl,
1448 msr: u32,
1449 is_write: bool,
1450 is_fault: bool,
1451 ) {
1452 if is_write && self.cvm_try_protect_msr_write(entered_from_vtl, msr) {
1453 return;
1454 }
1455
1456 let (avic_page, vmsa) = self.runner.secure_avic_page_vmsa_mut(entered_from_vtl);
1457 let gp = if is_write {
1458 let value = (vmsa.rax() as u32 as u64) | ((vmsa.rdx() as u32 as u64) << 32);
1459
1460 let r = self.backing.cvm.lapics[entered_from_vtl]
1461 .lapic
1462 .access(&mut SnpApicClient {
1463 partition: self.partition,
1464 vmsa,
1465 avic_page,
1466 dev,
1467 vmtime: &self.vmtime,
1468 vtl: entered_from_vtl,
1469 })
1470 .msr_write(msr, value)
1471 .or_else_if_unknown(|| self.write_msr_cvm(msr, value, entered_from_vtl))
1472 .or_else_if_unknown(|| self.write_msr_snp(dev, msr, value, entered_from_vtl));
1473
1474 match r {
1475 Ok(()) => false,
1476 Err(MsrError::Unknown) => {
1477 tracing::debug!(msr, value, "unknown cvm msr write");
1478 false
1479 }
1480 Err(MsrError::InvalidAccess) => true,
1481 }
1482 } else {
1483 let r = self.backing.cvm.lapics[entered_from_vtl]
1484 .lapic
1485 .access(&mut SnpApicClient {
1486 partition: self.partition,
1487 vmsa,
1488 avic_page,
1489 dev,
1490 vmtime: &self.vmtime,
1491 vtl: entered_from_vtl,
1492 })
1493 .msr_read(msr)
1494 .or_else_if_unknown(|| self.read_msr_cvm(msr, entered_from_vtl))
1495 .or_else_if_unknown(|| self.read_msr_snp(dev, msr, entered_from_vtl));
1496
1497 let value = match r {
1498 Ok(v) => Some(v),
1499 Err(MsrError::Unknown) => {
1500 tracing::debug!(msr, "unknown cvm msr read");
1501 Some(0)
1502 }
1503 Err(MsrError::InvalidAccess) => None,
1504 };
1505
1506 if let Some(value) = value {
1507 let mut vmsa = self.runner.vmsa_mut(entered_from_vtl);
1508 vmsa.set_rax((value as u32).into());
1509 vmsa.set_rdx(((value >> 32) as u32).into());
1510 false
1511 } else {
1512 true
1513 }
1514 };
1515
1516 let mut vmsa = self.runner.vmsa_mut(entered_from_vtl);
1517 if gp {
1518 vmsa.set_event_inject(
1519 SevEventInjectInfo::new()
1520 .with_interruption_type(x86defs::snp::SEV_INTR_TYPE_EXCEPT)
1521 .with_vector(x86defs::Exception::GENERAL_PROTECTION_FAULT.0)
1522 .with_deliver_error_code(true)
1523 .with_valid(true),
1524 );
1525 } else {
1526 if is_fault {
1527 advance_to_next_instruction(&mut vmsa);
1528 }
1529 }
1530 }
1531
1532 fn handle_xsetbv(&mut self, entered_from_vtl: GuestVtl) {
1533 let vmsa = self.runner.vmsa(entered_from_vtl);
1534 if let Some(value) = hardware_cvm::validate_xsetbv_exit(hardware_cvm::XsetbvExitInput {
1535 rax: vmsa.rax(),
1536 rcx: vmsa.rcx(),
1537 rdx: vmsa.rdx(),
1538 cr4: vmsa.cr4(),
1539 cpl: vmsa.cpl(),
1540 }) {
1541 if !self.cvm_try_protect_secure_register_write(
1542 entered_from_vtl,
1543 HvX64RegisterName::Xfem,
1544 value,
1545 ) {
1546 let mut vmsa = self.runner.vmsa_mut(entered_from_vtl);
1547 vmsa.set_xcr0(value);
1548 advance_to_next_instruction(&mut vmsa);
1549 }
1550 } else {
1551 let mut vmsa = self.runner.vmsa_mut(entered_from_vtl);
1552 vmsa.set_event_inject(
1553 SevEventInjectInfo::new()
1554 .with_interruption_type(x86defs::snp::SEV_INTR_TYPE_EXCEPT)
1555 .with_vector(x86defs::Exception::GENERAL_PROTECTION_FAULT.0)
1556 .with_deliver_error_code(true)
1557 .with_valid(true),
1558 );
1559 }
1560 }
1561
1562 fn handle_crx_intercept(&mut self, entered_from_vtl: GuestVtl, reg: HvX64RegisterName) {
1563 let vmsa = self.runner.vmsa(entered_from_vtl);
1564 let mov_crx_drx = x86defs::snp::MovCrxDrxInfo::from(vmsa.exit_info1());
1565 let reg_value = {
1566 let gpr_name =
1567 HvX64RegisterName(HvX64RegisterName::Rax.0 + mov_crx_drx.gpr_number() as u32);
1568
1569 match gpr_name {
1570 HvX64RegisterName::Rax => vmsa.rax(),
1571 HvX64RegisterName::Rbx => vmsa.rbx(),
1572 HvX64RegisterName::Rcx => vmsa.rcx(),
1573 HvX64RegisterName::Rdx => vmsa.rdx(),
1574 HvX64RegisterName::Rsp => vmsa.rsp(),
1575 HvX64RegisterName::Rbp => vmsa.rbp(),
1576 HvX64RegisterName::Rsi => vmsa.rsi(),
1577 HvX64RegisterName::Rdi => vmsa.rdi(),
1578 HvX64RegisterName::R8 => vmsa.r8(),
1579 HvX64RegisterName::R9 => vmsa.r9(),
1580 HvX64RegisterName::R10 => vmsa.r10(),
1581 HvX64RegisterName::R11 => vmsa.r11(),
1582 HvX64RegisterName::R12 => vmsa.r12(),
1583 HvX64RegisterName::R13 => vmsa.r13(),
1584 HvX64RegisterName::R14 => vmsa.r14(),
1585 HvX64RegisterName::R15 => vmsa.r15(),
1586 _ => unreachable!("unexpected register"),
1587 }
1588 };
1589
1590 if !mov_crx_drx.mov_crx() {
1597 tracelimit::warn_ratelimited!(
1598 CVM_ALLOWED,
1599 "Intercepted crx access, instruction is not mov crx"
1600 );
1601 return;
1602 }
1603
1604 if !self.cvm_try_protect_secure_register_write(entered_from_vtl, reg, reg_value) {
1605 let mut vmsa = self.runner.vmsa_mut(entered_from_vtl);
1606 match reg {
1607 HvX64RegisterName::Cr0 => vmsa.set_cr0(reg_value),
1608 HvX64RegisterName::Cr4 => vmsa.set_cr4(reg_value),
1609 _ => unreachable!(),
1610 }
1611 advance_to_next_instruction(&mut vmsa);
1612 }
1613 }
1614
1615 #[must_use]
1616 fn sync_lazy_eoi(&mut self, vtl: GuestVtl) -> bool {
1617 if self.backing.cvm.lapics[vtl].lapic.is_lazy_eoi_pending() {
1618 return self.backing.cvm.hv[vtl].set_lazy_eoi();
1619 }
1620
1621 false
1622 }
1623
1624 async fn run_vp_snp(&mut self, dev: &impl CpuIo) -> Result<(), VpHaltReason> {
1625 let next_vtl = self.backing.cvm.exit_vtl;
1626
1627 let mut vmsa = self.runner.vmsa_mut(next_vtl);
1628 let last_interrupt_ctrl = vmsa.v_intr_cntrl();
1629
1630 vmsa.v_intr_cntrl_mut().set_guest_busy(false);
1637
1638 self.unlock_tlb_lock(Vtl::Vtl2);
1639 let tlb_halt = self.should_halt_for_tlb_unlock(next_vtl);
1640 let halt = self.backing.cvm.lapics[next_vtl].activity != MpState::Running || tlb_halt;
1641
1642 let activity = self.backing.cvm.lapics[next_vtl].activity;
1646 let kernel_known_state =
1647 matches!(activity, MpState::Running | MpState::Halted | MpState::Idle);
1648 let halted_other = tlb_halt || !kernel_known_state;
1649
1650 self.runner.set_halted(halt);
1651 self.runner.set_exit_vtl(next_vtl);
1652
1653 if halt && next_vtl == GuestVtl::Vtl1 && !tlb_halt {
1654 tracelimit::warn_ratelimited!(CVM_ALLOWED, "halting VTL 1, which might halt the guest");
1655 }
1656
1657 let x2apic_enabled = self.backing.cvm.lapics[next_vtl].lapic.x2apic_enabled();
1658 let offload_enabled = self.backing.cvm.lapics[next_vtl].lapic.can_offload_irr();
1659 let offload_flags = hcl_intr_offload_flags::new()
1660 .with_offload_intr_inject(offload_enabled)
1661 .with_offload_x2apic(offload_enabled && x2apic_enabled)
1662 .with_halted_other(halted_other)
1663 .with_halted_hlt(activity == MpState::Halted)
1664 .with_halted_idle(activity == MpState::Idle);
1665 *self.runner.offload_flags_mut() = offload_flags;
1666
1667 let lazy_eoi = self.sync_lazy_eoi(next_vtl);
1669
1670 self.shared.guest_timer.begin_vtl_transition(self, next_vtl);
1671
1672 let mut has_intercept = self
1673 .runner
1674 .run()
1675 .map_err(|e| dev.fatal_error(SnpRunVpError::RunVpError(e).into()))?;
1676
1677 let entered_from_vtl = next_vtl;
1678
1679 self.shared
1680 .guest_timer
1681 .end_vtl_transition(self, entered_from_vtl);
1682
1683 if offload_enabled && kernel_known_state {
1687 let offload_flags = self.runner.offload_flags_mut();
1688
1689 self.backing.cvm.lapics[entered_from_vtl].activity =
1690 match (offload_flags.halted_hlt(), offload_flags.halted_idle()) {
1691 (false, false) => MpState::Running,
1692 (true, false) => MpState::Halted,
1693 (false, true) => MpState::Idle,
1694 (true, true) => {
1695 tracelimit::warn_ratelimited!(
1696 CVM_ALLOWED,
1697 "Kernel indicates VP is both halted and idle!"
1698 );
1699 activity
1700 }
1701 };
1702 }
1703
1704 let (avic_page, mut vmsa) = self.runner.secure_avic_page_vmsa_mut(entered_from_vtl);
1705
1706 let was_busy = vmsa.guest_busy_bit_test_and_set();
1710 let exit_int_info_trace = SevEventInjectInfo::from(vmsa.exit_int_info());
1711
1712 if was_busy {
1713 self.backing.general_stats[entered_from_vtl]
1714 .guest_busy
1715 .increment();
1716
1717 let sev_error_code = SevExitCode(vmsa.guest_error_code());
1718 match sev_error_code {
1719 SevExitCode::NOT_RESTARTABLE => {
1720 return Err(dev.fatal_error(SnpRunVpError::VpNotRestartableError.into()));
1722 }
1723 SevExitCode::NPF => {
1724 let exit_info = SevNpfInfo::from(vmsa.exit_info1());
1725 if exit_info.not_restartable() {
1726 return Err(dev.fatal_error(SnpRunVpError::VpNotRestartableError.into()));
1729 }
1730 }
1731 _ => {}
1732 }
1733 }
1734
1735 if vmsa.sev_features().alternate_injection() {
1736 let exit_int_info = SevEventInjectInfo::from(vmsa.exit_int_info());
1744
1745 if exit_int_info.valid() {
1746 let inject = match exit_int_info.interruption_type() {
1747 x86defs::snp::SEV_INTR_TYPE_EXCEPT => {
1748 if exit_int_info.vector() != 3 && exit_int_info.vector() != 4 {
1749 Some(exit_int_info)
1751 } else {
1752 None
1753 }
1754 }
1755 x86defs::snp::SEV_INTR_TYPE_SW => None,
1756 _ => Some(exit_int_info),
1757 };
1758
1759 if let Some(inject) = inject {
1760 vmsa.set_event_inject(inject);
1761 }
1762
1763 vmsa.set_exit_int_info(0);
1767 } else {
1768 }
1770 } else {
1771 assert!(
1772 cfg!(feature = "disable_secure_avic") || vmsa.sev_features().secure_avic(),
1773 "secure AVIC must be enabled"
1774 );
1775 }
1776
1777 if last_interrupt_ctrl.irq() && !vmsa.v_intr_cntrl().irq() {
1778 self.backing.general_stats[entered_from_vtl]
1779 .int_ack
1780 .increment();
1781 self.backing.cvm.lapics[entered_from_vtl]
1785 .lapic
1786 .acknowledge_interrupt(last_interrupt_ctrl.vector());
1787 }
1788
1789 vmsa.v_intr_cntrl_mut().set_irq(false);
1790
1791 if lazy_eoi && self.backing.cvm.hv[entered_from_vtl].clear_lazy_eoi() {
1793 self.backing.cvm.lapics[entered_from_vtl]
1794 .lapic
1795 .access(&mut SnpApicClient {
1796 partition: self.partition,
1797 vmsa,
1798 avic_page,
1799 dev,
1800 vmtime: &self.vmtime,
1801 vtl: entered_from_vtl,
1802 })
1803 .lazy_eoi();
1804 }
1805
1806 let mut vmsa = self.runner.vmsa_mut(entered_from_vtl);
1807 let sev_error_code = SevExitCode(vmsa.guest_error_code());
1808
1809 let stat = match sev_error_code {
1810 SevExitCode::CPUID => {
1811 self.handle_cpuid(entered_from_vtl);
1812 &mut self.backing.exit_stats[entered_from_vtl].cpuid
1813 }
1814
1815 SevExitCode::MSR => {
1816 let is_write = vmsa.exit_info1() & 1 != 0;
1817 let msr = vmsa.rcx() as u32;
1818 let is_fault = true;
1819 self.handle_msr_access(dev, entered_from_vtl, msr, is_write, is_fault);
1820
1821 if is_write {
1822 &mut self.backing.exit_stats[entered_from_vtl].msr_write
1823 } else {
1824 &mut self.backing.exit_stats[entered_from_vtl].msr_read
1825 }
1826 }
1827
1828 SevExitCode::IOIO => {
1829 let io_info =
1830 SevIoAccessInfo::from(self.runner.vmsa(entered_from_vtl).exit_info1() as u32);
1831
1832 let access_size = if io_info.access_size32() {
1833 4
1834 } else if io_info.access_size16() {
1835 2
1836 } else {
1837 1
1838 };
1839
1840 let port_access_protected = self.cvm_try_protect_io_port_access(
1841 entered_from_vtl,
1842 io_info.port(),
1843 io_info.read_access(),
1844 access_size,
1845 io_info.string_access(),
1846 io_info.rep_access(),
1847 );
1848
1849 let vmsa = self.runner.vmsa(entered_from_vtl);
1850 if !port_access_protected {
1851 if io_info.string_access() || io_info.rep_access() {
1852 let interruption_pending = vmsa.event_inject().valid()
1853 || SevEventInjectInfo::from(vmsa.exit_int_info()).valid();
1854
1855 self.emulate(dev, interruption_pending, entered_from_vtl, ())
1860 .await?;
1861 } else {
1862 let mut rax = vmsa.rax();
1863 emulate_io(
1864 self.inner.vp_info.base.vp_index,
1865 !io_info.read_access(),
1866 io_info.port(),
1867 &mut rax,
1868 access_size,
1869 dev,
1870 )
1871 .await;
1872
1873 let mut vmsa = self.runner.vmsa_mut(entered_from_vtl);
1874 vmsa.set_rax(rax);
1875 advance_to_next_instruction(&mut vmsa);
1876 }
1877 }
1878 &mut self.backing.exit_stats[entered_from_vtl].ioio
1879 }
1880
1881 SevExitCode::VMMCALL => {
1882 let is_64bit = self.long_mode(entered_from_vtl);
1883 let guest_memory = &self.partition.gm[entered_from_vtl];
1884 let handler = UhHypercallHandler {
1885 trusted: !self.cvm_partition().hide_isolation,
1886 vp: &mut *self,
1887 intercepted_vtl: entered_from_vtl,
1888 };
1889
1890 UhHypercallHandler::TRUSTED_DISPATCHER.dispatch(
1893 guest_memory,
1894 hv1_hypercall::X64RegisterIo::new(handler, is_64bit, true),
1895 );
1896 &mut self.backing.exit_stats[entered_from_vtl].vmmcall
1897 }
1898
1899 SevExitCode::SHUTDOWN => {
1900 return Err(VpHaltReason::TripleFault {
1901 vtl: entered_from_vtl.into(),
1902 });
1903 }
1904
1905 SevExitCode::WBINVD | SevExitCode::INVD => {
1906 advance_to_next_instruction(&mut vmsa);
1910 &mut self.backing.exit_stats[entered_from_vtl].invd
1911 }
1912
1913 SevExitCode::NPF if has_intercept => {
1914 let gpa = vmsa.exit_info2();
1933 let interruption_pending = vmsa.event_inject().valid()
1934 || SevEventInjectInfo::from(vmsa.exit_int_info()).valid();
1935 let exit_info = SevNpfInfo::from(vmsa.exit_info1());
1936 let exit_message = self.runner.exit_message();
1937 let real = match exit_message.header.typ {
1938 HvMessageType::HvMessageTypeExceptionIntercept => {
1939 let exception_message =
1940 exit_message.as_message::<hvdef::HvX64ExceptionInterceptMessage>();
1941
1942 exception_message.vector
1943 == x86defs::Exception::SEV_VMM_COMMUNICATION.0 as u16
1944 }
1945 HvMessageType::HvMessageTypeUnmappedGpa
1946 | HvMessageType::HvMessageTypeGpaIntercept
1947 | HvMessageType::HvMessageTypeUnacceptedGpa => {
1948 let gpa_message =
1949 exit_message.as_message::<hvdef::HvX64MemoryInterceptMessage>();
1950
1951 (gpa_message.guest_physical_address >> hvdef::HV_PAGE_SHIFT)
1953 == (gpa >> hvdef::HV_PAGE_SHIFT)
1954 }
1955 _ => false,
1956 };
1957
1958 if real {
1959 has_intercept = false;
1960 if self.check_mem_fault(entered_from_vtl, gpa, exit_info.is_write(), exit_info)
1961 {
1962 self.emulate(dev, interruption_pending, entered_from_vtl, ())
1963 .await?;
1964 }
1965 &mut self.backing.exit_stats[entered_from_vtl].npf
1966 } else {
1967 &mut self.backing.exit_stats[entered_from_vtl].npf_spurious
1968 }
1969 }
1970
1971 SevExitCode::NPF => &mut self.backing.exit_stats[entered_from_vtl].npf_no_intercept,
1972
1973 SevExitCode::HLT | SevExitCode::IDLE_HLT => {
1974 self.backing.cvm.lapics[entered_from_vtl].activity = MpState::Halted;
1975 vmsa.v_intr_cntrl_mut().set_intr_shadow(false);
1977 &mut self.backing.exit_stats[entered_from_vtl].hlt
1978 }
1979
1980 SevExitCode::INVALID_VMCB => {
1981 return Err(dev.fatal_error(InvalidVmcb.into()));
1982 }
1983
1984 SevExitCode::INVLPGB | SevExitCode::ILLEGAL_INVLPGB => {
1985 vmsa.set_event_inject(
1986 SevEventInjectInfo::new()
1987 .with_interruption_type(x86defs::snp::SEV_INTR_TYPE_EXCEPT)
1988 .with_vector(x86defs::Exception::INVALID_OPCODE.0)
1989 .with_valid(true),
1990 );
1991 &mut self.backing.exit_stats[entered_from_vtl].invlpgb
1992 }
1993
1994 SevExitCode::RDPMC => {
1995 let cr4 = vmsa.cr4();
1998 if ((vmsa.cpl() > 0) && (cr4 & x86defs::X64_CR4_PCE == 0))
1999 || (vmsa.rcx() as u32 >= 4)
2000 {
2001 vmsa.set_event_inject(
2002 SevEventInjectInfo::new()
2003 .with_interruption_type(x86defs::snp::SEV_INTR_TYPE_EXCEPT)
2004 .with_vector(x86defs::Exception::GENERAL_PROTECTION_FAULT.0)
2005 .with_deliver_error_code(true)
2006 .with_valid(true),
2007 );
2008 } else {
2009 vmsa.set_rax(0);
2010 vmsa.set_rdx(0);
2011 advance_to_next_instruction(&mut vmsa);
2012 }
2013 &mut self.backing.exit_stats[entered_from_vtl].rdpmc
2014 }
2015
2016 SevExitCode::VMGEXIT if has_intercept => {
2017 has_intercept = false;
2018 match self.runner.exit_message().header.typ {
2019 HvMessageType::HvMessageTypeX64SevVmgexitIntercept => {
2020 self.handle_vmgexit(dev, entered_from_vtl)
2021 .map_err(|e| dev.fatal_error(e.into()))?;
2022 }
2023 _ => has_intercept = true,
2024 }
2025 &mut self.backing.exit_stats[entered_from_vtl].vmgexit
2026 }
2027
2028 SevExitCode::NMI | SevExitCode::PAUSE | SevExitCode::SMI | SevExitCode::VMGEXIT => {
2029 &mut self.backing.exit_stats[entered_from_vtl].automatic_exit
2031 }
2032
2033 SevExitCode::BUSLOCK => {
2034 &mut self.backing.exit_stats[entered_from_vtl].bus_lock
2038 }
2039
2040 SevExitCode::VINTR => {
2041 unimplemented!("SevExitCode::VINTR");
2047 }
2048
2049 SevExitCode::INTR => {
2050 &mut self.backing.exit_stats[entered_from_vtl].intr
2053 }
2054
2055 SevExitCode::XSETBV => {
2056 self.handle_xsetbv(entered_from_vtl);
2057 &mut self.backing.exit_stats[entered_from_vtl].xsetbv
2058 }
2059
2060 SevExitCode::EXCP_DB => &mut self.backing.exit_stats[entered_from_vtl].excp_db,
2061
2062 SevExitCode::CR0_WRITE => {
2063 self.handle_crx_intercept(entered_from_vtl, HvX64RegisterName::Cr0);
2064 &mut self.backing.exit_stats[entered_from_vtl].secure_reg_write
2065 }
2066 SevExitCode::CR4_WRITE => {
2067 self.handle_crx_intercept(entered_from_vtl, HvX64RegisterName::Cr4);
2068 &mut self.backing.exit_stats[entered_from_vtl].secure_reg_write
2069 }
2070
2071 tr_exit_code @ (SevExitCode::GDTR_WRITE
2072 | SevExitCode::IDTR_WRITE
2073 | SevExitCode::LDTR_WRITE
2074 | SevExitCode::TR_WRITE) => {
2075 let reg = match tr_exit_code {
2076 SevExitCode::GDTR_WRITE => HvX64RegisterName::Gdtr,
2077 SevExitCode::IDTR_WRITE => HvX64RegisterName::Idtr,
2078 SevExitCode::LDTR_WRITE => HvX64RegisterName::Ldtr,
2079 SevExitCode::TR_WRITE => HvX64RegisterName::Tr,
2080 _ => unreachable!(),
2081 };
2082
2083 if !self.cvm_try_protect_secure_register_write(entered_from_vtl, reg, 0) {
2084 panic!("unexpected secure register");
2091 }
2092
2093 &mut self.backing.exit_stats[entered_from_vtl].secure_reg_write
2094 }
2095
2096 SevExitCode::AVIC_NOACCEL => {
2097 let no_accel_info = SevAvicNoAccelInfo::from(vmsa.exit_info1());
2098 tracing::debug!("AVIC no acceleration SEV exit: {no_accel_info:x?}");
2099
2100 if !matches!(
2101 no_accel_info.apic_register_number(),
2102 SevAvicRegisterNumber::APIC_ID
2103 | SevAvicRegisterNumber::VERSION
2104 | SevAvicRegisterNumber::TPR
2105 | SevAvicRegisterNumber::APR
2106 | SevAvicRegisterNumber::PPR
2107 | SevAvicRegisterNumber::EOI
2108 | SevAvicRegisterNumber::REMOTE_READ
2109 | SevAvicRegisterNumber::LDR
2110 | SevAvicRegisterNumber::DFR
2111 | SevAvicRegisterNumber::SPURIOUS
2112 | SevAvicRegisterNumber::ISR0
2113 | SevAvicRegisterNumber::ISR1
2114 | SevAvicRegisterNumber::ISR2
2115 | SevAvicRegisterNumber::ISR3
2116 | SevAvicRegisterNumber::ISR4
2117 | SevAvicRegisterNumber::ISR5
2118 | SevAvicRegisterNumber::ISR6
2119 | SevAvicRegisterNumber::ISR7
2120 | SevAvicRegisterNumber::TMR0
2121 | SevAvicRegisterNumber::TMR1
2122 | SevAvicRegisterNumber::TMR2
2123 | SevAvicRegisterNumber::TMR3
2124 | SevAvicRegisterNumber::TMR4
2125 | SevAvicRegisterNumber::TMR5
2126 | SevAvicRegisterNumber::TMR6
2127 | SevAvicRegisterNumber::TMR7
2128 | SevAvicRegisterNumber::IRR0
2129 | SevAvicRegisterNumber::IRR1
2130 | SevAvicRegisterNumber::IRR2
2131 | SevAvicRegisterNumber::IRR3
2132 | SevAvicRegisterNumber::IRR4
2133 | SevAvicRegisterNumber::IRR5
2134 | SevAvicRegisterNumber::IRR6
2135 | SevAvicRegisterNumber::IRR7
2136 | SevAvicRegisterNumber::ERROR
2137 | SevAvicRegisterNumber::ICR_LOW
2138 | SevAvicRegisterNumber::ICR_HIGH
2139 | SevAvicRegisterNumber::TIMER_LVT
2140 | SevAvicRegisterNumber::THERMAL_LVT
2141 | SevAvicRegisterNumber::PERFMON_LVT
2142 | SevAvicRegisterNumber::LINT0_LVT
2143 | SevAvicRegisterNumber::LINT1_LVT
2144 | SevAvicRegisterNumber::ERROR_LVT
2145 | SevAvicRegisterNumber::INITIAL_COUNT
2146 | SevAvicRegisterNumber::CURRENT_COUNT
2147 | SevAvicRegisterNumber::DIVIDER
2148 | SevAvicRegisterNumber::SELF_IPI
2149 ) {
2150 tracelimit::error_ratelimited!(
2151 register_number = no_accel_info.apic_register_number().0,
2152 "unexpected AVIC register number"
2153 );
2154 }
2155
2156 let is_write = no_accel_info.write_access();
2160 let is_fault = matches!(
2161 no_accel_info.apic_register_number(),
2162 SevAvicRegisterNumber::VERSION
2163 | SevAvicRegisterNumber::APR
2164 | SevAvicRegisterNumber::PPR
2165 | SevAvicRegisterNumber::ISR0
2166 | SevAvicRegisterNumber::ISR1
2167 | SevAvicRegisterNumber::ISR2
2168 | SevAvicRegisterNumber::ISR3
2169 | SevAvicRegisterNumber::ISR4
2170 | SevAvicRegisterNumber::ISR5
2171 | SevAvicRegisterNumber::ISR6
2172 | SevAvicRegisterNumber::ISR7
2173 | SevAvicRegisterNumber::TMR0
2174 | SevAvicRegisterNumber::TMR1
2175 | SevAvicRegisterNumber::TMR2
2176 | SevAvicRegisterNumber::TMR3
2177 | SevAvicRegisterNumber::TMR4
2178 | SevAvicRegisterNumber::TMR5
2179 | SevAvicRegisterNumber::TMR6
2180 | SevAvicRegisterNumber::TMR7
2181 | SevAvicRegisterNumber::IRR0
2182 | SevAvicRegisterNumber::IRR1
2183 | SevAvicRegisterNumber::IRR2
2184 | SevAvicRegisterNumber::IRR3
2185 | SevAvicRegisterNumber::IRR4
2186 | SevAvicRegisterNumber::IRR5
2187 | SevAvicRegisterNumber::IRR6
2188 | SevAvicRegisterNumber::IRR7
2189 | SevAvicRegisterNumber::CURRENT_COUNT
2190 );
2191 let msr = X2APIC_MSR_BASE + no_accel_info.apic_register_number().0;
2192 self.handle_msr_access(dev, entered_from_vtl, msr, is_write, is_fault);
2193
2194 &mut self.backing.exit_stats[entered_from_vtl].avic_no_accel
2195 }
2196
2197 SevExitCode::AVIC_INCOMPLETE_IPI => {
2198 let ipi_info1 = SevAvicIncompleteIpiInfo1::from(vmsa.exit_info1());
2199 let ipi_info2 = SevAvicIncompleteIpiInfo2::from(vmsa.exit_info2());
2200 let icr = x86defs::apic::Icr::from_bits(vmsa.exit_info1());
2201
2202 tracing::debug!(
2203 "AVIC incomplete IPI SEV exit: {ipi_info1:x?} {ipi_info2:x?}, {icr:x?}"
2204 );
2205
2206 let is_fault = false;
2209 let is_write = true;
2210 let msr = X2APIC_MSR_BASE + x86defs::apic::ApicRegister::ICR0.0 as u32;
2211
2212 self.handle_msr_access(dev, entered_from_vtl, msr, is_write, is_fault);
2216
2217 &mut self.backing.exit_stats[entered_from_vtl].avic_incomplete_ipi
2218 }
2219
2220 _ => {
2221 tracing::error!(
2222 CVM_CONFIDENTIAL,
2223 "SEV exit code {sev_error_code:x?} sev features {:x?} v_intr_control {:x?} event inject {:x?} \
2224 vmpl {:x?} cpl {:x?} exit_info1 {:x?} exit_info2 {:x?} exit_int_info {:x?} virtual_tom {:x?} \
2225 efer {:x?} cr4 {:x?} cr3 {:x?} cr0 {:x?} rflag {:x?} rip {:x?} next rip {:x?}",
2226 vmsa.sev_features(),
2227 vmsa.v_intr_cntrl(),
2228 vmsa.event_inject(),
2229 vmsa.vmpl(),
2230 vmsa.cpl(),
2231 vmsa.exit_info1(),
2232 vmsa.exit_info2(),
2233 exit_int_info_trace,
2234 vmsa.virtual_tom(),
2235 vmsa.efer(),
2236 vmsa.cr4(),
2237 vmsa.cr3(),
2238 vmsa.cr0(),
2239 vmsa.rflags(),
2240 vmsa.rip(),
2241 vmsa.next_rip(),
2242 );
2243 panic!("Received unexpected SEV exit code {sev_error_code:x?}");
2244 }
2245 };
2246 stat.increment();
2247
2248 if cfg!(feature = "gdb") && sev_error_code == SevExitCode::EXCP_DB {
2250 return self.handle_debug_exception(dev, entered_from_vtl);
2251 }
2252
2253 if has_intercept {
2257 self.backing.general_stats[entered_from_vtl]
2258 .synth_int
2259 .increment();
2260 match self.runner.exit_message().header.typ {
2261 HvMessageType::HvMessageTypeSynicSintDeliverable => {
2262 self.handle_synic_deliverable_exit();
2263 }
2264 HvMessageType::HvMessageTypeX64Halt
2265 | HvMessageType::HvMessageTypeExceptionIntercept => {
2266 }
2269 message_type => {
2270 tracelimit::error_ratelimited!(
2271 CVM_ALLOWED,
2272 ?message_type,
2273 "unknown synthetic exit"
2274 );
2275 }
2276 }
2277 }
2278
2279 self.runner
2288 .vmsa_mut(entered_from_vtl)
2289 .set_guest_error_code(SevExitCode::INTR.0);
2290 Ok(())
2291 }
2292
2293 fn long_mode(&self, vtl: GuestVtl) -> bool {
2294 let vmsa = self.runner.vmsa(vtl);
2295 vmsa.cr0() & x86defs::X64_CR0_PE != 0 && vmsa.efer() & x86defs::X64_EFER_LMA != 0
2296 }
2297
2298 fn handle_cpuid(&mut self, vtl: GuestVtl) {
2299 let vmsa = self.runner.vmsa(vtl);
2300 let leaf = vmsa.rax() as u32;
2301 let subleaf = vmsa.rcx() as u32;
2302 let [mut eax, mut ebx, mut ecx, mut edx] = self.cvm_cpuid_result(vtl, leaf, subleaf);
2303
2304 match CpuidFunction(leaf) {
2312 CpuidFunction::ProcessorTopologyDefinition => {
2313 let apic_id = self.inner.vp_info.apic_id;
2314 let vps_per_socket = self.cvm_partition().vps_per_socket;
2315 eax = x86defs::cpuid::ProcessorTopologyDefinitionEax::from(eax)
2316 .with_extended_apic_id(apic_id)
2317 .into();
2318
2319 let topology_ebx = x86defs::cpuid::ProcessorTopologyDefinitionEbx::from(ebx);
2320 let mut new_unit_id = apic_id & (vps_per_socket - 1);
2321
2322 if topology_ebx.threads_per_compute_unit() > 0 {
2323 new_unit_id /= 2;
2324 }
2325
2326 ebx = topology_ebx.with_compute_unit_id(new_unit_id as u8).into();
2327
2328 let amd_nodes_per_socket = 1u32;
2331
2332 let node_id = apic_id
2333 >> (vps_per_socket
2334 .trailing_zeros()
2335 .saturating_sub(amd_nodes_per_socket.trailing_zeros()));
2336 let nodes_per_processor = amd_nodes_per_socket - 1;
2338
2339 ecx = x86defs::cpuid::ProcessorTopologyDefinitionEcx::from(ecx)
2340 .with_node_id(node_id as u8)
2341 .with_nodes_per_processor(nodes_per_processor as u8)
2342 .into();
2343 }
2344 CpuidFunction::ExtendedSevFeatures => {
2345 eax = 0;
2349 ebx = 0;
2350 ecx = 0;
2351 edx = 0;
2352 }
2353 _ => {}
2354 }
2355
2356 let mut vmsa = self.runner.vmsa_mut(vtl);
2357 vmsa.set_rax(eax.into());
2358 vmsa.set_rbx(ebx.into());
2359 vmsa.set_rcx(ecx.into());
2360 vmsa.set_rdx(edx.into());
2361 advance_to_next_instruction(&mut vmsa);
2362 }
2363}
2364
2365impl<T: CpuIo> X86EmulatorSupport for UhEmulationState<'_, '_, T, SnpBacked> {
2366 fn flush(&mut self) {
2367 }
2369
2370 fn vp_index(&self) -> VpIndex {
2371 self.vp.vp_index()
2372 }
2373
2374 fn vendor(&self) -> x86defs::cpuid::Vendor {
2375 self.vp.partition.caps.vendor
2376 }
2377
2378 fn gp(&mut self, reg: x86emu::Gp) -> u64 {
2379 let vmsa = self.vp.runner.vmsa(self.vtl);
2380 match reg {
2381 x86emu::Gp::RAX => vmsa.rax(),
2382 x86emu::Gp::RCX => vmsa.rcx(),
2383 x86emu::Gp::RDX => vmsa.rdx(),
2384 x86emu::Gp::RBX => vmsa.rbx(),
2385 x86emu::Gp::RSP => vmsa.rsp(),
2386 x86emu::Gp::RBP => vmsa.rbp(),
2387 x86emu::Gp::RSI => vmsa.rsi(),
2388 x86emu::Gp::RDI => vmsa.rdi(),
2389 x86emu::Gp::R8 => vmsa.r8(),
2390 x86emu::Gp::R9 => vmsa.r9(),
2391 x86emu::Gp::R10 => vmsa.r10(),
2392 x86emu::Gp::R11 => vmsa.r11(),
2393 x86emu::Gp::R12 => vmsa.r12(),
2394 x86emu::Gp::R13 => vmsa.r13(),
2395 x86emu::Gp::R14 => vmsa.r14(),
2396 x86emu::Gp::R15 => vmsa.r15(),
2397 }
2398 }
2399
2400 fn set_gp(&mut self, reg: x86emu::Gp, v: u64) {
2401 let mut vmsa = self.vp.runner.vmsa_mut(self.vtl);
2402 match reg {
2403 x86emu::Gp::RAX => vmsa.set_rax(v),
2404 x86emu::Gp::RCX => vmsa.set_rcx(v),
2405 x86emu::Gp::RDX => vmsa.set_rdx(v),
2406 x86emu::Gp::RBX => vmsa.set_rbx(v),
2407 x86emu::Gp::RSP => vmsa.set_rsp(v),
2408 x86emu::Gp::RBP => vmsa.set_rbp(v),
2409 x86emu::Gp::RSI => vmsa.set_rsi(v),
2410 x86emu::Gp::RDI => vmsa.set_rdi(v),
2411 x86emu::Gp::R8 => vmsa.set_r8(v),
2412 x86emu::Gp::R9 => vmsa.set_r9(v),
2413 x86emu::Gp::R10 => vmsa.set_r10(v),
2414 x86emu::Gp::R11 => vmsa.set_r11(v),
2415 x86emu::Gp::R12 => vmsa.set_r12(v),
2416 x86emu::Gp::R13 => vmsa.set_r13(v),
2417 x86emu::Gp::R14 => vmsa.set_r14(v),
2418 x86emu::Gp::R15 => vmsa.set_r15(v),
2419 };
2420 }
2421
2422 fn xmm(&mut self, index: usize) -> u128 {
2423 self.vp.runner.vmsa_mut(self.vtl).xmm_registers(index)
2424 }
2425
2426 fn set_xmm(&mut self, index: usize, v: u128) {
2427 self.vp
2428 .runner
2429 .vmsa_mut(self.vtl)
2430 .set_xmm_registers(index, v);
2431 }
2432
2433 fn rip(&mut self) -> u64 {
2434 let vmsa = self.vp.runner.vmsa(self.vtl);
2435 vmsa.rip()
2436 }
2437
2438 fn set_rip(&mut self, v: u64) {
2439 let mut vmsa = self.vp.runner.vmsa_mut(self.vtl);
2440 vmsa.set_rip(v);
2441 }
2442
2443 fn segment(&mut self, index: x86emu::Segment) -> x86defs::SegmentRegister {
2444 let vmsa = self.vp.runner.vmsa(self.vtl);
2445 match index {
2446 x86emu::Segment::ES => virt_seg_from_snp(vmsa.es()),
2447 x86emu::Segment::CS => virt_seg_from_snp(vmsa.cs()),
2448 x86emu::Segment::SS => virt_seg_from_snp(vmsa.ss()),
2449 x86emu::Segment::DS => virt_seg_from_snp(vmsa.ds()),
2450 x86emu::Segment::FS => virt_seg_from_snp(vmsa.fs()),
2451 x86emu::Segment::GS => virt_seg_from_snp(vmsa.gs()),
2452 }
2453 .into()
2454 }
2455
2456 fn efer(&mut self) -> u64 {
2457 let vmsa = self.vp.runner.vmsa(self.vtl);
2458 vmsa.efer()
2459 }
2460
2461 fn cr0(&mut self) -> u64 {
2462 let vmsa = self.vp.runner.vmsa(self.vtl);
2463 vmsa.cr0()
2464 }
2465
2466 fn rflags(&mut self) -> RFlags {
2467 let vmsa = self.vp.runner.vmsa(self.vtl);
2468 vmsa.rflags().into()
2469 }
2470
2471 fn set_rflags(&mut self, v: RFlags) {
2472 let mut vmsa = self.vp.runner.vmsa_mut(self.vtl);
2473 vmsa.set_rflags(v.into());
2474 }
2475
2476 fn instruction_bytes(&self) -> &[u8] {
2477 &[]
2478 }
2479
2480 fn physical_address(&self) -> Option<u64> {
2481 Some(self.vp.runner.vmsa(self.vtl).exit_info2())
2482 }
2483
2484 fn initial_gva_translation(
2485 &mut self,
2486 ) -> Option<virt_support_x86emu::emulate::InitialTranslation> {
2487 None
2488 }
2489
2490 fn interruption_pending(&self) -> bool {
2491 self.interruption_pending
2492 }
2493
2494 fn check_vtl_access(
2495 &mut self,
2496 _gpa: u64,
2497 _mode: virt_support_x86emu::emulate::TranslateMode,
2498 ) -> Result<(), virt_support_x86emu::emulate::EmuCheckVtlAccessError> {
2499 Ok(())
2501 }
2502
2503 fn translate_gva(
2504 &mut self,
2505 gva: u64,
2506 mode: virt_support_x86emu::emulate::TranslateMode,
2507 ) -> Result<
2508 virt_support_x86emu::emulate::EmuTranslateResult,
2509 virt_support_x86emu::emulate::EmuTranslateError,
2510 > {
2511 emulate_translate_gva(self, gva, mode)
2512 }
2513
2514 fn inject_pending_event(&mut self, event_info: hvdef::HvX64PendingEvent) {
2515 assert!(event_info.reg_0.event_pending());
2516 assert_eq!(
2517 event_info.reg_0.event_type(),
2518 hvdef::HV_X64_PENDING_EVENT_EXCEPTION
2519 );
2520
2521 let exception = HvX64PendingExceptionEvent::from(event_info.reg_0.into_bits());
2522 assert!(!self.interruption_pending);
2523
2524 SnpBacked::set_pending_exception(self.vp, self.vtl, exception);
2527 }
2528
2529 fn is_gpa_mapped(&self, gpa: u64, write: bool) -> bool {
2530 let vtom = self.vp.partition.caps.vtom.unwrap();
2533 debug_assert!(vtom == 0 || vtom.is_power_of_two());
2534 self.vp.partition.is_gpa_mapped(gpa & !vtom, write)
2535 }
2536
2537 fn lapic_base_address(&self) -> Option<u64> {
2538 self.vp.backing.cvm.lapics[self.vtl].lapic.base_address()
2539 }
2540
2541 fn lapic_read(&mut self, address: u64, data: &mut [u8]) {
2542 let vtl = self.vtl;
2543 let (avic_page, vmsa) = self.vp.runner.secure_avic_page_vmsa_mut(vtl);
2544 self.vp.backing.cvm.lapics[vtl]
2545 .lapic
2546 .access(&mut SnpApicClient {
2547 partition: self.vp.partition,
2548 vmsa,
2549 avic_page,
2550 dev: self.devices,
2551 vmtime: &self.vp.vmtime,
2552 vtl,
2553 })
2554 .mmio_read(address, data);
2555 }
2556
2557 fn lapic_write(&mut self, address: u64, data: &[u8]) {
2558 let vtl = self.vtl;
2559 let (avic_page, vmsa) = self.vp.runner.secure_avic_page_vmsa_mut(vtl);
2560 self.vp.backing.cvm.lapics[vtl]
2561 .lapic
2562 .access(&mut SnpApicClient {
2563 partition: self.vp.partition,
2564 vmsa,
2565 avic_page,
2566 dev: self.devices,
2567 vmtime: &self.vp.vmtime,
2568 vtl,
2569 })
2570 .mmio_write(address, data);
2571 }
2572
2573 fn monitor_support(&self) -> Option<&dyn EmulatorMonitorSupport> {
2574 Some(self)
2575 }
2576}
2577
2578impl hv1_hypercall::X64RegisterState for UhHypercallHandler<'_, '_, SnpBacked> {
2579 fn rip(&mut self) -> u64 {
2580 self.vp.runner.vmsa(self.intercepted_vtl).rip()
2581 }
2582
2583 fn set_rip(&mut self, rip: u64) {
2584 self.vp.runner.vmsa_mut(self.intercepted_vtl).set_rip(rip);
2585 }
2586
2587 fn gp(&mut self, n: hv1_hypercall::X64HypercallRegister) -> u64 {
2588 let vmsa = self.vp.runner.vmsa(self.intercepted_vtl);
2589 match n {
2590 hv1_hypercall::X64HypercallRegister::Rax => vmsa.rax(),
2591 hv1_hypercall::X64HypercallRegister::Rcx => vmsa.rcx(),
2592 hv1_hypercall::X64HypercallRegister::Rdx => vmsa.rdx(),
2593 hv1_hypercall::X64HypercallRegister::Rbx => vmsa.rbx(),
2594 hv1_hypercall::X64HypercallRegister::Rsi => vmsa.rsi(),
2595 hv1_hypercall::X64HypercallRegister::Rdi => vmsa.rdi(),
2596 hv1_hypercall::X64HypercallRegister::R8 => vmsa.r8(),
2597 }
2598 }
2599
2600 fn set_gp(&mut self, n: hv1_hypercall::X64HypercallRegister, value: u64) {
2601 let mut vmsa = self.vp.runner.vmsa_mut(self.intercepted_vtl);
2602 match n {
2603 hv1_hypercall::X64HypercallRegister::Rax => vmsa.set_rax(value),
2604 hv1_hypercall::X64HypercallRegister::Rcx => vmsa.set_rcx(value),
2605 hv1_hypercall::X64HypercallRegister::Rdx => vmsa.set_rdx(value),
2606 hv1_hypercall::X64HypercallRegister::Rbx => vmsa.set_rbx(value),
2607 hv1_hypercall::X64HypercallRegister::Rsi => vmsa.set_rsi(value),
2608 hv1_hypercall::X64HypercallRegister::Rdi => vmsa.set_rdi(value),
2609 hv1_hypercall::X64HypercallRegister::R8 => vmsa.set_r8(value),
2610 }
2611 }
2612
2613 fn xmm(&mut self, n: usize) -> u128 {
2614 self.vp.runner.vmsa(self.intercepted_vtl).xmm_registers(n)
2615 }
2616
2617 fn set_xmm(&mut self, n: usize, value: u128) {
2618 self.vp
2619 .runner
2620 .vmsa_mut(self.intercepted_vtl)
2621 .set_xmm_registers(n, value);
2622 }
2623}
2624
2625impl AccessVpState for UhVpStateAccess<'_, '_, SnpBacked> {
2626 type Error = vp_state::Error;
2627
2628 fn caps(&self) -> &virt::x86::X86PartitionCapabilities {
2629 &self.vp.partition.caps
2630 }
2631
2632 fn commit(&mut self) -> Result<(), Self::Error> {
2633 Ok(())
2634 }
2635
2636 fn registers(&mut self) -> Result<vp::Registers, Self::Error> {
2637 let vmsa = self.vp.runner.vmsa(self.vtl);
2638
2639 Ok(vp::Registers {
2640 rax: vmsa.rax(),
2641 rcx: vmsa.rcx(),
2642 rdx: vmsa.rdx(),
2643 rbx: vmsa.rbx(),
2644 rsp: vmsa.rsp(),
2645 rbp: vmsa.rbp(),
2646 rsi: vmsa.rsi(),
2647 rdi: vmsa.rdi(),
2648 r8: vmsa.r8(),
2649 r9: vmsa.r9(),
2650 r10: vmsa.r10(),
2651 r11: vmsa.r11(),
2652 r12: vmsa.r12(),
2653 r13: vmsa.r13(),
2654 r14: vmsa.r14(),
2655 r15: vmsa.r15(),
2656 rip: vmsa.rip(),
2657 rflags: vmsa.rflags(),
2658 cs: virt_seg_from_snp(vmsa.cs()),
2659 ds: virt_seg_from_snp(vmsa.ds()),
2660 es: virt_seg_from_snp(vmsa.es()),
2661 fs: virt_seg_from_snp(vmsa.fs()),
2662 gs: virt_seg_from_snp(vmsa.gs()),
2663 ss: virt_seg_from_snp(vmsa.ss()),
2664 tr: virt_seg_from_snp(vmsa.tr()),
2665 ldtr: virt_seg_from_snp(vmsa.ldtr()),
2666 gdtr: virt_table_from_snp(vmsa.gdtr()),
2667 idtr: virt_table_from_snp(vmsa.idtr()),
2668 cr0: vmsa.cr0(),
2669 cr2: vmsa.cr2(),
2670 cr3: vmsa.cr3(),
2671 cr4: vmsa.cr4(),
2672 cr8: vmsa.v_intr_cntrl().tpr().into(),
2673 efer: vmsa.efer(),
2674 })
2675 }
2676
2677 fn set_registers(&mut self, value: &vp::Registers) -> Result<(), Self::Error> {
2678 let mut vmsa = self.vp.runner.vmsa_mut(self.vtl);
2679
2680 let vp::Registers {
2681 rax,
2682 rcx,
2683 rdx,
2684 rbx,
2685 rsp,
2686 rbp,
2687 rsi,
2688 rdi,
2689 r8,
2690 r9,
2691 r10,
2692 r11,
2693 r12,
2694 r13,
2695 r14,
2696 r15,
2697 rip,
2698 rflags,
2699 cs,
2700 ds,
2701 es,
2702 fs,
2703 gs,
2704 ss,
2705 tr,
2706 ldtr,
2707 gdtr,
2708 idtr,
2709 cr0,
2710 cr2,
2711 cr3,
2712 cr4,
2713 cr8,
2714 efer,
2715 } = *value;
2716 vmsa.set_rax(rax);
2717 vmsa.set_rcx(rcx);
2718 vmsa.set_rdx(rdx);
2719 vmsa.set_rbx(rbx);
2720 vmsa.set_rsp(rsp);
2721 vmsa.set_rbp(rbp);
2722 vmsa.set_rsi(rsi);
2723 vmsa.set_rdi(rdi);
2724 vmsa.set_r8(r8);
2725 vmsa.set_r9(r9);
2726 vmsa.set_r10(r10);
2727 vmsa.set_r11(r11);
2728 vmsa.set_r12(r12);
2729 vmsa.set_r13(r13);
2730 vmsa.set_r14(r14);
2731 vmsa.set_r15(r15);
2732 vmsa.set_rip(rip);
2733 vmsa.set_rflags(rflags);
2734 vmsa.set_cs(virt_seg_to_snp(cs));
2735 vmsa.set_ds(virt_seg_to_snp(ds));
2736 vmsa.set_es(virt_seg_to_snp(es));
2737 vmsa.set_fs(virt_seg_to_snp(fs));
2738 vmsa.set_gs(virt_seg_to_snp(gs));
2739 vmsa.set_ss(virt_seg_to_snp(ss));
2740 vmsa.set_tr(virt_seg_to_snp(tr));
2741 vmsa.set_ldtr(virt_seg_to_snp(ldtr));
2742 vmsa.set_gdtr(virt_table_to_snp(gdtr));
2743 vmsa.set_idtr(virt_table_to_snp(idtr));
2744 vmsa.set_cr0(cr0);
2745 vmsa.set_cr2(cr2);
2746 vmsa.set_cr3(cr3);
2747 vmsa.set_cr4(cr4);
2748 vmsa.v_intr_cntrl_mut().set_tpr(cr8 as u8);
2749 vmsa.set_efer(SnpBacked::calculate_efer(efer, cr0));
2750 Ok(())
2751 }
2752
2753 fn activity(&mut self) -> Result<vp::Activity, Self::Error> {
2754 let lapic = &self.vp.backing.cvm.lapics[self.vtl];
2755
2756 Ok(vp::Activity {
2757 mp_state: lapic.activity,
2758 nmi_pending: lapic.nmi_pending,
2759 nmi_masked: false, interrupt_shadow: false, pending_event: None, pending_interruption: None, })
2764 }
2765
2766 fn set_activity(&mut self, value: &vp::Activity) -> Result<(), Self::Error> {
2767 let &vp::Activity {
2768 mp_state,
2769 nmi_pending,
2770 nmi_masked: _, interrupt_shadow: _, pending_event: _, pending_interruption: _, } = value;
2775 let lapic = &mut self.vp.backing.cvm.lapics[self.vtl];
2776 lapic.activity = mp_state;
2777 lapic.nmi_pending = nmi_pending;
2778
2779 Ok(())
2780 }
2781
2782 fn xsave(&mut self) -> Result<vp::Xsave, Self::Error> {
2783 Err(vp_state::Error::Unimplemented("xsave"))
2784 }
2785
2786 fn set_xsave(&mut self, _value: &vp::Xsave) -> Result<(), Self::Error> {
2787 Err(vp_state::Error::Unimplemented("xsave"))
2788 }
2789
2790 fn apic(&mut self) -> Result<vp::Apic, Self::Error> {
2791 self.vp.access_apic_without_offload(self.vtl, |vp| {
2792 Ok(vp.backing.cvm.lapics[self.vtl].lapic.save())
2793 })
2794 }
2795
2796 fn set_apic(&mut self, value: &vp::Apic) -> Result<(), Self::Error> {
2797 self.vp.access_apic_without_offload(self.vtl, |vp| {
2798 vp.backing.cvm.lapics[self.vtl]
2799 .lapic
2800 .restore(value)
2801 .map_err(vp_state::Error::InvalidApicBase)?;
2802
2803 Ok(())
2804 })
2805 }
2806
2807 fn xcr(&mut self) -> Result<vp::Xcr0, Self::Error> {
2808 let vmsa = self.vp.runner.vmsa(self.vtl);
2809 Ok(vp::Xcr0 { value: vmsa.xcr0() })
2810 }
2811
2812 fn set_xcr(&mut self, value: &vp::Xcr0) -> Result<(), Self::Error> {
2813 let vp::Xcr0 { value } = *value;
2814 self.vp.runner.vmsa_mut(self.vtl).set_xcr0(value);
2815 Ok(())
2816 }
2817
2818 fn xss(&mut self) -> Result<vp::Xss, Self::Error> {
2819 let vmsa = self.vp.runner.vmsa(self.vtl);
2820 Ok(vp::Xss { value: vmsa.xss() })
2821 }
2822
2823 fn set_xss(&mut self, value: &vp::Xss) -> Result<(), Self::Error> {
2824 let vp::Xss { value } = *value;
2825 self.vp.runner.vmsa_mut(self.vtl).set_xss(value);
2826 Ok(())
2827 }
2828
2829 fn mtrrs(&mut self) -> Result<vp::Mtrrs, Self::Error> {
2830 Ok(vp::Mtrrs {
2831 msr_mtrr_def_type: 0,
2832 fixed: [0; 11],
2833 variable: [0; 16],
2834 })
2835 }
2836
2837 fn set_mtrrs(&mut self, _value: &vp::Mtrrs) -> Result<(), Self::Error> {
2838 Ok(())
2839 }
2840
2841 fn pat(&mut self) -> Result<vp::Pat, Self::Error> {
2842 let vmsa = self.vp.runner.vmsa(self.vtl);
2843 Ok(vp::Pat { value: vmsa.pat() })
2844 }
2845
2846 fn set_pat(&mut self, value: &vp::Pat) -> Result<(), Self::Error> {
2847 let vp::Pat { value } = *value;
2848 self.vp.runner.vmsa_mut(self.vtl).set_pat(value);
2849 Ok(())
2850 }
2851
2852 fn virtual_msrs(&mut self) -> Result<vp::VirtualMsrs, Self::Error> {
2853 let vmsa = self.vp.runner.vmsa(self.vtl);
2854
2855 Ok(vp::VirtualMsrs {
2856 kernel_gs_base: vmsa.kernel_gs_base(),
2857 sysenter_cs: vmsa.sysenter_cs(),
2858 sysenter_eip: vmsa.sysenter_eip(),
2859 sysenter_esp: vmsa.sysenter_esp(),
2860 star: vmsa.star(),
2861 lstar: vmsa.lstar(),
2862 cstar: vmsa.cstar(),
2863 sfmask: vmsa.sfmask(),
2864 })
2865 }
2866
2867 fn set_virtual_msrs(&mut self, value: &vp::VirtualMsrs) -> Result<(), Self::Error> {
2868 let mut vmsa = self.vp.runner.vmsa_mut(self.vtl);
2869 let vp::VirtualMsrs {
2870 kernel_gs_base,
2871 sysenter_cs,
2872 sysenter_eip,
2873 sysenter_esp,
2874 star,
2875 lstar,
2876 cstar,
2877 sfmask,
2878 } = *value;
2879 vmsa.set_kernel_gs_base(kernel_gs_base);
2880 vmsa.set_sysenter_cs(sysenter_cs);
2881 vmsa.set_sysenter_eip(sysenter_eip);
2882 vmsa.set_sysenter_esp(sysenter_esp);
2883 vmsa.set_star(star);
2884 vmsa.set_lstar(lstar);
2885 vmsa.set_cstar(cstar);
2886 vmsa.set_sfmask(sfmask);
2887
2888 Ok(())
2889 }
2890
2891 fn debug_regs(&mut self) -> Result<vp::DebugRegisters, Self::Error> {
2892 let vmsa = self.vp.runner.vmsa(self.vtl);
2893 Ok(vp::DebugRegisters {
2894 dr0: vmsa.dr0(),
2895 dr1: vmsa.dr1(),
2896 dr2: vmsa.dr2(),
2897 dr3: vmsa.dr3(),
2898 dr6: vmsa.dr6(),
2899 dr7: vmsa.dr7(),
2900 })
2901 }
2902
2903 fn set_debug_regs(&mut self, value: &vp::DebugRegisters) -> Result<(), Self::Error> {
2904 let mut vmsa = self.vp.runner.vmsa_mut(self.vtl);
2905 let vp::DebugRegisters {
2906 dr0,
2907 dr1,
2908 dr2,
2909 dr3,
2910 dr6,
2911 dr7,
2912 } = *value;
2913 vmsa.set_dr0(dr0);
2914 vmsa.set_dr1(dr1);
2915 vmsa.set_dr2(dr2);
2916 vmsa.set_dr3(dr3);
2917 vmsa.set_dr6(dr6);
2918 vmsa.set_dr7(dr7);
2919 Ok(())
2920 }
2921
2922 fn tsc(&mut self) -> Result<vp::Tsc, Self::Error> {
2923 Err(vp_state::Error::Unimplemented("tsc"))
2924 }
2925
2926 fn set_tsc(&mut self, _value: &vp::Tsc) -> Result<(), Self::Error> {
2927 Err(vp_state::Error::Unimplemented("tsc"))
2928 }
2929
2930 fn tsc_aux(&mut self) -> Result<vp::TscAux, Self::Error> {
2931 let vmsa = self.vp.runner.vmsa(self.vtl);
2932 Ok(vp::TscAux {
2933 value: vmsa.tsc_aux() as u64,
2934 })
2935 }
2936
2937 fn set_tsc_aux(&mut self, value: &vp::TscAux) -> Result<(), Self::Error> {
2938 let vp::TscAux { value } = *value;
2939 self.vp.runner.vmsa_mut(self.vtl).set_tsc_aux(value as u32);
2940 Ok(())
2941 }
2942
2943 fn cet(&mut self) -> Result<vp::Cet, Self::Error> {
2944 let vmsa = self.vp.runner.vmsa(self.vtl);
2945 Ok(vp::Cet { scet: vmsa.s_cet() })
2946 }
2947
2948 fn set_cet(&mut self, value: &vp::Cet) -> Result<(), Self::Error> {
2949 let vp::Cet { scet } = *value;
2950 self.vp.runner.vmsa_mut(self.vtl).set_s_cet(scet);
2951 Ok(())
2952 }
2953
2954 fn cet_ss(&mut self) -> Result<vp::CetSs, Self::Error> {
2955 let vmsa = self.vp.runner.vmsa(self.vtl);
2956 Ok(vp::CetSs {
2957 ssp: vmsa.ssp(),
2958 interrupt_ssp_table_addr: vmsa.interrupt_ssp_table_addr(),
2959 })
2960 }
2961
2962 fn set_cet_ss(&mut self, value: &vp::CetSs) -> Result<(), Self::Error> {
2963 let mut vmsa = self.vp.runner.vmsa_mut(self.vtl);
2964 let vp::CetSs {
2965 ssp,
2966 interrupt_ssp_table_addr,
2967 } = *value;
2968 vmsa.set_ssp(ssp);
2969 vmsa.set_interrupt_ssp_table_addr(interrupt_ssp_table_addr);
2970 Ok(())
2971 }
2972
2973 fn synic_msrs(&mut self) -> Result<vp::SyntheticMsrs, Self::Error> {
2974 Err(vp_state::Error::Unimplemented("synic_msrs"))
2975 }
2976
2977 fn set_synic_msrs(&mut self, _value: &vp::SyntheticMsrs) -> Result<(), Self::Error> {
2978 Err(vp_state::Error::Unimplemented("synic_msrs"))
2979 }
2980
2981 fn synic_message_page(&mut self) -> Result<vp::SynicMessagePage, Self::Error> {
2982 Err(vp_state::Error::Unimplemented("synic_message_page"))
2983 }
2984
2985 fn set_synic_message_page(&mut self, _value: &vp::SynicMessagePage) -> Result<(), Self::Error> {
2986 Err(vp_state::Error::Unimplemented("synic_message_page"))
2987 }
2988
2989 fn synic_event_flags_page(&mut self) -> Result<vp::SynicEventFlagsPage, Self::Error> {
2990 Err(vp_state::Error::Unimplemented("synic_event_flags_page"))
2991 }
2992
2993 fn set_synic_event_flags_page(
2994 &mut self,
2995 _value: &vp::SynicEventFlagsPage,
2996 ) -> Result<(), Self::Error> {
2997 Err(vp_state::Error::Unimplemented("synic_event_flags_page"))
2998 }
2999
3000 fn synic_message_queues(&mut self) -> Result<vp::SynicMessageQueues, Self::Error> {
3001 Err(vp_state::Error::Unimplemented("synic_message_queues"))
3002 }
3003
3004 fn set_synic_message_queues(
3005 &mut self,
3006 _value: &vp::SynicMessageQueues,
3007 ) -> Result<(), Self::Error> {
3008 Err(vp_state::Error::Unimplemented("synic_message_queues"))
3009 }
3010
3011 fn synic_timers(&mut self) -> Result<vp::SynicTimers, Self::Error> {
3012 Err(vp_state::Error::Unimplemented("synic_timers"))
3013 }
3014
3015 fn set_synic_timers(&mut self, _value: &vp::SynicTimers) -> Result<(), Self::Error> {
3016 Err(vp_state::Error::Unimplemented("synic_timers"))
3017 }
3018
3019 fn nested_state(&mut self) -> Result<vp::NestedState, Self::Error> {
3020 Err(vp_state::Error::Unimplemented("nested_state"))
3021 }
3022
3023 fn set_nested_state(&mut self, _value: &vp::NestedState) -> Result<(), Self::Error> {
3024 Err(vp_state::Error::Unimplemented("nested_state"))
3025 }
3026}
3027
3028fn advance_to_next_instruction(vmsa: &mut VmsaWrapper<'_, &mut SevVmsa>) {
3038 match SevExitCode(vmsa.guest_error_code()) {
3039 SevExitCode::AVIC_NOACCEL => {
3040 vmsa.set_rip(vmsa.rip() + 2);
3046 }
3047 _ => vmsa.set_rip(vmsa.next_rip()),
3048 }
3049
3050 if vmsa.rip() == 0 {
3057 tracing::warn!("rip is zero, might need to parse the instruction stream");
3058 }
3059
3060 vmsa.v_intr_cntrl_mut().set_intr_shadow(false);
3061}
3062
3063impl UhProcessor<'_, SnpBacked> {
3064 fn read_msr_snp(
3065 &mut self,
3066 _dev: &impl CpuIo,
3067 msr: u32,
3068 vtl: GuestVtl,
3069 ) -> Result<u64, MsrError> {
3070 let vmsa = self.runner.vmsa(vtl);
3071 let value = match msr {
3072 x86defs::X64_MSR_FS_BASE => vmsa.fs().base,
3073 x86defs::X64_MSR_GS_BASE => vmsa.gs().base,
3074 x86defs::X64_MSR_KERNEL_GS_BASE => vmsa.kernel_gs_base(),
3075 x86defs::X86X_MSR_TSC_AUX => {
3076 if self.shared.tsc_aux_virtualized {
3077 vmsa.tsc_aux() as u64
3078 } else {
3079 return Err(MsrError::InvalidAccess);
3080 }
3081 }
3082 x86defs::X86X_MSR_SPEC_CTRL => vmsa.spec_ctrl(),
3083 x86defs::X86X_MSR_U_CET => vmsa.u_cet(),
3084 x86defs::X86X_MSR_S_CET => vmsa.s_cet(),
3085 x86defs::X86X_MSR_PL0_SSP => vmsa.pl0_ssp(),
3086 x86defs::X86X_MSR_PL1_SSP => vmsa.pl1_ssp(),
3087 x86defs::X86X_MSR_PL2_SSP => vmsa.pl2_ssp(),
3088 x86defs::X86X_MSR_PL3_SSP => vmsa.pl3_ssp(),
3089 x86defs::X86X_MSR_INTERRUPT_SSP_TABLE_ADDR => vmsa.interrupt_ssp_table_addr(),
3090 x86defs::X86X_MSR_CR_PAT => vmsa.pat(),
3091 x86defs::X86X_MSR_EFER => vmsa.efer(),
3092 x86defs::X86X_MSR_STAR => vmsa.star(),
3093 x86defs::X86X_MSR_LSTAR => vmsa.lstar(),
3094 x86defs::X86X_MSR_CSTAR => vmsa.cstar(),
3095 x86defs::X86X_MSR_SFMASK => vmsa.sfmask(),
3096 x86defs::X86X_MSR_SYSENTER_CS => vmsa.sysenter_cs(),
3097 x86defs::X86X_MSR_SYSENTER_ESP => vmsa.sysenter_esp(),
3098 x86defs::X86X_MSR_SYSENTER_EIP => vmsa.sysenter_eip(),
3099 x86defs::X86X_MSR_XSS => vmsa.xss(),
3100 x86defs::X86X_AMD_MSR_VM_CR => 0,
3101 x86defs::X86X_MSR_TSC => safe_intrinsics::rdtsc(),
3102 x86defs::X86X_MSR_MC_UPDATE_PATCH_LEVEL => 0xffff_ffff,
3103 x86defs::X86X_MSR_MTRR_CAP => {
3104 0x400
3107 }
3108 x86defs::X86X_MSR_MTRR_DEF_TYPE => {
3109 0
3113 }
3114 x86defs::X86X_AMD_MSR_SYSCFG
3115 | x86defs::X86X_MSR_MCG_CAP
3116 | x86defs::X86X_MSR_MCG_STATUS => 0,
3117 hvdef::HV_X64_MSR_GUEST_IDLE => {
3118 self.backing.cvm.lapics[vtl].activity = MpState::Idle;
3119 let mut vmsa = self.runner.vmsa_mut(vtl);
3120 vmsa.v_intr_cntrl_mut().set_intr_shadow(false);
3121 0
3122 }
3123 _ => return Err(MsrError::Unknown),
3124 };
3125 Ok(value)
3126 }
3127
3128 fn write_msr_snp(
3129 &mut self,
3130 _dev: &impl CpuIo,
3131 msr: u32,
3132 value: u64,
3133 vtl: GuestVtl,
3134 ) -> Result<(), MsrError> {
3135 hardware_cvm::validate_cvm_msr_write(msr, value, &self.partition.caps.xsave)?;
3136
3137 let mut vmsa = self.runner.vmsa_mut(vtl);
3138 match msr {
3139 x86defs::X64_MSR_FS_BASE => {
3140 if !hardware_cvm::validate_canonical_address(value, vmsa.efer(), vmsa.cr4()) {
3143 return Err(MsrError::InvalidAccess);
3144 }
3145 let fs = vmsa.fs();
3146 vmsa.set_fs(SevSelector {
3147 attrib: fs.attrib,
3148 selector: fs.selector,
3149 limit: fs.limit,
3150 base: value,
3151 });
3152 }
3153 x86defs::X64_MSR_GS_BASE => {
3154 if !hardware_cvm::validate_canonical_address(value, vmsa.efer(), vmsa.cr4()) {
3157 return Err(MsrError::InvalidAccess);
3158 }
3159 let gs = vmsa.gs();
3160 vmsa.set_gs(SevSelector {
3161 attrib: gs.attrib,
3162 selector: gs.selector,
3163 limit: gs.limit,
3164 base: value,
3165 });
3166 }
3167 x86defs::X64_MSR_KERNEL_GS_BASE => vmsa.set_kernel_gs_base(value),
3168 x86defs::X86X_MSR_TSC_AUX => {
3169 if self.shared.tsc_aux_virtualized {
3170 vmsa.set_tsc_aux(value as u32);
3171 } else {
3172 return Err(MsrError::InvalidAccess);
3173 }
3174 }
3175 x86defs::X86X_MSR_SPEC_CTRL => vmsa.set_spec_ctrl(value),
3176 x86defs::X86X_MSR_U_CET => vmsa.set_u_cet(value),
3177 x86defs::X86X_MSR_S_CET => vmsa.set_s_cet(value),
3178 x86defs::X86X_MSR_PL0_SSP => vmsa.set_pl0_ssp(value),
3179 x86defs::X86X_MSR_PL1_SSP => vmsa.set_pl1_ssp(value),
3180 x86defs::X86X_MSR_PL2_SSP => vmsa.set_pl2_ssp(value),
3181 x86defs::X86X_MSR_PL3_SSP => vmsa.set_pl3_ssp(value),
3182 x86defs::X86X_MSR_INTERRUPT_SSP_TABLE_ADDR => vmsa.set_interrupt_ssp_table_addr(value),
3183
3184 x86defs::X86X_MSR_CR_PAT => vmsa.set_pat(value),
3185 x86defs::X86X_MSR_EFER => vmsa.set_efer(SnpBacked::calculate_efer(value, vmsa.cr0())),
3186
3187 x86defs::X86X_MSR_STAR => vmsa.set_star(value),
3188 x86defs::X86X_MSR_LSTAR => vmsa.set_lstar(value),
3189 x86defs::X86X_MSR_CSTAR => vmsa.set_cstar(value),
3190 x86defs::X86X_MSR_SFMASK => vmsa.set_sfmask(value),
3191 x86defs::X86X_MSR_SYSENTER_CS => vmsa.set_sysenter_cs(value),
3192 x86defs::X86X_MSR_SYSENTER_ESP => vmsa.set_sysenter_esp(value),
3193 x86defs::X86X_MSR_SYSENTER_EIP => vmsa.set_sysenter_eip(value),
3194 x86defs::X86X_MSR_XSS => vmsa.set_xss(value),
3195
3196 x86defs::X86X_MSR_TSC => {} x86defs::X86X_MSR_MC_UPDATE_PATCH_LEVEL => {}
3198 x86defs::X86X_MSR_MTRR_DEF_TYPE => {}
3199
3200 x86defs::X86X_AMD_MSR_VM_CR
3201 | x86defs::X86X_MSR_MTRR_CAP
3202 | x86defs::X86X_AMD_MSR_SYSCFG
3203 | x86defs::X86X_MSR_MCG_CAP => return Err(MsrError::InvalidAccess),
3204
3205 x86defs::X86X_MSR_MCG_STATUS => {
3206 if x86defs::X86xMcgStatusRegister::from(value).reserved0() != 0 {
3208 return Err(MsrError::InvalidAccess);
3209 }
3210 }
3211 _ => {
3212 tracing::debug!(msr, value, "unknown cvm msr write");
3213 }
3214 }
3215 Ok(())
3216 }
3217}
3218
3219impl hv1_hypercall::VtlSwitchOps for UhHypercallHandler<'_, '_, SnpBacked> {
3220 fn advance_ip(&mut self) {
3221 let is_64bit = self.vp.long_mode(self.intercepted_vtl);
3222 let mut io = hv1_hypercall::X64RegisterIo::new(self, is_64bit, true);
3223 io.advance_ip();
3224 }
3225
3226 fn inject_invalid_opcode_fault(&mut self) {
3227 self.vp
3228 .runner
3229 .vmsa_mut(self.intercepted_vtl)
3230 .set_event_inject(
3231 SevEventInjectInfo::new()
3232 .with_valid(true)
3233 .with_interruption_type(x86defs::snp::SEV_INTR_TYPE_EXCEPT)
3234 .with_vector(x86defs::Exception::INVALID_OPCODE.0),
3235 );
3236 }
3237}
3238
3239impl hv1_hypercall::FlushVirtualAddressList for UhHypercallHandler<'_, '_, SnpBacked> {
3240 fn flush_virtual_address_list(
3241 &mut self,
3242 processor_set: ProcessorSet<'_>,
3243 flags: HvFlushFlags,
3244 gva_ranges: &[HvGvaRange],
3245 ) -> HvRepResult {
3246 hv1_hypercall::FlushVirtualAddressListEx::flush_virtual_address_list_ex(
3247 self,
3248 processor_set,
3249 flags,
3250 gva_ranges,
3251 )
3252 }
3253}
3254
3255impl hv1_hypercall::FlushVirtualAddressListEx for UhHypercallHandler<'_, '_, SnpBacked> {
3256 fn flush_virtual_address_list_ex(
3257 &mut self,
3258 processor_set: ProcessorSet<'_>,
3259 flags: HvFlushFlags,
3260 gva_ranges: &[HvGvaRange],
3261 ) -> HvRepResult {
3262 self.hcvm_validate_flush_inputs(processor_set, flags, true)
3263 .map_err(|e| (e, 0))?;
3264
3265 if gva_ranges.len() > 16 || gva_ranges.iter().any(|range| if flags.use_extended_range_format() { range.as_extended().additional_pages() } else { range.as_simple().additional_pages() } > 16) {
3268 self.do_flush_virtual_address_space(processor_set, flags);
3269 } else {
3270 self.do_flush_virtual_address_list(flags, gva_ranges);
3271 }
3272
3273 self.vp.set_wait_for_tlb_locks(self.intercepted_vtl);
3275 Ok(())
3276 }
3277}
3278
3279impl hv1_hypercall::FlushVirtualAddressSpace for UhHypercallHandler<'_, '_, SnpBacked> {
3280 fn flush_virtual_address_space(
3281 &mut self,
3282 processor_set: ProcessorSet<'_>,
3283 flags: HvFlushFlags,
3284 ) -> hvdef::HvResult<()> {
3285 hv1_hypercall::FlushVirtualAddressSpaceEx::flush_virtual_address_space_ex(
3286 self,
3287 processor_set,
3288 flags,
3289 )
3290 }
3291}
3292
3293impl hv1_hypercall::FlushVirtualAddressSpaceEx for UhHypercallHandler<'_, '_, SnpBacked> {
3294 fn flush_virtual_address_space_ex(
3295 &mut self,
3296 processor_set: ProcessorSet<'_>,
3297 flags: HvFlushFlags,
3298 ) -> hvdef::HvResult<()> {
3299 self.hcvm_validate_flush_inputs(processor_set, flags, false)?;
3300
3301 self.do_flush_virtual_address_space(processor_set, flags);
3302
3303 self.vp.set_wait_for_tlb_locks(self.intercepted_vtl);
3305 Ok(())
3306 }
3307}
3308
3309impl UhHypercallHandler<'_, '_, SnpBacked> {
3310 fn do_flush_virtual_address_list(&mut self, flags: HvFlushFlags, gva_ranges: &[HvGvaRange]) {
3311 for range in gva_ranges {
3312 let mut rax = SevInvlpgbRax::new()
3313 .with_asid_valid(true)
3314 .with_va_valid(true)
3315 .with_global(!flags.non_global_mappings_only());
3316 let mut ecx = SevInvlpgbEcx::new();
3317 let mut count;
3318 let mut gpn;
3319
3320 if flags.use_extended_range_format() && range.as_extended().large_page() {
3321 ecx.set_large_page(true);
3322 if range.as_extended_large_page().page_size() {
3323 let range = range.as_extended_large_page();
3324 count = range.additional_pages();
3325 gpn = range.gva_large_page_number();
3326 } else {
3327 let range = range.as_extended();
3328 count = range.additional_pages();
3329 gpn = range.gva_page_number();
3330 }
3331 } else {
3332 let range = range.as_simple();
3333 count = range.additional_pages();
3334 gpn = range.gva_page_number();
3335 }
3336 count += 1; while count > 0 {
3339 rax.set_virtual_page_number(gpn);
3340 ecx.set_additional_count(std::cmp::min(
3341 count - 1,
3342 self.vp.shared.invlpgb_count_max.into(),
3343 ));
3344
3345 let edx = SevInvlpgbEdx::new();
3346 self.vp
3347 .partition
3348 .hcl
3349 .invlpgb(rax.into(), edx.into(), ecx.into());
3350
3351 count -= ecx.additional_count() + 1;
3352 gpn += ecx.additional_count() + 1;
3353 }
3354 }
3355
3356 self.vp.partition.hcl.tlbsync();
3357 }
3358
3359 fn do_flush_virtual_address_space(
3360 &mut self,
3361 processor_set: ProcessorSet<'_>,
3362 flags: HvFlushFlags,
3363 ) {
3364 let only_self = [self.vp.vp_index().index()].into_iter().eq(processor_set);
3365 if only_self && flags.non_global_mappings_only() {
3366 self.vp.runner.vmsa_mut(self.intercepted_vtl).set_pcpu_id(0);
3367 } else {
3368 self.vp.partition.hcl.invlpgb(
3369 SevInvlpgbRax::new()
3370 .with_asid_valid(true)
3371 .with_global(!flags.non_global_mappings_only())
3372 .into(),
3373 SevInvlpgbEdx::new().into(),
3374 SevInvlpgbEcx::new().into(),
3375 );
3376 self.vp.partition.hcl.tlbsync();
3377 }
3378 }
3379}
3380
3381struct SnpTlbLockFlushAccess<'a> {
3382 vp_index: Option<VpIndex>,
3383 partition: &'a UhPartitionInner,
3384 shared: &'a SnpBackedShared,
3385}
3386
3387impl TlbFlushLockAccess for SnpTlbLockFlushAccess<'_> {
3388 fn flush(&mut self, vtl: GuestVtl) {
3389 self.partition.hcl.invlpgb(
3392 SevInvlpgbRax::new()
3393 .with_asid_valid(true)
3394 .with_global(true)
3395 .into(),
3396 SevInvlpgbEdx::new().into(),
3397 SevInvlpgbEcx::new().into(),
3398 );
3399 self.partition.hcl.tlbsync();
3400 self.set_wait_for_tlb_locks(vtl);
3401 }
3402
3403 fn flush_entire(&mut self) {
3404 self.partition.hcl.invlpgb(
3405 SevInvlpgbRax::new()
3406 .with_asid_valid(true)
3407 .with_global(true)
3408 .into(),
3409 SevInvlpgbEdx::new().into(),
3410 SevInvlpgbEcx::new().into(),
3411 );
3412 self.partition.hcl.tlbsync();
3413 for vtl in [GuestVtl::Vtl0, GuestVtl::Vtl1] {
3414 self.set_wait_for_tlb_locks(vtl);
3415 }
3416 }
3417
3418 fn set_wait_for_tlb_locks(&mut self, vtl: GuestVtl) {
3419 if let Some(vp_index) = self.vp_index {
3420 hardware_cvm::tlb_lock::TlbLockAccess {
3421 vp_index,
3422 cvm_partition: &self.shared.cvm,
3423 }
3424 .set_wait_for_tlb_locks(vtl);
3425 }
3426 }
3427}
3428
3429mod save_restore {
3430 use super::SnpBacked;
3431 use super::UhProcessor;
3432 use vmcore::save_restore::RestoreError;
3433 use vmcore::save_restore::SaveError;
3434 use vmcore::save_restore::SaveRestore;
3435 use vmcore::save_restore::SavedStateNotSupported;
3436
3437 impl SaveRestore for UhProcessor<'_, SnpBacked> {
3438 type SavedState = SavedStateNotSupported;
3439
3440 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
3441 Err(SaveError::NotSupported)
3442 }
3443
3444 fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
3445 match state {}
3446 }
3447 }
3448}