1#![cfg_attr(
6 not(any(
7 feature = "virtio-console",
8 feature = "virtio-fs",
9 feature = "virtio-net",
10 feature = "virtio-vsock"
11 )),
12 allow(dead_code)
13)]
14
15pub mod transport;
16pub mod virtqueue;
17
18use core::fmt;
19
20use bitflags::Flags;
21use virtio::FeatureBits;
22
23use crate::drivers::virtio::error::VirtioError;
24use crate::drivers::virtio::transport::UniCapsColl;
25
26trait VirtioIdExt {
27 fn as_feature(&self) -> Option<&str>;
28}
29
30impl VirtioIdExt for virtio::Id {
31 fn as_feature(&self) -> Option<&str> {
32 let feature = match self {
33 Self::Net => "virtio-net",
34 Self::Console => "virtio-console",
35 Self::Fs => "virtio-fs",
36 Self::Vsock => "virtio-vsock",
37 _ => return None,
38 };
39
40 Some(feature)
41 }
42}
43
44mod control_registers_access {
45 use core::{array, mem};
46
47 use virtio::{le32, le128};
48 use volatile::VolatilePtr;
49 use volatile::access::ReadWrite;
50
51 pub trait ControlRegistersAccess<'a>: Sized + Copy {
52 fn read_device_feature_word(self, i: u32) -> le32;
53 fn write_driver_feature_word(self, i: u32, word: le32);
54
55 fn read_device_features(self) -> virtio::F {
56 let features = array::from_fn(|i| {
57 let i = u32::try_from(i).unwrap();
58 self.read_device_feature_word(i)
59 });
60
61 let features = unsafe { mem::transmute::<[le32; 4], le128>(features) };
62
63 virtio::F::from_bits_retain(features)
64 }
65
66 fn write_driver_features(self, features: virtio::F) {
67 let features = features.bits();
68
69 let features = unsafe { mem::transmute::<le128, [le32; 4]>(features) };
70
71 for (i, word) in features.into_iter().enumerate() {
72 let i = u32::try_from(i).unwrap();
73 self.write_driver_feature_word(i, word);
74 }
75 }
76 }
77
78 #[cfg(feature = "pci")]
79 impl<'a> ControlRegistersAccess<'a> for VolatilePtr<'a, virtio::pci::CommonCfg, ReadWrite> {
80 fn read_device_feature_word(self, i: u32) -> le32 {
81 use virtio::pci::CommonCfgVolatileFieldAccess;
82
83 self.device_feature_select().write(i.into());
84 self.device_feature().read()
85 }
86
87 fn write_driver_feature_word(self, i: u32, word: le32) {
88 use virtio::pci::CommonCfgVolatileFieldAccess;
89
90 self.driver_feature_select().write(i.into());
91 self.driver_feature().write(word);
92 }
93 }
94
95 #[cfg(not(feature = "pci"))]
96 impl<'a> ControlRegistersAccess<'a> for VolatilePtr<'a, virtio::mmio::DeviceRegisters, ReadWrite> {
97 fn read_device_feature_word(self, i: u32) -> le32 {
98 use virtio::mmio::DeviceRegistersVolatileFieldAccess;
99
100 if i > 1 {
103 return 0.into();
104 }
105
106 self.device_features_sel().write(i.into());
107 self.device_features().read()
108 }
109
110 fn write_driver_feature_word(self, i: u32, word: le32) {
111 use virtio::mmio::DeviceRegistersVolatileFieldAccess;
112
113 if i > 1 {
116 debug_assert!(word.to_ne() == 0);
117 return;
118 }
119
120 self.driver_features_sel().write(i.into());
121 self.driver_features().write(word);
122 }
123 }
124}
125
126pub trait ControlRegisters<'a>: control_registers_access::ControlRegistersAccess<'a> {
127 fn negotiate_features<DF>(self, driver_features: DF) -> DF
128 where
129 DF: FeatureBits + fmt::Debug + Copy;
130}
131
132impl<'a, T> ControlRegisters<'a> for T
133where
134 T: control_registers_access::ControlRegistersAccess<'a>,
135{
136 fn negotiate_features<DF>(self, driver_features: DF) -> DF
137 where
138 DF: FeatureBits + fmt::Debug + Copy,
139 {
140 let device_features = DF::from(self.read_device_features());
141 info!("device_features = {device_features:?}");
142 debug_assert!(
143 device_features.requirements_satisfied(),
144 "The device offers a feature which requires another feature which was not offered."
145 );
146
147 info!("driver_features = {driver_features:?}");
148 debug_assert!(
149 driver_features.requirements_satisfied(),
150 "The driver offers a feature which requires another feature which was not offered.",
151 );
152
153 let common_features = device_features.intersection(driver_features);
154 info!("common_features = {common_features:?}");
155 debug_assert!(
157 common_features.requirements_satisfied(),
158 "We negotiated a feature which requires another feature which was not negotiated."
159 );
160
161 self.write_driver_features(common_features.into());
162
163 common_features
164 }
165}
166
167pub(super) trait VirtioDriver: super::Driver + Sized
168where
169 virtio::F:
170 From<Self::DeviceFeatures> + AsRef<Self::DeviceFeatures> + AsMut<Self::DeviceFeatures>,
171{
172 type Config: 'static;
173 type Error: Into<VirtioError>;
174 type DeviceFeatures: FeatureBits + fmt::Debug + Copy;
175
176 const MINIMAL_FEATURES: Self::DeviceFeatures;
177 const OPTIONAL_FEATURES: Self::DeviceFeatures;
178
179 fn init_dev(
180 caps_tuple: (
181 UniCapsColl,
182 volatile::VolatileRef<'static, Self::Config, volatile::access::ReadOnly>,
183 ),
184 handlers: &mut super::InterruptHandlerMap,
185 irq: Option<super::InterruptLine>,
186 ) -> Result<Self, (VirtioError, UniCapsColl)>;
187
188 #[cfg(feature = "pci")]
189 fn no_dev_cfg_err(dev_id: u16) -> Self::Error;
190}
191
192impl UniCapsColl {
193 pub(super) fn init_caps<T: VirtioDriver>(
194 &mut self,
195 dev_cfg_raw: volatile::VolatileRef<'static, T::Config, volatile::access::ReadOnly>,
196 mut device_specific_setup: impl FnMut(&mut Self, &mut DevCfg<T>) -> Result<(), T::Error>,
197 ) -> Result<DevCfg<T>, VirtioError>
198 where
199 virtio::F: From<T::DeviceFeatures> + AsRef<T::DeviceFeatures> + AsMut<T::DeviceFeatures>,
200 {
201 self.com_cfg.reset_dev();
203
204 self.com_cfg.ack_dev();
206
207 self.com_cfg.set_drv();
209
210 let negotiated_features = self
211 .com_cfg
212 .control_registers()
213 .negotiate_features(T::MINIMAL_FEATURES.union(T::OPTIONAL_FEATURES));
214
215 if !negotiated_features.contains(T::MINIMAL_FEATURES) {
216 error!("Device features set, does not satisfy minimal features needed. Aborting!");
217 return Err(VirtioError::FailFeatureNeg);
218 }
219
220 self.com_cfg.features_ok();
223
224 let mut dev_cfg = if self.com_cfg.check_features() {
226 info!(
227 "Features have been negotiated between {} device and driver.",
228 T::get_name()
229 );
230 DevCfg {
232 raw: dev_cfg_raw,
233 features: negotiated_features,
234 }
235 } else {
236 error!("The device does not support our subset of features.");
237 return Err(VirtioError::FailFeatureNeg);
238 };
239
240 device_specific_setup(self, &mut dev_cfg).map_err(|err| err.into())?;
241
242 self.com_cfg.drv_ok();
244
245 Ok(dev_cfg)
246 }
247}
248
249pub(super) struct DevCfg<T: VirtioDriver>
253where
254 virtio::F: From<T::DeviceFeatures> + AsRef<T::DeviceFeatures> + AsMut<T::DeviceFeatures>,
255{
256 pub(super) features: T::DeviceFeatures,
257 #[cfg_attr(
258 all(
259 not(any(
260 feature = "virtio-fs",
261 feature = "virtio-net",
262 feature = "virtio-vsock",
263 )),
264 feature = "virtio-console"
265 ),
266 expect(dead_code)
267 )]
268 pub(super) raw: volatile::VolatileRef<'static, T::Config, volatile::access::ReadOnly>,
269}
270
271pub mod error {
272 use thiserror::Error;
273
274 #[cfg(feature = "virtio-console")]
275 pub use crate::drivers::console::error::VirtioConsoleError;
276 #[cfg(feature = "virtio-fs")]
277 pub use crate::drivers::fs::error::VirtioFsInitError;
278 #[cfg(all(
279 not(all(target_arch = "riscv64", feature = "gem-net", not(feature = "pci"))),
280 not(feature = "rtl8139"),
281 feature = "virtio-net",
282 ))]
283 pub use crate::drivers::net::virtio::error::VirtioNetError;
284 #[cfg(feature = "pci")]
285 use crate::drivers::pci::error::PciError;
286 #[cfg(feature = "virtio-rng")]
287 pub use crate::drivers::rng::error::VirtioRngError;
288 #[cfg(feature = "virtio-vsock")]
289 pub use crate::drivers::vsock::error::VirtioVsockError;
290
291 #[derive(Error, Debug)]
292 pub enum VirtioError {
293 #[cfg(feature = "pci")]
294 #[error(transparent)]
295 FromPci(PciError),
296
297 #[cfg(feature = "pci")]
298 #[error(
299 "Virtio driver failed, for device {0:x}, due to a missing or malformed common config!"
300 )]
301 NoComCfg(u16),
302
303 #[cfg(feature = "pci")]
304 #[error(
305 "Virtio driver failed, for device {0:x}, due to a missing or malformed ISR status config!"
306 )]
307 NoIsrCfg(u16),
308
309 #[cfg(feature = "pci")]
310 #[error(
311 "Virtio driver failed, for device {0:x}, due to a missing or malformed notification config!"
312 )]
313 NoNotifCfg(u16),
314
315 #[error("Device with id {0:#x} not supported.")]
316 DevNotSupported(u16),
317
318 #[error("Virtio driver failed, device did not acknowledge negotiated feature set!")]
319 FailFeatureNeg,
320
321 #[cfg(all(
322 not(all(target_arch = "riscv64", feature = "gem-net", not(feature = "pci"))),
323 not(feature = "rtl8139"),
324 feature = "virtio-net",
325 ))]
326 #[error(transparent)]
327 NetDriver(#[from] VirtioNetError),
328
329 #[cfg(feature = "virtio-fs")]
330 #[error(transparent)]
331 FsDriver(#[from] VirtioFsInitError),
332
333 #[cfg(feature = "virtio-vsock")]
334 #[error(transparent)]
335 VsockDriver(#[from] VirtioVsockError),
336
337 #[cfg(feature = "virtio-console")]
338 #[error(transparent)]
339 ConsoleDriver(#[from] VirtioConsoleError),
340
341 #[cfg(feature = "virtio-rng")]
342 #[error(transparent)]
343 RngDriver(#[from] VirtioRngError),
344 }
345}