1use super::MANA_INSTANCE;
11use super::NIC_MAC_ADDRESS;
12use super::PetriVmConfigOpenVmm;
13use chipset_resources::battery::BatteryDeviceHandleX64;
14use chipset_resources::battery::HostBatteryUpdate;
15use disk_backend_resources::LayeredDiskHandle;
16use disk_backend_resources::layer::RamDiskLayerHandle;
17use gdma_resources::GdmaDeviceHandle;
18use gdma_resources::VportDefinition;
19use get_resources::ged::IgvmAttestTestConfig;
20use guid::Guid;
21use net_backend_resources::mac_address::MacAddress;
22use nvme_resources::NamespaceDefinition;
23use nvme_resources::NvmeControllerHandle;
24use openvmm_defs::config::Config;
25use openvmm_defs::config::DeviceVtl;
26use openvmm_defs::config::LoadMode;
27use openvmm_defs::config::PcieDeviceConfig;
28use openvmm_defs::config::PcieMmioRangeConfig;
29use openvmm_defs::config::PcieRootComplexConfig;
30use openvmm_defs::config::PcieRootPortConfig;
31use openvmm_defs::config::PcieSwitchConfig;
32use openvmm_defs::config::SmmuInstanceConfig;
33use openvmm_defs::config::VpciDeviceConfig;
34use openvmm_defs::config::Vtl2BaseAddressType;
35use vm_resource::IntoResource;
36use vmotherboard::ChipsetDeviceHandle;
37
38impl PetriVmConfigOpenVmm {
39 pub fn with_vtl0_alias_map(mut self) -> Self {
42 self.config
43 .hypervisor
44 .with_vtl2
45 .as_mut()
46 .expect("Not an openhcl config.")
47 .vtl0_alias_map = true;
48 self
49 }
50
51 pub fn with_battery(mut self) -> Self {
53 if self.resources.properties.is_openhcl {
54 self.ged.as_mut().unwrap().enable_battery = true;
55 } else {
56 self.config.chipset_devices.push(ChipsetDeviceHandle {
57 name: "battery".to_string(),
58 resource: BatteryDeviceHandleX64 {
59 battery_status_recv: {
60 let (tx, rx) = mesh::channel();
61 tx.send(HostBatteryUpdate::default_present());
62 rx
63 },
64 }
65 .into_resource(),
66 });
67 if let LoadMode::Uefi { enable_battery, .. } = &mut self.config.load_mode {
68 *enable_battery = true;
69 }
70 }
71 self
72 }
73
74 pub fn with_igvm_attest_test_config(mut self, config: IgvmAttestTestConfig) -> Self {
76 if !self.resources.properties.is_openhcl {
77 panic!("IGVM Attest test config is only supported for OpenHCL.")
78 };
79
80 let ged = self.ged.as_mut().expect("No GED to configure TPM");
81
82 ged.igvm_attest_test_config = Some(config);
83
84 self
85 }
86
87 pub fn with_nic(mut self) -> Self {
91 let endpoint = net_backend_resources::consomme::ConsommeHandle {
92 cidr: None,
93 ports: Vec::new(),
94 }
95 .into_resource();
96 if let Some(vtl2_settings) = self.runtime_config.vtl2_settings.as_mut() {
97 self.config.vpci_devices.push(VpciDeviceConfig {
98 vtl: DeviceVtl::Vtl2,
99 instance_id: MANA_INSTANCE,
100 resource: GdmaDeviceHandle {
101 vports: vec![VportDefinition {
102 mac_address: NIC_MAC_ADDRESS,
103 endpoint,
104 }],
105 }
106 .into_resource(),
107 });
108
109 vtl2_settings.dynamic.as_mut().unwrap().nic_devices.push(
110 vtl2_settings_proto::NicDeviceLegacy {
111 instance_id: MANA_INSTANCE.to_string(),
112 subordinate_instance_id: None,
113 max_sub_channels: None,
114 },
115 );
116 } else {
117 const NETVSP_INSTANCE: Guid = guid::guid!("c6c46cc3-9302-4344-b206-aef65e5bd0a2");
118 self.config.vmbus_devices.push((
119 DeviceVtl::Vtl0,
120 netvsp_resources::NetvspHandle {
121 instance_id: NETVSP_INSTANCE,
122 mac_address: NIC_MAC_ADDRESS,
123 endpoint,
124 max_queues: None,
125 }
126 .into_resource(),
127 ));
128 }
129
130 self
131 }
132
133 pub fn with_pcie_nic(mut self, port_name: &str, mac_address: MacAddress) -> Self {
135 let endpoint = net_backend_resources::consomme::ConsommeHandle {
136 cidr: None,
137 ports: Vec::new(),
138 }
139 .into_resource();
140 self.config.pcie_devices.push(PcieDeviceConfig {
141 port_name: port_name.to_string(),
142 resource: GdmaDeviceHandle {
143 vports: vec![VportDefinition {
144 mac_address,
145 endpoint,
146 }],
147 }
148 .into_resource(),
149 });
150
151 self
152 }
153
154 pub fn with_pcie_nvme(mut self, port_name: &str, subsystem_id: Guid) -> Self {
156 self.config.pcie_devices.push(PcieDeviceConfig {
157 port_name: port_name.to_string(),
158 resource: NvmeControllerHandle {
159 subsystem_id,
160 max_io_queues: 64,
161 msix_count: 64,
162 namespaces: vec![NamespaceDefinition {
163 nsid: 1,
164 disk: LayeredDiskHandle::single_layer(RamDiskLayerHandle {
165 len: Some(1024 * 1024),
166 sector_size: None,
167 })
168 .into_resource(),
169 read_only: false,
170 }],
171 requests: None,
172 }
173 .into_resource(),
174 });
175
176 self
177 }
178
179 pub fn with_virtio_nic(mut self, port_name: &str) -> Self {
184 let endpoint = net_backend_resources::consomme::ConsommeHandle {
185 cidr: None,
186 ports: Vec::new(),
187 }
188 .into_resource();
189
190 self.config.pcie_devices.push(PcieDeviceConfig {
191 port_name: port_name.to_string(),
192 resource: virtio_resources::VirtioPciDeviceHandle(
193 virtio_resources::net::VirtioNetHandle {
194 max_queues: None,
195 mac_address: NIC_MAC_ADDRESS,
196 endpoint,
197 }
198 .into_resource(),
199 )
200 .into_resource(),
201 });
202
203 self
204 }
205
206 pub fn with_vtl2_relocation_mode(mut self, mode: Vtl2BaseAddressType) -> Self {
208 let LoadMode::Igvm {
209 vtl2_base_address, ..
210 } = &mut self.config.load_mode
211 else {
212 panic!("vtl2 relocation mode is only supported for OpenHCL firmware")
213 };
214 *vtl2_base_address = mode;
215 self
216 }
217
218 pub fn with_memory_backing_file(mut self, path: impl Into<std::path::PathBuf>) -> Self {
224 self.memory_backing_file = Some(path.into());
225 self
226 }
227
228 pub fn with_hugepages(mut self, hugepage_size: Option<u64>) -> Self {
230 self.config.memory.hugepages = true;
231 self.config.memory.hugepage_size = hugepage_size;
232 self
233 }
234
235 pub fn with_pcie_root_topology(
241 mut self,
242 segment_count: u64,
243 root_complex_per_segment: u64,
244 root_ports_per_root_complex: u64,
245 ) -> Self {
246 const LOW_MMIO_SIZE: u64 = 64 * 1024 * 1024; const HIGH_MMIO_SIZE: u64 = 1024 * 1024 * 1024; for segment in 0..segment_count {
251 let bus_count_per_rc = 256 / root_complex_per_segment;
252 for rc_index_in_segment in 0..root_complex_per_segment {
253 let index = segment * root_complex_per_segment + rc_index_in_segment;
254 let name = format!("s{}rc{}", segment, rc_index_in_segment);
255
256 let start_bus = rc_index_in_segment * bus_count_per_rc;
257 let end_bus = start_bus + bus_count_per_rc - 1;
258
259 let ports = (0..root_ports_per_root_complex)
260 .map(|i| PcieRootPortConfig {
261 name: format!("s{}rc{}rp{}", segment, rc_index_in_segment, i),
262 hotplug: true,
263 acs_capabilities_supported: Some(0),
264 cxl: false,
265 })
266 .collect();
267
268 self.config.pcie_root_complexes.push(PcieRootComplexConfig {
269 index: index.try_into().unwrap(),
270 name,
271 segment: segment.try_into().unwrap(),
272 start_bus: start_bus.try_into().unwrap(),
273 end_bus: end_bus.try_into().unwrap(),
274 low_mmio: PcieMmioRangeConfig::Dynamic {
275 size: LOW_MMIO_SIZE,
276 },
277 high_mmio: PcieMmioRangeConfig::Dynamic {
278 size: HIGH_MMIO_SIZE,
279 },
280 cxl: None,
281 ports,
282 });
283 }
284 }
285
286 self
287 }
288
289 pub fn with_pcie_switch(
291 mut self,
292 port_name: &str,
293 switch_name: &str,
294 port_count: u8,
295 hotplug: bool,
296 ) -> Self {
297 self.config.pcie_switches.push(PcieSwitchConfig {
298 name: switch_name.to_string(),
299 num_downstream_ports: port_count,
300 parent_port: port_name.to_string(),
301 hotplug,
302 acs_capabilities_supported: Some(0),
303 });
304 self
305 }
306
307 pub fn with_smmu(mut self, rc_names: &[&str]) -> Self {
314 let arch = self
315 .config
316 .processor_topology
317 .arch
318 .as_mut()
319 .expect("arch topology not set");
320
321 match arch {
322 openvmm_defs::config::ArchTopologyConfig::Aarch64(aarch64) => {
323 aarch64.smmu = rc_names
324 .iter()
325 .map(|name| SmmuInstanceConfig {
326 rc_name: name.to_string(),
327 })
328 .collect();
329 }
330 _ => panic!("SMMU is only supported on aarch64"),
331 }
332 self
333 }
334
335 pub fn with_custom_config(mut self, f: impl FnOnce(&mut Config)) -> Self {
339 f(&mut self.config);
340 self
341 }
342
343 pub fn with_allow_early_vtl0_access(mut self, allow: bool) -> Self {
349 self.config
350 .hypervisor
351 .with_vtl2
352 .as_mut()
353 .unwrap()
354 .late_map_vtl0_memory =
355 (!allow).then_some(openvmm_defs::config::LateMapVtl0MemoryPolicy::InjectException);
356
357 self
358 }
359}