petri/vm/openvmm/
modify.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Helpers to modify a [`PetriVmConfigOpenVmm`] from its defaults.
5
6// TODO: Delete all modification functions that are not backend-specific
7// from this file, add necessary settings to the backend-agnostic
8// `PetriVmConfig`, and add corresponding functions to `PetriVmBuilder`.
9
10use super::MANA_INSTANCE;
11use super::NIC_MAC_ADDRESS;
12use super::PetriVmConfigOpenVmm;
13use chipset_resources::battery::BatteryDeviceHandleX64;
14use chipset_resources::battery::HostBatteryUpdate;
15use gdma_resources::GdmaDeviceHandle;
16use gdma_resources::VportDefinition;
17use get_resources::ged::IgvmAttestTestConfig;
18use hvlite_defs::config::Config;
19use hvlite_defs::config::DeviceVtl;
20use hvlite_defs::config::LoadMode;
21use hvlite_defs::config::VpciDeviceConfig;
22use hvlite_defs::config::Vtl2BaseAddressType;
23use vm_resource::IntoResource;
24use vmotherboard::ChipsetDeviceHandle;
25use vtl2_settings_proto::Vtl2Settings;
26
27impl PetriVmConfigOpenVmm {
28    /// Enable the VTL0 alias map.
29    // TODO: Remove once #912 is fixed.
30    pub fn with_vtl0_alias_map(mut self) -> Self {
31        self.config
32            .hypervisor
33            .with_vtl2
34            .as_mut()
35            .expect("Not an openhcl config.")
36            .vtl0_alias_map = true;
37        self
38    }
39
40    /// Enable the battery for the VM.
41    pub fn with_battery(mut self) -> Self {
42        if self.firmware.is_openhcl() {
43            self.ged.as_mut().unwrap().enable_battery = true;
44        } else {
45            self.config.chipset_devices.push(ChipsetDeviceHandle {
46                name: "battery".to_string(),
47                resource: BatteryDeviceHandleX64 {
48                    battery_status_recv: {
49                        let (tx, rx) = mesh::channel();
50                        tx.send(HostBatteryUpdate::default_present());
51                        rx
52                    },
53                }
54                .into_resource(),
55            });
56            if let LoadMode::Uefi { enable_battery, .. } = &mut self.config.load_mode {
57                *enable_battery = true;
58            }
59        }
60        self
61    }
62
63    /// Set test config for the GED's IGVM attest request handler
64    pub fn with_igvm_attest_test_config(mut self, config: IgvmAttestTestConfig) -> Self {
65        if !self.firmware.is_openhcl() {
66            panic!("IGVM Attest test config is only supported for OpenHCL.")
67        };
68
69        let ged = self.ged.as_mut().expect("No GED to configure TPM");
70
71        ged.igvm_attest_test_config = Some(config);
72
73        self
74    }
75
76    /// Enable a synthnic for the VM.
77    ///
78    /// Uses a mana emulator and the paravisor if a paravisor is present.
79    pub fn with_nic(mut self) -> Self {
80        let endpoint =
81            net_backend_resources::consomme::ConsommeHandle { cidr: None }.into_resource();
82        if self.resources.vtl2_settings.is_some() {
83            self.config.vpci_devices.push(VpciDeviceConfig {
84                vtl: DeviceVtl::Vtl2,
85                instance_id: MANA_INSTANCE,
86                resource: GdmaDeviceHandle {
87                    vports: vec![VportDefinition {
88                        mac_address: NIC_MAC_ADDRESS,
89                        endpoint,
90                    }],
91                }
92                .into_resource(),
93            });
94
95            self.resources
96                .vtl2_settings
97                .as_mut()
98                .unwrap()
99                .dynamic
100                .as_mut()
101                .unwrap()
102                .nic_devices
103                .push(vtl2_settings_proto::NicDeviceLegacy {
104                    instance_id: MANA_INSTANCE.to_string(),
105                    subordinate_instance_id: None,
106                    max_sub_channels: None,
107                });
108        } else {
109            const NETVSP_INSTANCE: guid::Guid = guid::guid!("c6c46cc3-9302-4344-b206-aef65e5bd0a2");
110            self.config.vmbus_devices.push((
111                DeviceVtl::Vtl0,
112                netvsp_resources::NetvspHandle {
113                    instance_id: NETVSP_INSTANCE,
114                    mac_address: NIC_MAC_ADDRESS,
115                    endpoint,
116                    max_queues: None,
117                }
118                .into_resource(),
119            ));
120        }
121
122        self
123    }
124
125    /// Add custom VTL 2 settings.
126    // TODO: At some point we want to replace uses of this with nicer with_disk,
127    // with_nic, etc. methods.
128    pub fn with_custom_vtl2_settings(mut self, f: impl FnOnce(&mut Vtl2Settings)) -> Self {
129        f(self
130            .resources
131            .vtl2_settings
132            .as_mut()
133            .expect("Custom VTL 2 settings are only supported with OpenHCL."));
134        self
135    }
136
137    /// Load with the specified VTL2 relocation mode.
138    pub fn with_vtl2_relocation_mode(mut self, mode: Vtl2BaseAddressType) -> Self {
139        let LoadMode::Igvm {
140            vtl2_base_address, ..
141        } = &mut self.config.load_mode
142        else {
143            panic!("vtl2 relocation mode is only supported for OpenHCL firmware")
144        };
145        *vtl2_base_address = mode;
146        self
147    }
148
149    /// This is intended for special one-off use cases. As soon as something
150    /// is needed in multiple tests we should consider making it a supported
151    /// pattern.
152    pub fn with_custom_config(mut self, f: impl FnOnce(&mut Config)) -> Self {
153        f(&mut self.config);
154        self
155    }
156
157    /// Specifies whether VTL2 should be allowed to access VTL0 memory before it
158    /// sets any VTL protections.
159    ///
160    /// This is needed just for the TMK VMM, and only until it gains support for
161    /// setting VTL protections.
162    pub fn with_allow_early_vtl0_access(mut self, allow: bool) -> Self {
163        self.config
164            .hypervisor
165            .with_vtl2
166            .as_mut()
167            .unwrap()
168            .late_map_vtl0_memory =
169            (!allow).then_some(hvlite_defs::config::LateMapVtl0MemoryPolicy::InjectException);
170
171        self
172    }
173}