Skip to main content

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}