Skip to main content

firmware_uefi/
resolver.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Resource resolver for the Hyper-V UEFI helper chipset device.
5
6use crate::UefiDevice;
7use crate::UefiRuntimeDeps;
8use async_trait::async_trait;
9use chipset_device_resources::GPE0_LINE_SET;
10use chipset_device_resources::IRQ_LINE_SET;
11use chipset_device_resources::ResolveChipsetDeviceHandleParams;
12use chipset_device_resources::ResolvedChipsetDevice;
13use chipset_resources::CmosRtcTimeSourceHandleKind;
14use firmware_uefi_resources::ResolvedUefiWatchdogPlatform;
15use firmware_uefi_resources::UefiCommandSet;
16use firmware_uefi_resources::UefiDeviceHandle;
17use firmware_uefi_resources::UefiLoggerHandleKind;
18use firmware_uefi_resources::UefiVsmConfigHandleKind;
19use firmware_uefi_resources::UefiWatchdogPlatformHandleKind;
20use hcl_compat_uefi_nvram_storage::HclCompatNvram;
21use thiserror::Error;
22use vm_resource::AsyncResolveResource;
23use vm_resource::ResolveError;
24use vm_resource::ResourceResolver;
25use vm_resource::declare_static_async_resolver;
26use vm_resource::kind::ChipsetDeviceHandleKind;
27use vm_resource::kind::NonVolatileStoreKind;
28
29/// Resolver for the Hyper-V UEFI helper device.
30pub struct UefiDeviceResolver;
31
32declare_static_async_resolver! {
33    UefiDeviceResolver,
34    (ChipsetDeviceHandleKind, UefiDeviceHandle),
35}
36
37/// Errors that can occur while resolving a UEFI device handle.
38#[derive(Debug, Error)]
39pub enum ResolveUefiDeviceError {
40    /// Failed to resolve the UEFI logger.
41    #[error("failed to resolve UEFI logger")]
42    ResolveLogger(#[source] ResolveError),
43    /// Failed to resolve the UEFI NVRAM storage.
44    #[error("failed to resolve UEFI NVRAM storage")]
45    ResolveNvramStorage(#[source] ResolveError),
46    /// Failed to resolve the UEFI watchdog platform.
47    #[error("failed to resolve UEFI watchdog platform")]
48    ResolveWatchdogPlatform(#[source] ResolveError),
49    /// Failed to resolve the UEFI VSM configuration.
50    #[error("failed to resolve UEFI VSM configuration")]
51    ResolveVsmConfig(#[source] ResolveError),
52    /// Failed to resolve the UEFI time source.
53    #[error("failed to resolve UEFI time source")]
54    ResolveTimeSource(#[source] ResolveError),
55    /// Failed to initialize the UEFI device.
56    #[error("failed to initialize UEFI device")]
57    Init(#[from] crate::UefiInitError),
58}
59
60// The ACPI GPE0 line to use for generation ID. This must match the value in
61// the DSDT.
62const GPE0_LINE_GENERATION_ID: u32 = 0;
63// For ARM64, 3 + 32 (SPI range start) = 35, the SYSTEM_SPI_GENCOUNTER vector
64// for the GIC.
65const GENERATION_ID_IRQ: u32 = 3;
66
67#[async_trait]
68impl AsyncResolveResource<ChipsetDeviceHandleKind, UefiDeviceHandle> for UefiDeviceResolver {
69    type Output = ResolvedChipsetDevice;
70    type Error = ResolveUefiDeviceError;
71
72    async fn resolve(
73        &self,
74        resolver: &ResourceResolver,
75        resource: UefiDeviceHandle,
76        input: ResolveChipsetDeviceHandleParams<'_>,
77    ) -> Result<Self::Output, Self::Error> {
78        let UefiDeviceHandle {
79            config,
80            storage_quirks,
81            generation_id_recv,
82            logger,
83            nvram_storage,
84            watchdog_platform,
85            vsm_config,
86            time_source,
87        } = resource;
88
89        let logger = resolver
90            .resolve::<UefiLoggerHandleKind, _>(logger, ())
91            .await
92            .map_err(ResolveUefiDeviceError::ResolveLogger)?
93            .0;
94        let nvram_storage = resolver
95            .resolve::<NonVolatileStoreKind, _>(nvram_storage, &())
96            .await
97            .map_err(ResolveUefiDeviceError::ResolveNvramStorage)?
98            .0;
99        let ResolvedUefiWatchdogPlatform {
100            platform: watchdog_platform,
101            watchdog_recv,
102        } = resolver
103            .resolve::<UefiWatchdogPlatformHandleKind, _>(watchdog_platform, &())
104            .await
105            .map_err(ResolveUefiDeviceError::ResolveWatchdogPlatform)?;
106        let vsm_config = if let Some(vsm_config) = vsm_config {
107            Some(
108                resolver
109                    .resolve::<UefiVsmConfigHandleKind, _>(vsm_config, ())
110                    .await
111                    .map_err(ResolveUefiDeviceError::ResolveVsmConfig)?
112                    .0,
113            )
114        } else {
115            None
116        };
117        let time_source = resolver
118            .resolve::<CmosRtcTimeSourceHandleKind, _>(time_source, ())
119            .await
120            .map_err(ResolveUefiDeviceError::ResolveTimeSource)?
121            .0;
122
123        let notify_interrupt = match config.command_set {
124            UefiCommandSet::X64 => {
125                input
126                    .configure
127                    .new_line(GPE0_LINE_SET, "genid", GPE0_LINE_GENERATION_ID)
128            }
129            UefiCommandSet::Aarch64 => {
130                input
131                    .configure
132                    .new_line(IRQ_LINE_SET, "genid", GENERATION_ID_IRQ)
133            }
134        };
135
136        let nvram_storage = Box::new(HclCompatNvram::new(
137            vmm_core::emuplat::hcl_compat_uefi_nvram_storage::VmgsStorageBackendAdapter(
138                nvram_storage,
139            ),
140            storage_quirks,
141        ));
142
143        let gm = input.encrypted_guest_memory.clone();
144        let runtime_deps = UefiRuntimeDeps {
145            gm: gm.clone(),
146            nvram_storage,
147            logger,
148            vmtime: input.vmtime,
149            watchdog_platform,
150            watchdog_recv,
151            generation_id_deps: generation_id::GenerationIdRuntimeDeps {
152                generation_id_recv,
153                gm,
154                notify_interrupt,
155            },
156            vsm_config,
157            time_source,
158        };
159
160        let device = UefiDevice::new(runtime_deps, config, input.is_restoring).await?;
161        Ok(device.into())
162    }
163}