1#![cfg(guest_arch = "x86_64")]
7
8type VpRegisterName = HvX64RegisterName;
9
10use super::super::BackingParams;
11use super::super::BackingPrivate;
12use super::super::UhEmulationState;
13use super::super::signal_mnf;
14use super::super::vp_state;
15use super::super::vp_state::UhVpStateAccess;
16use super::MshvRunVpError;
17use super::VbsIsolatedVtl1State;
18use crate::BackingShared;
19use crate::Error;
20use crate::GuestVsmState;
21use crate::GuestVtl;
22use crate::UhPartitionNewParams;
23use crate::processor::BackingSharedParams;
24use crate::processor::SidecarExitReason;
25use crate::processor::SidecarRemoveExit;
26use crate::processor::UhHypercallHandler;
27use crate::processor::UhProcessor;
28use crate::validate_vtl_gpa_flags;
29use hcl::ioctl;
30use hcl::ioctl::ApplyVtlProtectionsError;
31use hcl::ioctl::x64::MshvX64;
32use hcl::protocol;
33use hv1_emulator::hv::ProcessorVtlHv;
34use hv1_hypercall::HvRepResult;
35use hv1_structs::VtlSet;
36use hvdef::HV_PAGE_SIZE;
37use hvdef::HvDeliverabilityNotificationsRegister;
38use hvdef::HvError;
39use hvdef::HvInterceptAccessType;
40use hvdef::HvMapGpaFlags;
41use hvdef::HvMessageType;
42use hvdef::HvRegisterValue;
43use hvdef::HvRegisterVsmPartitionConfig;
44use hvdef::HvX64InterceptMessageHeader;
45use hvdef::HvX64PendingEvent;
46use hvdef::HvX64PendingInterruptionType;
47use hvdef::HvX64RegisterName;
48use hvdef::Vtl;
49use hvdef::hypercall;
50use inspect::Inspect;
51use inspect::InspectMut;
52use inspect_counters::Counter;
53use parking_lot::RwLock;
54use std::sync::atomic::Ordering::Relaxed;
55use virt::EmulatorMonitorSupport;
56use virt::StopVp;
57use virt::VpHaltReason;
58use virt::VpIndex;
59use virt::io::CpuIo;
60use virt::state::HvRegisterState;
61use virt::state::StateElement;
62use virt::vp;
63use virt::vp::AccessVpState;
64use virt::x86::MsrError;
65use virt_support_x86emu::emulate::EmuCheckVtlAccessError;
66use virt_support_x86emu::emulate::EmuTranslateError;
67use virt_support_x86emu::emulate::EmuTranslateResult;
68use virt_support_x86emu::emulate::EmulatorSupport;
69use x86defs::RFlags;
70use x86defs::SegmentRegister;
71use x86defs::xsave::Fxsave;
72use x86defs::xsave::XFEATURE_SSE;
73use x86defs::xsave::XFEATURE_X87;
74use x86defs::xsave::XsaveHeader;
75use zerocopy::FromZeros;
76use zerocopy::Immutable;
77use zerocopy::IntoBytes;
78use zerocopy::KnownLayout;
79
80#[derive(InspectMut)]
83pub struct HypervisorBackedX86 {
84 #[inspect(hex, with = "|&x| u64::from(x)")]
87 deliverability_notifications: HvDeliverabilityNotificationsRegister,
88 #[inspect(hex, with = "|&x| u64::from(x)")]
90 pub(super) next_deliverability_notifications: HvDeliverabilityNotificationsRegister,
91 stats: ProcessorStatsX86,
92 deferred_init: bool,
98}
99
100#[derive(Inspect)]
102pub struct HypervisorBackedX86Shared {
103 pub(crate) guest_vsm: RwLock<GuestVsmState<VbsIsolatedVtl1State>>,
104}
105
106impl HypervisorBackedX86Shared {
107 pub(crate) fn new(
109 _partition_params: &UhPartitionNewParams<'_>,
110 params: BackingSharedParams<'_>,
111 ) -> Result<Self, Error> {
112 Ok(Self {
113 guest_vsm: RwLock::new(GuestVsmState::from_availability(params.guest_vsm_available)),
114 })
115 }
116}
117
118#[derive(Inspect, Default)]
119struct ProcessorStatsX86 {
120 io_port: Counter,
121 mmio: Counter,
122 unaccepted_gpa: Counter,
123 hypercall: Counter,
124 synic_deliverable: Counter,
125 interrupt_deliverable: Counter,
126 cpuid: Counter,
127 msr: Counter,
128 eoi: Counter,
129 unrecoverable_exception: Counter,
130 halt: Counter,
131 exception_intercept: Counter,
132}
133
134pub struct MshvEmulationCache {
135 rsp: u64,
136 es: SegmentRegister,
137 ds: SegmentRegister,
138 fs: SegmentRegister,
139 gs: SegmentRegister,
140 ss: SegmentRegister,
141 cr0: u64,
142 efer: u64,
143 rip: u64,
144 rflags: RFlags,
145}
146
147#[expect(private_interfaces)]
148impl BackingPrivate for HypervisorBackedX86 {
149 type HclBacking<'mshv> = MshvX64<'mshv>;
150 type Shared = HypervisorBackedX86Shared;
151 type EmulationCache = MshvEmulationCache;
152
153 fn shared(shared: &BackingShared) -> &Self::Shared {
154 let BackingShared::Hypervisor(shared) = shared else {
155 unreachable!()
156 };
157 shared
158 }
159
160 fn new(
161 params: BackingParams<'_, '_, Self>,
162 _shared: &HypervisorBackedX86Shared,
163 ) -> Result<Self, Error> {
164 let regs = vp::Registers::at_reset(¶ms.partition.caps, params.vp_info);
170 *params.runner.cpu_context_mut() = protocol::hcl_cpu_context_x64 {
171 gps_no_rsp: [
172 regs.rax, regs.rcx, regs.rdx, regs.rbx, 0, regs.rbp, regs.rsi, regs.rdi, regs.r8, regs.r9, regs.r10, regs.r11, regs.r12,
174 regs.r13, regs.r14, regs.r15,
175 ],
176 fx_state: vp::Xsave::at_reset(¶ms.partition.caps, params.vp_info).fxsave(),
177 reserved: [0; 384],
178 };
179
180 Ok(Self {
181 deliverability_notifications: Default::default(),
182 next_deliverability_notifications: Default::default(),
183 stats: Default::default(),
184 deferred_init: false,
185 })
186 }
187
188 fn init(this: &mut UhProcessor<'_, Self>) {
189 if !this.vp_index().is_bsp() {
202 this.backing.deferred_init = match this.set_vtl0_startup_suspend(true) {
203 Ok(()) => false,
204 Err(err) => {
205 tracelimit::warn_ratelimited!(
206 error = &err as &dyn std::error::Error,
207 vp = this.vp_index().index(),
208 "unable to set internal activity register, falling back to deferred init"
209 );
210 true
211 }
212 };
213 }
214 }
215
216 type StateAccess<'p, 'a>
217 = UhVpStateAccess<'a, 'p, Self>
218 where
219 Self: 'a + 'p,
220 'p: 'a;
221
222 fn access_vp_state<'a, 'p>(
223 this: &'a mut UhProcessor<'p, Self>,
224 vtl: GuestVtl,
225 ) -> Self::StateAccess<'p, 'a> {
226 UhVpStateAccess::new(this, vtl)
227 }
228
229 fn pre_run_vp(this: &mut UhProcessor<'_, Self>) {
230 if std::mem::take(&mut this.backing.deferred_init) {
231 tracing::debug!(
232 vp = this.vp_index().index(),
233 "sending deferred INIT to set startup suspend"
234 );
235 this.partition.request_msi(
236 GuestVtl::Vtl0,
237 virt::irqcon::MsiRequest::new_x86(
238 virt::irqcon::DeliveryMode::INIT,
239 this.inner.vp_info.apic_id,
240 false,
241 0,
242 true,
243 ),
244 );
245 }
246 }
247
248 async fn run_vp(
249 this: &mut UhProcessor<'_, Self>,
250 dev: &impl CpuIo,
251 stop: &mut StopVp<'_>,
252 ) -> Result<(), VpHaltReason> {
253 if this.backing.deliverability_notifications
254 != this.backing.next_deliverability_notifications
255 {
256 let notifications = this.backing.next_deliverability_notifications;
257 tracing::trace!(?notifications, "setting notifications");
258 this.runner
259 .set_vp_register(
260 GuestVtl::Vtl0,
262 VpRegisterName::DeliverabilityNotifications,
263 u64::from(notifications).into(),
264 )
265 .expect("requesting deliverability is not a fallable operation");
266 this.backing.deliverability_notifications =
267 this.backing.next_deliverability_notifications;
268 }
269
270 let intercepted = if this.runner.is_sidecar() {
271 let mut run = this
272 .runner
273 .run_sidecar()
274 .map_err(|e| dev.fatal_error(e.into()))?;
275 match stop.until_stop(run.wait()).await {
276 Ok(r) => r,
277 Err(stop) => {
278 run.cancel();
279 let r = run.wait().await;
280 if matches!(r, Ok(false)) {
281 return Err(stop.into());
283 }
284 r
285 }
286 }
287 .map_err(|e| dev.fatal_error(ioctl::Error::Sidecar(e).into()))?
288 } else {
289 this.unlock_tlb_lock(Vtl::Vtl2);
290 this.runner
291 .run()
292 .map_err(|e| dev.fatal_error(MshvRunVpError(e).into()))?
293 };
294
295 if intercepted {
296 let message_type = this.runner.exit_message().header.typ;
297
298 let mut intercept_handler =
299 InterceptHandler::new(this).map_err(|e| dev.fatal_error(e.into()))?;
300
301 let stat = match message_type {
302 HvMessageType::HvMessageTypeX64IoPortIntercept => {
303 intercept_handler.handle_io_port_exit(dev).await?;
304 &mut this.backing.stats.io_port
305 }
306 HvMessageType::HvMessageTypeUnmappedGpa
307 | HvMessageType::HvMessageTypeGpaIntercept => {
308 intercept_handler.handle_mmio_exit(dev).await?;
309 &mut this.backing.stats.mmio
310 }
311 HvMessageType::HvMessageTypeUnacceptedGpa => {
312 intercept_handler
313 .handle_unaccepted_gpa_intercept(dev)
314 .await?;
315 &mut this.backing.stats.unaccepted_gpa
316 }
317 HvMessageType::HvMessageTypeHypercallIntercept => {
318 intercept_handler.handle_hypercall_exit();
319 &mut this.backing.stats.hypercall
320 }
321 HvMessageType::HvMessageTypeSynicSintDeliverable => {
322 intercept_handler.handle_synic_deliverable_exit();
323 &mut this.backing.stats.synic_deliverable
324 }
325 HvMessageType::HvMessageTypeX64InterruptionDeliverable => {
326 intercept_handler.handle_interrupt_deliverable_exit(dev)?;
327 &mut this.backing.stats.interrupt_deliverable
328 }
329 HvMessageType::HvMessageTypeX64CpuidIntercept => {
330 intercept_handler.handle_cpuid_intercept();
331 &mut this.backing.stats.cpuid
332 }
333 HvMessageType::HvMessageTypeMsrIntercept => {
334 intercept_handler.handle_msr_intercept();
335 &mut this.backing.stats.msr
336 }
337 HvMessageType::HvMessageTypeX64ApicEoi => {
338 intercept_handler.handle_eoi(dev);
339 &mut this.backing.stats.eoi
340 }
341 HvMessageType::HvMessageTypeUnrecoverableException => {
342 intercept_handler.handle_unrecoverable_exception()?;
343 &mut this.backing.stats.unrecoverable_exception
344 }
345 HvMessageType::HvMessageTypeExceptionIntercept => {
346 intercept_handler.handle_exception(dev)?;
347 &mut this.backing.stats.exception_intercept
348 }
349 reason => unreachable!("unknown exit reason: {:#x?}", reason),
350 };
351 stat.increment();
352
353 if this.runner.is_sidecar()
354 && !this.signaled_sidecar_exit
355 && !this.partition.no_sidecar_hotplug.load(Relaxed)
356 {
357 let message = this.runner.exit_message();
366 this.inner
367 .set_sidecar_exit_reason(SidecarExitReason::Exit(parse_sidecar_exit(message)));
368 this.signaled_sidecar_exit = true;
369 return Err(VpHaltReason::Cancel);
370 }
371 }
372 Ok(())
373 }
374
375 fn poll_apic(_this: &mut UhProcessor<'_, Self>, _vtl: GuestVtl, _scan_irr: bool) {}
376
377 fn process_interrupts(
378 _this: &mut UhProcessor<'_, Self>,
379 _scan_irr: hv1_structs::VtlArray<bool, 2>,
380 _first_scan_irr: &mut bool,
381 _dev: &impl CpuIo,
382 ) -> bool {
383 false
384 }
385
386 fn request_extint_readiness(this: &mut UhProcessor<'_, Self>) {
387 this.backing
388 .next_deliverability_notifications
389 .set_interrupt_notification(true);
390 }
391
392 fn request_untrusted_sint_readiness(this: &mut UhProcessor<'_, Self>, sints: u16) {
393 this.backing
394 .next_deliverability_notifications
395 .set_sints(this.backing.next_deliverability_notifications.sints() | sints);
396 }
397
398 fn hv(&self, _vtl: GuestVtl) -> Option<&ProcessorVtlHv> {
399 None
400 }
401
402 fn hv_mut(&mut self, _vtl: GuestVtl) -> Option<&mut ProcessorVtlHv> {
403 None
404 }
405
406 fn handle_vp_start_enable_vtl_wake(_this: &mut UhProcessor<'_, Self>, _vtl: GuestVtl) {
407 unimplemented!()
408 }
409
410 fn vtl1_inspectable(_this: &UhProcessor<'_, Self>) -> bool {
411 false
414 }
415}
416
417fn parse_sidecar_exit(message: &hvdef::HvMessage) -> SidecarRemoveExit {
418 match message.header.typ {
419 HvMessageType::HvMessageTypeX64IoPortIntercept => {
420 let message = message.as_message::<hvdef::HvX64IoPortInterceptMessage>();
421 SidecarRemoveExit::Io {
422 port: message.port_number,
423 write: message.header.intercept_access_type == HvInterceptAccessType::WRITE,
424 }
425 }
426 HvMessageType::HvMessageTypeUnmappedGpa | HvMessageType::HvMessageTypeGpaIntercept => {
427 let message = message.as_message::<hvdef::HvX64MemoryInterceptMessage>();
428 SidecarRemoveExit::Mmio {
429 gpa: message.guest_physical_address,
430 write: message.header.intercept_access_type == HvInterceptAccessType::WRITE,
431 }
432 }
433 HvMessageType::HvMessageTypeHypercallIntercept => {
434 let message = message.as_message::<hvdef::HvX64HypercallInterceptMessage>();
435 let is_64bit = message.header.execution_state.cr0_pe()
436 && message.header.execution_state.efer_lma();
437 let control = if is_64bit {
438 message.rcx
439 } else {
440 (message.rdx << 32) | (message.rax as u32 as u64)
441 };
442 SidecarRemoveExit::Hypercall {
443 code: hvdef::HypercallCode(hypercall::Control::from(control).code()),
444 }
445 }
446 HvMessageType::HvMessageTypeX64CpuidIntercept => {
447 let message = message.as_message::<hvdef::HvX64CpuidInterceptMessage>();
448 SidecarRemoveExit::Cpuid {
449 leaf: message.rax as u32,
450 subleaf: message.rcx as u32,
451 }
452 }
453 HvMessageType::HvMessageTypeMsrIntercept => {
454 let message = message.as_message::<hvdef::HvX64MsrInterceptMessage>();
455 SidecarRemoveExit::Msr {
456 msr: message.msr_number,
457 value: (message.header.intercept_access_type == HvInterceptAccessType::WRITE)
458 .then_some((message.rdx << 32) | message.rax as u32 as u64),
459 }
460 }
461 typ => SidecarRemoveExit::Hypervisor { message: typ },
462 }
463}
464
465fn next_rip(value: &HvX64InterceptMessageHeader) -> u64 {
466 value.rip.wrapping_add(value.instruction_len() as u64)
467}
468
469struct InterceptHandler<'a, 'b> {
470 vp: &'a mut UhProcessor<'b, HypervisorBackedX86>,
471 intercepted_vtl: GuestVtl,
472}
473
474#[derive(Debug, Error)]
475#[error("invalid intercepted vtl {0:?}")]
476struct InvalidInterceptedVtl(u8);
477
478#[derive(Debug, Error)]
479#[error("guest accessed unaccepted gpa {0}")]
480struct UnacceptedMemoryAccess(u64);
481
482impl<'a, 'b> InterceptHandler<'a, 'b> {
483 fn new(
484 vp: &'a mut UhProcessor<'b, HypervisorBackedX86>,
485 ) -> Result<Self, InvalidInterceptedVtl> {
486 let message_type = vp.runner.exit_message().header.typ;
487
488 let intercepted_vtl = match vp.runner.reg_page_vtl() {
489 Ok(vtl) => vtl,
490 Err(ioctl::x64::RegisterPageVtlError::InvalidVtl(vtl)) => {
491 return Err(InvalidInterceptedVtl(vtl));
492 }
493 Err(ioctl::x64::RegisterPageVtlError::NoRegisterPage) => {
494 if matches!(&message_type, &HvMessageType::HvMessageTypeX64ApicEoi) {
495 GuestVtl::Vtl0
498 } else {
499 let message_header = match &message_type {
500 &HvMessageType::HvMessageTypeX64IoPortIntercept => {
501 &vp.runner
502 .exit_message()
503 .as_message::<hvdef::HvX64IoPortInterceptMessage>()
504 .header
505 }
506 &HvMessageType::HvMessageTypeUnmappedGpa
507 | &HvMessageType::HvMessageTypeGpaIntercept => {
508 &vp.runner
509 .exit_message()
510 .as_message::<hvdef::HvX64MemoryInterceptMessage>()
511 .header
512 }
513 &HvMessageType::HvMessageTypeUnacceptedGpa => {
514 &vp.runner
515 .exit_message()
516 .as_message::<hvdef::HvX64MemoryInterceptMessage>()
517 .header
518 }
519 &HvMessageType::HvMessageTypeHypercallIntercept => {
520 &vp.runner
521 .exit_message()
522 .as_message::<hvdef::HvX64HypercallInterceptMessage>()
523 .header
524 }
525 &HvMessageType::HvMessageTypeSynicSintDeliverable => {
526 &vp.runner
527 .exit_message()
528 .as_message::<hvdef::HvX64SynicSintDeliverableMessage>()
529 .header
530 }
531 &HvMessageType::HvMessageTypeX64InterruptionDeliverable => {
532 &vp.runner
533 .exit_message()
534 .as_message::<hvdef::HvX64InterruptionDeliverableMessage>()
535 .header
536 }
537 &HvMessageType::HvMessageTypeX64CpuidIntercept => {
538 &vp.runner
539 .exit_message()
540 .as_message::<hvdef::HvX64CpuidInterceptMessage>()
541 .header
542 }
543 &HvMessageType::HvMessageTypeMsrIntercept => {
544 &vp.runner
545 .exit_message()
546 .as_message::<hvdef::HvX64MsrInterceptMessage>()
547 .header
548 }
549 &HvMessageType::HvMessageTypeUnrecoverableException => {
550 &vp.runner
551 .exit_message()
552 .as_message::<hvdef::HvX64UnrecoverableExceptionMessage>()
553 .header
554 }
555 &HvMessageType::HvMessageTypeX64Halt => {
556 &vp.runner
557 .exit_message()
558 .as_message::<hvdef::HvX64HaltMessage>()
559 .header
560 }
561 &HvMessageType::HvMessageTypeExceptionIntercept => {
562 &vp.runner
563 .exit_message()
564 .as_message::<hvdef::HvX64ExceptionInterceptMessage>()
565 .header
566 }
567 reason => unreachable!("unknown exit reason: {:#x?}", reason),
568 };
569
570 message_header
571 .execution_state
572 .vtl()
573 .try_into()
574 .map_err(|hcl::UnsupportedGuestVtl(vtl)| InvalidInterceptedVtl(vtl))?
575 }
576 }
577 };
578
579 Ok(Self {
580 vp,
581 intercepted_vtl,
582 })
583 }
584
585 fn handle_interrupt_deliverable_exit(&mut self, bus: &impl CpuIo) -> Result<(), VpHaltReason> {
586 let message = self
587 .vp
588 .runner
589 .exit_message()
590 .as_message::<hvdef::HvX64InterruptionDeliverableMessage>();
591
592 assert_eq!(
593 message.deliverable_type,
594 HvX64PendingInterruptionType::HV_X64_PENDING_INTERRUPT
595 );
596
597 self.vp
598 .backing
599 .deliverability_notifications
600 .set_interrupt_notification(false);
601
602 self.vp
603 .backing
604 .next_deliverability_notifications
605 .set_interrupt_notification(false);
606
607 if let Some(vector) = bus.acknowledge_pic_interrupt() {
608 let event = hvdef::HvX64PendingExtIntEvent::new()
609 .with_event_pending(true)
610 .with_event_type(hvdef::HV_X64_PENDING_EVENT_EXT_INT)
611 .with_vector(vector);
612
613 self.vp
614 .runner
615 .set_vp_register(
616 self.intercepted_vtl,
617 HvX64RegisterName::PendingEvent0,
618 u128::from(event).into(),
619 )
620 .unwrap();
621 }
622
623 Ok(())
624 }
625
626 fn handle_synic_deliverable_exit(&mut self) {
627 let message = self
628 .vp
629 .runner
630 .exit_message()
631 .as_message::<hvdef::HvX64SynicSintDeliverableMessage>();
632
633 tracing::trace!(
634 deliverable_sints = message.deliverable_sints,
635 "sint deliverable"
636 );
637
638 self.vp.backing.deliverability_notifications.set_sints(
639 self.vp.backing.deliverability_notifications.sints() & !message.deliverable_sints,
640 );
641
642 self.vp
644 .backing
645 .next_deliverability_notifications
646 .set_sints(0);
647
648 self.vp
650 .deliver_synic_messages(GuestVtl::Vtl0, message.deliverable_sints);
651 }
652
653 fn handle_hypercall_exit(&mut self) {
654 let message = self
655 .vp
656 .runner
657 .exit_message()
658 .as_message::<hvdef::HvX64HypercallInterceptMessage>();
659
660 tracing::trace!(msg = %format_args!("{:x?}", message), "hypercall");
661
662 let is_64bit =
663 message.header.execution_state.cr0_pe() && message.header.execution_state.efer_lma();
664
665 let guest_memory = &self.vp.partition.gm[self.intercepted_vtl];
666 let handler = UhHypercallHandler {
667 vp: self.vp,
668 trusted: false,
669 intercepted_vtl: self.intercepted_vtl,
670 };
671 UhHypercallHandler::MSHV_DISPATCHER.dispatch(
672 guest_memory,
673 hv1_hypercall::X64RegisterIo::new(handler, is_64bit, true),
674 );
675 }
676
677 async fn handle_mmio_exit(&mut self, dev: &impl CpuIo) -> Result<(), VpHaltReason> {
678 let message = self
679 .vp
680 .runner
681 .exit_message()
682 .as_message::<hvdef::HvX64MemoryInterceptMessage>();
683
684 tracing::trace!(msg = %format_args!("{:x?}", message), "mmio");
685
686 let interruption_pending = message.header.execution_state.interruption_pending();
687
688 if Some(message.guest_physical_address & !(HV_PAGE_SIZE - 1))
690 == self.vp.partition.monitor_page.gpa()
691 && message.header.intercept_access_type == HvInterceptAccessType::WRITE
692 {
693 let tlb_lock_held = message.memory_access_info.gva_gpa_valid()
694 || message.memory_access_info.tlb_locked();
695 let guest_memory = &self.vp.partition.gm[self.intercepted_vtl];
696 let cache = self.vp.emulation_cache(self.intercepted_vtl);
697 let mut emulation_state = UhEmulationState {
698 vp: &mut *self.vp,
699 interruption_pending,
700 devices: dev,
701 vtl: self.intercepted_vtl,
702 cache,
703 };
704 if let Some(bit) = virt_support_x86emu::emulate::emulate_mnf_write_fast_path(
705 &mut emulation_state,
706 guest_memory,
707 dev,
708 interruption_pending,
709 tlb_lock_held,
710 ) {
711 if let Some(connection_id) = self.vp.partition.monitor_page.write_bit(bit) {
712 signal_mnf(&self.vp.partition.synic_ports, connection_id);
713 }
714 return Ok(());
715 }
716 }
717
718 let cache = self.vp.emulation_cache(self.intercepted_vtl);
719 self.vp
720 .emulate(dev, interruption_pending, self.intercepted_vtl, cache)
721 .await
722 }
723
724 async fn handle_io_port_exit(&mut self, dev: &impl CpuIo) -> Result<(), VpHaltReason> {
725 let message = self
726 .vp
727 .runner
728 .exit_message()
729 .as_message::<hvdef::HvX64IoPortInterceptMessage>();
730
731 tracing::trace!(msg = %format_args!("{:x?}", message), "io_port");
732
733 assert_eq!(
734 message.rax,
735 self.vp.runner.cpu_context().gps_no_rsp[protocol::RAX]
736 );
737
738 let interruption_pending = message.header.execution_state.interruption_pending();
739
740 if message.access_info.string_op() || message.access_info.rep_prefix() {
741 let cache = self.vp.emulation_cache(self.intercepted_vtl);
742 self.vp
743 .emulate(dev, interruption_pending, self.intercepted_vtl, cache)
744 .await
745 } else {
746 let next_rip = next_rip(&message.header);
747 let access_size = message.access_info.access_size();
748 virt_support_x86emu::emulate::emulate_io(
749 self.vp.vp_index(),
750 message.header.intercept_access_type == HvInterceptAccessType::WRITE,
751 message.port_number,
752 &mut self.vp.runner.cpu_context_mut().gps_no_rsp[protocol::RAX],
753 access_size,
754 dev,
755 )
756 .await;
757 self.vp.set_rip(self.intercepted_vtl, next_rip);
758 Ok(())
759 }
760 }
761
762 async fn handle_unaccepted_gpa_intercept(
763 &mut self,
764 dev: &impl CpuIo,
765 ) -> Result<(), VpHaltReason> {
766 let gpa = self
767 .vp
768 .runner
769 .exit_message()
770 .as_message::<hvdef::HvX64MemoryInterceptMessage>()
771 .guest_physical_address;
772
773 if self.vp.partition.is_gpa_lower_vtl_ram(gpa) {
774 Err(dev.fatal_error(UnacceptedMemoryAccess(gpa).into()))
782 } else {
783 self.handle_mmio_exit(dev).await
784 }
785 }
786
787 fn handle_cpuid_intercept(&mut self) {
788 let message = self
789 .vp
790 .runner
791 .exit_message()
792 .as_message::<hvdef::HvX64CpuidInterceptMessage>();
793
794 let default_result = [
795 message.default_result_rax as u32,
796 message.default_result_rbx as u32,
797 message.default_result_rcx as u32,
798 message.default_result_rdx as u32,
799 ];
800
801 tracing::trace!(msg = %format_args!("{:x?}", message), "cpuid");
802
803 let [eax, ebx, ecx, edx] =
804 self.vp
805 .partition
806 .cpuid
807 .result(message.rax as u32, message.rcx as u32, &default_result);
808
809 let next_rip = next_rip(&message.header);
810 self.vp.runner.cpu_context_mut().gps_no_rsp[protocol::RAX] = eax.into();
811 self.vp.runner.cpu_context_mut().gps_no_rsp[protocol::RBX] = ebx.into();
812 self.vp.runner.cpu_context_mut().gps_no_rsp[protocol::RCX] = ecx.into();
813 self.vp.runner.cpu_context_mut().gps_no_rsp[protocol::RDX] = edx.into();
814
815 self.vp.set_rip(self.intercepted_vtl, next_rip);
816 }
817
818 fn handle_msr_intercept(&mut self) {
819 let message = self
820 .vp
821 .runner
822 .exit_message()
823 .as_message::<hvdef::HvX64MsrInterceptMessage>();
824 let rip = next_rip(&message.header);
825
826 tracing::trace!(msg = %format_args!("{:x?}", message), "msr");
827
828 let msr = message.msr_number;
829 match message.header.intercept_access_type {
830 HvInterceptAccessType::READ => {
831 let value = match self.vp.read_crash_msr(msr, self.intercepted_vtl) {
833 Ok(v) => v,
834 Err(MsrError::Unknown) => {
835 tracing::trace!(msr, "unknown msr read");
836 0
837 }
838 Err(MsrError::InvalidAccess) => {
839 self.vp.inject_gpf(self.intercepted_vtl);
840 return;
842 }
843 };
844
845 self.vp.runner.cpu_context_mut().gps_no_rsp[protocol::RAX] = value & 0xffff_ffff;
846 self.vp.runner.cpu_context_mut().gps_no_rsp[protocol::RDX] = value >> 32;
847 }
848 HvInterceptAccessType::WRITE => {
849 let value = (message.rax & 0xffff_ffff) | (message.rdx << 32);
850 match self.vp.write_crash_msr(msr, value, self.intercepted_vtl) {
852 Ok(()) => {}
853 Err(MsrError::Unknown) => {
854 tracing::trace!(msr, value, "unknown msr write");
855 }
856 Err(MsrError::InvalidAccess) => {
857 self.vp.inject_gpf(self.intercepted_vtl);
858 return;
860 }
861 }
862 }
863 _ => unreachable!(),
864 }
865
866 self.vp.set_rip(self.intercepted_vtl, rip);
867 }
868
869 fn handle_eoi(&self, dev: &impl CpuIo) {
870 let message = self
871 .vp
872 .runner
873 .exit_message()
874 .as_message::<hvdef::HvX64ApicEoiMessage>();
875
876 tracing::trace!(msg = %format_args!("{:x?}", message), "eoi");
877
878 dev.handle_eoi(message.interrupt_vector);
879 }
880
881 fn handle_unrecoverable_exception(&self) -> Result<(), VpHaltReason> {
882 Err(VpHaltReason::TripleFault {
883 vtl: self.intercepted_vtl.into(),
884 })
885 }
886
887 fn handle_exception(&mut self, dev: &impl CpuIo) -> Result<(), VpHaltReason> {
888 let message = self
889 .vp
890 .runner
891 .exit_message()
892 .as_message::<hvdef::HvX64ExceptionInterceptMessage>();
893
894 match x86defs::Exception(message.vector as u8) {
895 x86defs::Exception::DEBUG if cfg!(feature = "gdb") => {
896 self.vp.handle_debug_exception(dev, self.intercepted_vtl)?
897 }
898 _ => tracing::error!("unexpected exception type {:#x?}", message.vector),
899 }
900 Ok(())
901 }
902}
903
904impl UhProcessor<'_, HypervisorBackedX86> {
905 fn set_rip(&mut self, vtl: GuestVtl, rip: u64) {
906 self.runner
907 .set_vp_register(vtl, HvX64RegisterName::Rip, rip.into())
908 .unwrap();
909 }
910
911 fn inject_gpf(&mut self, vtl: GuestVtl) {
912 let exception_event = hvdef::HvX64PendingExceptionEvent::new()
913 .with_event_pending(true)
914 .with_event_type(hvdef::HV_X64_PENDING_EVENT_EXCEPTION)
915 .with_vector(x86defs::Exception::GENERAL_PROTECTION_FAULT.0.into())
916 .with_deliver_error_code(true)
917 .with_error_code(0);
918
919 self.runner
920 .set_vp_register(
921 vtl,
922 HvX64RegisterName::PendingEvent0,
923 u128::from(exception_event).into(),
924 )
925 .expect("set_vp_register should succeed for pending event");
926 }
927
928 fn set_vsm_partition_config(
929 &mut self,
930 vtl: GuestVtl,
931 value: HvRegisterVsmPartitionConfig,
932 ) -> Result<(), HvError> {
933 if vtl != GuestVtl::Vtl1 {
934 return Err(HvError::InvalidParameter);
935 }
936
937 assert!(self.partition.isolation.is_isolated());
938
939 let status = self
940 .partition
941 .vsm_status()
942 .expect("cannot fail to query vsm status");
943
944 let vtl1_enabled = VtlSet::from(status.enabled_vtl_set()).is_set(GuestVtl::Vtl1);
945 if !vtl1_enabled {
946 return Err(HvError::InvalidVtlState);
947 }
948
949 let mut guest_vsm_lock = self.shared.guest_vsm.write();
950
951 match *guest_vsm_lock {
953 GuestVsmState::NotPlatformSupported => {
954 return Err(HvError::AccessDenied);
955 }
956 GuestVsmState::NotGuestEnabled => {
957 *guest_vsm_lock = GuestVsmState::Enabled {
959 vtl1: Default::default(),
960 };
961 }
962 GuestVsmState::Enabled { .. } => {}
963 }
964
965 let GuestVsmState::Enabled { vtl1 } = &mut *guest_vsm_lock else {
966 unreachable!()
967 };
968 let protections = HvMapGpaFlags::from(value.default_vtl_protection_mask() as u32);
969
970 if value.reserved() != 0 {
971 return Err(HvError::InvalidRegisterValue);
972 }
973
974 if !value.enable_vtl_protection() {
980 if vtl1.enable_vtl_protection {
981 return Err(HvError::InvalidRegisterValue);
985 } else {
986 panic!("unexpected SetVpRegisters intercept");
987 }
988 }
989
990 let mbec_enabled = VtlSet::from(status.mbec_enabled_vtl_set()).is_set(GuestVtl::Vtl0);
993 let shadow_supervisor_stack_enabled =
994 VtlSet::from(status.supervisor_shadow_stack_enabled_vtl_set() as u16)
995 .is_set(GuestVtl::Vtl0);
996
997 if !validate_vtl_gpa_flags(protections, mbec_enabled, shadow_supervisor_stack_enabled) {
998 return Err(HvError::InvalidRegisterValue);
999 }
1000
1001 if !(protections.readable() && protections.writable()) {
1003 return Err(HvError::InvalidRegisterValue);
1004 }
1005
1006 if let Some(current_protections) = vtl1.default_vtl_protections {
1008 if protections != current_protections {
1009 return Err(HvError::InvalidRegisterValue);
1010 }
1011 }
1012 vtl1.default_vtl_protections = Some(protections);
1013
1014 for ram_range in self.partition.lower_vtl_memory_layout.ram().iter() {
1015 self.partition
1016 .hcl
1017 .modify_vtl_protection_mask(ram_range.range, protections, vtl.into())
1018 .map_err(|e| match e {
1019 ApplyVtlProtectionsError::Hypervisor {
1020 range: _,
1021 output: _,
1022 hv_error,
1023 vtl: _,
1024 } => hv_error,
1025 _ => unreachable!(),
1026 })?;
1027 }
1028
1029 let hc_regs = [(HvX64RegisterName::VsmPartitionConfig, u64::from(value))];
1030 self.runner.set_vp_registers_hvcall(vtl.into(), hc_regs)?;
1031 vtl1.enable_vtl_protection = true;
1032
1033 Ok(())
1034 }
1035
1036 fn emulation_cache(&mut self, vtl: GuestVtl) -> MshvEmulationCache {
1040 const NAMES: &[HvX64RegisterName] = &[
1041 HvX64RegisterName::Rsp,
1042 HvX64RegisterName::Es,
1043 HvX64RegisterName::Ds,
1044 HvX64RegisterName::Fs,
1045 HvX64RegisterName::Gs,
1046 HvX64RegisterName::Ss,
1047 HvX64RegisterName::Cr0,
1048 HvX64RegisterName::Efer,
1049 ];
1050 let mut values = [FromZeros::new_zeroed(); NAMES.len()];
1051 self.runner
1052 .get_vp_registers(vtl, NAMES, &mut values)
1053 .expect("register query should not fail");
1054
1055 let [rsp, es, ds, fs, gs, ss, cr0, efer] = values;
1056
1057 let header = self
1058 .runner
1059 .exit_message()
1060 .as_message::<HvX64InterceptMessageHeader>();
1061
1062 MshvEmulationCache {
1063 rsp: rsp.as_u64(),
1064 es: from_seg(es.into()),
1065 ds: from_seg(ds.into()),
1066 fs: from_seg(fs.into()),
1067 gs: from_seg(gs.into()),
1068 ss: from_seg(ss.into()),
1069 cr0: cr0.as_u64(),
1070 efer: efer.as_u64(),
1071 rip: header.rip,
1072 rflags: header.rflags.into(),
1073 }
1074 }
1075}
1076
1077fn from_seg(reg: hvdef::HvX64SegmentRegister) -> SegmentRegister {
1078 SegmentRegister {
1079 base: reg.base,
1080 limit: reg.limit,
1081 selector: reg.selector,
1082 attributes: reg.attributes.into(),
1083 }
1084}
1085
1086impl<T: CpuIo> EmulatorSupport for UhEmulationState<'_, '_, T, HypervisorBackedX86> {
1087 fn flush(&mut self) {
1088 self.vp
1089 .runner
1090 .set_vp_registers(
1091 self.vtl,
1092 [
1093 (HvX64RegisterName::Rip, self.cache.rip),
1094 (HvX64RegisterName::Rflags, self.cache.rflags.into()),
1095 (HvX64RegisterName::Rsp, self.cache.rsp),
1096 ],
1097 )
1098 .unwrap();
1099 }
1100
1101 fn vp_index(&self) -> VpIndex {
1102 self.vp.vp_index()
1103 }
1104
1105 fn vendor(&self) -> x86defs::cpuid::Vendor {
1106 self.vp.partition.caps.vendor
1107 }
1108
1109 fn gp(&mut self, reg: x86emu::Gp) -> u64 {
1110 match reg {
1111 x86emu::Gp::RSP => self.cache.rsp,
1112 _ => self.vp.runner.cpu_context().gps_no_rsp[reg as usize],
1113 }
1114 }
1115
1116 fn set_gp(&mut self, reg: x86emu::Gp, v: u64) {
1117 match reg {
1118 x86emu::Gp::RSP => self.cache.rsp = v,
1119 _ => self.vp.runner.cpu_context_mut().gps_no_rsp[reg as usize] = v,
1120 }
1121 }
1122
1123 fn xmm(&mut self, index: usize) -> u128 {
1124 u128::from_le_bytes(self.vp.runner.cpu_context().fx_state.xmm[index])
1125 }
1126
1127 fn set_xmm(&mut self, index: usize, v: u128) {
1128 self.vp.runner.cpu_context_mut().fx_state.xmm[index] = v.to_le_bytes();
1129 }
1130
1131 fn rip(&mut self) -> u64 {
1132 self.cache.rip
1133 }
1134
1135 fn set_rip(&mut self, v: u64) {
1136 self.cache.rip = v;
1137 }
1138
1139 fn segment(&mut self, index: x86emu::Segment) -> SegmentRegister {
1140 match index {
1141 x86emu::Segment::CS => {
1142 let header = self
1143 .vp
1144 .runner
1145 .exit_message()
1146 .as_message::<HvX64InterceptMessageHeader>();
1147 from_seg(header.cs_segment)
1148 }
1149 x86emu::Segment::ES => self.cache.es,
1150 x86emu::Segment::SS => self.cache.ss,
1151 x86emu::Segment::DS => self.cache.ds,
1152 x86emu::Segment::FS => self.cache.fs,
1153 x86emu::Segment::GS => self.cache.gs,
1154 }
1155 }
1156
1157 fn efer(&mut self) -> u64 {
1158 self.cache.efer
1159 }
1160
1161 fn cr0(&mut self) -> u64 {
1162 self.cache.cr0
1163 }
1164
1165 fn rflags(&mut self) -> RFlags {
1166 self.cache.rflags
1167 }
1168
1169 fn set_rflags(&mut self, v: RFlags) {
1170 self.cache.rflags = v;
1171 }
1172
1173 fn instruction_bytes(&self) -> &[u8] {
1174 let message = self.vp.runner.exit_message();
1175 match message.header.typ {
1176 HvMessageType::HvMessageTypeGpaIntercept
1177 | HvMessageType::HvMessageTypeUnmappedGpa
1178 | HvMessageType::HvMessageTypeUnacceptedGpa => {
1179 let message = message.as_message::<hvdef::HvX64MemoryInterceptMessage>();
1180 &message.instruction_bytes[..message.instruction_byte_count as usize]
1181 }
1182 HvMessageType::HvMessageTypeX64IoPortIntercept => {
1183 let message = message.as_message::<hvdef::HvX64IoPortInterceptMessage>();
1184 &message.instruction_bytes[..message.instruction_byte_count as usize]
1185 }
1186 _ => unreachable!(),
1187 }
1188 }
1189
1190 fn physical_address(&self) -> Option<u64> {
1191 let message = self.vp.runner.exit_message();
1192 match message.header.typ {
1193 HvMessageType::HvMessageTypeGpaIntercept
1194 | HvMessageType::HvMessageTypeUnmappedGpa
1195 | HvMessageType::HvMessageTypeUnacceptedGpa => {
1196 let message = message.as_message::<hvdef::HvX64MemoryInterceptMessage>();
1197 Some(message.guest_physical_address)
1198 }
1199 _ => None,
1200 }
1201 }
1202
1203 fn initial_gva_translation(
1204 &mut self,
1205 ) -> Option<virt_support_x86emu::emulate::InitialTranslation> {
1206 if (self.vp.runner.exit_message().header.typ != HvMessageType::HvMessageTypeGpaIntercept)
1207 && (self.vp.runner.exit_message().header.typ != HvMessageType::HvMessageTypeUnmappedGpa)
1208 && (self.vp.runner.exit_message().header.typ
1209 != HvMessageType::HvMessageTypeUnacceptedGpa)
1210 {
1211 return None;
1212 }
1213
1214 let message = self
1215 .vp
1216 .runner
1217 .exit_message()
1218 .as_message::<hvdef::HvX64MemoryInterceptMessage>();
1219
1220 if !message.memory_access_info.gva_gpa_valid() {
1221 tracing::trace!(?message.guest_virtual_address, ?message.guest_physical_address, "gva gpa not valid {:?}", self.vp.runner.exit_message().payload());
1222 return None;
1223 }
1224
1225 let translate_mode = virt_support_x86emu::emulate::TranslateMode::try_from(
1226 message.header.intercept_access_type,
1227 )
1228 .expect("unexpected intercept access type");
1229
1230 let translation = virt_support_x86emu::emulate::InitialTranslation {
1231 gva: message.guest_virtual_address,
1232 gpa: message.guest_physical_address,
1233 translate_mode,
1234 };
1235
1236 tracing::trace!(?translation, "initial translation");
1237
1238 self.vp.mark_tlb_locked(Vtl::Vtl2, self.vtl);
1242
1243 Some(translation)
1244 }
1245
1246 fn interruption_pending(&self) -> bool {
1247 self.interruption_pending
1248 }
1249
1250 fn check_vtl_access(
1251 &mut self,
1252 gpa: u64,
1253 mode: virt_support_x86emu::emulate::TranslateMode,
1254 ) -> Result<(), EmuCheckVtlAccessError> {
1255 if mode == virt_support_x86emu::emulate::TranslateMode::Execute
1269 && self.vtl == GuestVtl::Vtl0
1270 && !matches!(
1271 *self.vp.shared.guest_vsm.read(),
1272 GuestVsmState::NotPlatformSupported,
1273 )
1274 {
1275 debug_assert!(self.vp.is_tlb_locked(Vtl::Vtl2, self.vtl));
1278
1279 if !self.vp.partition.is_gpa_lower_vtl_ram(gpa) {
1284 return Ok(());
1285 }
1286
1287 let mbec_user_execute = self
1288 .vp
1289 .runner
1290 .get_vp_register(self.vtl, HvX64RegisterName::InstructionEmulationHints)
1291 .unwrap();
1292
1293 let flags =
1294 if hvdef::HvInstructionEmulatorHintsRegister::from(mbec_user_execute.as_u64())
1295 .mbec_user_execute_control()
1296 {
1297 HvMapGpaFlags::new().with_user_executable(true)
1298 } else {
1299 HvMapGpaFlags::new().with_kernel_executable(true)
1300 };
1301
1302 let access_result = self
1303 .vp
1304 .partition
1305 .hcl
1306 .check_vtl_access(gpa, self.vtl, flags)
1307 .unwrap();
1308
1309 if let Some(ioctl::CheckVtlAccessResult { vtl, denied_flags }) = access_result {
1310 return Err(EmuCheckVtlAccessError::AccessDenied { vtl, denied_flags });
1311 };
1312 }
1313
1314 Ok(())
1315 }
1316
1317 fn translate_gva(
1318 &mut self,
1319 gva: u64,
1320 mode: virt_support_x86emu::emulate::TranslateMode,
1321 ) -> Result<EmuTranslateResult, EmuTranslateError> {
1322 let mut control_flags = hypercall::TranslateGvaControlFlagsX64::new();
1323 match mode {
1324 virt_support_x86emu::emulate::TranslateMode::Read => {
1325 control_flags.set_validate_read(true)
1326 }
1327 virt_support_x86emu::emulate::TranslateMode::Write => {
1328 control_flags.set_validate_read(true);
1329 control_flags.set_validate_write(true);
1330 }
1331 virt_support_x86emu::emulate::TranslateMode::Execute => {
1332 control_flags.set_validate_execute(true)
1333 }
1334 };
1335
1336 control_flags.set_set_page_table_bits(true);
1342 control_flags.set_tlb_flush_inhibit(true);
1343
1344 assert!(!control_flags.privilege_exempt());
1351
1352 control_flags.set_input_vtl(self.vtl.into());
1354
1355 match self
1356 .vp
1357 .runner
1358 .translate_gva_to_gpa(gva, control_flags)
1359 .unwrap()
1360 {
1361 Ok(ioctl::TranslateResult {
1362 gpa_page,
1363 overlay_page,
1364 }) => {
1365 self.vp.mark_tlb_locked(Vtl::Vtl2, self.vtl);
1366 Ok(EmuTranslateResult {
1367 gpa: (gpa_page << hvdef::HV_PAGE_SHIFT) + (gva & (HV_PAGE_SIZE - 1)),
1368 overlay_page: Some(overlay_page),
1369 })
1370 }
1371 Err(ioctl::x64::TranslateErrorX64 { code, event_info }) => Err(EmuTranslateError {
1372 code: hypercall::TranslateGvaResultCode(code),
1373 event_info: Some(event_info),
1374 }),
1375 }
1376 }
1377
1378 fn inject_pending_event(&mut self, event_info: HvX64PendingEvent) {
1379 let regs = [
1380 (
1381 HvX64RegisterName::PendingEvent0,
1382 u128::from(event_info.reg_0),
1383 ),
1384 (
1385 HvX64RegisterName::PendingEvent1,
1386 u128::from(event_info.reg_1),
1387 ),
1388 ];
1389
1390 self.vp
1391 .runner
1392 .set_vp_registers_hvcall(self.vtl.into(), regs)
1393 .expect("set_vp_registers hypercall for setting pending event should not fail");
1394 }
1395
1396 fn monitor_support(&self) -> Option<&dyn EmulatorMonitorSupport> {
1397 Some(self)
1398 }
1399
1400 fn is_gpa_mapped(&self, gpa: u64, write: bool) -> bool {
1401 self.vp.partition.is_gpa_mapped(gpa, write)
1402 }
1403
1404 fn lapic_base_address(&self) -> Option<u64> {
1405 None
1406 }
1407
1408 fn lapic_read(&mut self, _address: u64, _data: &mut [u8]) {
1409 unimplemented!()
1410 }
1411
1412 fn lapic_write(&mut self, _address: u64, _data: &[u8]) {
1413 unimplemented!()
1414 }
1415}
1416
1417impl UhHypercallHandler<'_, '_, HypervisorBackedX86> {
1418 const MSHV_DISPATCHER: hv1_hypercall::Dispatcher<Self> = hv1_hypercall::dispatcher!(
1419 Self,
1420 [
1421 hv1_hypercall::HvPostMessage,
1422 hv1_hypercall::HvSignalEvent,
1423 hv1_hypercall::HvRetargetDeviceInterrupt,
1424 hv1_hypercall::HvGetVpIndexFromApicId,
1425 hv1_hypercall::HvSetVpRegisters,
1426 hv1_hypercall::HvModifyVtlProtectionMask,
1427 hv1_hypercall::HvRestorePartitionTime,
1428 ]
1429 );
1430}
1431
1432impl hv1_hypercall::X64RegisterState for UhHypercallHandler<'_, '_, HypervisorBackedX86> {
1433 fn rip(&mut self) -> u64 {
1434 self.vp
1435 .runner
1436 .exit_message()
1437 .as_message::<HvX64InterceptMessageHeader>()
1438 .rip
1439 }
1440
1441 fn set_rip(&mut self, rip: u64) {
1442 self.vp.set_rip(self.intercepted_vtl, rip)
1443 }
1444
1445 fn gp(&mut self, n: hv1_hypercall::X64HypercallRegister) -> u64 {
1446 self.vp.runner.cpu_context().gps_no_rsp[n as usize]
1448 }
1449
1450 fn set_gp(&mut self, n: hv1_hypercall::X64HypercallRegister, value: u64) {
1451 self.vp.runner.cpu_context_mut().gps_no_rsp[n as usize] = value;
1453 }
1454
1455 fn xmm(&mut self, n: usize) -> u128 {
1456 u128::from_ne_bytes(self.vp.runner.cpu_context().fx_state.xmm[n])
1457 }
1458
1459 fn set_xmm(&mut self, n: usize, value: u128) {
1460 self.vp.runner.cpu_context_mut().fx_state.xmm[n] = value.to_ne_bytes();
1461 }
1462}
1463
1464trait ToVpRegisterName: 'static + Copy + std::fmt::Debug {
1465 fn to_vp_reg_name(self) -> VpRegisterName;
1466}
1467
1468impl ToVpRegisterName for VpRegisterName {
1469 fn to_vp_reg_name(self) -> VpRegisterName {
1470 self
1471 }
1472}
1473
1474impl UhVpStateAccess<'_, '_, HypervisorBackedX86> {
1475 fn set_register_state<T, R: ToVpRegisterName, const N: usize>(
1476 &mut self,
1477 regs: &T,
1478 ) -> Result<(), vp_state::Error>
1479 where
1480 T: HvRegisterState<R, N>,
1481 {
1482 let names = regs.names().map(|r| r.to_vp_reg_name());
1483 let mut values = [HvRegisterValue::new_zeroed(); N];
1484 regs.get_values(values.iter_mut());
1485 self.vp
1486 .runner
1487 .set_vp_registers(self.vtl, names.iter().copied().zip(values))
1488 .map_err(vp_state::Error::SetRegisters)?;
1489 Ok(())
1490 }
1491
1492 fn get_register_state<T, R: ToVpRegisterName, const N: usize>(
1493 &mut self,
1494 ) -> Result<T, vp_state::Error>
1495 where
1496 T: HvRegisterState<R, N>,
1497 {
1498 let mut regs = T::default();
1499 let names = regs.names().map(|r| r.to_vp_reg_name());
1500 let mut values = [HvRegisterValue::new_zeroed(); N];
1501 self.vp
1502 .runner
1503 .get_vp_registers(self.vtl, &names, &mut values)
1504 .map_err(vp_state::Error::GetRegisters)?;
1505
1506 regs.set_values(values.into_iter());
1507 Ok(regs)
1508 }
1509}
1510
1511impl AccessVpState for UhVpStateAccess<'_, '_, HypervisorBackedX86> {
1512 type Error = vp_state::Error;
1513
1514 fn caps(&self) -> &virt::x86::X86PartitionCapabilities {
1515 &self.vp.partition.caps
1516 }
1517
1518 fn commit(&mut self) -> Result<(), Self::Error> {
1519 Ok(())
1520 }
1521
1522 fn registers(&mut self) -> Result<vp::Registers, Self::Error> {
1523 self.get_register_state()
1524 }
1525
1526 fn set_registers(&mut self, value: &vp::Registers) -> Result<(), Self::Error> {
1527 self.set_register_state(value)
1528 }
1529
1530 fn activity(&mut self) -> Result<vp::Activity, Self::Error> {
1531 let activity: vp::Activity = self.get_register_state()?;
1532
1533 Ok(activity)
1537 }
1538
1539 fn set_activity(&mut self, value: &vp::Activity) -> Result<(), Self::Error> {
1540 self.set_register_state(value)?;
1541
1542 Ok(())
1547 }
1548
1549 fn xsave(&mut self) -> Result<vp::Xsave, Self::Error> {
1550 #[repr(C)]
1554 #[derive(IntoBytes, Immutable, KnownLayout)]
1555 struct XsaveStandard {
1556 fxsave: Fxsave,
1557 xsave_header: XsaveHeader,
1558 }
1559 let state = XsaveStandard {
1560 fxsave: self.vp.runner.cpu_context().fx_state.clone(),
1561 xsave_header: XsaveHeader {
1562 xstate_bv: XFEATURE_X87 | XFEATURE_SSE,
1563 ..FromZeros::new_zeroed()
1564 },
1565 };
1566 Ok(vp::Xsave::from_standard(state.as_bytes(), self.caps()))
1567 }
1568
1569 fn set_xsave(&mut self, _value: &vp::Xsave) -> Result<(), Self::Error> {
1570 Err(vp_state::Error::Unimplemented("xsave"))
1571 }
1572
1573 fn apic(&mut self) -> Result<vp::Apic, Self::Error> {
1574 Err(vp_state::Error::Unimplemented("apic"))
1575 }
1576
1577 fn set_apic(&mut self, _value: &vp::Apic) -> Result<(), Self::Error> {
1578 Err(vp_state::Error::Unimplemented("apic"))
1579 }
1580
1581 fn xcr(&mut self) -> Result<vp::Xcr0, Self::Error> {
1582 self.get_register_state()
1583 }
1584
1585 fn set_xcr(&mut self, value: &vp::Xcr0) -> Result<(), Self::Error> {
1586 self.set_register_state(value)
1587 }
1588
1589 fn xss(&mut self) -> Result<vp::Xss, Self::Error> {
1590 self.get_register_state()
1591 }
1592
1593 fn set_xss(&mut self, value: &vp::Xss) -> Result<(), Self::Error> {
1594 self.set_register_state(value)
1595 }
1596
1597 fn mtrrs(&mut self) -> Result<vp::Mtrrs, Self::Error> {
1598 self.get_register_state()
1599 }
1600
1601 fn set_mtrrs(&mut self, cc: &vp::Mtrrs) -> Result<(), Self::Error> {
1602 self.set_register_state(cc)
1603 }
1604
1605 fn pat(&mut self) -> Result<vp::Pat, Self::Error> {
1606 self.get_register_state()
1607 }
1608
1609 fn set_pat(&mut self, value: &vp::Pat) -> Result<(), Self::Error> {
1610 self.set_register_state(value)
1611 }
1612
1613 fn virtual_msrs(&mut self) -> Result<vp::VirtualMsrs, Self::Error> {
1614 self.get_register_state()
1615 }
1616
1617 fn set_virtual_msrs(&mut self, msrs: &vp::VirtualMsrs) -> Result<(), Self::Error> {
1618 self.set_register_state(msrs)
1619 }
1620
1621 fn debug_regs(&mut self) -> Result<vp::DebugRegisters, Self::Error> {
1622 self.get_register_state()
1623 }
1624
1625 fn set_debug_regs(&mut self, value: &vp::DebugRegisters) -> Result<(), Self::Error> {
1626 self.set_register_state(value)
1627 }
1628
1629 fn tsc(&mut self) -> Result<vp::Tsc, Self::Error> {
1630 self.get_register_state()
1631 }
1632
1633 fn set_tsc(&mut self, value: &vp::Tsc) -> Result<(), Self::Error> {
1634 self.set_register_state(value)
1635 }
1636
1637 fn cet(&mut self) -> Result<vp::Cet, Self::Error> {
1638 self.get_register_state()
1639 }
1640
1641 fn set_cet(&mut self, value: &vp::Cet) -> Result<(), Self::Error> {
1642 self.set_register_state(value)
1643 }
1644
1645 fn cet_ss(&mut self) -> Result<vp::CetSs, Self::Error> {
1646 self.get_register_state()
1647 }
1648
1649 fn set_cet_ss(&mut self, value: &vp::CetSs) -> Result<(), Self::Error> {
1650 self.set_register_state(value)
1651 }
1652
1653 fn tsc_aux(&mut self) -> Result<vp::TscAux, Self::Error> {
1654 self.get_register_state()
1655 }
1656
1657 fn set_tsc_aux(&mut self, value: &vp::TscAux) -> Result<(), Self::Error> {
1658 self.set_register_state(value)
1659 }
1660
1661 fn synic_msrs(&mut self) -> Result<vp::SyntheticMsrs, Self::Error> {
1662 self.get_register_state()
1663 }
1664
1665 fn set_synic_msrs(&mut self, value: &vp::SyntheticMsrs) -> Result<(), Self::Error> {
1666 self.set_register_state(value)
1667 }
1668
1669 fn synic_timers(&mut self) -> Result<vp::SynicTimers, Self::Error> {
1670 Err(vp_state::Error::Unimplemented("synic_timers"))
1671 }
1672
1673 fn set_synic_timers(&mut self, _value: &vp::SynicTimers) -> Result<(), Self::Error> {
1674 Err(vp_state::Error::Unimplemented("synic_timers"))
1675 }
1676
1677 fn synic_message_queues(&mut self) -> Result<vp::SynicMessageQueues, Self::Error> {
1678 Ok(self.vp.inner.message_queues[self.vtl].save())
1679 }
1680
1681 fn set_synic_message_queues(
1682 &mut self,
1683 value: &vp::SynicMessageQueues,
1684 ) -> Result<(), Self::Error> {
1685 self.vp.inner.message_queues[self.vtl].restore(value);
1686 Ok(())
1687 }
1688
1689 fn synic_message_page(&mut self) -> Result<vp::SynicMessagePage, Self::Error> {
1690 Err(vp_state::Error::Unimplemented("synic_message_page"))
1691 }
1692
1693 fn set_synic_message_page(&mut self, _value: &vp::SynicMessagePage) -> Result<(), Self::Error> {
1694 Err(vp_state::Error::Unimplemented("synic_message_page"))
1695 }
1696
1697 fn synic_event_flags_page(&mut self) -> Result<vp::SynicEventFlagsPage, Self::Error> {
1698 Err(vp_state::Error::Unimplemented("synic_event_flags_page"))
1699 }
1700
1701 fn set_synic_event_flags_page(
1702 &mut self,
1703 _value: &vp::SynicEventFlagsPage,
1704 ) -> Result<(), Self::Error> {
1705 Err(vp_state::Error::Unimplemented("synic_event_flags_page"))
1706 }
1707
1708 fn nested_state(&mut self) -> Result<vp::NestedState, Self::Error> {
1709 Err(vp_state::Error::Unimplemented("nested_state"))
1710 }
1711
1712 fn set_nested_state(&mut self, _value: &vp::NestedState) -> Result<(), Self::Error> {
1713 Err(vp_state::Error::Unimplemented("nested_state"))
1714 }
1715}
1716
1717impl hv1_hypercall::RetargetDeviceInterrupt for UhHypercallHandler<'_, '_, HypervisorBackedX86> {
1718 fn retarget_interrupt(
1719 &mut self,
1720 device_id: u64,
1721 address: u64,
1722 data: u32,
1723 params: hv1_hypercall::HvInterruptParameters<'_>,
1724 ) -> hvdef::HvResult<()> {
1725 self.retarget_virtual_interrupt(
1726 device_id,
1727 address,
1728 data,
1729 params.vector,
1730 params.multicast,
1731 params.target_processors,
1732 )
1733 }
1734}
1735
1736impl hv1_hypercall::SetVpRegisters for UhHypercallHandler<'_, '_, HypervisorBackedX86> {
1737 fn set_vp_registers(
1738 &mut self,
1739 partition_id: u64,
1740 vp_index: u32,
1741 vtl: Option<Vtl>,
1742 registers: &[hypercall::HvRegisterAssoc],
1743 ) -> HvRepResult {
1744 if partition_id != hvdef::HV_PARTITION_ID_SELF {
1745 return Err((HvError::AccessDenied, 0));
1746 }
1747
1748 if vp_index != hvdef::HV_VP_INDEX_SELF && vp_index != self.vp.vp_index().index() {
1749 return Err((HvError::InvalidVpIndex, 0));
1750 }
1751
1752 let target_vtl = self
1753 .target_vtl_no_higher(vtl.unwrap_or(self.intercepted_vtl.into()))
1754 .map_err(|e| (e, 0))?;
1755
1756 for (i, reg) in registers.iter().enumerate() {
1757 if reg.name == HvX64RegisterName::VsmPartitionConfig.into() {
1758 let value = HvRegisterVsmPartitionConfig::from(reg.value.as_u64());
1759 self.vp
1760 .set_vsm_partition_config(target_vtl, value)
1761 .map_err(|e| (e, i))?;
1762 } else {
1763 return Err((HvError::InvalidParameter, i));
1764 }
1765 }
1766
1767 Ok(())
1768 }
1769}
1770
1771impl hv1_hypercall::ModifyVtlProtectionMask for UhHypercallHandler<'_, '_, HypervisorBackedX86> {
1772 fn modify_vtl_protection_mask(
1773 &mut self,
1774 partition_id: u64,
1775 _map_flags: HvMapGpaFlags,
1776 target_vtl: Option<Vtl>,
1777 gpa_pages: &[u64],
1778 ) -> HvRepResult {
1779 if partition_id != hvdef::HV_PARTITION_ID_SELF {
1780 return Err((HvError::AccessDenied, 0));
1781 }
1782
1783 let target_vtl = self
1784 .target_vtl_no_higher(target_vtl.unwrap_or(self.intercepted_vtl.into()))
1785 .map_err(|e| (e, 0))?;
1786 if target_vtl == GuestVtl::Vtl0 {
1787 return Err((HvError::InvalidParameter, 0));
1788 }
1789
1790 if target_vtl == self.intercepted_vtl
1794 && !matches!(
1795 *self.vp.shared.guest_vsm.read(),
1796 GuestVsmState::Enabled {
1797 vtl1: VbsIsolatedVtl1State {
1798 enable_vtl_protection: true,
1799 default_vtl_protections: Some(_),
1800 },
1801 }
1802 )
1803 {
1804 return Err((HvError::AccessDenied, 0));
1805 }
1806
1807 if self.vp.partition.isolation.is_isolated() {
1813 return Err((HvError::OperationDenied, 0));
1814 } else {
1815 if !gpa_pages.is_empty() {
1816 if !self.vp.partition.is_gpa_lower_vtl_ram(gpa_pages[0]) {
1817 return Err((HvError::OperationDenied, 0));
1818 } else {
1819 panic!("Should not be handling this hypercall for guest ram");
1820 }
1821 }
1822 }
1823
1824 Ok(())
1825 }
1826}
1827
1828mod save_restore {
1829 use super::HypervisorBackedX86;
1830 use super::UhProcessor;
1831 use anyhow::Context;
1832 use hcl::GuestVtl;
1833 use hvdef::HV_X64_MSR_GUEST_CRASH_CTL;
1834 use hvdef::HvInternalActivityRegister;
1835 use hvdef::HvX64RegisterName;
1836 use hvdef::Vtl;
1837 use virt::Processor;
1838 use virt::vp::AccessVpState;
1839 use virt::vp::Mtrrs;
1840 use vmcore::save_restore::RestoreError;
1841 use vmcore::save_restore::SaveError;
1842 use vmcore::save_restore::SaveRestore;
1843 use zerocopy::FromZeros;
1844 use zerocopy::IntoBytes;
1845
1846 mod state {
1847 use mesh::payload::Protobuf;
1848 use vmcore::save_restore::SavedStateRoot;
1849
1850 #[derive(Protobuf, SavedStateRoot)]
1851 #[mesh(package = "underhill.partition")]
1852 pub struct ProcessorSavedState {
1853 #[mesh(1)]
1854 pub(super) rax: u64,
1855 #[mesh(2)]
1856 pub(super) rcx: u64,
1857 #[mesh(3)]
1858 pub(super) rdx: u64,
1859 #[mesh(4)]
1860 pub(super) rbx: u64,
1861 #[mesh(5)]
1862 pub(super) cr2: u64,
1863 #[mesh(6)]
1864 pub(super) rbp: u64,
1865 #[mesh(7)]
1866 pub(super) rsi: u64,
1867 #[mesh(8)]
1868 pub(super) rdi: u64,
1869 #[mesh(9)]
1870 pub(super) r8: u64,
1871 #[mesh(10)]
1872 pub(super) r9: u64,
1873 #[mesh(11)]
1874 pub(super) r10: u64,
1875 #[mesh(12)]
1876 pub(super) r11: u64,
1877 #[mesh(13)]
1878 pub(super) r12: u64,
1879 #[mesh(14)]
1880 pub(super) r13: u64,
1881 #[mesh(15)]
1882 pub(super) r14: u64,
1883 #[mesh(16)]
1884 pub(super) r15: u64,
1885 #[mesh(17)]
1886 pub(super) fx_state: Vec<u8>,
1887 #[mesh(18)]
1888 pub(super) dr0: u64,
1889 #[mesh(19)]
1890 pub(super) dr1: u64,
1891 #[mesh(20)]
1892 pub(super) dr2: u64,
1893 #[mesh(21)]
1894 pub(super) dr3: u64,
1895
1896 #[mesh(22)]
1898 pub(super) dr6: Option<u64>,
1899
1900 #[mesh(23)]
1904 pub(super) startup_suspend: Option<bool>,
1905
1906 #[mesh(24)]
1907 pub(super) crash_reg: Option<[u64; 5]>,
1908
1909 #[mesh(25)]
1912 pub(super) crash_control: u64,
1913
1914 #[mesh(26)]
1915 pub(super) msr_mtrr_def_type: u64,
1916 #[mesh(27)]
1917 pub(super) fixed_mtrrs: Option<[u64; 11]>,
1918 #[mesh(28)]
1919 pub(super) variable_mtrrs: Option<[u64; 16]>,
1920 #[mesh(29)]
1921 pub(super) per_vtl: Vec<ProcessorVtlSavedState>,
1922 }
1923
1924 #[derive(Protobuf, SavedStateRoot)]
1925 #[mesh(package = "underhill.partition")]
1926 pub struct ProcessorVtlSavedState {
1927 #[mesh(1)]
1928 pub(super) message_queue: virt::vp::SynicMessageQueues,
1929 }
1930 }
1931
1932 const SHARED_REGISTERS: &[HvX64RegisterName] = &[
1933 HvX64RegisterName::Dr0,
1934 HvX64RegisterName::Dr1,
1935 HvX64RegisterName::Dr2,
1936 HvX64RegisterName::Dr3,
1937 HvX64RegisterName::Dr6, ];
1939
1940 impl SaveRestore for UhProcessor<'_, HypervisorBackedX86> {
1941 type SavedState = state::ProcessorSavedState;
1942
1943 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
1944 self.flush_async_requests();
1946
1947 let dr6_shared = self.partition.hcl.dr6_shared();
1948 let mut values = [FromZeros::new_zeroed(); SHARED_REGISTERS.len()];
1949 let len = if dr6_shared {
1950 SHARED_REGISTERS.len()
1951 } else {
1952 SHARED_REGISTERS.len() - 1
1953 };
1954
1955 self.runner
1956 .get_vp_registers(GuestVtl::Vtl0, &SHARED_REGISTERS[..len], &mut values[..len])
1958 .context("failed to get shared registers")
1959 .map_err(SaveError::Other)?;
1960
1961 let [
1962 rax,
1963 rcx,
1964 rdx,
1965 rbx,
1966 cr2,
1967 rbp,
1968 rsi,
1969 rdi,
1970 r8,
1971 r9,
1972 r10,
1973 r11,
1974 r12,
1975 r13,
1976 r14,
1977 r15,
1978 ] = self.runner.cpu_context().gps_no_rsp;
1979
1980 let Mtrrs {
1983 msr_mtrr_def_type,
1984 fixed: fixed_mtrrs,
1985 variable: variable_mtrrs,
1986 } = self
1987 .access_state(Vtl::Vtl0)
1989 .mtrrs()
1990 .context("failed to get MTRRs")
1991 .map_err(SaveError::Other)?;
1992
1993 let crash_control = self
1996 .read_crash_msr(HV_X64_MSR_GUEST_CRASH_CTL, GuestVtl::Vtl0)
1997 .unwrap();
1998
1999 let UhProcessor {
2000 _not_send,
2001 inner:
2002 crate::UhVpInner {
2003 message_queues,
2005 sidecar_exit_reason: _,
2007 wake_reasons: _,
2009 waker: _,
2011 vp_info: _,
2013 cpu_index: _,
2014 },
2015 crash_reg,
2017 partition: _,
2019 idle_control: _,
2020 vmtime: _,
2021 timer: _,
2022 force_exit_sidecar: _,
2024 signaled_sidecar_exit: _,
2025 vtls_tlb_locked: _,
2027 kernel_returns: _,
2029 shared: _,
2031 runner: _,
2033 backing:
2034 HypervisorBackedX86 {
2035 deliverability_notifications: _,
2036 next_deliverability_notifications: _,
2037 stats: _,
2038 deferred_init,
2039 },
2040 exit_activities: _,
2042 } = *self;
2043
2044 let startup_suspend = if deferred_init {
2047 Some(true)
2048 } else {
2049 let internal_activity = self
2050 .runner
2051 .get_vp_register(GuestVtl::Vtl0, HvX64RegisterName::InternalActivityState)
2052 .inspect_err(|e| {
2053 tracing::warn!(
2057 error = e as &dyn std::error::Error,
2058 "unable to query startup suspend, unable to save VTL0 startup suspend state"
2059 );
2060 })
2061 .ok();
2062
2063 internal_activity
2064 .map(|a| HvInternalActivityRegister::from(a.as_u64()).startup_suspend())
2065 };
2066
2067 let per_vtl = [GuestVtl::Vtl0, GuestVtl::Vtl1]
2068 .map(|vtl| state::ProcessorVtlSavedState {
2069 message_queue: message_queues[vtl].save(),
2070 })
2071 .into();
2072
2073 let state = state::ProcessorSavedState {
2074 rax,
2075 rcx,
2076 rdx,
2077 rbx,
2078 cr2,
2079 rbp,
2080 rsi,
2081 rdi,
2082 r8,
2083 r9,
2084 r10,
2085 r11,
2086 r12,
2087 r13,
2088 r14,
2089 r15,
2090 fx_state: self.runner.cpu_context().fx_state.as_bytes().to_vec(),
2091 dr0: values[0].as_u64(),
2092 dr1: values[1].as_u64(),
2093 dr2: values[2].as_u64(),
2094 dr3: values[3].as_u64(),
2095 dr6: dr6_shared.then(|| values[4].as_u64()),
2096 startup_suspend,
2097 crash_reg: Some(crash_reg),
2098 crash_control,
2099 msr_mtrr_def_type,
2100 fixed_mtrrs: Some(fixed_mtrrs),
2101 variable_mtrrs: Some(variable_mtrrs),
2102 per_vtl,
2103 };
2104
2105 Ok(state)
2106 }
2107
2108 fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
2109 let state::ProcessorSavedState {
2110 rax,
2111 rcx,
2112 rdx,
2113 rbx,
2114 cr2,
2115 rbp,
2116 rsi,
2117 rdi,
2118 r8,
2119 r9,
2120 r10,
2121 r11,
2122 r12,
2123 r13,
2124 r14,
2125 r15,
2126 fx_state,
2127 dr0,
2128 dr1,
2129 dr2,
2130 dr3,
2131 dr6,
2132 startup_suspend,
2133 crash_reg,
2134 crash_control: _crash_control,
2135 msr_mtrr_def_type,
2136 fixed_mtrrs,
2137 variable_mtrrs,
2138 per_vtl,
2139 } = state;
2140
2141 let dr6_shared = self.partition.hcl.dr6_shared();
2142 self.runner.cpu_context_mut().gps_no_rsp = [
2143 rax, rcx, rdx, rbx, cr2, rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15,
2144 ];
2145 if fx_state.len() != self.runner.cpu_context_mut().fx_state.as_bytes().len() {
2146 return Err(RestoreError::InvalidSavedState(anyhow::anyhow!(
2147 "invalid fpu state"
2148 )));
2149 }
2150 if dr6_shared != state.dr6.is_some() {
2151 return Err(RestoreError::InvalidSavedState(anyhow::anyhow!(
2152 "dr6 state mismatch"
2153 )));
2154 }
2155
2156 let len = if dr6_shared {
2157 SHARED_REGISTERS.len()
2158 } else {
2159 SHARED_REGISTERS.len() - 1
2160 };
2161
2162 let values = [dr0, dr1, dr2, dr3, dr6.unwrap_or(0)];
2163 self.runner
2164 .set_vp_registers(
2165 GuestVtl::Vtl0,
2166 SHARED_REGISTERS[..len].iter().copied().zip(values),
2167 )
2168 .context("failed to set shared registers")
2169 .map_err(RestoreError::Other)?;
2170
2171 self.runner
2172 .cpu_context_mut()
2173 .fx_state
2174 .as_mut_bytes()
2175 .copy_from_slice(&fx_state);
2176
2177 self.crash_reg = crash_reg.unwrap_or_default();
2178
2179 if let (Some(fixed), Some(variable)) = (fixed_mtrrs, variable_mtrrs) {
2183 let mut access = self.access_state(Vtl::Vtl0);
2184 access
2185 .set_mtrrs(&Mtrrs {
2186 msr_mtrr_def_type,
2187 fixed,
2188 variable,
2189 })
2190 .context("failed to set MTRRs")
2191 .map_err(RestoreError::Other)?;
2192 }
2193
2194 for (per, vtl) in per_vtl.into_iter().zip(0u8..) {
2195 let vtl = GuestVtl::try_from(vtl)
2196 .context("too many vtls")
2197 .map_err(RestoreError::Other)?;
2198 self.inner.message_queues[vtl].restore(&per.message_queue);
2199 }
2200
2201 let startup_suspend = match startup_suspend {
2202 Some(true) => {
2203 true
2209 }
2210 None if !self.vp_index().is_bsp() => {
2211 const NAMES: [HvX64RegisterName; 4] = [
2216 HvX64RegisterName::Rip,
2217 HvX64RegisterName::Rflags,
2218 HvX64RegisterName::Cr0,
2219 HvX64RegisterName::Efer,
2220 ];
2221 let mut values = [FromZeros::new_zeroed(); NAMES.len()];
2222 self.runner
2223 .get_vp_registers(GuestVtl::Vtl0, &NAMES, &mut values)
2225 .context("failed to get VP registers for startup suspend log")
2226 .map_err(RestoreError::Other)?;
2227 let [rip, rflags, cr0, efer] = values.map(|reg| reg.as_u64());
2228
2229 tracing::error!(
2230 vp_index = self.vp_index().index(),
2231 rip,
2232 rflags,
2233 cr0,
2234 efer,
2235 "previous version of underhill did not save startup_suspend state"
2236 );
2237
2238 false
2239 }
2240 Some(false) | None => false,
2241 };
2242
2243 self.backing.deferred_init = match self.set_vtl0_startup_suspend(startup_suspend) {
2244 Ok(()) => false,
2245 Err(e) => {
2246 if startup_suspend {
2247 tracing::warn!(
2248 error = &e as &dyn std::error::Error,
2249 "unable to set internal activity register, falling back to deferred init"
2250 );
2251 }
2252 startup_suspend
2253 }
2254 };
2255 Ok(())
2256 }
2257 }
2258}