Skip to main content

hypervisor_resources/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Resource types and probe infrastructure for hypervisor backends.
5//!
6//! This crate defines [`HypervisorKind`] (the resource kind for hypervisor
7//! backends), per-backend handle types, and the [`HypervisorProbe`] trait +
8//! distributed slice used for auto-detection.
9//!
10//! Backends register probes via the `register_hypervisor_probes!` macro in
11//! `openvmm_core`. Callers use [`probes()`] to iterate registered backends
12//! and [`probe_by_name()`] to look up a specific one.
13
14use mesh::MeshPayload;
15use vm_resource::Resource;
16use vm_resource::ResourceId;
17use vm_resource::ResourceKind;
18
19/// Resource kind for hypervisor backends.
20///
21/// A [`Resource<HypervisorKind>`] identifies which hypervisor backend to use
22/// and can carry backend-specific initialization data.
23pub enum HypervisorKind {}
24
25impl ResourceKind for HypervisorKind {
26    const NAME: &'static str = "hypervisor";
27}
28
29/// Handle for the KVM hypervisor backend.
30///
31/// Contains the open `/dev/kvm` file descriptor so that it can be probed
32/// early and reused when creating the partition.
33#[derive(MeshPayload)]
34pub struct KvmHandle {
35    /// An open `/dev/kvm` file descriptor, open with read and write
36    /// permissions.
37    pub kvm: std::fs::File,
38}
39
40impl ResourceId<HypervisorKind> for KvmHandle {
41    const ID: &'static str = "kvm";
42}
43
44/// Handle for the MSHV hypervisor backend.
45#[derive(MeshPayload)]
46pub struct MshvHandle {
47    /// An open `/dev/mshv` file descriptor.
48    pub mshv: std::fs::File,
49}
50
51impl ResourceId<HypervisorKind> for MshvHandle {
52    const ID: &'static str = "mshv";
53}
54
55/// Handle for the WHP hypervisor backend.
56#[derive(MeshPayload)]
57pub struct WhpHandle {
58    /// Use the user-mode APIC emulator instead of the in-hypervisor one.
59    ///
60    /// Only supported on x86_64. Setting this on aarch64 will cause partition
61    /// creation to fail.
62    pub user_mode_apic: bool,
63    /// Use the hypervisor's in-built enlightenment support if available.
64    ///
65    /// Only supported on x86_64. Setting this to `false` on aarch64 will cause
66    /// partition creation to fail.
67    pub offload_enlightenments: bool,
68}
69
70impl Default for WhpHandle {
71    fn default() -> Self {
72        Self {
73            user_mode_apic: false,
74            offload_enlightenments: true,
75        }
76    }
77}
78
79impl ResourceId<HypervisorKind> for WhpHandle {
80    const ID: &'static str = "whp";
81}
82
83/// Handle for the HVF hypervisor backend.
84#[derive(MeshPayload)]
85pub struct HvfHandle;
86
87impl ResourceId<HypervisorKind> for HvfHandle {
88    const ID: &'static str = "hvf";
89}
90
91/// Trait for probing hypervisor backend availability.
92///
93/// Each registered backend provides a probe that can check whether the
94/// backend is available and construct a resource for it.
95pub trait HypervisorProbe: Send + Sync + 'static {
96    /// Short name (e.g. "kvm", "whp"). Matches the handle's `ResourceId::ID`.
97    fn name(&self) -> &str;
98
99    /// Checks whether this backend is available and, if so, returns a new
100    /// [`Resource<HypervisorKind>`] for it with default settings.
101    ///
102    /// Used for auto-detection: backends are tried in priority order, and
103    /// `Ok(None)` means "skip me, try the next one".
104    fn try_new_resource(&self) -> anyhow::Result<Option<Resource<HypervisorKind>>>;
105
106    /// Constructs a [`Resource<HypervisorKind>`] for an explicitly selected
107    /// backend, with optional parameters.
108    ///
109    /// Unlike [`try_new_resource`](Self::try_new_resource), this returns
110    /// `Err` (not `Ok(None)`) if the backend is unavailable, so the caller
111    /// gets a specific error message.
112    ///
113    /// `params` contains backend-specific key-value pairs parsed from the
114    /// `--hypervisor name:key=val,...` CLI syntax. A bare key (no `=`) is
115    /// passed as `(key, "true")`. Backends should return an error for
116    /// unrecognized keys.
117    fn new_resource(&self, params: &[(&str, &str)]) -> anyhow::Result<Resource<HypervisorKind>>;
118}
119
120/// Private module for linkme infrastructure.
121#[doc(hidden)]
122pub mod private {
123    // UNSAFETY: Needed for linkme.
124    #![expect(unsafe_code)]
125
126    pub use linkme;
127
128    use super::HypervisorProbe;
129
130    // Use Option<&X> in case the linker inserts some stray nulls, as we
131    // think it might on Windows.
132    //
133    // See <https://devblogs.microsoft.com/oldnewthing/20181108-00/?p=100165>.
134    #[linkme::distributed_slice]
135    pub static HYPERVISOR_PROBES: [Option<&'static dyn HypervisorProbe>] = [..];
136
137    // Always have at least one entry to work around linker bugs.
138    //
139    // See <https://github.com/llvm/llvm-project/issues/65855>.
140    #[linkme::distributed_slice(HYPERVISOR_PROBES)]
141    static WORKAROUND: Option<&'static dyn HypervisorProbe> = None;
142}
143
144/// Returns an iterator over all registered hypervisor probes.
145///
146/// Probes are returned in registration order (highest priority first).
147pub fn probes() -> impl Iterator<Item = &'static dyn HypervisorProbe> {
148    private::HYPERVISOR_PROBES.iter().flatten().copied()
149}
150
151/// Looks up a probe by backend name.
152pub fn probe_by_name(name: &str) -> Option<&'static dyn HypervisorProbe> {
153    probes().find(|p| p.name() == name)
154}