Skip to main content

firmware_uefi_resources/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Resource definitions for the Hyper-V UEFI helper device
5//! ([`firmware_uefi`](../firmware_uefi/index.html)).
6//!
7//! This crate exists so that crates which need to construct a UEFI device
8//! handle (e.g., `vm_manifest_builder`) or register platform-specific
9//! resolvers (e.g., `openvmm_core`, `underhill_core`) do not need to take a
10//! dependency on the full `firmware_uefi` device implementation.
11
12#![forbid(unsafe_code)]
13#![expect(missing_docs)]
14
15pub use firmware_uefi_custom_vars::BaseTemplate;
16pub use firmware_uefi_custom_vars::UefiVarsDeltaJson;
17pub use hcl_compat_uefi_nvram_resources::HclCompatNvramQuirks;
18pub use hyperv_secure_boot_templates::aarch64 as aarch64_secure_boot_templates;
19pub use hyperv_secure_boot_templates::x64 as x64_secure_boot_templates;
20
21use chipset_resources::CmosRtcTimeSourceHandleKind;
22use inspect::Inspect;
23use mesh::MeshPayload;
24use mesh_protobuf::Protobuf;
25use std::borrow::Cow;
26use uefi_specs::hyperv::debug_level::DEBUG_ERROR;
27use uefi_specs::hyperv::debug_level::DEBUG_FLAG_NAMES;
28use uefi_specs::hyperv::debug_level::DEBUG_INFO;
29use uefi_specs::hyperv::debug_level::DEBUG_WARN;
30use vm_resource::CanResolveTo;
31use vm_resource::Resource;
32use vm_resource::ResourceId;
33use vm_resource::ResourceKind;
34use vm_resource::kind::ChipsetDeviceHandleKind;
35use vm_resource::kind::NonVolatileStoreKind;
36use watchdog_core::platform::WatchdogPlatform;
37
38/// A centralized place to expose various service-specific interface traits that
39/// must be implemented by the "platform" hosting the UEFI device.
40///
41/// This layer of abstraction allows the re-using the same UEFI emulator between
42/// multiple VMMs (OpenVMM, Underhill, etc...), without tying the emulator to any
43/// VMM specific infrastructure (via some kind of compile-time feature flag
44/// infrastructure).
45pub mod platform {
46    /// A UEFI event that should be surfaced to the host.
47    #[derive(Debug)]
48    pub enum UefiEvent {
49        BootSuccess(BootInfo),
50        BootFailure(BootInfo),
51        NoBootDevice,
52    }
53
54    /// Information about a boot attempt.
55    #[derive(Debug)]
56    pub struct BootInfo {
57        pub secure_boot_succeeded: bool,
58    }
59
60    /// Interface to log UEFI events.
61    pub trait UefiLogger: Send {
62        fn log_event(&self, event: UefiEvent);
63    }
64
65    /// Callbacks that enable nvram services to revoke VSM on
66    /// `ExitBootServices` if requested by the guest.
67    pub trait VsmConfig: Send {
68        fn revoke_guest_vsm(&self);
69    }
70}
71
72/// The UEFI command set understood by the device.
73#[derive(Debug, Inspect, PartialEq, Clone, Protobuf)]
74pub enum UefiCommandSet {
75    X64,
76    Aarch64,
77}
78
79/// Log level configuration - encapsulates a `u32` mask where [`u32::MAX`] means
80/// "log everything".
81#[derive(Debug, Clone, Copy, PartialEq, Eq, Protobuf)]
82#[mesh(transparent)]
83pub struct LogLevel(u32);
84
85impl LogLevel {
86    /// Create default log level configuration (ERROR and WARN only)
87    pub const fn make_default() -> Self {
88        Self(DEBUG_ERROR | DEBUG_WARN)
89    }
90
91    /// Create info log level configuration (ERROR, WARN, and INFO)
92    pub const fn make_info() -> Self {
93        Self(DEBUG_ERROR | DEBUG_WARN | DEBUG_INFO)
94    }
95
96    /// Create full log level configuration (all levels)
97    pub const fn make_full() -> Self {
98        Self(u32::MAX)
99    }
100
101    /// Checks if a raw debug level should be logged based on this log level
102    /// configuration.
103    pub fn should_log(self, raw_debug_level: u32) -> bool {
104        if self.0 == u32::MAX {
105            true
106        } else {
107            (raw_debug_level & self.0) != 0
108        }
109    }
110
111    /// Returns the raw u32 mask.
112    pub fn as_u32(self) -> u32 {
113        self.0
114    }
115}
116
117impl Default for LogLevel {
118    fn default() -> Self {
119        Self::make_default()
120    }
121}
122
123impl Inspect for LogLevel {
124    fn inspect(&self, req: inspect::Request<'_>) {
125        let human_readable = debug_level_to_string(self.0);
126        req.respond()
127            .field("raw_value", self.0)
128            .field("debug_levels", human_readable.as_ref());
129    }
130}
131
132/// Converts a debug level mask to a human-readable string.
133pub fn debug_level_to_string(debug_level: u32) -> Cow<'static, str> {
134    if debug_level.count_ones() == 1 {
135        if let Some(&(_, name)) = DEBUG_FLAG_NAMES
136            .iter()
137            .find(|&&(flag, _)| flag == debug_level)
138        {
139            return Cow::Borrowed(name);
140        }
141    }
142
143    let flags: Vec<&str> = DEBUG_FLAG_NAMES
144        .iter()
145        .filter(|&&(flag, _)| debug_level & flag != 0)
146        .map(|&(_, name)| name)
147        .collect();
148
149    if flags.is_empty() {
150        Cow::Borrowed("UNKNOWN")
151    } else {
152        Cow::Owned(flags.join("+"))
153    }
154}
155
156/// Static configuration for the UEFI device.
157#[derive(Clone, Protobuf)]
158pub struct UefiConfig {
159    pub base_template: Option<BaseTemplate>,
160    pub custom_uefi_json: Option<UefiVarsDeltaJson>,
161    pub secure_boot: bool,
162    pub initial_generation_id: [u8; 16],
163    pub use_mmio: bool,
164    pub command_set: UefiCommandSet,
165    pub diagnostics_log_level: LogLevel,
166    pub diagnostics_rate_limit: Option<u32>,
167}
168
169/// Resource kind for the platform-provided UEFI logger.
170pub enum UefiLoggerHandleKind {}
171
172impl ResourceKind for UefiLoggerHandleKind {
173    const NAME: &'static str = "uefi_logger";
174}
175
176/// Resolved UEFI logger.
177pub struct ResolvedUefiLogger(pub Box<dyn platform::UefiLogger>);
178
179impl CanResolveTo<ResolvedUefiLogger> for UefiLoggerHandleKind {
180    type Input<'a> = ();
181}
182
183/// Resource kind for the UEFI watchdog platform implementation.
184pub enum UefiWatchdogPlatformHandleKind {}
185
186impl ResourceKind for UefiWatchdogPlatformHandleKind {
187    const NAME: &'static str = "uefi_watchdog_platform";
188}
189
190/// Resolved UEFI watchdog platform, including the receiver used by the device
191/// to wake up on watchdog timeout notifications.
192pub struct ResolvedUefiWatchdogPlatform {
193    pub platform: Box<dyn WatchdogPlatform>,
194    pub watchdog_recv: mesh::Receiver<()>,
195}
196
197impl CanResolveTo<ResolvedUefiWatchdogPlatform> for UefiWatchdogPlatformHandleKind {
198    type Input<'a> = &'a ();
199}
200
201/// Resource kind for the platform VSM configuration callbacks.
202pub enum UefiVsmConfigHandleKind {}
203
204impl ResourceKind for UefiVsmConfigHandleKind {
205    const NAME: &'static str = "uefi_vsm_config";
206}
207
208/// Resolved VSM configuration callbacks.
209pub struct ResolvedUefiVsmConfig(pub Box<dyn platform::VsmConfig>);
210
211impl CanResolveTo<ResolvedUefiVsmConfig> for UefiVsmConfigHandleKind {
212    type Input<'a> = ();
213}
214
215/// A handle to the Hyper-V UEFI helper chipset device.
216#[derive(MeshPayload)]
217pub struct UefiDeviceHandle {
218    /// Static configuration data.
219    pub config: UefiConfig,
220    /// Quirks for the NVRAM storage.
221    pub storage_quirks: Option<HclCompatNvramQuirks>,
222    /// Channel receiver for updated generation ID values.
223    pub generation_id_recv: mesh::Receiver<[u8; 16]>,
224    /// Platform-provided UEFI event logger.
225    pub logger: Resource<UefiLoggerHandleKind>,
226    /// UEFI NVRAM backing storage.
227    pub nvram_storage: Resource<NonVolatileStoreKind>,
228    /// Platform-provided UEFI watchdog hooks (NMI on x64, halt on aarch64,
229    /// etc.).
230    pub watchdog_platform: Resource<UefiWatchdogPlatformHandleKind>,
231    /// Optional platform-provided VSM revocation callbacks. Only used by
232    /// platforms that support guest VSM.
233    pub vsm_config: Option<Resource<UefiVsmConfigHandleKind>>,
234    /// Real-time clock time source used for UEFI time services.
235    pub time_source: Resource<CmosRtcTimeSourceHandleKind>,
236}
237
238impl ResourceId<ChipsetDeviceHandleKind> for UefiDeviceHandle {
239    const ID: &'static str = "hyperv_firmware_uefi";
240}