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#[derive(MeshPayload)]
31pub struct KvmHandle;
32
33impl ResourceId<HypervisorKind> for KvmHandle {
34 const ID: &'static str = "kvm";
35}
36
37/// Handle for the MSHV hypervisor backend.
38#[derive(MeshPayload)]
39pub struct MshvHandle;
40
41impl ResourceId<HypervisorKind> for MshvHandle {
42 const ID: &'static str = "mshv";
43}
44
45/// Handle for the WHP hypervisor backend.
46#[derive(MeshPayload)]
47pub struct WhpHandle;
48
49impl ResourceId<HypervisorKind> for WhpHandle {
50 const ID: &'static str = "whp";
51}
52
53/// Handle for the HVF hypervisor backend.
54#[derive(MeshPayload)]
55pub struct HvfHandle;
56
57impl ResourceId<HypervisorKind> for HvfHandle {
58 const ID: &'static str = "hvf";
59}
60
61/// Trait for probing hypervisor backend availability.
62///
63/// Each registered backend provides a probe that can check whether the
64/// backend is available and construct a resource for it.
65pub trait HypervisorProbe: Send + Sync + 'static {
66 /// Short name (e.g. "kvm", "whp"). Matches the handle's `ResourceId::ID`.
67 fn name(&self) -> &str;
68
69 /// Checks whether this backend is available and, if so, returns a new
70 /// [`Resource<HypervisorKind>`] for it.
71 ///
72 /// Returns `Ok(None)` if the backend is not available on this system.
73 fn try_new_resource(&self) -> anyhow::Result<Option<Resource<HypervisorKind>>>;
74}
75
76/// Private module for linkme infrastructure.
77#[doc(hidden)]
78pub mod private {
79 // UNSAFETY: Needed for linkme.
80 #![expect(unsafe_code)]
81
82 pub use linkme;
83
84 use super::HypervisorProbe;
85
86 // Use Option<&X> in case the linker inserts some stray nulls, as we
87 // think it might on Windows.
88 //
89 // See <https://devblogs.microsoft.com/oldnewthing/20181108-00/?p=100165>.
90 #[linkme::distributed_slice]
91 pub static HYPERVISOR_PROBES: [Option<&'static dyn HypervisorProbe>] = [..];
92
93 // Always have at least one entry to work around linker bugs.
94 //
95 // See <https://github.com/llvm/llvm-project/issues/65855>.
96 #[linkme::distributed_slice(HYPERVISOR_PROBES)]
97 static WORKAROUND: Option<&'static dyn HypervisorProbe> = None;
98}
99
100/// Returns an iterator over all registered hypervisor probes.
101///
102/// Probes are returned in registration order (highest priority first).
103pub fn probes() -> impl Iterator<Item = &'static dyn HypervisorProbe> {
104 private::HYPERVISOR_PROBES.iter().flatten().copied()
105}
106
107/// Looks up a probe by backend name.
108pub fn probe_by_name(name: &str) -> Option<&'static dyn HypervisorProbe> {
109 probes().find(|p| p.name() == name)
110}