openvmm_core/hypervisor_backend.rs
1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Hypervisor backend resolution infrastructure.
5//!
6//! A [`ResolvedHypervisorBackend`] wraps any concrete [`virt::Hypervisor`]
7//! implementation into an erased form that the VM worker can use to create
8//! a VM.
9//!
10//! Resource resolvers construct a `ResolvedHypervisorBackend` via
11//! [`ResolvedHypervisorBackend::new`], passing in the concrete hypervisor
12//! instance (e.g. `virt_kvm::Kvm`).
13
14use crate::partition::HvlitePartition;
15use crate::worker::dispatch::InitializedVm;
16use crate::worker::dispatch::Manifest;
17use futures::future::BoxFuture;
18use hypervisor_resources::HypervisorKind;
19use membacking::SharedMemoryBacking;
20use vm_resource::CanResolveTo;
21use vmcore::vm_task::VmTaskDriverSource;
22
23/// Marker trait for [`virt::Hypervisor`] implementations that are compatible
24/// with `openvmm_core`.
25///
26/// A blanket impl is provided for any [`virt::Hypervisor`] whose partition
27/// type satisfies `openvmm_core`'s requirements. This trait exists to
28/// provide a single, clean bound for [`ResolvedHypervisorBackend::new`].
29pub trait HypervisorBackend:
30 virt::Hypervisor<Partition: 'static + HvlitePartition> + Send + 'static
31where
32 for<'a> Self::ProtoPartition<'a>: Send,
33{
34}
35
36impl<H> HypervisorBackend for H
37where
38 H: virt::Hypervisor + Send + 'static,
39 H::Partition: 'static + HvlitePartition,
40 for<'a> H::ProtoPartition<'a>: Send,
41{
42}
43
44// ---- ResolvedHypervisorBackend ----
45
46/// Type alias for the VM creation function stored inside
47/// [`ResolvedHypervisorBackend`].
48pub(crate) type CreateVmFn = Box<
49 dyn FnOnce(
50 VmTaskDriverSource,
51 Manifest,
52 Option<SharedMemoryBacking>,
53 ) -> BoxFuture<'static, anyhow::Result<InitializedVm>>
54 + Send,
55>;
56
57/// The resolved output of a `Resource<HypervisorKind>`.
58///
59/// Wraps an erased hypervisor instance. Construct via [`Self::new`].
60pub struct ResolvedHypervisorBackend(pub(crate) CreateVmFn);
61
62impl ResolvedHypervisorBackend {
63 /// Wraps a [`virt::Hypervisor`] into a resolved backend.
64 ///
65 /// Only compiles for hypervisors whose partition type is compatible
66 /// with `openvmm_core`.
67 pub fn new<H>(hypervisor: H) -> Self
68 where
69 H: HypervisorBackend,
70 for<'a> H::ProtoPartition<'a>: Send,
71 {
72 Self(Box::new(move |driver_source, cfg, shared_memory| {
73 Box::pin(async move {
74 let mut hv = hypervisor;
75 let platform_info = virt::Hypervisor::platform_info(&hv);
76 InitializedVm::new_with_hypervisor(
77 driver_source,
78 &mut hv,
79 platform_info,
80 cfg,
81 shared_memory,
82 )
83 .await
84 })
85 }))
86 }
87}
88
89impl CanResolveTo<ResolvedHypervisorBackend> for HypervisorKind {
90 type Input<'a> = ();
91}
92
93/// Registers hypervisor backend probes for auto-detection.
94///
95/// Each entry is a unit struct implementing
96/// [`HypervisorProbe`](hypervisor_resources::HypervisorProbe).
97///
98/// Probes are checked in registration order when auto-detecting the
99/// hypervisor, so register them from highest to lowest priority.
100///
101/// Resource resolvers should be registered separately via
102/// [`vm_resource::register_static_resolvers!`].
103///
104/// # Example
105///
106/// ```ignore
107/// openvmm_core::register_hypervisor_probes! {
108/// #[cfg(all(target_os = "linux", feature = "virt_kvm", guest_is_native))]
109/// openvmm_hypervisors::kvm::KvmProbe,
110/// }
111/// ```
112#[macro_export]
113macro_rules! register_hypervisor_probes {
114 {} => {};
115 { $( $(#[$a:meta])* $probe:path ),+ $(,)? } => {
116 $(
117 $(#[$a])*
118 const _: () = {
119 static PROBE_INSTANCE: $probe = $probe;
120
121 #[hypervisor_resources::private::linkme::distributed_slice(
122 hypervisor_resources::private::HYPERVISOR_PROBES
123 )]
124 #[linkme(crate = hypervisor_resources::private::linkme)]
125 static PROBE: Option<&'static dyn hypervisor_resources::HypervisorProbe> =
126 Some(&PROBE_INSTANCE);
127 };
128 )*
129 };
130}