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 openvmm_defs::config::Config;
19use openvmm_defs::config::DeviceVtl;
20use openvmm_defs::config::LoadMode;
21use openvmm_defs::config::VpciDeviceConfig;
22use openvmm_defs::config::Vtl2BaseAddressType;
23use vm_resource::IntoResource;
24use vmotherboard::ChipsetDeviceHandle;
25
26impl PetriVmConfigOpenVmm {
27    /// Enable the VTL0 alias map.
28    // TODO: Remove once #912 is fixed.
29    pub fn with_vtl0_alias_map(mut self) -> Self {
30        self.config
31            .hypervisor
32            .with_vtl2
33            .as_mut()
34            .expect("Not an openhcl config.")
35            .vtl0_alias_map = true;
36        self
37    }
38
39    /// Enable the battery for the VM.
40    pub fn with_battery(mut self) -> Self {
41        if self.resources.properties.is_openhcl {
42            self.ged.as_mut().unwrap().enable_battery = true;
43        } else {
44            self.config.chipset_devices.push(ChipsetDeviceHandle {
45                name: "battery".to_string(),
46                resource: BatteryDeviceHandleX64 {
47                    battery_status_recv: {
48                        let (tx, rx) = mesh::channel();
49                        tx.send(HostBatteryUpdate::default_present());
50                        rx
51                    },
52                }
53                .into_resource(),
54            });
55            if let LoadMode::Uefi { enable_battery, .. } = &mut self.config.load_mode {
56                *enable_battery = true;
57            }
58        }
59        self
60    }
61
62    /// Set test config for the GED's IGVM attest request handler
63    pub fn with_igvm_attest_test_config(mut self, config: IgvmAttestTestConfig) -> Self {
64        if !self.resources.properties.is_openhcl {
65            panic!("IGVM Attest test config is only supported for OpenHCL.")
66        };
67
68        let ged = self.ged.as_mut().expect("No GED to configure TPM");
69
70        ged.igvm_attest_test_config = Some(config);
71
72        self
73    }
74
75    /// Enable a synthnic for the VM.
76    ///
77    /// Uses a mana emulator and the paravisor if a paravisor is present.
78    pub fn with_nic(mut self) -> Self {
79        let endpoint =
80            net_backend_resources::consomme::ConsommeHandle { cidr: None }.into_resource();
81        if let Some(vtl2_settings) = self.runtime_config.vtl2_settings.as_mut() {
82            self.config.vpci_devices.push(VpciDeviceConfig {
83                vtl: DeviceVtl::Vtl2,
84                instance_id: MANA_INSTANCE,
85                resource: GdmaDeviceHandle {
86                    vports: vec![VportDefinition {
87                        mac_address: NIC_MAC_ADDRESS,
88                        endpoint,
89                    }],
90                }
91                .into_resource(),
92            });
93
94            vtl2_settings.dynamic.as_mut().unwrap().nic_devices.push(
95                vtl2_settings_proto::NicDeviceLegacy {
96                    instance_id: MANA_INSTANCE.to_string(),
97                    subordinate_instance_id: None,
98                    max_sub_channels: None,
99                },
100            );
101        } else {
102            const NETVSP_INSTANCE: guid::Guid = guid::guid!("c6c46cc3-9302-4344-b206-aef65e5bd0a2");
103            self.config.vmbus_devices.push((
104                DeviceVtl::Vtl0,
105                netvsp_resources::NetvspHandle {
106                    instance_id: NETVSP_INSTANCE,
107                    mac_address: NIC_MAC_ADDRESS,
108                    endpoint,
109                    max_queues: None,
110                }
111                .into_resource(),
112            ));
113        }
114
115        self
116    }
117
118    /// Load with the specified VTL2 relocation mode.
119    pub fn with_vtl2_relocation_mode(mut self, mode: Vtl2BaseAddressType) -> Self {
120        let LoadMode::Igvm {
121            vtl2_base_address, ..
122        } = &mut self.config.load_mode
123        else {
124            panic!("vtl2 relocation mode is only supported for OpenHCL firmware")
125        };
126        *vtl2_base_address = mode;
127        self
128    }
129
130    /// This is intended for special one-off use cases. As soon as something
131    /// is needed in multiple tests we should consider making it a supported
132    /// pattern.
133    pub fn with_custom_config(mut self, f: impl FnOnce(&mut Config)) -> Self {
134        f(&mut self.config);
135        self
136    }
137
138    /// Specifies whether VTL2 should be allowed to access VTL0 memory before it
139    /// sets any VTL protections.
140    ///
141    /// This is needed just for the TMK VMM, and only until it gains support for
142    /// setting VTL protections.
143    pub fn with_allow_early_vtl0_access(mut self, allow: bool) -> Self {
144        self.config
145            .hypervisor
146            .with_vtl2
147            .as_mut()
148            .unwrap()
149            .late_map_vtl0_memory =
150            (!allow).then_some(openvmm_defs::config::LateMapVtl0MemoryPolicy::InjectException);
151
152        self
153    }
154}