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