vmotherboard/chipset/builder/
mod.rs1mod errors;
7
8use self::errors::ChipsetBuilderError;
9use self::errors::ErrorListExt;
10use self::errors::FinalChipsetBuilderError;
11use super::backing::arc_mutex::device::ArcMutexChipsetDeviceBuilder;
12use super::backing::arc_mutex::pci::BusResolverWeakMutexPci;
13use super::backing::arc_mutex::pci::BusResolverWeakMutexPcie;
14use super::backing::arc_mutex::pci::RegisterWeakMutexPci;
15use super::backing::arc_mutex::pci::RegisterWeakMutexPcie;
16use super::backing::arc_mutex::pci::WeakMutexPciEntry;
17use super::backing::arc_mutex::pci::WeakMutexPcieDeviceEntry;
18use super::backing::arc_mutex::pci::WeakMutexPcieRciepEntry;
19use super::backing::arc_mutex::services::ArcMutexChipsetServices;
20use super::backing::arc_mutex::state_unit::ArcMutexChipsetDeviceUnit;
21use crate::BusId;
22use crate::BusIdPci;
23use crate::BusIdPcieDownstreamPort;
24use crate::BusIdPcieEnumerator;
25use crate::DebugEventHandler;
26use crate::VmmChipsetDevice;
27use crate::chipset::Chipset;
28use crate::chipset::io_ranges::IoRanges;
29use anyhow::Context as _;
30use arc_cyclic_builder::ArcCyclicBuilderExt as _;
31use chipset_device::ChipsetDevice;
32use chipset_device::mmio::RegisterMmioIntercept;
33use chipset_device_resources::LineSetId;
34use closeable_mutex::CloseableMutex;
35use pal_async::task::Spawn;
36use pal_async::task::Task;
37use parking_lot::Mutex;
38use state_unit::SpawnedUnit;
39use state_unit::StateUnits;
40use state_unit::UnitHandle;
41use std::ops::RangeInclusive;
42use std::sync::Arc;
43use std::sync::Weak;
44use vmcore::line_interrupt::LineSetTarget;
45use vmcore::vm_task::VmTaskDriverSource;
46use vmcore::vmtime::VmTimeSource;
47
48pub struct ChipsetDevices {
50 chipset_unit: UnitHandle,
51 _chipset_task: Task<()>,
52 _arc_mutex_device_units: Vec<SpawnedUnit<ArcMutexChipsetDeviceUnit>>,
53 _line_set_units: Vec<SpawnedUnit<()>>,
54 mmio_ranges: IoRanges<u64>,
55}
56
57impl ChipsetDevices {
58 pub fn chipset_unit(&self) -> &UnitHandle {
63 &self.chipset_unit
64 }
65
66 pub async fn add_dyn_device<T: VmmChipsetDevice>(
68 &self,
69 driver_source: &VmTaskDriverSource,
70 units: &StateUnits,
71 name: impl Into<Arc<str>>,
72 f: impl AsyncFnOnce(&mut (dyn RegisterMmioIntercept + Send)) -> anyhow::Result<T>,
73 ) -> anyhow::Result<(DynamicDeviceUnit, Arc<CloseableMutex<T>>)> {
74 let name = name.into();
75 let arc_builder = Arc::<CloseableMutex<T>>::new_cyclic_builder();
76 let device = f(
77 &mut super::backing::arc_mutex::services::register_mmio_for_device(
78 name.clone(),
79 arc_builder.weak(),
80 self.mmio_ranges.clone(),
81 ),
82 )
83 .await?;
84 let device = arc_builder.build(CloseableMutex::new(device));
85 let device_unit = ArcMutexChipsetDeviceUnit::new(device.clone(), false);
86 let builder = units.add(name).dependency_of(self.chipset_unit());
87 let unit = builder
88 .spawn(driver_source.simple(), |recv| device_unit.run(recv))
89 .context("name in use")?;
90
91 Ok((DynamicDeviceUnit(unit), device))
92 }
93}
94
95pub struct DynamicDeviceUnit(SpawnedUnit<ArcMutexChipsetDeviceUnit>);
97
98impl DynamicDeviceUnit {
99 pub async fn remove(self) {
101 self.0.remove().await;
102 }
103}
104
105#[derive(Default)]
106pub(crate) struct BusResolver {
107 pci: BusResolverWeakMutexPci,
108 pcie: BusResolverWeakMutexPcie,
109}
110
111pub(crate) struct ChipsetBuilderInner {
113 pub(crate) vm_chipset: Chipset,
114 pub(crate) bus_resolver: BusResolver,
115 pub(crate) line_sets: super::line_sets::LineSets,
116 pub(crate) arc_mutex_device_units: Vec<SpawnedUnit<ArcMutexChipsetDeviceUnit>>,
117 chipset_recv: mesh::Receiver<state_unit::StateRequest>,
118}
119
120pub struct ChipsetBuilder<'a> {
125 pub(crate) inner: Mutex<ChipsetBuilderInner>,
126
127 pub(crate) units: &'a StateUnits,
129 pub(crate) driver_source: &'a VmTaskDriverSource,
130 pub(crate) vmtime: &'a VmTimeSource,
131 pub(crate) vmtime_unit: &'a UnitHandle,
132
133 pub(crate) chipset_unit: UnitHandle,
135}
136
137impl<'a> ChipsetBuilder<'a> {
138 pub(crate) fn new(
139 driver_source: &'a VmTaskDriverSource,
140 units: &'a StateUnits,
141 debug_event_handler: Arc<dyn DebugEventHandler>,
142 vmtime: &'a VmTimeSource,
143 vmtime_unit: &'a UnitHandle,
144 trace_unknown_pio: bool,
145 trace_unknown_mmio: bool,
146 fallback_mmio_device: Option<Arc<CloseableMutex<dyn ChipsetDevice>>>,
147 ) -> Self {
148 let (send, chipset_recv) = mesh::channel();
149 let chipset_unit = units.add("chipset").build(send).unwrap();
150
151 Self {
152 inner: Mutex::new(ChipsetBuilderInner {
153 vm_chipset: Chipset {
154 mmio_ranges: IoRanges::new(trace_unknown_mmio, fallback_mmio_device),
155 pio_ranges: IoRanges::new(trace_unknown_pio, None),
156
157 pic: None,
158 eoi_handler: None,
159 debug_event_handler,
160 },
161
162 bus_resolver: BusResolver::default(),
163 line_sets: super::line_sets::LineSets::new(),
164 arc_mutex_device_units: Vec::new(),
165 chipset_recv,
166 }),
167
168 units,
169 driver_source,
170 vmtime,
171 vmtime_unit,
172
173 chipset_unit,
174 }
175 }
176
177 pub(crate) fn register_weak_mutex_pci_bus(
178 &self,
179 bus_id: BusIdPci,
180 bus: Box<dyn RegisterWeakMutexPci>,
181 ) {
182 let mut inner = self.inner.lock();
183 let existing = inner.bus_resolver.pci.buses.insert(bus_id.clone(), bus);
184 assert!(
185 existing.is_none(),
186 "shouldn't be possible to have duplicate bus IDs: {:?}",
187 bus_id
188 )
189 }
190
191 pub(crate) fn register_weak_mutex_pci_device(
192 &self,
193 bus_id: BusIdPci,
194 bdf: (u8, u8, u8),
195 name: Arc<str>,
196 dev: Weak<CloseableMutex<dyn ChipsetDevice>>,
197 ) {
198 self.inner
199 .lock()
200 .bus_resolver
201 .pci
202 .devices
203 .entry(bus_id)
204 .or_default()
205 .push(WeakMutexPciEntry { bdf, name, dev });
206 }
207
208 pub fn register_weak_mutex_pcie_enumerator(
211 &self,
212 bus_id: BusIdPcieEnumerator,
213 enumerator: Box<dyn RegisterWeakMutexPcie>,
214 ) {
215 let downstream_ports = enumerator.downstream_ports();
216 let mut inner = self.inner.lock();
217 let existing = inner
218 .bus_resolver
219 .pcie
220 .enumerators
221 .insert(bus_id.clone(), enumerator);
222 assert!(
223 existing.is_none(),
224 "duplicate pcie enumerator ID: {:?}",
225 bus_id
226 );
227
228 for port_info in downstream_ports {
229 let existing = inner.bus_resolver.pcie.ports.insert(
230 BusId::new(&port_info.name),
231 (port_info.devfn, bus_id.clone()),
232 );
233 assert!(
234 existing.is_none(),
235 "duplicate pcie port ID: {:?}",
236 port_info.name
237 );
238 }
239 }
240
241 pub(crate) fn register_weak_mutex_pcie_device(
242 &self,
243 bus_id_port: BusIdPcieDownstreamPort,
244 name: Arc<str>,
245 dev: Weak<CloseableMutex<dyn ChipsetDevice>>,
246 ) {
247 self.inner
248 .lock()
249 .bus_resolver
250 .pcie
251 .devices
252 .push(WeakMutexPcieDeviceEntry {
253 bus_id_port,
254 name,
255 dev,
256 });
257 }
258
259 pub(crate) fn register_weak_mutex_pcie_rciep(
260 &self,
261 bus_id_enumerator: BusIdPcieEnumerator,
262 devfn: u8,
263 name: Arc<str>,
264 dev: Weak<CloseableMutex<dyn ChipsetDevice>>,
265 ) {
266 self.inner
267 .lock()
268 .bus_resolver
269 .pcie
270 .rcieps
271 .push(WeakMutexPcieRciepEntry {
272 bus_id_enumerator,
273 devfn,
274 name,
275 dev,
276 });
277 }
278
279 pub fn arc_mutex_device<'b, T: VmmChipsetDevice>(
282 &'b self,
283 dev_name: impl Into<Arc<str>>,
284 ) -> ArcMutexChipsetDeviceBuilder<'b, 'a, T> {
285 ArcMutexChipsetDeviceBuilder::new(dev_name.into(), |dev, name| {
286 ArcMutexChipsetServices::new(self, dev.clone(), name)
287 })
288 }
289
290 pub fn build(self) -> Result<(Arc<Chipset>, ChipsetDevices), FinalChipsetBuilderError> {
292 let mut inner = self.inner.into_inner();
293 let mut errs = None;
294
295 for conflict in (inner.vm_chipset.mmio_ranges).take_static_registration_conflicts() {
296 errs.append(ChipsetBuilderError::MmioConflict(conflict));
297 }
298
299 for conflict in (inner.vm_chipset.pio_ranges).take_static_registration_conflicts() {
300 errs.append(ChipsetBuilderError::PioConflict(conflict));
301 }
302
303 {
304 let BusResolver { pci, pcie } = inner.bus_resolver;
305
306 match pci.resolve() {
307 Ok(()) => {}
308 Err(conflicts) => {
309 for conflict in conflicts {
310 errs.append(ChipsetBuilderError::PciConflict(conflict));
311 }
312 }
313 }
314
315 match pcie.resolve() {
316 Ok(()) => {}
317 Err(conflicts) => {
318 for conflict in conflicts {
319 errs.append(ChipsetBuilderError::PcieConflict(conflict));
320 }
321 }
322 }
323 }
324
325 if let Some(err) = errs {
326 return Err(FinalChipsetBuilderError(err));
327 }
328
329 let mmio_ranges = inner.vm_chipset.mmio_ranges.clone();
330
331 let vm_chipset = Arc::new(inner.vm_chipset);
333 let chipset_task = self.driver_source.simple().spawn("chipset-unit", {
334 let vm_chipset = vm_chipset.clone();
335 let mut recv = inner.chipset_recv;
336 async move {
337 while let Ok(req) = recv.recv().await {
338 req.apply(&mut chipset_unit::ChipsetUnit(&vm_chipset)).await;
339 }
340 }
341 });
342
343 let devices = ChipsetDevices {
344 chipset_unit: self.chipset_unit,
345 _chipset_task: chipset_task,
346 _arc_mutex_device_units: inner.arc_mutex_device_units,
347 _line_set_units: inner.line_sets.units,
348 mmio_ranges,
349 };
350
351 Ok((vm_chipset, devices))
352 }
353
354 pub fn add_external_line_target(
356 &self,
357 id: LineSetId,
358 source_range: RangeInclusive<u32>,
359 target_start: u32,
360 debug_label: &str,
361 target: Arc<dyn LineSetTarget>,
362 ) {
363 let mut inner = self.inner.lock();
364 let (line_set, _) = inner.line_sets.line_set(self.driver_source, self.units, id);
365 line_set.add_target(source_range, target_start, debug_label, target)
366 }
367}
368
369mod chipset_unit {
370 use crate::Chipset;
371 use inspect::InspectMut;
372 use state_unit::StateUnit;
373 use vmcore::save_restore::RestoreError;
374 use vmcore::save_restore::SaveError;
375 use vmcore::save_restore::SavedStateBlob;
376
377 #[derive(InspectMut)]
378 #[inspect(transparent)]
379 pub struct ChipsetUnit<'a>(pub &'a Chipset);
380
381 impl StateUnit for ChipsetUnit<'_> {
382 async fn start(&mut self) {}
383
384 async fn stop(&mut self) {}
385
386 async fn reset(&mut self) -> anyhow::Result<()> {
387 Ok(())
388 }
389
390 async fn save(&mut self) -> Result<Option<SavedStateBlob>, SaveError> {
391 Ok(None)
392 }
393
394 async fn restore(&mut self, _buffer: SavedStateBlob) -> Result<(), RestoreError> {
395 Err(RestoreError::SavedStateNotSupported)
396 }
397 }
398}