chipset_arc_mutex_device/
device.rs1use crate::services::ChipsetServices;
8use arc_cyclic_builder::ArcCyclicBuilder;
9use arc_cyclic_builder::ArcCyclicBuilderExt;
10use chipset_device::ChipsetDevice;
11use chipset_device::mmio::RegisterMmioIntercept;
12use chipset_device::pio::RegisterPortIoIntercept;
13use closeable_mutex::CloseableMutex;
14use std::sync::Arc;
15use std::sync::Weak;
16use thiserror::Error;
17use tracing::instrument;
18
19#[derive(Debug, Clone, Copy)]
20pub(crate) enum ServiceKind {
21 Mmio,
22 PortIo,
23 Pci,
24 PollDevice,
25}
26
27impl ServiceKind {
28 fn supports_fn(self) -> &'static str {
29 match self {
30 ServiceKind::Mmio => "mmio",
31 ServiceKind::PortIo => "pio",
32 ServiceKind::Pci => "pci",
33 ServiceKind::PollDevice => "poll_device",
34 }
35 }
36}
37
38#[derive(Debug, Error)]
39pub(crate) enum AddDeviceErrorKind {
40 #[error("could not construct device")]
41 DeviceError(#[source] Box<dyn std::error::Error + Send + Sync + 'static>),
42
43 #[error("device attmpted to use {0:?} services without overriding supports_{sup}", sup = .0.supports_fn())]
44 DeviceMissingSupports(ServiceKind),
45 #[error("chipset does not support {0:?} services (`ChipsetServices::supports_{sup}` returned `None`)", sup = .0.supports_fn())]
46 ChipsetMissingSupports(ServiceKind),
47
48 #[error("no pci bus address provided")]
49 NoPciBusAddress,
50}
51
52impl AddDeviceErrorKind {
53 pub(crate) fn with_dev_name(self, dev_name: Arc<str>) -> AddDeviceError {
54 AddDeviceError {
55 dev_name,
56 inner: self,
57 }
58 }
59}
60
61#[derive(Debug, Error)]
63#[error("could not initialize {dev_name}")]
64pub struct AddDeviceError {
65 dev_name: Arc<str>,
66 #[source]
67 inner: AddDeviceErrorKind,
68}
69
70pub trait ArcMutexChipsetServicesFinalize<T> {
77 fn finalize(self, dev: &Arc<CloseableMutex<T>>, name: Arc<str>);
80}
81
82pub struct ArcMutexChipsetDeviceBuilder<S, T> {
85 services: S,
86 arc_builder: ArcCyclicBuilder<CloseableMutex<T>>,
87
88 dev_name: Arc<str>,
89
90 pci_addr: Option<(u8, u8, u8)>,
91 external_pci: bool,
92}
93
94impl<S, T> ArcMutexChipsetDeviceBuilder<S, T>
95where
96 T: ChipsetDevice,
97 S: ChipsetServices + ArcMutexChipsetServicesFinalize<T>,
98{
99 pub fn new(
101 name: Arc<str>,
102 new_device_services: impl FnOnce(Weak<CloseableMutex<dyn ChipsetDevice>>, Arc<str>) -> S,
103 ) -> ArcMutexChipsetDeviceBuilder<S, T> {
104 let arc_builder: ArcCyclicBuilder<CloseableMutex<T>> = Arc::new_cyclic_builder();
105 let services = (new_device_services)(arc_builder.weak(), name.clone());
106
107 ArcMutexChipsetDeviceBuilder {
108 services,
109 arc_builder,
110
111 dev_name: name,
112
113 pci_addr: None,
114 external_pci: false,
115 }
116 }
117
118 pub fn with_pci_addr(mut self, bus: u8, device: u8, function: u8) -> Self {
120 self.pci_addr = Some((bus, device, function));
121 self
122 }
123
124 pub fn with_external_pci(mut self) -> Self {
128 self.external_pci = true;
129 self
130 }
131
132 fn inner_add(
133 mut self,
134 typed_dev: Result<T, AddDeviceError>,
135 ) -> Result<Arc<CloseableMutex<T>>, AddDeviceError> {
136 let mut typed_dev = typed_dev?;
137
138 macro_rules! wire_up_service {
142 (
143 ($supports_fn:ident, $service_kind:expr);
144 ($service:pat, $dev:pat) => $body:block
145 ) => {
146 match (self.services.$supports_fn(), typed_dev.$supports_fn()) {
147 (Some($service), Some($dev)) => $body,
148 (None, Some(_)) => {
149 return Err(AddDeviceErrorKind::ChipsetMissingSupports($service_kind)
150 .with_dev_name(self.dev_name))
151 }
152 (Some(service), None) => {
153 if service.is_being_used() {
155 return Err(AddDeviceErrorKind::DeviceMissingSupports($service_kind)
156 .with_dev_name(self.dev_name));
157 }
158 }
159 (None, None) => {}
160 }
161 };
162 }
163
164 wire_up_service! {
165 (supports_mmio, ServiceKind::Mmio);
166 (service, dev) => {
167 for (label, range) in dev.get_static_regions() {
169 service
170 .register_mmio()
171 .new_io_region(label, range.end() - range.start() + 1)
172 .map(*range.start());
173 }
174 }
175 };
176
177 wire_up_service! {
178 (supports_pio, ServiceKind::PortIo);
179 (service, dev) => {
180 for (label, range) in dev.get_static_regions() {
182 service
183 .register_pio()
184 .new_io_region(label, range.end() - range.start() + 1)
185 .map(*range.start());
186 }
187 }
188 };
189
190 if !self.external_pci {
191 wire_up_service! {
192 (supports_pci, ServiceKind::Pci);
193 (service, dev) => {
194 let (bus, device, function) = match (self.pci_addr, dev.suggested_bdf()) {
196 (Some(override_bdf), Some(suggested_bdf)) => {
197 let (ob, od, of) = override_bdf;
198 let (sb, sd, sf) = suggested_bdf;
199 tracing::info!(
200 "overriding suggested bdf: using {:02x}:{:02x}:{} instead of {:02x}:{:02x}:{}",
201 ob, od, of,
202 sb, sd, sf
203 );
204 override_bdf
205 }
206 (None, Some(bdf)) | (Some(bdf), None) => bdf,
207 (None, None) => {
208 return Err(AddDeviceErrorKind::NoPciBusAddress.with_dev_name(self.dev_name))
209 }
210 };
211
212 service.register_static_pci(bus, device, function);
213 }
214 }
215 }
216
217 wire_up_service! {
218 (supports_poll_device, ServiceKind::PollDevice);
219 (service, _) => {
220 service.register_poll();
221 }
222 }
223
224 let dev = self.arc_builder.build(CloseableMutex::new(typed_dev));
225
226 self.services.finalize(&dev, self.dev_name);
228
229 Ok(dev)
230 }
231
232 #[instrument(name = "add_device", skip_all, fields(device = self.dev_name.as_ref()))]
241 pub fn add<F>(mut self, f: F) -> Result<Arc<CloseableMutex<T>>, AddDeviceError>
242 where
243 F: FnOnce(&mut S) -> T,
244 {
245 let dev = (f)(&mut self.services);
246 self.inner_add(Ok(dev))
247 }
248
249 #[instrument(name = "add_device", skip_all, fields(device = self.dev_name.as_ref()))]
251 pub async fn add_async<F, Fut>(mut self, f: F) -> Result<Arc<CloseableMutex<T>>, AddDeviceError>
252 where
253 F: AsyncFnOnce(&mut S) -> T,
254 {
255 let dev = (f)(&mut self.services).await;
256 self.inner_add(Ok(dev))
257 }
258
259 #[instrument(name = "add_device", skip_all, fields(device = self.dev_name.as_ref()))]
261 pub fn try_add<F, E>(mut self, f: F) -> Result<Arc<CloseableMutex<T>>, AddDeviceError>
262 where
263 F: FnOnce(&mut S) -> Result<T, E>,
264 E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
265 {
266 let dev = match (f)(&mut self.services) {
267 Ok(dev) => dev,
268 Err(e) => {
269 return Err(AddDeviceErrorKind::DeviceError(e.into()).with_dev_name(self.dev_name));
270 }
271 };
272 self.inner_add(Ok(dev))
273 }
274
275 #[instrument(name = "add_device", skip_all, fields(device = self.dev_name.as_ref()))]
277 pub async fn try_add_async<F, E>(
278 mut self,
279 f: F,
280 ) -> Result<Arc<CloseableMutex<T>>, AddDeviceError>
281 where
282 F: AsyncFnOnce(&mut S) -> Result<T, E>,
283 E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
284 {
285 let dev = match (f)(&mut self.services).await {
286 Ok(dev) => dev,
287 Err(e) => {
288 return Err(AddDeviceErrorKind::DeviceError(e.into()).with_dev_name(self.dev_name));
289 }
290 };
291 self.inner_add(Ok(dev))
292 }
293}