get_protocol/
dps_json.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! The schema defined in this file must match the one defined in
5//! `onecore/vm/schema/mars/Config/Config.Devices.Chipset.mars`.
6
7use guid::Guid;
8use serde::Deserialize;
9use serde::Serialize;
10
11/// A type-alias to mark fields as _temporarily_ optional to preserve
12/// build-to-compat compatibility during internal testing.
13///
14/// i.e: a newly added field should be marked as `DevLoopCompatOption` until
15/// we're sure that all hosts that we expect this new underhill version to run
16/// on are updated to send the new field.
17///
18/// It would be **very bad form** to ship a library/binary that includes
19/// `DevLoopCompatOption` fields!
20pub type DevLoopCompatOption<T> = Option<T>;
21
22#[derive(Debug, Default, Deserialize, Serialize)]
23#[serde(rename_all = "PascalCase")]
24pub struct DevicePlatformSettingsV2Json {
25    pub v1: HclDevicePlatformSettings,
26    pub v2: HclDevicePlatformSettingsV2,
27}
28
29// The legacy DPS response's mars schema specifies all fields as [OmitEmpty],
30// which we handle by setting `serde(default)` at the struct level.
31//
32// This is _not_ the case in the newer DPS packet, whereby all fields must be
33// present, specifying "empty values" if the data is not set.
34#[derive(Debug, Default, Deserialize, Serialize)]
35#[serde(default, rename_all = "PascalCase")]
36pub struct HclDevicePlatformSettings {
37    pub secure_boot_enabled: bool,
38    pub secure_boot_template_id: HclSecureBootTemplateId,
39    pub enable_battery: bool,
40    pub enable_processor_idle: bool,
41    pub enable_tpm: bool,
42    pub com1: HclUartSettings,
43    pub com2: HclUartSettings,
44    #[serde(with = "serde_helpers::as_string")]
45    pub bios_guid: Guid,
46    pub console_mode: u8,
47    pub enable_firmware_debugging: bool,
48    pub enable_hibernation: bool,
49    pub serial_number: String,
50    pub base_board_serial_number: String,
51    pub chassis_serial_number: String,
52    pub chassis_asset_tag: String,
53}
54
55// requires a `Default` derive, due to [OmitEmpty] used in parent struct
56#[derive(Debug, Default, Deserialize, Serialize)]
57#[serde(rename_all = "PascalCase")]
58pub enum HclSecureBootTemplateId {
59    #[serde(rename = "None")]
60    #[default]
61    None,
62    #[serde(rename = "MicrosoftWindows")]
63    MicrosoftWindows,
64    #[serde(rename = "MicrosoftUEFICertificateAuthority")]
65    MicrosoftUEFICertificateAuthority,
66}
67
68// requires a `Default` derive, due to [OmitEmpty] used in parent struct
69#[derive(Debug, Default, Deserialize, Serialize)]
70#[serde(default, rename_all = "PascalCase")]
71pub struct HclUartSettings {
72    pub enable_port: bool,
73    pub debugger_mode: bool,
74    pub enable_vmbus_redirector: bool,
75}
76
77#[derive(Debug, Default, Deserialize, Serialize)]
78#[serde(rename_all = "PascalCase")]
79pub struct HclDevicePlatformSettingsV2 {
80    pub r#static: HclDevicePlatformSettingsV2Static,
81    pub dynamic: HclDevicePlatformSettingsV2Dynamic,
82}
83
84/// Boot device order entry used by the PCAT Bios.
85#[derive(Debug, Copy, Clone, Deserialize, Serialize)]
86pub enum PcatBootDevice {
87    Floppy,
88    Optical,
89    HardDrive,
90    Network,
91}
92
93/// Guest state lifetime
94#[derive(Debug, Copy, Clone, Deserialize, Serialize, Default)]
95pub enum GuestStateLifetime {
96    #[default]
97    Default,
98    ReprovisionOnFailure,
99    Reprovision,
100    Ephemeral,
101}
102
103#[derive(Debug, Default, Deserialize, Serialize)]
104#[serde(rename_all = "PascalCase")]
105pub struct HclDevicePlatformSettingsV2Static {
106    //UEFI flags
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 memory_protection_mode: u8,
115    #[serde(default)]
116    pub default_boot_always_attempt: bool,
117
118    // UEFI info
119    pub vpci_boot_enabled: bool,
120    #[serde(default)]
121    #[serde(with = "serde_helpers::opt_guid_str")]
122    pub vpci_instance_filter: Option<Guid>,
123
124    // PCAT info
125    pub num_lock_enabled: bool,
126    pub pcat_boot_device_order: Option<[PcatBootDevice; 4]>,
127
128    pub smbios: HclDevicePlatformSettingsV2StaticSmbios,
129
130    // Per field serde(default) is required here because that
131    // we can't reply on serde's normal behavior for optional
132    // fields (put None if not present in json) because we're
133    // using custom serialize/deserialize methods
134    #[serde(default)]
135    #[serde(with = "serde_helpers::opt_base64_vec")]
136    pub vtl2_settings: Option<Vec<u8>>,
137
138    pub vmbus_redirection_enabled: bool,
139    pub no_persistent_secrets: bool,
140    pub watchdog_enabled: bool,
141    // this `#[serde(default)]` shouldn't have been necessary, but we let a
142    // `[OmitEmpty]` marker slip past in code review...
143    #[serde(default)]
144    pub firmware_mode_is_pcat: bool,
145    #[serde(default)]
146    pub always_relay_host_mmio: bool,
147    #[serde(default)]
148    pub imc_enabled: bool,
149    #[serde(default)]
150    pub cxl_memory_enabled: bool,
151    #[serde(default)]
152    pub guest_state_lifetime: GuestStateLifetime,
153}
154
155#[derive(Debug, Default, Deserialize, Serialize)]
156#[serde(rename_all = "PascalCase")]
157pub struct HclDevicePlatformSettingsV2StaticSmbios {
158    pub system_manufacturer: String,
159    pub system_product_name: String,
160    pub system_version: String,
161    #[serde(rename = "SystemSKUNumber")]
162    pub system_sku_number: String,
163    pub system_family: String,
164    pub bios_lock_string: String,
165    pub memory_device_serial_number: String,
166}
167
168#[derive(Debug, Default, Deserialize, Serialize)]
169#[serde(rename_all = "PascalCase")]
170pub struct HclDevicePlatformSettingsV2Dynamic {
171    pub nvdimm_count: u16,
172    pub enable_psp: bool,
173    pub generation_id_low: u64,
174    pub generation_id_high: u64,
175    pub smbios: HclDevicePlatformSettingsV2DynamicSmbios,
176    pub is_servicing_scenario: bool,
177
178    #[serde(default)]
179    #[serde(with = "serde_helpers::vec_base64_vec")]
180    pub acpi_tables: Vec<Vec<u8>>,
181}
182
183#[derive(Debug, Default, Deserialize, Serialize)]
184#[serde(rename_all = "PascalCase")]
185pub struct HclDevicePlatformSettingsV2DynamicSmbios {
186    #[serde(with = "serde_helpers::base64_vec")]
187    pub processor_manufacturer: Vec<u8>,
188    #[serde(with = "serde_helpers::base64_vec")]
189    pub processor_version: Vec<u8>,
190
191    #[serde(rename = "ProcessorID")]
192    pub processor_id: u64,
193    pub external_clock: u16,
194    pub max_speed: u16,
195    pub current_speed: u16,
196    pub processor_characteristics: u16,
197    pub processor_family2: u16,
198    pub processor_type: u8,
199    pub voltage: u8,
200    pub status: u8,
201    pub processor_upgrade: u8,
202}
203
204#[cfg(test)]
205mod test {
206    use super::*;
207
208    #[test]
209    fn smoke_test_sample() {
210        serde_json::from_slice::<DevicePlatformSettingsV2Json>(include_bytes!(
211            "dps_test_json.json"
212        ))
213        .unwrap();
214    }
215
216    #[test]
217    fn smoke_test_sample_with_vtl2settings() {
218        serde_json::from_slice::<DevicePlatformSettingsV2Json>(include_bytes!(
219            "dps_test_json_with_vtl2settings.json"
220        ))
221        .unwrap();
222    }
223}