Skip to main content

guest_emulation_transport/
api.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Friendly Rust representations of the data sent over the GET.
5
6// These types are re-exported as-is, in order to avoid requiring consumers of
7// the GET and GED to also import get_protocol.
8pub use get_protocol::CreateRamGpaRangeFlags;
9pub use get_protocol::EventLogId;
10pub use get_protocol::GSP_CIPHERTEXT_MAX;
11pub use get_protocol::GspCiphertextContent;
12pub use get_protocol::GspCleartextContent;
13pub use get_protocol::GspExtendedStatusFlags;
14pub use get_protocol::IGVM_ATTEST_MSG_REQ_AGENT_DATA_MAX_SIZE;
15pub use get_protocol::MAX_TRANSFER_SIZE;
16pub use get_protocol::NUMBER_GSP;
17pub use get_protocol::ProtocolVersion;
18pub use get_protocol::SaveGuestVtl2StateFlags;
19pub use get_protocol::VmgsIoStatus;
20
21use guid::Guid;
22use mesh::MeshPayload;
23use std::time::Duration;
24use zerocopy::FromZeros;
25
26/// Device platform settings.
27#[expect(missing_docs)]
28pub mod platform_settings {
29    pub use get_protocol::dps_json::PcatBootDevice;
30
31    use get_protocol::dps_json::EfiDiagnosticsLogLevelType;
32    use get_protocol::dps_json::GetTpmVersion;
33    use get_protocol::dps_json::GuestStateEncryptionPolicy;
34    use get_protocol::dps_json::GuestStateLifetime;
35    use get_protocol::dps_json::HardwareSealingPolicy;
36    use get_protocol::dps_json::ManagementVtlFeatures;
37    use guid::Guid;
38    use inspect::Inspect;
39
40    /// All available device platform settings.
41    #[derive(Debug, Inspect)]
42    pub struct DevicePlatformSettings {
43        pub smbios: Smbios,
44        pub general: General,
45        #[inspect(with = "inspect::iter_by_index")]
46        pub acpi_tables: Vec<Vec<u8>>,
47    }
48
49    /// All available SMBIOS related config.
50    #[derive(Debug, Inspect)]
51    pub struct Smbios {
52        pub serial_number: String,
53        pub base_board_serial_number: String,
54        pub chassis_serial_number: String,
55        pub chassis_asset_tag: String,
56
57        pub system_manufacturer: String,
58        pub system_product_name: String,
59        pub system_version: String,
60        pub system_sku_number: String,
61        pub system_family: String,
62        pub bios_lock_string: String,
63        pub memory_device_serial_number: String,
64
65        // These two arrive base64-encoded as raw bytes in the DPS JSON, so they
66        // are kept as `Vec<u8>` rather than forcing a UTF-8 conversion.
67        pub processor_manufacturer: Vec<u8>,
68        pub processor_version: Vec<u8>,
69        pub processor_id: u64,
70        pub external_clock: u16,
71        pub max_speed: u16,
72        pub current_speed: u16,
73        pub processor_characteristics: u16,
74        pub processor_family2: u16,
75        pub processor_type: u8,
76        pub voltage: u8,
77        pub status: u8,
78        pub processor_upgrade: u8,
79    }
80
81    /// All available general device platform configuration.
82    // DEVNOTE: "general" is code for "not well organized", so if you've got a
83    // better way to organize these settings, do consider cleaning this up a bit!
84    #[derive(Debug, Inspect)]
85    pub struct General {
86        pub secure_boot_enabled: bool,
87        pub secure_boot_template: SecureBootTemplateType,
88        pub bios_guid: Guid,
89        pub console_mode: UefiConsoleMode,
90        pub battery_enabled: bool,
91        pub processor_idle_enabled: bool,
92        pub tpm_enabled: bool,
93
94        pub com1_enabled: bool,
95        pub com1_debugger_mode: bool,
96        pub com1_vmbus_redirector: bool,
97        pub com2_enabled: bool,
98        pub com2_debugger_mode: bool,
99        pub com2_vmbus_redirector: bool,
100
101        pub firmware_debugging_enabled: bool,
102        pub hibernation_enabled: bool,
103
104        pub suppress_attestation: Option<bool>,
105        pub generation_id: Option<[u8; 16]>,
106
107        pub legacy_memory_map: bool,
108        pub pause_after_boot_failure: bool,
109        pub pxe_ip_v6: bool,
110        pub measure_additional_pcrs: bool,
111        pub disable_frontpage: bool,
112        pub disable_sha384_pcr: bool,
113        pub media_present_enabled_by_default: bool,
114        pub vpci_boot_enabled: bool,
115        pub memory_protection_mode: MemoryProtectionMode,
116        pub default_boot_always_attempt: bool,
117        pub num_lock_enabled: bool,
118        #[inspect(with = "|x| inspect::iter_by_index(x).map_value(inspect::AsDebug)")]
119        pub pcat_boot_device_order: [PcatBootDevice; 4],
120
121        pub vpci_instance_filter: Option<Guid>,
122        pub nvdimm_count: u16,
123        pub psp_enabled: bool,
124
125        pub vmbus_redirection_enabled: bool,
126        pub always_relay_host_mmio: bool,
127        pub vtl2_settings: Option<underhill_config::Vtl2Settings>,
128
129        pub is_servicing_scenario: bool,
130        pub watchdog_enabled: bool,
131        pub firmware_mode_is_pcat: bool,
132        pub imc_enabled: bool,
133        pub cxl_memory_enabled: bool,
134        #[inspect(debug)]
135        pub efi_diagnostics_log_level: EfiDiagnosticsLogLevelType,
136        #[inspect(debug)]
137        pub guest_state_lifetime: GuestStateLifetime,
138        #[inspect(debug)]
139        pub guest_state_encryption_policy: GuestStateEncryptionPolicy,
140        #[inspect(debug)]
141        pub management_vtl_features: ManagementVtlFeatures,
142        pub force_dma_bounce_enabled: bool,
143        #[inspect(debug)]
144        pub hardware_sealing_policy: HardwareSealingPolicy,
145        #[inspect(debug)]
146        pub tpm_version: Option<GetTpmVersion>,
147    }
148
149    #[derive(Copy, Clone, Debug, Inspect)]
150    pub enum MemoryProtectionMode {
151        Disabled = 0,
152        Default = 1,
153        Strict = 2,
154        Relaxed = 3,
155    }
156
157    #[derive(Debug, Inspect)]
158    pub enum UefiConsoleMode {
159        /// video+kbd (having a head)
160        Default = 0,
161        /// headless with COM1 serial console
162        COM1 = 1,
163        /// headless with COM2 serial console
164        COM2 = 2,
165        /// headless
166        None = 3,
167    }
168
169    #[derive(Debug, Inspect)]
170    pub enum SecureBootTemplateType {
171        /// No template to apply.
172        None,
173        /// Apply the Windows only CA.
174        MicrosoftWindows,
175        /// Apply the Microsoft UEFI CA.
176        MicrosoftUefiCertificateAuthority,
177    }
178}
179
180/// Response fields for Guest State Protection sent from the host
181pub struct GuestStateProtection {
182    /// Guest State Protection ciphertext content
183    pub encrypted_gsp: GspCiphertextContent,
184    /// Guest State Protection cleartext content
185    pub decrypted_gsp: [GspCleartextContent; NUMBER_GSP as usize],
186    /// Extended status flags
187    pub extended_status_flags: GspExtendedStatusFlags,
188    /// Randomized new_gsp sent in the GuestStateProtectionRequest message to
189    /// the host
190    pub new_gsp: GspCleartextContent,
191}
192
193impl GuestStateProtection {
194    /// Construct a blank instance of `GuestStateProtection`
195    pub fn new_zeroed() -> GuestStateProtection {
196        GuestStateProtection {
197            encrypted_gsp: GspCiphertextContent::new_zeroed(),
198            decrypted_gsp: [GspCleartextContent::new_zeroed(); NUMBER_GSP as usize],
199            extended_status_flags: GspExtendedStatusFlags::new_zeroed(),
200            new_gsp: GspCleartextContent::new_zeroed(),
201        }
202    }
203}
204
205/// Response fields for Guest State Protection by ID from the host
206#[derive(Copy, Clone)]
207pub struct GuestStateProtectionById {
208    /// Guest State Protection cleartext content
209    pub seed: GspCleartextContent,
210    /// Extended status flags
211    pub extended_status_flags: GspExtendedStatusFlags,
212}
213
214impl GuestStateProtectionById {
215    /// Construct a blank instance of `GuestStateProtectionById`
216    pub fn new_zeroed() -> GuestStateProtectionById {
217        GuestStateProtectionById {
218            seed: GspCleartextContent::new_zeroed(),
219            extended_status_flags: GspExtendedStatusFlags::new_zeroed(),
220        }
221    }
222}
223
224/// Response for IGVM Attest from the host
225#[derive(Clone)]
226pub struct IgvmAttest {
227    /// Response data
228    pub response: Vec<u8>,
229}
230
231/// Response fields for VMGS Get Device Info from the host
232pub struct VmgsGetDeviceInfo {
233    /// Status of the request
234    pub status: VmgsIoStatus,
235    /// Logical sectors
236    pub capacity: u64,
237    /// Bytes per logical sector
238    pub bytes_per_logical_sector: u16,
239    /// Bytes per physical sector
240    pub bytes_per_physical_sector: u16,
241    /// Maximum transfer size bytes
242    pub maximum_transfer_size_bytes: u32,
243}
244
245/// Response fields from Time from the host
246#[derive(Debug, Copy, Clone)]
247pub struct Time {
248    /// UTC, in 100ns units since Jan 1 1601.
249    ///
250    /// (corresponds to `RtlGetSystemTime()` on the Host)
251    pub utc: i64,
252    /// Time zone (as minutes from UTC)
253    pub time_zone: i16,
254}
255
256impl Time {
257    /// Convert this time to a `jiff::Zoned`.
258    pub fn to_jiff(self) -> jiff::Zoned {
259        const NANOS_IN_SECOND: i64 = 1_000_000_000;
260        const NANOS_100_IN_SECOND: i64 = NANOS_IN_SECOND / 100;
261
262        let windows_epoch_unix_seconds = jiff::civil::date(1601, 1, 1)
263            .at(0, 0, 0, 0)
264            .to_zoned(jiff::tz::TimeZone::UTC)
265            .unwrap()
266            .timestamp();
267
268        let host_time_secs = self.utc / NANOS_100_IN_SECOND;
269        let host_time_nanos = (self.utc % NANOS_100_IN_SECOND) * 100;
270
271        let host_time_utc = jiff::Timestamp::new(
272            windows_epoch_unix_seconds.as_second() + host_time_secs,
273            host_time_nanos as i32,
274        )
275        .unwrap();
276
277        let offset_seconds = -self.time_zone as i32 * 60;
278        let tz = jiff::tz::TimeZone::fixed(jiff::tz::Offset::from_seconds(offset_seconds).unwrap());
279        host_time_utc.to_zoned(tz)
280    }
281}
282
283/// A handle returned by `CreateRamGpaRange`, which can be passed to
284/// `ResetRamGpaRange` in order to reset the associated range.
285#[derive(Debug)]
286pub struct RemoteRamGpaRangeHandle(u32);
287
288impl RemoteRamGpaRangeHandle {
289    /// Return a raw u32 that represents this handle
290    pub fn as_raw(&self) -> u32 {
291        self.0
292    }
293
294    /// Create a new [`RemoteRamGpaRangeHandle`] from a raw u32 previously
295    /// returned from `into_raw`.
296    pub fn from_raw(handle: u32) -> Self {
297        RemoteRamGpaRangeHandle(handle)
298    }
299}
300
301/// Request to save Guest state during servicing.
302#[derive(MeshPayload)]
303pub struct GuestSaveRequest {
304    /// GUID associated with the request.
305    pub correlation_id: Guid,
306    /// When to complete the request.
307    pub timeout_hint: Duration,
308    /// Flags bitfield.
309    #[mesh(encoding = "mesh::payload::encoding::ZeroCopyEncoding")]
310    pub capabilities_flags: SaveGuestVtl2StateFlags,
311}