virt_mshv/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Linux /dev/mshv implementation of the virt::generic interfaces.
5
6#![cfg(all(target_os = "linux", guest_is_native, guest_arch = "x86_64"))]
7#![expect(missing_docs)]
8// UNSAFETY: Calling HV APIs and manually managing memory.
9#![expect(unsafe_code)]
10
11mod vm_state;
12mod vp_state;
13
14use arrayvec::ArrayVec;
15use guestmem::DoorbellRegistration;
16use guestmem::GuestMemory;
17use hv1_emulator::message_queues::MessageQueues;
18use hv1_hypercall::X64RegisterIo;
19use hvdef::HV_PAGE_SHIFT;
20use hvdef::HvDeliverabilityNotificationsRegister;
21use hvdef::HvError;
22use hvdef::HvMessage;
23use hvdef::HvMessageType;
24use hvdef::HvX64RegisterName;
25use hvdef::HvX64VpExecutionState;
26use hvdef::Vtl;
27use hvdef::hypercall::HV_INTERCEPT_ACCESS_MASK_EXECUTE;
28use hvdef::hypercall::HvRegisterAssoc;
29use inspect::Inspect;
30use inspect::InspectMut;
31use mshv_bindings::MSHV_SET_MEM_BIT_EXECUTABLE;
32use mshv_bindings::MSHV_SET_MEM_BIT_WRITABLE;
33use mshv_bindings::hv_message;
34use mshv_bindings::hv_register_assoc;
35use mshv_bindings::hv_register_value;
36use mshv_bindings::hv_u128;
37use mshv_bindings::hv_x64_io_port_intercept_message;
38use mshv_bindings::hv_x64_memory_intercept_message;
39use mshv_bindings::hv_x64_segment_register;
40use mshv_bindings::mshv_install_intercept;
41use mshv_bindings::mshv_user_mem_region;
42use mshv_ioctls::InterruptRequest;
43use mshv_ioctls::Mshv;
44use mshv_ioctls::MshvError;
45use mshv_ioctls::VcpuFd;
46use mshv_ioctls::VmFd;
47use mshv_ioctls::set_bits;
48use mshv_ioctls::set_registers_64;
49use pal::unix::pthread::*;
50use pal_event::Event;
51use parking_lot::Mutex;
52use parking_lot::RwLock;
53use pci_core::msi::SignalMsi;
54use std::convert::Infallible;
55use std::io;
56use std::sync::Arc;
57use std::sync::Once;
58use std::sync::Weak;
59use thiserror::Error;
60use virt::Hv1;
61use virt::NeedsYield;
62use virt::PartitionAccessState;
63use virt::PartitionConfig;
64use virt::ProtoPartition;
65use virt::ProtoPartitionConfig;
66use virt::StopVp;
67use virt::VpHaltReason;
68use virt::VpIndex;
69use virt::io::CpuIo;
70use virt::irqcon::MsiRequest;
71use virt::x86::max_physical_address_size_from_cpuid;
72use virt_support_x86emu::emulate::EmuTranslateError;
73use virt_support_x86emu::emulate::EmuTranslateResult;
74use virt_support_x86emu::emulate::EmulatorSupport;
75use virt_support_x86emu::emulate::TranslateGvaSupport;
76use virt_support_x86emu::emulate::TranslateMode;
77use virt_support_x86emu::emulate::emulate_translate_gva;
78use virt_support_x86emu::translate::TranslationRegisters;
79use vmcore::interrupt::Interrupt;
80use vmcore::reference_time::GetReferenceTime;
81use vmcore::reference_time::ReferenceTimeResult;
82use vmcore::reference_time::ReferenceTimeSource;
83use vmcore::synic::GuestEventPort;
84use x86defs::RFlags;
85use x86defs::SegmentRegister;
86use zerocopy::IntoBytes;
87
88#[derive(Debug)]
89pub struct LinuxMshv;
90
91struct MshvEmuCache {
92    /// GP registers, in the canonical order (as defined by `RAX`, etc.).
93    gps: [u64; 16],
94    /// Segment registers, in the canonical order (as defined by `ES`, etc.).
95    segs: [SegmentRegister; 6],
96    rip: u64,
97    rflags: RFlags,
98
99    cr0: u64,
100    efer: u64,
101}
102
103impl virt::Hypervisor for LinuxMshv {
104    type ProtoPartition<'a> = MshvProtoPartition<'a>;
105    type Partition = MshvPartition;
106    type Error = Error;
107
108    fn new_partition<'a>(
109        &mut self,
110        config: ProtoPartitionConfig<'a>,
111    ) -> Result<MshvProtoPartition<'a>, Self::Error> {
112        if config.isolation.is_isolated() {
113            return Err(Error::IsolationNotSupported);
114        }
115
116        // Open /dev/mshv.
117        let mshv = Mshv::new().map_err(Error::OpenMshv)?;
118
119        // Create VM.
120        //
121        // TODO: really need to pass some partition properties here (e.g., for
122        // APIC configuration), but the underlying crate just hardcodes
123        // everything.
124        let vmfd: VmFd;
125        loop {
126            match mshv.create_vm() {
127                Ok(fd) => vmfd = fd,
128                Err(e) => {
129                    if e.errno() == libc::EINTR {
130                        // If the error returned is EINTR, which means the
131                        // ioctl has been interrupted, we have to retry as
132                        // this can't be considered as a regular error.
133                        continue;
134                    } else {
135                        return Err(Error::CreateVMFailed);
136                    }
137                }
138            }
139            break;
140        }
141
142        vmfd.initialize()
143            .map_err(|e| Error::CreateVMInitFailed(e.into()))?;
144
145        // Create virtual CPUs.
146        let mut vps: Vec<MshvVpInner> = Vec::new();
147        for vp in config.processor_topology.vps_arch() {
148            if vp.base.vp_index.index() != vp.apic_id {
149                // TODO
150                return Err(Error::NotSupported);
151            }
152
153            let vcpufd = vmfd
154                .create_vcpu(vp.base.vp_index.index() as u8)
155                .map_err(Error::CreateVcpu)?;
156
157            vps.push(MshvVpInner {
158                vcpufd,
159                thread: RwLock::new(None),
160                needs_yield: NeedsYield::new(),
161                message_queues: MessageQueues::new(),
162                deliverability_notifications: Mutex::new(
163                    HvDeliverabilityNotificationsRegister::new(),
164                ),
165            });
166        }
167
168        // Install required intercepts
169        let intercept_args = mshv_install_intercept {
170            access_type_mask: HV_INTERCEPT_ACCESS_MASK_EXECUTE,
171            intercept_type: hvdef::hypercall::HvInterceptType::HvInterceptTypeHypercall.0,
172            intercept_parameter: Default::default(),
173        };
174        vmfd.install_intercept(intercept_args)
175            .map_err(Error::InstallIntercept)?;
176
177        // Set up a signal for forcing vcpufd.run() ioctl to exit.
178        static SIGNAL_HANDLER_INIT: Once = Once::new();
179        // SAFETY: The signal handler does not perform any actions that are forbidden
180        // for signal handlers to perform, as it performs nothing.
181        SIGNAL_HANDLER_INIT.call_once(|| unsafe {
182            signal_hook::low_level::register(libc::SIGRTMIN(), || {
183                // Signal handler does nothing other than enabling run_fd() iotcl to
184                // return with EINTR, when the associated signal is sent to run_fd() thread.
185            })
186            .unwrap();
187        });
188
189        if let Some(hv_config) = &config.hv_config {
190            if hv_config.vtl2.is_some() {
191                return Err(Error::Vtl2NotSupported);
192            }
193        }
194
195        Ok(MshvProtoPartition { config, vmfd, vps })
196    }
197
198    fn is_available(&self) -> Result<bool, Self::Error> {
199        match std::fs::metadata("/dev/mshv") {
200            Ok(_) => Ok(true),
201            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(false),
202            Err(err) => Err(Error::AvailableCheck(err)),
203        }
204    }
205}
206
207/// Prototype partition.
208pub struct MshvProtoPartition<'a> {
209    config: ProtoPartitionConfig<'a>,
210    vmfd: VmFd,
211    vps: Vec<MshvVpInner>,
212}
213
214impl ProtoPartition for MshvProtoPartition<'_> {
215    type Partition = MshvPartition;
216    type ProcessorBinder = MshvProcessorBinder;
217    type Error = Error;
218
219    fn cpuid(&self, eax: u32, ecx: u32) -> [u32; 4] {
220        // This call should never fail unless there is a kernel or hypervisor
221        // bug.
222        self.vps[0]
223            .vcpufd
224            .get_cpuid_values(eax, ecx, 0, 0)
225            .expect("cpuid should not fail")
226    }
227
228    fn max_physical_address_size(&self) -> u8 {
229        max_physical_address_size_from_cpuid(&|eax, ecx| self.cpuid(eax, ecx))
230    }
231
232    fn build(
233        self,
234        config: PartitionConfig<'_>,
235    ) -> Result<(Self::Partition, Vec<Self::ProcessorBinder>), Self::Error> {
236        // TODO: do something with cpuid.
237
238        // Get caps via cpuid
239        let caps = virt::PartitionCapabilities::from_cpuid(
240            self.config.processor_topology,
241            &mut |function, index| {
242                self.vps[0]
243                    .vcpufd
244                    .get_cpuid_values(function, index, 0, 0)
245                    .expect("cpuid should not fail")
246            },
247        )
248        .map_err(Error::Capabilities)?;
249
250        // Attach all the resources created above to a Partition object.
251        let partition = MshvPartition {
252            inner: Arc::new(MshvPartitionInner {
253                vmfd: self.vmfd,
254                memory: Default::default(),
255                gm: config.guest_memory.clone(),
256                vps: self.vps,
257                irq_routes: Default::default(),
258                caps,
259            }),
260        };
261
262        let vps = self
263            .config
264            .processor_topology
265            .vps()
266            .map(|vp| MshvProcessorBinder {
267                partition: partition.inner.clone(),
268                vpindex: vp.vp_index,
269            })
270            .collect();
271
272        Ok((partition, vps))
273    }
274}
275
276// TODO: remove these workarounds when mshv-ioctl implements the Debug trait
277#[derive(Debug)]
278pub struct MshvPartition {
279    inner: Arc<MshvPartitionInner>,
280}
281
282#[derive(Debug)]
283struct MshvPartitionInner {
284    vmfd: VmFd,
285    memory: Mutex<MshvMemoryRangeState>,
286    gm: GuestMemory,
287    vps: Vec<MshvVpInner>,
288    irq_routes: virt::irqcon::IrqRoutes,
289    caps: virt::PartitionCapabilities,
290}
291
292#[derive(Debug)]
293struct MshvVpInner {
294    vcpufd: VcpuFd,
295    thread: RwLock<Option<Pthread>>,
296    needs_yield: NeedsYield,
297    message_queues: MessageQueues,
298    deliverability_notifications: Mutex<HvDeliverabilityNotificationsRegister>,
299}
300
301struct MshvVpInnerCleaner<'a> {
302    vpinner: &'a MshvVpInner,
303}
304
305impl Drop for MshvVpInnerCleaner<'_> {
306    fn drop(&mut self) {
307        self.vpinner.thread.write().take();
308    }
309}
310
311impl virt::Partition for MshvPartition {
312    fn supports_reset(&self) -> Option<&dyn virt::ResetPartition<Error = Error>> {
313        None
314    }
315
316    fn doorbell_registration(
317        self: &Arc<Self>,
318        _minimum_vtl: Vtl,
319    ) -> Option<Arc<dyn DoorbellRegistration>> {
320        // TODO: implementation
321
322        Some(self.clone())
323    }
324
325    fn caps(&self) -> &virt::PartitionCapabilities {
326        &self.inner.caps
327    }
328
329    fn request_msi(&self, _vtl: Vtl, request: MsiRequest) {
330        self.inner.request_msi(request)
331    }
332
333    fn as_signal_msi(self: &Arc<Self>, _vtl: Vtl) -> Option<Arc<dyn SignalMsi>> {
334        Some(self.inner.clone())
335    }
336
337    fn request_yield(&self, vp_index: VpIndex) {
338        let vp = self.inner.vp(vp_index);
339        if vp.needs_yield.request_yield() {
340            // Send a signal to the thread who called vcpufd.run() to force an exit.
341            let thread = vp.thread.read();
342            if let Some(thread) = *thread {
343                if thread != Pthread::current() {
344                    thread
345                        .signal(libc::SIGRTMIN())
346                        .expect("thread cancel signal failed");
347                }
348            }
349        }
350    }
351}
352
353impl virt::X86Partition for MshvPartition {
354    fn ioapic_routing(&self) -> Arc<dyn virt::irqcon::IoApicRouting> {
355        self.inner.clone()
356    }
357
358    fn pulse_lint(&self, vp_index: VpIndex, vtl: Vtl, lint: u8) {
359        // TODO
360        tracing::warn!(?vp_index, ?vtl, lint, "ignored lint pulse");
361    }
362}
363
364impl PartitionAccessState for MshvPartition {
365    type StateAccess<'a> = &'a MshvPartition;
366
367    fn access_state(&self, vtl: Vtl) -> Self::StateAccess<'_> {
368        assert_eq!(vtl, Vtl::Vtl0);
369
370        self
371    }
372}
373
374impl Hv1 for MshvPartition {
375    type Error = Error;
376    type Device = virt::UnimplementedDevice;
377
378    fn reference_time_source(&self) -> Option<ReferenceTimeSource> {
379        Some(ReferenceTimeSource::from(self.inner.clone() as Arc<_>))
380    }
381
382    fn new_virtual_device(
383        &self,
384    ) -> Option<&dyn virt::DeviceBuilder<Device = Self::Device, Error = Self::Error>> {
385        None
386    }
387}
388
389impl GetReferenceTime for MshvPartitionInner {
390    fn now(&self) -> ReferenceTimeResult {
391        let mut regs = [hv_register_assoc {
392            name: hvdef::HvAllArchRegisterName::TimeRefCount.0,
393            value: hv_register_value { reg64: 0 },
394            ..Default::default()
395        }];
396        self.vp(VpIndex::BSP).vcpufd.get_reg(&mut regs).unwrap();
397        // SAFETY: the value has been written by the kernel.
398        let ref_time = unsafe { regs[0].value.reg64 };
399        ReferenceTimeResult {
400            ref_time,
401            system_time: None,
402        }
403    }
404}
405
406impl MshvPartitionInner {
407    fn vp(&self, vp_index: VpIndex) -> &MshvVpInner {
408        &self.vps[vp_index.index() as usize]
409    }
410
411    fn post_message(&self, vp_index: VpIndex, sint: u8, message: &HvMessage) {
412        let request_notification = self
413            .vp(vp_index)
414            .message_queues
415            .enqueue_message(sint, message);
416
417        if request_notification {
418            self.request_sint_notifications(vp_index, 1 << sint);
419        }
420    }
421
422    fn request_sint_notifications(&self, vp_index: VpIndex, sints: u16) {
423        let mut notifications = self.vp(vp_index).deliverability_notifications.lock();
424        if notifications.sints() != sints {
425            notifications.set_sints(sints);
426            self.vmfd
427                .register_deliverabilty_notifications(vp_index.index(), (*notifications).into())
428                .expect("Requesting deliverability is not a fallable operation");
429        }
430    }
431}
432
433pub struct MshvProcessorBinder {
434    partition: Arc<MshvPartitionInner>,
435    vpindex: VpIndex,
436}
437
438impl virt::BindProcessor for MshvProcessorBinder {
439    type Processor<'a>
440        = MshvProcessor<'a>
441    where
442        Self: 'a;
443    type Error = Error;
444
445    fn bind(&mut self) -> Result<Self::Processor<'_>, Self::Error> {
446        Ok(MshvProcessor {
447            partition: &self.partition,
448            inner: &self.partition.vps[self.vpindex.index() as usize],
449            vpindex: self.vpindex,
450        })
451    }
452}
453
454pub struct MshvProcessor<'a> {
455    partition: &'a MshvPartitionInner,
456    inner: &'a MshvVpInner,
457    vpindex: VpIndex,
458}
459
460impl MshvProcessor<'_> {
461    async fn emulate(
462        &self,
463        message: &hv_message,
464        devices: &impl CpuIo,
465        interruption_pending: bool,
466    ) -> Result<(), VpHaltReason> {
467        let cache = self.emulation_cache();
468        let emu_mem = virt_support_x86emu::emulate::EmulatorMemoryAccess {
469            gm: &self.partition.gm,
470            kx_gm: &self.partition.gm,
471            ux_gm: &self.partition.gm,
472        };
473
474        let mut support = MshvEmulationState {
475            partition: self.partition,
476            processor: self.inner,
477            vp_index: self.vpindex,
478            message,
479            interruption_pending,
480            cache,
481        };
482        virt_support_x86emu::emulate::emulate(&mut support, &emu_mem, devices).await
483    }
484
485    async fn handle_io_port_intercept(
486        &self,
487        message: &hv_message,
488        devices: &impl CpuIo,
489    ) -> Result<(), VpHaltReason> {
490        let info = message.to_ioport_info().unwrap();
491        let access_info = info.access_info;
492        // SAFETY: This union only contains one field.
493        let port_access_info = unsafe { access_info.__bindgen_anon_1 };
494
495        if port_access_info.string_op() != 0 || port_access_info.rep_prefix() != 0 {
496            let execution_state = info.header.execution_state;
497            // SAFETY: This union only contains one field.
498            let io_execution_state = unsafe { execution_state.__bindgen_anon_1 };
499            let interruption_pending = io_execution_state.interruption_pending() != 0;
500
501            self.emulate(message, devices, interruption_pending).await?
502        } else {
503            let mut ret_rax = info.rax;
504            virt_support_x86emu::emulate::emulate_io(
505                self.vpindex,
506                info.header.intercept_access_type == 1,
507                info.port_number,
508                &mut ret_rax,
509                port_access_info.access_size(),
510                devices,
511            )
512            .await;
513
514            let insn_len = info.header.instruction_length() as u64;
515
516            /* Advance RIP and update RAX */
517            let arr_reg_name_value = [
518                (
519                    mshv_bindings::hv_register_name_HV_X64_REGISTER_RIP,
520                    info.header.rip + insn_len,
521                ),
522                (mshv_bindings::hv_register_name_HV_X64_REGISTER_RAX, ret_rax),
523            ];
524
525            set_registers_64!(self.inner.vcpufd, arr_reg_name_value).unwrap();
526        }
527
528        Ok(())
529    }
530
531    async fn handle_mmio_intercept(
532        &self,
533        message: &hv_message,
534        devices: &impl CpuIo,
535    ) -> Result<(), VpHaltReason> {
536        let execution_state = message.to_memory_info().unwrap().header.execution_state;
537        // SAFETY: This union only contains one field.
538        let mmio_execution_state = unsafe { execution_state.__bindgen_anon_1 };
539        let interruption_pending = mmio_execution_state.interruption_pending() != 0;
540
541        self.emulate(message, devices, interruption_pending).await
542    }
543
544    fn handle_synic_deliverable_exit(&self, message: &hv_message, _devices: &impl CpuIo) {
545        let info = message.to_sint_deliverable_info().unwrap();
546        self.flush_messages(info.deliverable_sints);
547    }
548
549    fn handle_hypercall_intercept(&self, message: &hv_message, devices: &impl CpuIo) {
550        let info = message.to_hypercall_intercept_info().unwrap();
551        let execution_state = info.header.execution_state;
552        // SAFETY: Accessing the raw field of this union is always safe.
553        let vp_state = unsafe { HvX64VpExecutionState::from(execution_state.as_uint16) };
554        let is_64bit = vp_state.cr0_pe() && vp_state.efer_lma();
555        let mut hpc_context = MshvHypercallContext {
556            rax: info.rax,
557            rbx: info.rbx,
558            rcx: info.rcx,
559            rdx: info.rdx,
560            r8: info.r8,
561            rsi: info.rsi,
562            rdi: info.rdi,
563            xmm: info.xmmregisters,
564        };
565        let mut handler = MshvHypercallHandler {
566            bus: devices,
567            context: &mut hpc_context,
568            rip: info.header.rip,
569            rip_dirty: false,
570            xmm_dirty: false,
571            gp_dirty: false,
572        };
573
574        MshvHypercallHandler::DISPATCHER.dispatch(
575            &self.partition.gm,
576            X64RegisterIo::new(&mut handler, is_64bit),
577        );
578
579        let mut dirty_regs = ArrayVec::<hv_register_assoc, 14>::new();
580
581        if handler.gp_dirty {
582            dirty_regs.extend([
583                hv_register_assoc {
584                    name: mshv_bindings::hv_register_name_HV_X64_REGISTER_RAX,
585                    value: hv_register_value {
586                        reg64: handler.context.rax,
587                    },
588                    ..Default::default()
589                },
590                hv_register_assoc {
591                    name: mshv_bindings::hv_register_name_HV_X64_REGISTER_RBX,
592                    value: hv_register_value {
593                        reg64: handler.context.rbx,
594                    },
595                    ..Default::default()
596                },
597                hv_register_assoc {
598                    name: mshv_bindings::hv_register_name_HV_X64_REGISTER_RCX,
599                    value: hv_register_value {
600                        reg64: handler.context.rcx,
601                    },
602                    ..Default::default()
603                },
604                hv_register_assoc {
605                    name: mshv_bindings::hv_register_name_HV_X64_REGISTER_RDX,
606                    value: hv_register_value {
607                        reg64: handler.context.rdx,
608                    },
609                    ..Default::default()
610                },
611                hv_register_assoc {
612                    name: mshv_bindings::hv_register_name_HV_X64_REGISTER_R8,
613                    value: hv_register_value {
614                        reg64: handler.context.r8,
615                    },
616                    ..Default::default()
617                },
618                hv_register_assoc {
619                    name: mshv_bindings::hv_register_name_HV_X64_REGISTER_RSI,
620                    value: hv_register_value {
621                        reg64: handler.context.rsi,
622                    },
623                    ..Default::default()
624                },
625                hv_register_assoc {
626                    name: mshv_bindings::hv_register_name_HV_X64_REGISTER_RDI,
627                    value: hv_register_value {
628                        reg64: handler.context.rdi,
629                    },
630                    ..Default::default()
631                },
632            ]);
633        }
634
635        if handler.xmm_dirty {
636            dirty_regs.extend((0..5).map(|i| hv_register_assoc {
637                name: mshv_bindings::hv_register_name_HV_X64_REGISTER_XMM0 + i,
638                value: hv_register_value {
639                    reg128: handler.context.xmm[i as usize],
640                },
641                ..Default::default()
642            }));
643        }
644
645        if handler.rip_dirty {
646            dirty_regs.push(hv_register_assoc {
647                name: mshv_bindings::hv_register_name_HV_X64_REGISTER_RIP,
648                value: hv_register_value { reg64: handler.rip },
649                ..Default::default()
650            });
651        }
652
653        if !dirty_regs.is_empty() {
654            self.inner
655                .vcpufd
656                .set_reg(&dirty_regs)
657                .expect("RIP setting is not a fallable operation");
658        }
659    }
660
661    fn flush_messages(&self, deliverable_sints: u16) {
662        let nonempty_sints =
663            self.inner
664                .message_queues
665                .post_pending_messages(deliverable_sints, |sint, message| {
666                    match self.partition.vmfd.post_message_direct(
667                        self.vpindex.index(),
668                        sint,
669                        message.as_bytes(),
670                    ) {
671                        Ok(()) => {
672                            tracing::trace!(sint, "sint message posted successfully");
673                            Ok(())
674                        }
675                        Err(e) => {
676                            // TODO: handle errors appropriately
677                            tracing::trace!(error = %e, "dropping sint message");
678                            Err(HvError::ObjectInUse)
679                        }
680                    }
681                });
682
683        {
684            // To avoid an additional get_reg hypercall, clear w/ deliverable sints mask
685            let mut notifications = self.inner.deliverability_notifications.lock();
686            let remaining_sints = notifications.sints() & !deliverable_sints;
687            notifications.set_sints(remaining_sints);
688        }
689
690        if nonempty_sints != 0 {
691            self.partition
692                .request_sint_notifications(self.vpindex, nonempty_sints);
693        }
694    }
695
696    fn emulation_cache(&self) -> MshvEmuCache {
697        let regs = self.inner.vcpufd.get_regs().unwrap();
698        let gps = [
699            regs.rax, regs.rcx, regs.rdx, regs.rbx, regs.rsp, regs.rbp, regs.rsi, regs.rdi,
700            regs.r8, regs.r9, regs.r10, regs.r11, regs.r12, regs.r13, regs.r14, regs.r15,
701        ];
702        let rip = regs.rip;
703        let rflags = regs.rflags;
704
705        let sregs = self.inner.vcpufd.get_sregs().unwrap();
706        let segs = [
707            x86emu_sreg_from_mshv_sreg(sregs.es),
708            x86emu_sreg_from_mshv_sreg(sregs.cs),
709            x86emu_sreg_from_mshv_sreg(sregs.ss),
710            x86emu_sreg_from_mshv_sreg(sregs.ds),
711            x86emu_sreg_from_mshv_sreg(sregs.fs),
712            x86emu_sreg_from_mshv_sreg(sregs.gs),
713        ];
714        let cr0 = sregs.cr0;
715        let efer = sregs.efer;
716
717        MshvEmuCache {
718            gps,
719            segs,
720            rip,
721            rflags: rflags.into(),
722            cr0,
723            efer,
724        }
725    }
726}
727
728struct MshvEmulationState<'a> {
729    partition: &'a MshvPartitionInner,
730    processor: &'a MshvVpInner,
731    vp_index: VpIndex,
732    message: &'a hv_message,
733    interruption_pending: bool,
734    cache: MshvEmuCache,
735}
736
737impl EmulatorSupport for MshvEmulationState<'_> {
738    fn vp_index(&self) -> VpIndex {
739        self.vp_index
740    }
741
742    fn vendor(&self) -> x86defs::cpuid::Vendor {
743        self.partition.caps.vendor
744    }
745
746    fn gp(&mut self, reg: x86emu::Gp) -> u64 {
747        self.cache.gps[reg as usize]
748    }
749
750    fn set_gp(&mut self, reg: x86emu::Gp, v: u64) {
751        self.cache.gps[reg as usize] = v;
752    }
753
754    fn rip(&mut self) -> u64 {
755        self.cache.rip
756    }
757
758    fn set_rip(&mut self, v: u64) {
759        self.cache.rip = v;
760    }
761
762    fn segment(&mut self, reg: x86emu::Segment) -> SegmentRegister {
763        self.cache.segs[reg as usize]
764    }
765
766    fn efer(&mut self) -> u64 {
767        self.cache.efer
768    }
769
770    fn cr0(&mut self) -> u64 {
771        self.cache.cr0
772    }
773
774    fn rflags(&mut self) -> RFlags {
775        self.cache.rflags
776    }
777
778    fn set_rflags(&mut self, v: RFlags) {
779        self.cache.rflags = v;
780    }
781
782    fn xmm(&mut self, reg: usize) -> u128 {
783        assert!(reg < 16);
784        let name = HvX64RegisterName(HvX64RegisterName::Xmm0.0 + reg as u32);
785        // SAFETY: `HvRegisterAssoc` and `hv_register_assoc` have the same layout.
786        let reg = unsafe {
787            std::mem::transmute::<HvRegisterAssoc, hv_register_assoc>(HvRegisterAssoc::from((
788                name, 0u128,
789            )))
790        };
791        let _ = self.processor.vcpufd.get_reg(&mut [reg]);
792        // SAFETY: Accessing the u128 field of this union is always safe.
793        hvu128_to_u128(unsafe { &reg.value.reg128 })
794    }
795
796    fn set_xmm(&mut self, reg: usize, value: u128) {
797        assert!(reg < 16);
798        let name = HvX64RegisterName(HvX64RegisterName::Xmm0.0 + reg as u32);
799        // SAFETY: `HvRegisterAssoc` and `hv_register_assoc` have the same layout.
800        let reg = unsafe {
801            std::mem::transmute::<HvRegisterAssoc, hv_register_assoc>(HvRegisterAssoc::from((
802                name, value,
803            )))
804        };
805        self.processor.vcpufd.set_reg(&[reg]).unwrap();
806    }
807
808    fn flush(&mut self) {
809        let arr_reg_name_value = [
810            (
811                mshv_bindings::hv_register_name_HV_X64_REGISTER_RIP,
812                self.cache.rip,
813            ),
814            (
815                mshv_bindings::hv_register_name_HV_X64_REGISTER_RFLAGS,
816                self.cache.rflags.into(),
817            ),
818            (
819                mshv_bindings::hv_register_name_HV_X64_REGISTER_RAX,
820                self.cache.gps[0],
821            ),
822            (
823                mshv_bindings::hv_register_name_HV_X64_REGISTER_RCX,
824                self.cache.gps[1],
825            ),
826            (
827                mshv_bindings::hv_register_name_HV_X64_REGISTER_RDX,
828                self.cache.gps[2],
829            ),
830            (
831                mshv_bindings::hv_register_name_HV_X64_REGISTER_RBX,
832                self.cache.gps[3],
833            ),
834            (
835                mshv_bindings::hv_register_name_HV_X64_REGISTER_RSP,
836                self.cache.gps[4],
837            ),
838            (
839                mshv_bindings::hv_register_name_HV_X64_REGISTER_RBP,
840                self.cache.gps[5],
841            ),
842            (
843                mshv_bindings::hv_register_name_HV_X64_REGISTER_RSI,
844                self.cache.gps[6],
845            ),
846            (
847                mshv_bindings::hv_register_name_HV_X64_REGISTER_RDI,
848                self.cache.gps[7],
849            ),
850            (
851                mshv_bindings::hv_register_name_HV_X64_REGISTER_R8,
852                self.cache.gps[8],
853            ),
854            (
855                mshv_bindings::hv_register_name_HV_X64_REGISTER_R9,
856                self.cache.gps[9],
857            ),
858            (
859                mshv_bindings::hv_register_name_HV_X64_REGISTER_R10,
860                self.cache.gps[10],
861            ),
862            (
863                mshv_bindings::hv_register_name_HV_X64_REGISTER_R11,
864                self.cache.gps[11],
865            ),
866            (
867                mshv_bindings::hv_register_name_HV_X64_REGISTER_R12,
868                self.cache.gps[12],
869            ),
870            (
871                mshv_bindings::hv_register_name_HV_X64_REGISTER_R13,
872                self.cache.gps[13],
873            ),
874            (
875                mshv_bindings::hv_register_name_HV_X64_REGISTER_R14,
876                self.cache.gps[14],
877            ),
878            (
879                mshv_bindings::hv_register_name_HV_X64_REGISTER_R15,
880                self.cache.gps[15],
881            ),
882        ];
883
884        set_registers_64!(self.processor.vcpufd, arr_reg_name_value).unwrap();
885    }
886
887    fn instruction_bytes(&self) -> &[u8] {
888        match HvMessageType(self.message.header.message_type) {
889            HvMessageType::HvMessageTypeGpaIntercept
890            | HvMessageType::HvMessageTypeUnmappedGpa
891            | HvMessageType::HvMessageTypeUnacceptedGpa => {
892                // SAFETY: We have checked the message type.
893                unsafe {
894                    let info = (&raw const self.message.u.payload)
895                        .cast::<hv_x64_memory_intercept_message>();
896                    let instruction_bytes = &raw const (*info).instruction_bytes;
897                    let instruction_byte_count =
898                        std::ptr::read_unaligned(&raw const (*info).instruction_byte_count);
899                    std::slice::from_raw_parts(
900                        instruction_bytes.cast(),
901                        instruction_byte_count as usize,
902                    )
903                }
904            }
905            HvMessageType::HvMessageTypeX64IoPortIntercept => {
906                // SAFETY: We have checked the message type.
907                unsafe {
908                    let info = (&raw const self.message.u.payload)
909                        .cast::<hv_x64_io_port_intercept_message>();
910                    let instruction_bytes = &raw const (*info).instruction_bytes;
911                    let instruction_byte_count =
912                        std::ptr::read_unaligned(&raw const (*info).instruction_byte_count);
913                    std::slice::from_raw_parts(
914                        instruction_bytes.cast(),
915                        instruction_byte_count as usize,
916                    )
917                }
918            }
919            _ => unreachable!(),
920        }
921    }
922
923    fn physical_address(&self) -> Option<u64> {
924        if self.message.header.message_type == HvMessageType::HvMessageTypeGpaIntercept.0
925            || self.message.header.message_type == HvMessageType::HvMessageTypeUnmappedGpa.0
926            || self.message.header.message_type == HvMessageType::HvMessageTypeUnacceptedGpa.0
927        {
928            let info = self.message.to_memory_info().unwrap();
929            Some(info.guest_physical_address)
930        } else {
931            None
932        }
933    }
934
935    fn initial_gva_translation(
936        &mut self,
937    ) -> Option<virt_support_x86emu::emulate::InitialTranslation> {
938        if (self.message.header.message_type != HvMessageType::HvMessageTypeGpaIntercept.0)
939            && (self.message.header.message_type != HvMessageType::HvMessageTypeUnmappedGpa.0)
940            && (self.message.header.message_type != HvMessageType::HvMessageTypeUnacceptedGpa.0)
941        {
942            return None;
943        }
944
945        let message = self.message.to_memory_info().unwrap();
946
947        // SAFETY: access to union as uint8 is safe because in this case, the actual
948        // type doesn't matter so much as the bits
949        let memory_access_info =
950            unsafe { hvdef::HvX64MemoryAccessInfo::from(message.memory_access_info.as_uint8) };
951
952        if !memory_access_info.gva_gpa_valid() {
953            return None;
954        }
955
956        if let Ok(translate_mode) = TranslateMode::try_from(hvdef::HvInterceptAccessType(
957            message.header.intercept_access_type,
958        )) {
959            Some(virt_support_x86emu::emulate::InitialTranslation {
960                gva: message.guest_virtual_address,
961                gpa: message.guest_physical_address,
962                translate_mode,
963            })
964        } else {
965            None
966        }
967    }
968
969    fn interruption_pending(&self) -> bool {
970        self.interruption_pending
971    }
972
973    fn check_vtl_access(
974        &mut self,
975        _gpa: u64,
976        _mode: TranslateMode,
977    ) -> Result<(), virt_support_x86emu::emulate::EmuCheckVtlAccessError> {
978        // TODO: No VTL2 supported so always return Ok.
979        Ok(())
980    }
981
982    fn translate_gva(
983        &mut self,
984        gva: u64,
985        mode: TranslateMode,
986    ) -> Result<EmuTranslateResult, EmuTranslateError> {
987        emulate_translate_gva(self, gva, mode)
988    }
989
990    fn inject_pending_event(&mut self, event_info: hvdef::HvX64PendingEvent) {
991        // SAFETY: `HvRegisterAssoc` and `hv_register_assoc` have the same layout.
992        let reg = unsafe {
993            &[
994                std::mem::transmute::<HvRegisterAssoc, hv_register_assoc>(HvRegisterAssoc::from((
995                    HvX64RegisterName::PendingEvent0,
996                    u128::from(event_info.reg_0),
997                ))),
998                std::mem::transmute::<HvRegisterAssoc, hv_register_assoc>(HvRegisterAssoc::from((
999                    HvX64RegisterName::PendingEvent1,
1000                    u128::from(event_info.reg_1),
1001                ))),
1002            ]
1003        };
1004        self.processor.vcpufd.set_reg(reg).unwrap();
1005    }
1006
1007    fn is_gpa_mapped(&self, gpa: u64, write: bool) -> bool {
1008        self.partition
1009            .memory
1010            .lock()
1011            .ranges
1012            .iter()
1013            .flatten()
1014            .any(|range| {
1015                (range.guest_pfn..range.guest_pfn + range.size).contains(&gpa)
1016                    && (!write
1017                        || range.flags & set_bits!(u8, MSHV_SET_MEM_BIT_WRITABLE)
1018                            == set_bits!(u8, MSHV_SET_MEM_BIT_WRITABLE))
1019            })
1020    }
1021
1022    fn lapic_base_address(&self) -> Option<u64> {
1023        None
1024    }
1025
1026    fn lapic_read(&mut self, _address: u64, _data: &mut [u8]) {
1027        unreachable!()
1028    }
1029
1030    fn lapic_write(&mut self, _address: u64, _data: &[u8]) {
1031        unreachable!()
1032    }
1033}
1034
1035impl TranslateGvaSupport for MshvEmulationState<'_> {
1036    fn guest_memory(&self) -> &GuestMemory {
1037        &self.partition.gm
1038    }
1039
1040    fn acquire_tlb_lock(&mut self) {
1041        // The hypervisor automatically acquires the TLB lock for exo partitions.
1042    }
1043
1044    fn registers(&mut self) -> TranslationRegisters {
1045        let mut reg = [
1046            HvX64RegisterName::Cr0,
1047            HvX64RegisterName::Cr4,
1048            HvX64RegisterName::Efer,
1049            HvX64RegisterName::Cr3,
1050            HvX64RegisterName::Rflags,
1051            HvX64RegisterName::Ss,
1052        ]
1053        .map(|n| HvRegisterAssoc::from((n, 0u64)));
1054
1055        // SAFETY: `HvRegisterAssoc` and `hv_register_assoc` have the same size.
1056        unsafe {
1057            self.processor
1058                .vcpufd
1059                .get_reg(std::mem::transmute::<
1060                    &mut [HvRegisterAssoc],
1061                    &mut [hv_register_assoc],
1062                >(&mut reg[..]))
1063                .unwrap();
1064        }
1065
1066        let [cr0, cr4, efer, cr3, rflags, ss] = reg.map(|v| v.value);
1067
1068        TranslationRegisters {
1069            cr0: cr0.as_u64(),
1070            cr4: cr4.as_u64(),
1071            efer: efer.as_u64(),
1072            cr3: cr3.as_u64(),
1073            rflags: rflags.as_u64(),
1074            ss: from_seg(ss.as_segment()),
1075            encryption_mode: virt_support_x86emu::translate::EncryptionMode::None,
1076        }
1077    }
1078}
1079
1080// TODO: Chunk this up into smaller types.
1081#[derive(Error, Debug)]
1082pub enum Error {
1083    #[error("operation not supported")]
1084    NotSupported,
1085    #[error("create_vm failed")]
1086    CreateVMFailed,
1087    #[error("failed to initialize VM")]
1088    CreateVMInitFailed(#[source] anyhow::Error),
1089    #[error("failed to create VCPU")]
1090    CreateVcpu(#[source] MshvError),
1091    #[error("vtl2 not supported")]
1092    Vtl2NotSupported,
1093    #[error("isolation not supported")]
1094    IsolationNotSupported,
1095    #[error("failed to stat /dev/mshv")]
1096    AvailableCheck(#[source] io::Error),
1097    #[error("failed to open /dev/mshv")]
1098    OpenMshv(#[source] MshvError),
1099    #[error("register access error")]
1100    Register(#[source] MshvError),
1101    #[error("install instercept failed")]
1102    InstallIntercept(#[source] MshvError),
1103    #[error("host does not support required cpu capabilities")]
1104    Capabilities(virt::PartitionCapabilitiesError),
1105}
1106
1107impl MshvPartitionInner {
1108    fn request_msi(&self, request: MsiRequest) {
1109        let (address, data) = request.as_x86();
1110        let control = request.hv_x86_interrupt_control();
1111        let mshv_req = InterruptRequest {
1112            interrupt_type: control.interrupt_type().0,
1113            apic_id: address.virt_destination().into(),
1114            vector: data.vector().into(),
1115            level_triggered: control.x86_level_triggered(),
1116            logical_destination_mode: control.x86_logical_destination_mode(),
1117            long_mode: false,
1118        };
1119
1120        if let Err(err) = self.vmfd.request_virtual_interrupt(&mshv_req) {
1121            tracelimit::warn_ratelimited!(
1122                address = request.address,
1123                data = request.data,
1124                error = &err as &dyn std::error::Error,
1125                "failed to request msi"
1126            );
1127        }
1128    }
1129}
1130
1131impl SignalMsi for MshvPartitionInner {
1132    fn signal_msi(&self, _rid: u32, address: u64, data: u32) {
1133        self.request_msi(MsiRequest { address, data });
1134    }
1135}
1136
1137impl virt::irqcon::IoApicRouting for MshvPartitionInner {
1138    fn set_irq_route(&self, irq: u8, request: Option<MsiRequest>) {
1139        self.irq_routes.set_irq_route(irq, request)
1140    }
1141
1142    fn assert_irq(&self, irq: u8) {
1143        self.irq_routes
1144            .assert_irq(irq, |request| self.request_msi(request))
1145    }
1146}
1147
1148#[derive(Debug, Default)]
1149struct MshvMemoryRangeState {
1150    ranges: Vec<Option<mshv_user_mem_region>>,
1151}
1152
1153impl virt::PartitionMemoryMapper for MshvPartition {
1154    fn memory_mapper(&self, vtl: Vtl) -> Arc<dyn virt::PartitionMemoryMap> {
1155        assert_eq!(vtl, Vtl::Vtl0);
1156        self.inner.clone()
1157    }
1158}
1159
1160// TODO: figure out a better abstraction that also works for KVM and WHP.
1161impl virt::PartitionMemoryMap for MshvPartitionInner {
1162    unsafe fn map_range(
1163        &self,
1164        data: *mut u8,
1165        size: usize,
1166        addr: u64,
1167        writable: bool,
1168        exec: bool,
1169    ) -> anyhow::Result<()> {
1170        let mut state = self.memory.lock();
1171
1172        // Memory slots cannot be resized but can be moved within the guest
1173        // address space. Find the existing slot if there is one.
1174        let mut slot_to_use = None;
1175        for (slot, range) in state.ranges.iter_mut().enumerate() {
1176            match range {
1177                Some(range) if range.userspace_addr == data as u64 => {
1178                    slot_to_use = Some(slot);
1179                    break;
1180                }
1181                Some(_) => (),
1182                None => slot_to_use = Some(slot),
1183            }
1184        }
1185        if slot_to_use.is_none() {
1186            slot_to_use = Some(state.ranges.len());
1187            state.ranges.push(None);
1188        }
1189        let slot_to_use = slot_to_use.unwrap();
1190
1191        let mut flags = 0;
1192        if writable {
1193            flags |= set_bits!(u8, MSHV_SET_MEM_BIT_WRITABLE);
1194        }
1195        if exec {
1196            flags |= set_bits!(u8, MSHV_SET_MEM_BIT_EXECUTABLE);
1197        }
1198        let mem_region = mshv_user_mem_region {
1199            size: size as u64,
1200            guest_pfn: addr >> HV_PAGE_SHIFT,
1201            userspace_addr: data as u64,
1202            flags,
1203            rsvd: [0; 7],
1204        };
1205
1206        self.vmfd.map_user_memory(mem_region)?;
1207        state.ranges[slot_to_use] = Some(mem_region);
1208        Ok(())
1209    }
1210
1211    fn unmap_range(&self, addr: u64, size: u64) -> anyhow::Result<()> {
1212        let mut state = self.memory.lock();
1213        let (slot, range) = state
1214            .ranges
1215            .iter_mut()
1216            .enumerate()
1217            .find(|(_, range)| {
1218                range.as_ref().map(|r| (r.guest_pfn, r.size)) == Some((addr >> HV_PAGE_SHIFT, size))
1219            })
1220            .expect("can only unmap existing ranges of exact size");
1221
1222        self.vmfd.unmap_user_memory(range.unwrap())?;
1223        state.ranges[slot] = None;
1224        Ok(())
1225    }
1226}
1227
1228// TODO: implementation
1229struct MshvDoorbellEntry;
1230
1231impl MshvDoorbellEntry {
1232    pub fn new(
1233        _guest_address: u64,
1234        _value: Option<u64>,
1235        _length: Option<u32>,
1236        _fd: &Event,
1237    ) -> io::Result<MshvDoorbellEntry> {
1238        // TODO: implementation
1239
1240        Ok(Self)
1241    }
1242}
1243
1244impl DoorbellRegistration for MshvPartition {
1245    fn register_doorbell(
1246        &self,
1247        guest_address: u64,
1248        value: Option<u64>,
1249        length: Option<u32>,
1250        fd: &Event,
1251    ) -> io::Result<Box<dyn Send + Sync>> {
1252        Ok(Box::new(MshvDoorbellEntry::new(
1253            guest_address,
1254            value,
1255            length,
1256            fd,
1257        )?))
1258    }
1259}
1260
1261pub struct MshvHypercallContext {
1262    pub rax: u64,
1263    pub rbx: u64,
1264    pub rcx: u64,
1265    pub rdx: u64,
1266    pub r8: u64,
1267    pub rsi: u64,
1268    pub rdi: u64,
1269    pub xmm: [hv_u128; 6],
1270}
1271
1272impl<T> hv1_hypercall::X64RegisterState for MshvHypercallHandler<'_, T> {
1273    fn rip(&mut self) -> u64 {
1274        self.rip
1275    }
1276
1277    fn set_rip(&mut self, rip: u64) {
1278        self.rip = rip;
1279        self.rip_dirty = true;
1280    }
1281
1282    fn gp(&mut self, n: hv1_hypercall::X64HypercallRegister) -> u64 {
1283        match n {
1284            hv1_hypercall::X64HypercallRegister::Rax => self.context.rax,
1285            hv1_hypercall::X64HypercallRegister::Rcx => self.context.rcx,
1286            hv1_hypercall::X64HypercallRegister::Rdx => self.context.rdx,
1287            hv1_hypercall::X64HypercallRegister::Rbx => self.context.rbx,
1288            hv1_hypercall::X64HypercallRegister::Rsi => self.context.rsi,
1289            hv1_hypercall::X64HypercallRegister::Rdi => self.context.rdi,
1290            hv1_hypercall::X64HypercallRegister::R8 => self.context.r8,
1291        }
1292    }
1293
1294    fn set_gp(&mut self, n: hv1_hypercall::X64HypercallRegister, value: u64) {
1295        *match n {
1296            hv1_hypercall::X64HypercallRegister::Rax => &mut self.context.rax,
1297            hv1_hypercall::X64HypercallRegister::Rcx => &mut self.context.rcx,
1298            hv1_hypercall::X64HypercallRegister::Rdx => &mut self.context.rdx,
1299            hv1_hypercall::X64HypercallRegister::Rbx => &mut self.context.rbx,
1300            hv1_hypercall::X64HypercallRegister::Rsi => &mut self.context.rsi,
1301            hv1_hypercall::X64HypercallRegister::Rdi => &mut self.context.rdi,
1302            hv1_hypercall::X64HypercallRegister::R8 => &mut self.context.r8,
1303        } = value;
1304        self.gp_dirty = true;
1305    }
1306
1307    fn xmm(&mut self, n: usize) -> u128 {
1308        let r = &self.context.xmm[n];
1309        hvu128_to_u128(r)
1310    }
1311
1312    fn set_xmm(&mut self, n: usize, value: u128) {
1313        self.context.xmm[n] = u128_to_hvu128(value);
1314        self.xmm_dirty = true;
1315    }
1316}
1317
1318fn hvu128_to_u128(r: &hv_u128) -> u128 {
1319    (r.high_part as u128) << 64 | r.low_part as u128
1320}
1321
1322fn u128_to_hvu128(value: u128) -> hv_u128 {
1323    hv_u128 {
1324        high_part: (value >> 64) as u64,
1325        low_part: (value & (u64::MAX as u128)) as u64,
1326    }
1327}
1328
1329#[cfg(test)]
1330mod tests {
1331    use super::*;
1332
1333    #[test]
1334    fn u128_roundtrip() {
1335        let original = 0x0123_4567_89ab_cdef_fedc_ba98_7654_3210;
1336        let hv = u128_to_hvu128(original);
1337        let roundtrip = hvu128_to_u128(&hv);
1338        assert_eq!(roundtrip, original);
1339    }
1340}
1341
1342struct MshvHypercallHandler<'a, T> {
1343    bus: &'a T,
1344    context: &'a mut MshvHypercallContext,
1345    rip: u64,
1346    rip_dirty: bool,
1347    xmm_dirty: bool,
1348    gp_dirty: bool,
1349}
1350
1351impl<T: CpuIo> MshvHypercallHandler<'_, T> {
1352    const DISPATCHER: hv1_hypercall::Dispatcher<Self> = hv1_hypercall::dispatcher!(
1353        Self,
1354        [hv1_hypercall::HvPostMessage, hv1_hypercall::HvSignalEvent],
1355    );
1356}
1357
1358impl<T: CpuIo> hv1_hypercall::PostMessage for MshvHypercallHandler<'_, T> {
1359    fn post_message(&mut self, connection_id: u32, message: &[u8]) -> hvdef::HvResult<()> {
1360        self.bus
1361            .post_synic_message(Vtl::Vtl0, connection_id, false, message)
1362    }
1363}
1364
1365impl<T: CpuIo> hv1_hypercall::SignalEvent for MshvHypercallHandler<'_, T> {
1366    fn signal_event(&mut self, connection_id: u32, flag: u16) -> hvdef::HvResult<()> {
1367        self.bus.signal_synic_event(Vtl::Vtl0, connection_id, flag)
1368    }
1369}
1370
1371impl Inspect for MshvPartition {
1372    fn inspect(&self, req: inspect::Request<'_>) {
1373        // TODO: implementation
1374        req.respond();
1375    }
1376}
1377
1378impl InspectMut for MshvProcessor<'_> {
1379    fn inspect_mut(&mut self, req: inspect::Request<'_>) {
1380        req.respond();
1381    }
1382}
1383
1384impl virt::Processor for MshvProcessor<'_> {
1385    type StateAccess<'a>
1386        = &'a mut Self
1387    where
1388        Self: 'a;
1389
1390    fn set_debug_state(
1391        &mut self,
1392        _vtl: Vtl,
1393        _state: Option<&virt::x86::DebugState>,
1394    ) -> Result<(), <&mut Self as virt::vp::AccessVpState>::Error> {
1395        Err(Error::NotSupported)
1396    }
1397
1398    async fn run_vp(
1399        &mut self,
1400        stop: StopVp<'_>,
1401        dev: &impl CpuIo,
1402    ) -> Result<Infallible, VpHaltReason> {
1403        let vpinner = self.inner;
1404        let _cleaner = MshvVpInnerCleaner { vpinner };
1405        let vcpufd = &vpinner.vcpufd;
1406
1407        // Ensure this thread is uniquely running the VP, and store the thread
1408        // ID to support cancellation.
1409        assert!(vpinner.thread.write().replace(Pthread::current()).is_none());
1410
1411        loop {
1412            vpinner.needs_yield.maybe_yield().await;
1413            stop.check()?;
1414
1415            match vcpufd.run() {
1416                Ok(exit) => match HvMessageType(exit.header.message_type) {
1417                    HvMessageType::HvMessageTypeUnrecoverableException => {
1418                        return Err(VpHaltReason::TripleFault { vtl: Vtl::Vtl0 });
1419                    }
1420                    HvMessageType::HvMessageTypeX64IoPortIntercept => {
1421                        self.handle_io_port_intercept(&exit, dev).await?;
1422                    }
1423                    HvMessageType::HvMessageTypeUnmappedGpa
1424                    | HvMessageType::HvMessageTypeGpaIntercept => {
1425                        self.handle_mmio_intercept(&exit, dev).await?;
1426                    }
1427                    HvMessageType::HvMessageTypeSynicSintDeliverable => {
1428                        tracing::trace!("SYNIC_SINT_DELIVERABLE");
1429                        self.handle_synic_deliverable_exit(&exit, dev);
1430                    }
1431                    HvMessageType::HvMessageTypeHypercallIntercept => {
1432                        tracing::trace!("HYPERCALL_INTERCEPT");
1433                        self.handle_hypercall_intercept(&exit, dev);
1434                    }
1435                    exit => {
1436                        panic!("Unhandled vcpu exit code {exit:?}");
1437                    }
1438                },
1439
1440                Err(e) => match e.errno() {
1441                    libc::EAGAIN | libc::EINTR => {}
1442                    _ => tracing::error!(
1443                        error = &e as &dyn std::error::Error,
1444                        "vcpufd.run returned error"
1445                    ),
1446                },
1447            }
1448        }
1449    }
1450
1451    fn flush_async_requests(&mut self) {}
1452
1453    fn access_state(&mut self, vtl: Vtl) -> Self::StateAccess<'_> {
1454        assert_eq!(vtl, Vtl::Vtl0);
1455        self
1456    }
1457}
1458
1459fn x86emu_sreg_from_mshv_sreg(reg: mshv_bindings::SegmentRegister) -> SegmentRegister {
1460    let reg: hv_x64_segment_register = hv_x64_segment_register::from(reg);
1461    // SAFETY: This union only contains one field.
1462    let attributes: u16 = unsafe { reg.__bindgen_anon_1.attributes };
1463
1464    SegmentRegister {
1465        base: reg.base,
1466        limit: reg.limit,
1467        selector: reg.selector,
1468        attributes: attributes.into(),
1469    }
1470}
1471
1472fn from_seg(reg: hvdef::HvX64SegmentRegister) -> SegmentRegister {
1473    SegmentRegister {
1474        base: reg.base,
1475        limit: reg.limit,
1476        selector: reg.selector,
1477        attributes: reg.attributes.into(),
1478    }
1479}
1480
1481impl virt::Synic for MshvPartition {
1482    fn post_message(&self, _vtl: Vtl, vp: VpIndex, sint: u8, typ: u32, payload: &[u8]) {
1483        self.inner
1484            .post_message(vp, sint, &HvMessage::new(HvMessageType(typ), 0, payload));
1485    }
1486
1487    fn new_guest_event_port(
1488        &self,
1489        _vtl: Vtl,
1490        vp: u32,
1491        sint: u8,
1492        flag: u16,
1493    ) -> Box<dyn GuestEventPort> {
1494        Box::new(MshvGuestEventPort {
1495            partition: Arc::downgrade(&self.inner),
1496            params: Arc::new(Mutex::new(MshvEventPortParams {
1497                vp: VpIndex::new(vp),
1498                sint,
1499                flag,
1500            })),
1501        })
1502    }
1503
1504    fn prefer_os_events(&self) -> bool {
1505        false
1506    }
1507}
1508
1509/// `GuestEventPort` implementation for MSHV partitions.
1510#[derive(Debug, Clone)]
1511struct MshvGuestEventPort {
1512    partition: Weak<MshvPartitionInner>,
1513    params: Arc<Mutex<MshvEventPortParams>>,
1514}
1515
1516#[derive(Debug, Copy, Clone)]
1517struct MshvEventPortParams {
1518    vp: VpIndex,
1519    sint: u8,
1520    flag: u16,
1521}
1522
1523impl GuestEventPort for MshvGuestEventPort {
1524    fn interrupt(&self) -> Interrupt {
1525        let partition = self.partition.clone();
1526        let params = self.params.clone();
1527        Interrupt::from_fn(move || {
1528            let MshvEventPortParams { vp, sint, flag } = *params.lock();
1529            if let Some(partition) = partition.upgrade() {
1530                partition
1531                    .vmfd
1532                    .signal_event_direct(vp.index(), sint, flag)
1533                    .unwrap_or_else(|_| {
1534                        panic!(
1535                            "Failed signal synic sint {} on vp {:?} with flag {}",
1536                            sint, vp, flag
1537                        )
1538                    });
1539            }
1540        })
1541    }
1542
1543    fn set_target_vp(&mut self, vp: u32) -> Result<(), vmcore::synic::HypervisorError> {
1544        self.params.lock().vp = VpIndex::new(vp);
1545        Ok(())
1546    }
1547}