1use kernel::utilities::cells::OptionalCell;
8use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
9use kernel::utilities::registers::{
10 register_bitfields, InMemoryRegister, ReadOnly, ReadWrite, WriteOnly,
11};
12use kernel::utilities::StaticRef;
13
14use super::super::devices::{VirtIODeviceDriver, VirtIODeviceType};
15use super::super::queues::Virtqueue;
16use super::super::transports::{VirtIOInitializationError, VirtIOTransport};
17
18const VIRTIO_MAGIC_VALUE: [u8; 4] = [0x76, 0x69, 0x72, 0x74];
20
21#[repr(C)]
22pub struct VirtIOMMIODeviceRegisters {
23 magic_value: ReadOnly<u32>,
25 device_version: ReadOnly<u32>,
27 device_id: ReadOnly<u32>,
29 vendor_id: ReadOnly<u32>,
31 device_features: ReadOnly<u32, DeviceFeatures::Register>,
33 device_features_sel: WriteOnly<u32, DeviceFeatures::Register>,
35 _reversed0: [u32; 2],
37 driver_features: WriteOnly<u32>,
39 driver_features_sel: WriteOnly<u32>,
41 _reserved1: [u32; 2],
43 queue_sel: WriteOnly<u32>,
45 queue_num_max: ReadOnly<u32>,
47 queue_num: WriteOnly<u32>,
49 _reserved2: [u32; 2],
51 queue_ready: ReadWrite<u32>,
53 _reserved3: [u32; 2],
55 queue_notify: WriteOnly<u32>,
57 _reserved4: [u32; 3],
59 interrupt_status: ReadOnly<u32, InterruptStatus::Register>,
61 interrupt_ack: WriteOnly<u32, InterruptStatus::Register>,
63 _reserved5: [u32; 2],
65 device_status: ReadWrite<u32, DeviceStatus::Register>,
67 _reserved6: [u32; 3],
69 queue_desc_low: WriteOnly<u32>,
71 queue_desc_high: WriteOnly<u32>,
72 _reserved7: [u32; 2],
74 queue_driver_low: WriteOnly<u32>,
76 queue_driver_high: WriteOnly<u32>,
77 _reserved8: [u32; 2],
79 queue_device_low: WriteOnly<u32>,
81 queue_device_high: WriteOnly<u32>,
82 _reserved9: [u32; 21],
84 config_generation: ReadOnly<u32>,
86 config: [u32; 40],
92}
93
94register_bitfields![u32,
95 DeviceStatus [
96 Acknowledge OFFSET(0) NUMBITS(1) [],
97 Driver OFFSET(1) NUMBITS(1) [],
98 Failed OFFSET(7) NUMBITS(1) [],
99 FeaturesOk OFFSET(3) NUMBITS(1) [],
100 DriverOk OFFSET(2) NUMBITS(1) [],
101 DeviceNeedsReset OFFSET(6) NUMBITS(1) []
102 ],
103 DeviceFeatures [
104 Dummy OFFSET(0) NUMBITS(1) []
106 ],
107 InterruptStatus [
108 UsedBuffer OFFSET(0) NUMBITS(1) [],
109 ConfigChange OFFSET(1) NUMBITS(1) []
110 ]
111];
112
113register_bitfields![u64,
114 TransportFeatures [
115 RingIndirectDesc OFFSET(28) NUMBITS(1) [],
116 RingEventIdx OFFSET(29) NUMBITS(1) [],
117 Version1 OFFSET(32) NUMBITS(1) [],
118 AccessPlatform OFFSET(33) NUMBITS(1) [],
119 RingPacked OFFSET(34) NUMBITS(1) [],
120 InOrder OFFSET(35) NUMBITS(1) [],
121 OrderPlatform OFFSET(36) NUMBITS(1) [],
122 SRIOV OFFSET(37) NUMBITS(1) []
123 ]
124];
125
126pub struct VirtIOMMIODevice {
127 regs: StaticRef<VirtIOMMIODeviceRegisters>,
128 device_type: OptionalCell<VirtIODeviceType>,
129 queues: OptionalCell<&'static [&'static dyn Virtqueue]>,
130}
131
132impl VirtIOMMIODevice {
133 pub const fn new(regs: StaticRef<VirtIOMMIODeviceRegisters>) -> VirtIOMMIODevice {
134 VirtIOMMIODevice {
135 regs,
136 device_type: OptionalCell::empty(),
137 queues: OptionalCell::empty(),
138 }
139 }
140
141 pub fn handle_interrupt(&self) {
142 assert!(self.queues.is_some());
143
144 let isr = self.regs.interrupt_status.extract();
145 self.regs.interrupt_ack.set(isr.get());
147
148 if isr.is_set(InterruptStatus::UsedBuffer) {
149 self.queues.map(|queues| {
152 for queue in queues.iter() {
153 queue.used_interrupt();
154 }
155 });
156 }
157
158 if isr.is_set(InterruptStatus::ConfigChange) {
159 }
161 }
162
163 pub fn query(&self) -> Option<VirtIODeviceType> {
170 if self.regs.magic_value.get() != u32::from_le_bytes(VIRTIO_MAGIC_VALUE) {
172 panic!("Not a VirtIO MMIO device");
173 }
174
175 if self.regs.device_version.get() != 0x0002 {
177 panic!(
178 "Unknown VirtIO MMIO device version: {}",
179 self.regs.device_version.get()
180 );
181 }
182
183 VirtIODeviceType::from_device_id(self.regs.device_id.get())
185 }
186}
187
188impl VirtIOTransport for VirtIOMMIODevice {
189 fn initialize(
190 &self,
191 driver: &dyn VirtIODeviceDriver,
192 queues: &'static [&'static dyn Virtqueue],
193 ) -> Result<VirtIODeviceType, VirtIOInitializationError> {
194 if self.regs.magic_value.get() != u32::from_le_bytes(VIRTIO_MAGIC_VALUE) {
199 return Err(VirtIOInitializationError::NotAVirtIODevice);
200 }
201
202 if self.regs.device_version.get() != 0x0002 {
204 return Err(VirtIOInitializationError::InvalidTransportVersion);
205 }
206
207 let device_id = self.regs.device_id.get();
210 let device_type = VirtIODeviceType::from_device_id(device_id)
211 .ok_or(VirtIOInitializationError::UnknownDeviceType(device_id))?;
212
213 if device_type != driver.device_type() {
214 return Err(VirtIOInitializationError::IncompatibleDriverDeviceType(
215 device_type,
216 ));
217 }
218
219 self.regs.device_status.set(0x0000);
223
224 self.regs
227 .device_status
228 .modify(DeviceStatus::Acknowledge::SET);
229
230 self.regs.device_status.modify(DeviceStatus::Driver::SET);
235
236 self.regs.device_features_sel.set(0);
252 let mut device_features_reg: u64 = self.regs.device_features.get() as u64;
253 self.regs.device_features_sel.set(1);
254 device_features_reg |= (self.regs.device_features.get() as u64) << 32;
255
256 let offered_transport_features: InMemoryRegister<u64, TransportFeatures::Register> =
258 InMemoryRegister::new(device_features_reg);
259 let selected_transport_features: InMemoryRegister<u64, TransportFeatures::Register> =
260 InMemoryRegister::new(0x0000000000000000);
261
262 if !offered_transport_features.is_set(TransportFeatures::Version1) {
264 return Err(VirtIOInitializationError::InvalidVirtIOVersion);
265 } else {
266 selected_transport_features.modify(TransportFeatures::Version1::SET);
267 }
268
269 let driver_negotiated =
273 if let Some(nf) = driver.negotiate_features(device_features_reg & 0xFFF) {
274 nf & 0xFFF
276 } else {
277 self.regs.device_status.modify(DeviceStatus::Failed::SET);
280 return Err(VirtIOInitializationError::FeatureNegotiationFailed {
281 offered: offered_transport_features.get(),
282 accepted: None,
283 });
284 };
285
286 let selected_features = selected_transport_features.get() | driver_negotiated;
287
288 self.regs.driver_features_sel.set(0);
290 self.regs
291 .driver_features
292 .set((selected_features & 0xFFFF) as u32);
293 self.regs.driver_features_sel.set(1);
294 self.regs
295 .driver_features
296 .set((selected_features >> 32 & 0xFFFF) as u32);
297
298 self.regs
301 .device_status
302 .modify(DeviceStatus::FeaturesOk::SET);
303
304 if !self.regs.device_status.is_set(DeviceStatus::FeaturesOk) {
308 self.regs.device_status.modify(DeviceStatus::Failed::SET);
311 return Err(VirtIOInitializationError::FeatureNegotiationFailed {
312 offered: offered_transport_features.get(),
313 accepted: Some(selected_features),
314 });
315 }
316
317 for (index, queue) in queues.iter().enumerate() {
328 self.regs.queue_sel.set(index as u32);
330
331 if self.regs.queue_ready.get() != 0 {
334 self.regs.device_status.modify(DeviceStatus::Failed::SET);
335 return Err(VirtIOInitializationError::DeviceError);
336 }
337
338 let queue_num_max = self.regs.queue_num_max.get() as usize;
342 if queue_num_max == 0 {
343 self.regs.device_status.modify(DeviceStatus::Failed::SET);
344 return Err(VirtIOInitializationError::VirtqueueNotAvailable(index));
345 }
346
347 let queue_num = queue.negotiate_queue_size(queue_num_max);
351
352 queue.initialize(index as u32, queue_num);
354
355 self.regs.queue_num.set(queue_num as u32);
357
358 let addrs = queue.physical_addresses();
360 self.regs.queue_desc_low.set(addrs.descriptor_area as u32);
361 self.regs
362 .queue_desc_high
363 .set((addrs.descriptor_area >> 32) as u32);
364 self.regs.queue_driver_low.set(addrs.driver_area as u32);
365 self.regs
366 .queue_driver_high
367 .set((addrs.driver_area >> 32) as u32);
368 self.regs.queue_device_low.set(addrs.device_area as u32);
369 self.regs
370 .queue_device_high
371 .set((addrs.device_area >> 32) as u32);
372
373 self.regs.queue_ready.set(0x0001);
375 }
376
377 self.queues.set(queues);
379
380 driver
382 .pre_device_initialization()
383 .map_err(VirtIOInitializationError::DriverPreInitializationError)?;
384
385 self.regs.device_status.modify(DeviceStatus::DriverOk::SET);
387
388 self.device_type.set(device_type);
390
391 driver.device_initialized().map_err(|err| {
392 VirtIOInitializationError::DriverInitializationError(device_type, err)
393 })?;
394
395 Ok(device_type)
396 }
397
398 fn queue_notify(&self, queue_id: u32) {
399 assert!(
402 queue_id
403 < self
404 .queues
405 .get()
406 .expect("VirtIO transport not initialized")
407 .len() as u32
408 );
409
410 self.regs.queue_notify.set(queue_id);
411 }
412}