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::RegisterWeakMutexPci;
14use super::backing::arc_mutex::pci::WeakMutexPciEntry;
15use super::backing::arc_mutex::services::ArcMutexChipsetServices;
16use super::backing::arc_mutex::state_unit::ArcMutexChipsetDeviceUnit;
17use crate::BusIdPci;
18use crate::DebugEventHandler;
19use crate::VmmChipsetDevice;
20use crate::chipset::Chipset;
21use crate::chipset::io_ranges::IoRanges;
22use anyhow::Context as _;
23use arc_cyclic_builder::ArcCyclicBuilderExt as _;
24use chipset_device::ChipsetDevice;
25use chipset_device::mmio::RegisterMmioIntercept;
26use chipset_device_resources::LineSetId;
27use closeable_mutex::CloseableMutex;
28use pal_async::task::Spawn;
29use pal_async::task::Task;
30use state_unit::SpawnedUnit;
31use state_unit::StateUnits;
32use state_unit::UnitHandle;
33use std::ops::RangeInclusive;
34use std::sync::Arc;
35use std::sync::Weak;
36use vmcore::line_interrupt::LineSetTarget;
37use vmcore::vm_task::VmTaskDriverSource;
38use vmcore::vmtime::VmTimeSource;
39
40pub struct ChipsetDevices {
42 chipset_unit: UnitHandle,
43 _chipset_task: Task<()>,
44 _arc_mutex_device_units: Vec<SpawnedUnit<ArcMutexChipsetDeviceUnit>>,
45 _line_set_units: Vec<SpawnedUnit<()>>,
46 mmio_ranges: IoRanges<u64>,
47}
48
49impl ChipsetDevices {
50 pub fn chipset_unit(&self) -> &UnitHandle {
55 &self.chipset_unit
56 }
57
58 pub async fn add_dyn_device<T: VmmChipsetDevice>(
60 &self,
61 driver_source: &VmTaskDriverSource,
62 units: &StateUnits,
63 name: impl Into<Arc<str>>,
64 f: impl AsyncFnOnce(&mut dyn RegisterMmioIntercept) -> anyhow::Result<T>,
65 ) -> anyhow::Result<(DynamicDeviceUnit, Arc<CloseableMutex<T>>)> {
66 let name = name.into();
67 let arc_builder = Arc::<CloseableMutex<T>>::new_cyclic_builder();
68 let device = f(
69 &mut super::backing::arc_mutex::services::register_mmio_for_device(
70 name.clone(),
71 arc_builder.weak(),
72 self.mmio_ranges.clone(),
73 ),
74 )
75 .await?;
76 let device = arc_builder.build(CloseableMutex::new(device));
77 let device_unit = ArcMutexChipsetDeviceUnit::new(device.clone(), false);
78 let builder = units.add(name).dependency_of(self.chipset_unit());
79 let unit = builder
80 .spawn(driver_source.simple(), |recv| device_unit.run(recv))
81 .context("name in use")?;
82
83 Ok((DynamicDeviceUnit(unit), device))
84 }
85}
86
87pub struct DynamicDeviceUnit(SpawnedUnit<ArcMutexChipsetDeviceUnit>);
89
90impl DynamicDeviceUnit {
91 pub async fn remove(self) {
93 self.0.remove().await;
94 }
95}
96
97#[derive(Default)]
98pub(crate) struct BusResolver {
99 pci: BusResolverWeakMutexPci,
100}
101
102pub struct ChipsetBuilder<'a> {
104 pub(crate) vm_chipset: Chipset,
106
107 pub(crate) bus_resolver: BusResolver,
108
109 pub(crate) units: &'a StateUnits,
111 pub(crate) driver_source: &'a VmTaskDriverSource,
112 pub(crate) vmtime: &'a VmTimeSource,
113 pub(crate) vmtime_unit: &'a UnitHandle,
114
115 pub(crate) chipset_unit: UnitHandle,
118 chipset_recv: mesh::Receiver<state_unit::StateRequest>,
119
120 line_sets: super::line_sets::LineSets,
121
122 arc_mutex_device_units: Vec<SpawnedUnit<ArcMutexChipsetDeviceUnit>>,
124}
125
126impl<'a> ChipsetBuilder<'a> {
127 pub(crate) fn new(
128 driver_source: &'a VmTaskDriverSource,
129 units: &'a StateUnits,
130 debug_event_handler: Arc<dyn DebugEventHandler>,
131 vmtime: &'a VmTimeSource,
132 vmtime_unit: &'a UnitHandle,
133 trace_unknown_pio: bool,
134 trace_unknown_mmio: bool,
135 fallback_mmio_device: Option<Arc<CloseableMutex<dyn ChipsetDevice>>>,
136 ) -> Self {
137 let (send, chipset_recv) = mesh::channel();
138 let chipset_unit = units.add("chipset").build(send).unwrap();
139
140 Self {
141 vm_chipset: Chipset {
142 mmio_ranges: IoRanges::new(trace_unknown_mmio, fallback_mmio_device),
143 pio_ranges: IoRanges::new(trace_unknown_pio, None),
144
145 pic: None,
146 eoi_handler: None,
147 debug_event_handler,
148 },
149
150 bus_resolver: BusResolver::default(),
151
152 units,
153 driver_source,
154 vmtime,
155 vmtime_unit,
156
157 chipset_unit,
158 chipset_recv,
159
160 line_sets: super::line_sets::LineSets::new(),
161
162 arc_mutex_device_units: Vec::new(),
163 }
164 }
165
166 pub(crate) fn register_arc_mutex_device_unit(
167 &mut self,
168 unit: SpawnedUnit<ArcMutexChipsetDeviceUnit>,
169 ) {
170 self.arc_mutex_device_units.push(unit)
171 }
172
173 pub(crate) fn register_weak_mutex_pci_bus(
174 &mut self,
175 bus_id: BusIdPci,
176 bus: Box<dyn RegisterWeakMutexPci>,
177 ) {
178 let existing = self.bus_resolver.pci.buses.insert(bus_id.clone(), bus);
179 assert!(
180 existing.is_none(),
181 "shouldn't be possible to have duplicate bus IDs: {:?}",
182 bus_id
183 )
184 }
185
186 pub(crate) fn register_weak_mutex_pci_device(
187 &mut self,
188 bus_id: BusIdPci,
189 bdf: (u8, u8, u8),
190 name: Arc<str>,
191 dev: Weak<CloseableMutex<dyn ChipsetDevice>>,
192 ) {
193 self.bus_resolver
194 .pci
195 .devices
196 .entry(bus_id)
197 .or_default()
198 .push(WeakMutexPciEntry { bdf, name, dev });
199 }
200
201 pub(crate) fn line_set(
202 &mut self,
203 id: LineSetId,
204 ) -> (&vmcore::line_interrupt::LineSet, &UnitHandle) {
205 self.line_sets.line_set(self.driver_source, self.units, id)
206 }
207
208 #[must_use]
209 pub(crate) fn try_set_pic(
210 &mut self,
211 pic: Option<Arc<CloseableMutex<dyn ChipsetDevice>>>,
212 ) -> bool {
213 if self.vm_chipset.pic.is_some() {
214 return false;
215 }
216 self.vm_chipset.pic = pic;
217 true
218 }
219
220 #[must_use]
221 pub(crate) fn try_set_eoi_handler(
222 &mut self,
223 eoi_handler: Option<Arc<CloseableMutex<dyn ChipsetDevice>>>,
224 ) -> bool {
225 if self.vm_chipset.eoi_handler.is_some() {
226 return false;
227 }
228 self.vm_chipset.eoi_handler = eoi_handler;
229 true
230 }
231
232 pub fn arc_mutex_device<'b, T: VmmChipsetDevice>(
235 &'b mut self,
236 dev_name: impl Into<Arc<str>>,
237 ) -> ArcMutexChipsetDeviceBuilder<'b, 'a, T> {
238 ArcMutexChipsetDeviceBuilder::new(dev_name.into(), |dev, name| {
239 ArcMutexChipsetServices::new(self, dev.clone(), name)
240 })
241 }
242
243 pub fn build(mut self) -> Result<(Arc<Chipset>, ChipsetDevices), FinalChipsetBuilderError> {
245 let mut errs = None;
246
247 for conflict in (self.vm_chipset.mmio_ranges).take_static_registration_conflicts() {
248 errs.append(ChipsetBuilderError::MmioConflict(conflict));
249 }
250
251 for conflict in (self.vm_chipset.pio_ranges).take_static_registration_conflicts() {
252 errs.append(ChipsetBuilderError::PioConflict(conflict));
253 }
254
255 {
256 let BusResolver { pci } = self.bus_resolver;
257
258 match pci.resolve() {
259 Ok(()) => {}
260 Err(conflicts) => {
261 for conflict in conflicts {
262 errs.append(ChipsetBuilderError::PciConflict(conflict));
263 }
264 }
265 }
266 }
267
268 if let Some(err) = errs {
269 return Err(FinalChipsetBuilderError(err));
270 }
271
272 let mmio_ranges = self.vm_chipset.mmio_ranges.clone();
273
274 let vm_chipset = Arc::new(self.vm_chipset);
276 let chipset_task = self.driver_source.simple().spawn("chipset-unit", {
277 let vm_chipset = vm_chipset.clone();
278 let mut recv = self.chipset_recv;
279 async move {
280 while let Ok(req) = recv.recv().await {
281 req.apply(&mut chipset_unit::ChipsetUnit(&vm_chipset)).await;
282 }
283 }
284 });
285
286 let devices = ChipsetDevices {
287 chipset_unit: self.chipset_unit,
288 _chipset_task: chipset_task,
289 _arc_mutex_device_units: self.arc_mutex_device_units,
290 _line_set_units: self.line_sets.units,
291 mmio_ranges,
292 };
293
294 Ok((vm_chipset, devices))
295 }
296
297 pub fn add_external_line_target(
299 &mut self,
300 id: LineSetId,
301 source_range: RangeInclusive<u32>,
302 target_start: u32,
303 debug_label: &str,
304 target: Arc<dyn LineSetTarget>,
305 ) {
306 self.line_set(id)
307 .0
308 .add_target(source_range, target_start, debug_label, target)
309 }
310}
311
312mod chipset_unit {
313 use crate::Chipset;
314 use inspect::InspectMut;
315 use state_unit::StateUnit;
316 use vmcore::save_restore::RestoreError;
317 use vmcore::save_restore::SaveError;
318 use vmcore::save_restore::SavedStateBlob;
319
320 #[derive(InspectMut)]
321 #[inspect(transparent)]
322 pub struct ChipsetUnit<'a>(pub &'a Chipset);
323
324 impl StateUnit for ChipsetUnit<'_> {
325 async fn start(&mut self) {}
326
327 async fn stop(&mut self) {}
328
329 async fn reset(&mut self) -> anyhow::Result<()> {
330 Ok(())
331 }
332
333 async fn save(&mut self) -> Result<Option<SavedStateBlob>, SaveError> {
334 Ok(None)
335 }
336
337 async fn restore(&mut self, _buffer: SavedStateBlob) -> Result<(), RestoreError> {
338 Err(RestoreError::SavedStateNotSupported)
339 }
340 }
341}