vmotherboard/chipset/backing/arc_mutex/
device.rs1use super::services::ArcMutexChipsetServices;
8use crate::BusIdPci;
9use crate::VmmChipsetDevice;
10use arc_cyclic_builder::ArcCyclicBuilder;
11use arc_cyclic_builder::ArcCyclicBuilderExt;
12use chipset_device::mmio::RegisterMmioIntercept;
13use chipset_device::pio::RegisterPortIoIntercept;
14use closeable_mutex::CloseableMutex;
15use std::sync::Arc;
16use std::sync::Weak;
17use thiserror::Error;
18use tracing::instrument;
19
20#[derive(Debug, Error)]
21pub(crate) enum AddDeviceErrorKind {
22 #[error("could not construct device")]
23 DeviceError(#[source] Box<dyn std::error::Error + Send + Sync + 'static>),
24
25 #[error("no pci bus address provided")]
26 NoPciBusAddress,
27 #[error("error finalizing device")]
28 Finalize(#[source] Box<dyn std::error::Error + Send + Sync + 'static>),
29}
30
31impl AddDeviceErrorKind {
32 pub(crate) fn with_dev_name(self, dev_name: Arc<str>) -> AddDeviceError {
33 AddDeviceError {
34 dev_name,
35 inner: self,
36 }
37 }
38}
39
40#[derive(Debug, Error)]
42#[error("could not initialize {dev_name}")]
43pub struct AddDeviceError {
44 dev_name: Arc<str>,
45 #[source]
46 inner: AddDeviceErrorKind,
47}
48
49pub trait ArcMutexChipsetServicesFinalize<T> {
56 type Error;
58
59 fn finalize(self, dev: &Arc<CloseableMutex<T>>, name: Arc<str>) -> Result<(), Self::Error>;
62}
63
64pub struct ArcMutexChipsetDeviceBuilder<'a, 'b, T> {
67 services: ArcMutexChipsetServices<'a, 'b>,
68 arc_builder: ArcCyclicBuilder<CloseableMutex<T>>,
69
70 dev_name: Arc<str>,
71
72 pci_addr: Option<(u8, u8, u8)>,
73 pci_bus_id: Option<BusIdPci>,
74 external_pci: bool,
75}
76
77impl<'a, 'b, T> ArcMutexChipsetDeviceBuilder<'a, 'b, T>
78where
79 T: VmmChipsetDevice,
80{
81 pub fn new(
83 name: Arc<str>,
84 new_device_services: impl FnOnce(
85 Weak<CloseableMutex<T>>,
86 Arc<str>,
87 ) -> ArcMutexChipsetServices<'a, 'b>,
88 ) -> Self {
89 let arc_builder: ArcCyclicBuilder<CloseableMutex<T>> = Arc::new_cyclic_builder();
90 let services = (new_device_services)(arc_builder.weak(), name.clone());
91
92 ArcMutexChipsetDeviceBuilder {
93 services,
94 arc_builder,
95
96 dev_name: name,
97
98 pci_addr: None,
99 pci_bus_id: None,
100 external_pci: false,
101 }
102 }
103
104 pub fn omit_saved_state(mut self) -> Self {
107 self.services.omit_saved_state();
108 self
109 }
110
111 pub fn with_pci_addr(mut self, bus: u8, device: u8, function: u8) -> Self {
113 self.pci_addr = Some((bus, device, function));
114 self
115 }
116
117 pub fn on_pci_bus(mut self, id: BusIdPci) -> Self {
119 self.pci_bus_id = Some(id);
120 self
121 }
122
123 pub fn with_external_pci(mut self) -> Self {
127 self.external_pci = true;
128 self
129 }
130
131 fn inner_add(
132 mut self,
133 typed_dev: Result<T, AddDeviceError>,
134 ) -> Result<Arc<CloseableMutex<T>>, AddDeviceError> {
135 let mut typed_dev = typed_dev?;
136
137 if let Some(dev) = typed_dev.supports_mmio() {
138 for (label, range) in dev.get_static_regions() {
140 self.services
141 .register_mmio()
142 .new_io_region(label, range.end() - range.start() + 1)
143 .map(*range.start());
144 }
145 }
146
147 if let Some(dev) = typed_dev.supports_pio() {
148 for (label, range) in dev.get_static_regions() {
150 self.services
151 .register_pio()
152 .new_io_region(label, range.end() - range.start() + 1)
153 .map(*range.start());
154 }
155 }
156
157 if !self.external_pci {
158 if let Some(dev) = typed_dev.supports_pci() {
159 let bdf = match (self.pci_addr, dev.suggested_bdf()) {
161 (Some(override_bdf), Some(suggested_bdf)) => {
162 let (ob, od, of) = override_bdf;
163 let (sb, sd, sf) = suggested_bdf;
164 tracing::info!(
165 "overriding suggested bdf: using {:02x}:{:02x}:{} instead of {:02x}:{:02x}:{}",
166 ob,
167 od,
168 of,
169 sb,
170 sd,
171 sf
172 );
173 override_bdf
174 }
175 (None, Some(bdf)) | (Some(bdf), None) => bdf,
176 (None, None) => {
177 return Err(
178 AddDeviceErrorKind::NoPciBusAddress.with_dev_name(self.dev_name)
179 );
180 }
181 };
182
183 let bus_id = match self.pci_bus_id.take() {
184 Some(bus_id) => bus_id,
185 None => panic!(
186 "wiring error: did not invoke `on_pci_bus` for `{}`",
187 self.dev_name
188 ),
189 };
190
191 self.services.register_static_pci(bus_id, bdf);
192 }
193 }
194
195 let dev = self.arc_builder.build(CloseableMutex::new(typed_dev));
196
197 self.services
199 .finalize(&dev, self.dev_name.clone())
200 .map_err(|err| AddDeviceErrorKind::Finalize(err.into()).with_dev_name(self.dev_name))?;
201
202 Ok(dev)
203 }
204
205 #[instrument(name = "add_device", skip_all, fields(device = self.dev_name.as_ref()))]
214 pub fn add<F>(mut self, f: F) -> Result<Arc<CloseableMutex<T>>, AddDeviceError>
215 where
216 F: FnOnce(&mut ArcMutexChipsetServices<'a, 'b>) -> T,
217 {
218 let dev = (f)(&mut self.services);
219 self.inner_add(Ok(dev))
220 }
221
222 #[instrument(name = "add_device", skip_all, fields(device = self.dev_name.as_ref()))]
224 pub async fn add_async<F>(mut self, f: F) -> Result<Arc<CloseableMutex<T>>, AddDeviceError>
225 where
226 F: AsyncFnOnce(&mut ArcMutexChipsetServices<'a, 'b>) -> T,
227 {
228 let dev = (f)(&mut self.services).await;
229 self.inner_add(Ok(dev))
230 }
231
232 #[instrument(name = "add_device", skip_all, fields(device = self.dev_name.as_ref()))]
234 pub fn try_add<F, E>(mut self, f: F) -> Result<Arc<CloseableMutex<T>>, AddDeviceError>
235 where
236 F: FnOnce(&mut ArcMutexChipsetServices<'a, 'b>) -> Result<T, E>,
237 E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
238 {
239 let dev = match (f)(&mut self.services) {
240 Ok(dev) => dev,
241 Err(e) => {
242 return Err(AddDeviceErrorKind::DeviceError(e.into()).with_dev_name(self.dev_name));
243 }
244 };
245 self.inner_add(Ok(dev))
246 }
247
248 #[instrument(name = "add_device", skip_all, fields(device = self.dev_name.as_ref()))]
250 pub async fn try_add_async<F, E>(
251 mut self,
252 f: F,
253 ) -> Result<Arc<CloseableMutex<T>>, AddDeviceError>
254 where
255 F: AsyncFnOnce(&mut ArcMutexChipsetServices<'a, 'b>) -> Result<T, E>,
256 E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
257 {
258 let dev = match (f)(&mut self.services).await {
259 Ok(dev) => dev,
260 Err(e) => {
261 return Err(AddDeviceErrorKind::DeviceError(e.into()).with_dev_name(self.dev_name));
262 }
263 };
264 self.inner_add(Ok(dev))
265 }
266}