hermit/drivers/virtio/
mod.rs1#![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 virtio::FeatureBits;
21
22trait VirtioIdExt {
23 fn as_feature(&self) -> Option<&str>;
24}
25
26impl VirtioIdExt for virtio::Id {
27 fn as_feature(&self) -> Option<&str> {
28 let feature = match self {
29 Self::Net => "virtio-net",
30 Self::Console => "virtio-console",
31 Self::Fs => "virtio-fs",
32 Self::Vsock => "virtio-vsock",
33 _ => return None,
34 };
35
36 Some(feature)
37 }
38}
39
40mod control_registers_access {
41 use core::{array, mem};
42
43 use virtio::{le32, le128};
44 use volatile::VolatilePtr;
45 use volatile::access::ReadWrite;
46
47 pub trait ControlRegistersAccess<'a>: Sized + Copy {
48 fn read_device_feature_word(self, i: u32) -> le32;
49 fn write_driver_feature_word(self, i: u32, word: le32);
50
51 fn read_device_features(self) -> virtio::F {
52 let features = array::from_fn(|i| {
53 let i = u32::try_from(i).unwrap();
54 self.read_device_feature_word(i)
55 });
56
57 let features = unsafe { mem::transmute::<[le32; 4], le128>(features) };
58
59 virtio::F::from_bits_retain(features)
60 }
61
62 fn write_driver_features(self, features: virtio::F) {
63 let features = features.bits();
64
65 let features = unsafe { mem::transmute::<le128, [le32; 4]>(features) };
66
67 for (i, word) in features.into_iter().enumerate() {
68 let i = u32::try_from(i).unwrap();
69 self.write_driver_feature_word(i, word);
70 }
71 }
72 }
73
74 #[cfg(feature = "pci")]
75 impl<'a> ControlRegistersAccess<'a> for VolatilePtr<'a, virtio::pci::CommonCfg, ReadWrite> {
76 fn read_device_feature_word(self, i: u32) -> le32 {
77 use virtio::pci::CommonCfgVolatileFieldAccess;
78
79 self.device_feature_select().write(i.into());
80 self.device_feature().read()
81 }
82
83 fn write_driver_feature_word(self, i: u32, word: le32) {
84 use virtio::pci::CommonCfgVolatileFieldAccess;
85
86 self.driver_feature_select().write(i.into());
87 self.driver_feature().write(word);
88 }
89 }
90
91 #[cfg(not(feature = "pci"))]
92 impl<'a> ControlRegistersAccess<'a> for VolatilePtr<'a, virtio::mmio::DeviceRegisters, ReadWrite> {
93 fn read_device_feature_word(self, i: u32) -> le32 {
94 use virtio::mmio::DeviceRegistersVolatileFieldAccess;
95
96 if i > 1 {
99 return 0.into();
100 }
101
102 self.device_features_sel().write(i.into());
103 self.device_features().read()
104 }
105
106 fn write_driver_feature_word(self, i: u32, word: le32) {
107 use virtio::mmio::DeviceRegistersVolatileFieldAccess;
108
109 if i > 1 {
112 debug_assert!(word.to_ne() == 0);
113 return;
114 }
115
116 self.driver_features_sel().write(i.into());
117 self.driver_features().write(word);
118 }
119 }
120}
121
122pub trait ControlRegisters<'a>: self::control_registers_access::ControlRegistersAccess<'a> {
123 fn negotiate_features<DF>(self, driver_features: DF) -> DF
124 where
125 DF: FeatureBits + From<virtio::F> + AsRef<virtio::F> + AsMut<virtio::F> + fmt::Debug + Copy,
126 virtio::F: From<DF> + AsRef<DF> + AsMut<DF>;
127}
128
129impl<'a, T> ControlRegisters<'a> for T
130where
131 T: self::control_registers_access::ControlRegistersAccess<'a>,
132{
133 fn negotiate_features<DF>(self, driver_features: DF) -> DF
134 where
135 DF: FeatureBits + From<virtio::F> + AsRef<virtio::F> + AsMut<virtio::F> + fmt::Debug + Copy,
136 virtio::F: From<DF> + AsRef<DF> + AsMut<DF>,
137 {
138 let device_features = DF::from(self.read_device_features());
139 info!("device_features = {device_features:?}");
140 debug_assert!(
141 device_features.requirements_satisfied(),
142 "The device offers a feature which requires another feature which was not offered."
143 );
144
145 info!("driver_features = {driver_features:?}");
146 debug_assert!(
147 driver_features.requirements_satisfied(),
148 "The driver offers a feature which requires another feature which was not offered.",
149 );
150
151 let common_features = device_features.intersection(driver_features);
152 info!("common_features = {common_features:?}");
153 debug_assert!(
155 common_features.requirements_satisfied(),
156 "We negotiated a feature which requires another feature which was not negotiated."
157 );
158
159 self.write_driver_features(common_features.into());
160
161 common_features
162 }
163}
164
165pub mod error {
166 use thiserror::Error;
167
168 #[cfg(feature = "virtio-console")]
169 pub use crate::drivers::console::error::VirtioConsoleError;
170 #[cfg(feature = "virtio-fs")]
171 pub use crate::drivers::fs::error::VirtioFsError;
172 #[cfg(all(
173 not(all(target_arch = "riscv64", feature = "gem-net", not(feature = "pci"))),
174 not(feature = "rtl8139"),
175 feature = "virtio-net",
176 ))]
177 pub use crate::drivers::net::virtio::error::VirtioNetError;
178 #[cfg(feature = "pci")]
179 use crate::drivers::pci::error::PciError;
180 #[cfg(feature = "virtio-vsock")]
181 pub use crate::drivers::vsock::error::VirtioVsockError;
182
183 #[derive(Error, Debug)]
184 pub enum VirtioError {
185 #[cfg(feature = "pci")]
186 #[error(transparent)]
187 FromPci(PciError),
188
189 #[cfg(feature = "pci")]
190 #[error(
191 "Virtio driver failed, for device {0:x}, due to a missing or malformed common config!"
192 )]
193 NoComCfg(u16),
194
195 #[cfg(feature = "pci")]
196 #[error(
197 "Virtio driver failed, for device {0:x}, due to a missing or malformed ISR status config!"
198 )]
199 NoIsrCfg(u16),
200
201 #[cfg(feature = "pci")]
202 #[error(
203 "Virtio driver failed, for device {0:x}, due to a missing or malformed notification config!"
204 )]
205 NoNotifCfg(u16),
206
207 #[error("Device with id {0:#x} not supported.")]
208 DevNotSupported(u16),
209
210 #[cfg(all(
211 not(all(target_arch = "riscv64", feature = "gem-net", not(feature = "pci"))),
212 not(feature = "rtl8139"),
213 feature = "virtio-net",
214 ))]
215 #[error(transparent)]
216 NetDriver(VirtioNetError),
217
218 #[cfg(feature = "virtio-fs")]
219 #[error(transparent)]
220 FsDriver(VirtioFsError),
221
222 #[cfg(feature = "virtio-vsock")]
223 #[error(transparent)]
224 VsockDriver(VirtioVsockError),
225
226 #[cfg(feature = "virtio-console")]
227 #[error(transparent)]
228 ConsoleDriver(VirtioConsoleError),
229 }
230}