kernel/drivers/virtio/device/
mod.rs

1//! Virtio device driver interface module.
2//! 
3
4use core::result::Result;
5
6use alloc::{boxed::Box, vec};
7
8use crate::{device::{manager::DeviceManager, platform::{resource::PlatformDeviceResourceType, PlatformDeviceDriver, PlatformDeviceInfo}, Device}, driver_initcall, drivers::block::virtio_blk::VirtioBlockDevice};
9use super::queue::VirtQueue;
10
11/// Register enum for Virtio devices
12/// 
13/// This enum represents the registers of the Virtio device.
14/// Each variant corresponds to a specific register offset.
15/// The offsets are defined in the Virtio specification.
16/// The register offsets are used to access the device's configuration and status.
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum Register {
19    MagicValue = 0x00,
20    Version = 0x04,
21    DeviceId = 0x08,
22    VendorId = 0x0c,
23    DeviceFeatures = 0x10,
24    DeviceFeaturesSel = 0x14,
25    DriverFeatures = 0x20,
26    DriverFeaturesSel = 0x24,
27    GuestPageSize = 0x28,
28    QueueSel = 0x30,
29    QueueNumMax = 0x34,
30    QueueNum = 0x38,
31    QueueAlign = 0x3c,
32    QueuePfn = 0x40,
33    QueueReady = 0x44,
34    QueueNotify = 0x50,
35    InterruptStatus = 0x60,
36    InterruptAck = 0x64,
37    Status = 0x70,
38    QueueDescLow = 0x80,
39    QueueDescHigh = 0x84,
40    DriverDescLow = 0x90,
41    DriverDescHigh = 0x94,
42    DeviceDescLow = 0xa0,
43    DeviceDescHigh = 0xa4,
44    DeviceConfig = 0x100,
45}
46
47impl Register {
48    pub fn offset(&self) -> usize {
49        *self as usize
50    }
51
52    pub fn from_offset(offset: usize) -> Self {
53        match offset {
54            0x00 => Register::MagicValue,
55            0x04 => Register::Version,
56            0x08 => Register::DeviceId,
57            0x0c => Register::VendorId,
58            0x10 => Register::DeviceFeatures,
59            0x14 => Register::DeviceFeaturesSel,
60            0x20 => Register::DriverFeatures,
61            0x24 => Register::DriverFeaturesSel,
62            0x28 => Register::GuestPageSize,
63            0x30 => Register::QueueSel,
64            0x34 => Register::QueueNumMax,
65            0x38 => Register::QueueNum,
66            0x3c => Register::QueueAlign,
67            0x40 => Register::QueuePfn,
68            0x44 => Register::QueueReady,
69            0x50 => Register::QueueNotify,
70            0x60 => Register::InterruptStatus,
71            0x64 => Register::InterruptAck,
72            0x70 => Register::Status,
73            0x80 => Register::QueueDescLow,
74            0x84 => Register::QueueDescHigh,
75            0x90 => Register::DriverDescLow,
76            0x94 => Register::DriverDescHigh,
77            0xa0 => Register::DeviceDescLow,
78            0xa4 => Register::DeviceDescHigh,
79            _ => panic!("Invalid register offset"),
80        }
81    }
82}
83
84/// DeviceStatus enum for Virtio devices
85/// 
86/// This enum represents the status of the Virtio device.
87/// Each variant corresponds to a specific status bit.
88/// The status bits are defined in the Virtio specification.
89#[derive(Debug, Clone, Copy)]
90pub enum DeviceStatus {
91    Reset = 0x00,
92    Acknowledge = 0x01,
93    Driver = 0x02,
94    DriverOK = 0x04,
95    FeaturesOK = 0x08,
96    DeviceNeedReset = 0x40,
97    Failed = 0x80,
98}
99
100impl DeviceStatus {
101    /// Check if the status is set
102    /// 
103    /// This method checks if the specified status bit is set in the given status.
104    /// 
105    /// # Arguments
106    /// 
107    /// * `status` - The status to check.
108    /// 
109    /// # Returns
110    /// 
111    /// Returns true if the status bit is set, false otherwise.
112    pub fn is_set(&self, status: u32) -> bool {
113        (status & *self as u32) != 0
114    }
115
116    /// Set the status bit
117    /// 
118    /// This method sets the specified status bit in the given status.
119    /// 
120    /// # Arguments
121    /// 
122    /// * `status` - A mutable reference to the status to modify.
123    /// 
124    pub fn set(&self, status: &mut u32) {
125        *status |= *self as u32;
126    }
127
128    /// Clear the status bit
129    /// 
130    /// This method clears the specified status bit in the given status.
131    /// 
132    /// # Arguments
133    /// 
134    /// * `status` - A mutable reference to the status to modify.
135    /// 
136    pub fn clear(&self, status: &mut u32) {
137        *status &= !(*self as u32);
138    }
139
140    /// Toggle the status bit
141    /// 
142    /// This method toggles the specified status bit in the given status.
143    /// 
144    /// # Arguments
145    /// 
146    /// * `status` - A mutable reference to the status to modify.
147    /// 
148    pub fn toggle(&self, status: &mut u32) {
149        *status ^= *self as u32;
150    }
151
152    /// Convert from u32 to DeviceStatus
153    /// 
154    /// This method converts a u32 value to the corresponding DeviceStatus variant.
155    /// 
156    /// # Arguments
157    /// 
158    /// * `status` - The u32 value to convert.
159    /// 
160    /// # Returns
161    /// 
162    /// Returns the corresponding DeviceStatus variant.
163    ///
164    pub fn from_u32(status: u32) -> Self {
165        match status {
166            0x00 => DeviceStatus::Reset,
167            0x01 => DeviceStatus::Acknowledge,
168            0x02 => DeviceStatus::Driver,
169            0x04 => DeviceStatus::DriverOK,
170            0x08 => DeviceStatus::FeaturesOK,
171            0x40 => DeviceStatus::DeviceNeedReset,
172            0x80 => DeviceStatus::Failed,
173            _ => panic!("Invalid device status"),
174        }
175    }
176    
177    /// Convert DeviceStatus to u32
178    /// 
179    /// This method converts the DeviceStatus variant to its corresponding u32 value.
180    /// 
181    /// # Returns
182    /// 
183    /// Returns the u32 value corresponding to the DeviceStatus variant.
184    /// 
185    pub fn to_u32(&self) -> u32 {
186        *self as u32
187    }
188}
189
190/// VirtioDevice trait
191/// 
192/// This trait defines the interface for VirtIO devices.
193/// It provides methods for initializing the device, accessing registers,
194/// and performing device operations according to the VirtIO specification.
195pub trait VirtioDevice {
196    /// Initialize the device
197    ///
198    /// This method performs the standard VirtIO initialization sequence:
199    /// 1. Reset the device
200    /// 2. Acknowledge the device
201    /// 3. Set driver status
202    /// 4. Negotiate features
203    /// 5. Set up virtqueues
204    /// 6. Set driver OK status
205    fn init(&mut self) -> Result<(), &'static str> {
206        // Verify device (Magic Value should be "virt")
207        if self.read32_register(Register::MagicValue) != 0x74726976 {
208            self.set_failed();
209            return Err("Invalid Magic Value");
210        }
211
212        // Check device version
213        let version = self.read32_register(Register::Version);
214        if version != 2 {
215            self.set_failed();
216            return Err("Invalid Version");
217        }
218
219        // Reset device
220        self.reset();
221        
222        // Acknowledge device
223        self.acknowledge();
224
225        // Set driver status
226        self.driver();
227
228        // Negotiate features
229        if !self.negotiate_features() {
230            self.set_failed();
231            return Err("Feature negotiation failed");
232        }
233
234        // Set up virtqueues
235        for i in 0..self.get_virtqueue_count() {
236            if !self.setup_queue(i) {
237                self.set_failed();
238                return Err("Failed to set up virtqueue");
239            }
240        }
241
242        // Mark driver OK
243        self.driver_ok();
244        Ok(())
245    }
246
247    /// Reset the device by writing 0 to the Status register
248    fn reset(&mut self) {
249        self.write32_register(Register::Status, 0);
250    }
251
252    /// Set ACKNOWLEDGE status bit
253    fn acknowledge(&mut self) {
254        let mut status = self.read32_register(Register::Status);
255        DeviceStatus::Acknowledge.set(&mut status);
256        self.write32_register(Register::Status, status);
257    }
258
259    /// Set DRIVER status bit
260    fn driver(&mut self) {
261        let mut status = self.read32_register(Register::Status);
262        DeviceStatus::Driver.set(&mut status);
263        self.write32_register(Register::Status, status);
264    }
265
266    /// Set DRIVER_OK status bit
267    fn driver_ok(&mut self) {
268        let mut status = self.read32_register(Register::Status);
269        DeviceStatus::DriverOK.set(&mut status);
270        self.write32_register(Register::Status, status);
271    }
272
273    /// Set FAILED status bit
274    fn set_failed(&mut self) {
275        let mut status = self.read32_register(Register::Status);
276        DeviceStatus::Failed.set(&mut status);
277        self.write32_register(Register::Status, status);
278    }
279
280    /// Negotiate device features
281    ///
282    /// This method reads device features, selects supported features, 
283    /// sets driver features, and verifies features OK status.
284    ///
285    /// # Returns
286    ///
287    /// Returns true if feature negotiation was successful, false otherwise
288    fn negotiate_features(&mut self) -> bool {
289        // Read device features
290        let device_features = self.read32_register(Register::DeviceFeatures);
291        // Select supported features
292        let driver_features = self.get_supported_features(device_features);
293        // Write driver features
294        self.write32_register(Register::DriverFeatures, driver_features);
295        
296        // Set FEATURES_OK status bit
297        let mut status = self.read32_register(Register::Status);
298        DeviceStatus::FeaturesOK.set(&mut status);
299        self.write32_register(Register::Status, status);
300        
301        // Verify FEATURES_OK status bit
302        let status = self.read32_register(Register::Status);
303        DeviceStatus::FeaturesOK.is_set(status)
304    }
305    
306    /// Get device features supported by this driver
307    ///
308    /// This method can be overridden by specific device implementations
309    /// to select which features to support.
310    ///
311    /// # Arguments
312    ///
313    /// * `device_features` - The features offered by the device
314    ///
315    /// # Returns
316    ///
317    /// The features supported by the driver
318    fn get_supported_features(&self, device_features: u32) -> u32 {
319        // By default, accept all device features
320        // Device-specific implementations should override this
321        device_features
322    }
323    
324    /// Set up a virtqueue
325    ///
326    /// This method configures a virtqueue by setting the queue selection,
327    /// size, alignment, and ready status.
328    ///
329    /// # Arguments
330    ///
331    /// * `queue_idx` - The index of the queue to set up
332    ///
333    /// # Returns
334    ///
335    /// Returns true if queue setup was successful, false otherwise
336    fn setup_queue(&mut self, queue_idx: usize) -> bool {
337        if queue_idx >= self.get_virtqueue_count() {
338            return false;
339        }
340        
341        // Select the queue
342        self.write32_register(Register::QueueSel, queue_idx as u32);
343        // Check if the queue is ready
344        let ready = self.read32_register(Register::QueueReady);
345        if ready != 0 {
346            return false; // Queue already set up
347        }
348        
349        // Get maximum queue size
350        let queue_size = self.read32_register(Register::QueueNumMax);
351        if queue_size == 0 {
352            return false; // Queue not available
353        }
354        
355        // Set queue size
356        self.write32_register(Register::QueueNum, queue_size);
357        
358        let virtqueue = self.get_virtqueue(queue_idx);
359
360        // Set the queue descriptor address
361        let desc_addr = virtqueue.get_raw_ptr() as u64;
362        let desc_addr_low = (desc_addr & 0xffffffff) as u32;
363        let desc_addr_high = (desc_addr >> 32) as u32;
364        self.write32_register(Register::QueueDescLow, desc_addr_low);
365        self.write32_register(Register::QueueDescHigh, desc_addr_high);
366
367        // Set the driver area (available ring)  address
368        let driver_addr = virtqueue.avail.flags as *const _ as u64;
369        let driver_addr_low = (driver_addr & 0xffffffff) as u32;
370        let driver_addr_high = (driver_addr >> 32) as u32;
371        self.write32_register(Register::DriverDescLow, driver_addr_low);
372        self.write32_register(Register::DriverDescHigh, driver_addr_high);
373
374        // Set the device area (used ring) address
375        let device_addr = virtqueue.used.flags as *const _ as u64;
376        let device_addr_low = (device_addr & 0xffffffff) as u32;
377        let device_addr_high = (device_addr >> 32) as u32;
378        self.write32_register(Register::DeviceDescLow, device_addr_low);
379        self.write32_register(Register::DeviceDescHigh, device_addr_high);
380
381        // Check the status of the queue
382        let status = self.read32_register(Register::Status);
383        if DeviceStatus::Failed.is_set(status) {
384            return false; // Queue setup failed
385        }
386        
387        // Mark queue as ready
388        self.write32_register(Register::QueueReady, 1);
389
390        // Check the status of the queue
391        let status = self.read32_register(Register::Status);
392        if DeviceStatus::Failed.is_set(status) {
393            return false; // Queue setup failed
394        }
395        
396        true
397    }
398    
399    /// Read device-specific configuration
400    ///
401    /// This method reads configuration data from the device-specific configuration space.
402    ///
403    /// # Arguments
404    ///
405    /// * `offset` - The offset within the configuration space
406    ///
407    /// # Returns
408    ///
409    /// The configuration value of type T
410    fn read_config<T: Sized>(&self, offset: usize) -> T {
411        let addr = self.get_base_addr() + Register::DeviceConfig.offset() + offset;
412        unsafe { core::ptr::read_volatile(addr as *const T) }
413    }
414    
415    /// Write device-specific configuration
416    ///
417    /// This method writes configuration data to the device-specific configuration space.
418    ///
419    /// # Arguments
420    ///
421    /// * `offset` - The offset within the configuration space
422    /// * `value` - The value to write
423    fn write_config<T: Sized>(&self, offset: usize, value: T) {
424        let addr = self.get_base_addr() + Register::DeviceConfig.offset() + offset;
425        unsafe { core::ptr::write_volatile(addr as *mut T, value) }
426    }
427    
428    /// Get device and vendor IDs
429    ///
430    /// # Returns
431    ///
432    /// A tuple containing (device_id, vendor_id)
433    fn get_device_info(&self) -> (u32, u32) {
434        let device_id = self.read32_register(Register::DeviceId);
435        let vendor_id = self.read32_register(Register::VendorId);
436        (device_id, vendor_id)
437    }
438    
439    /// Get interrupt status
440    ///
441    /// # Returns
442    ///
443    /// The interrupt status register value
444    fn get_interrupt_status(&self) -> u32 {
445        self.read32_register(Register::InterruptStatus)
446    }
447    
448    /// Process interrupts (polling method)
449    ///
450    /// This method checks for interrupts and acknowledges them.
451    ///
452    /// # Returns
453    ///
454    /// The interrupt status before acknowledgment
455    fn process_interrupts(&mut self) -> u32 {
456        let status = self.get_interrupt_status();
457        if status != 0 {
458            self.write32_register(Register::InterruptAck, status & 0x03);
459        }
460        status
461    }
462    
463    /// Memory barrier for ensuring memory operations ordering
464    fn memory_barrier(&self) {
465        core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
466    }
467    
468    /// Notify the device about new buffers in a specified virtqueue
469    ///
470    /// This method notifies the device that new buffers are available in the specified virtqueue.
471    /// It selects the queue using the QueueSel register and then writes to the QueueNotify register.
472    ///
473    /// # Arguments
474    ///
475    /// * `virtqueue_idx` - The index of the virtqueue to notify
476    ///
477    /// # Panics
478    ///
479    /// Panics if the virtqueue index is invalid
480    fn notify(&mut self, virtqueue_idx: usize) {
481        if virtqueue_idx >= self.get_virtqueue_count() {
482            panic!("Invalid virtqueue index");
483        }
484        // Insert memory barrier before notification
485        self.memory_barrier();
486        self.write32_register(Register::QueueNotify, virtqueue_idx as u32);
487    }
488
489    /// Read a 32-bit value from a device register
490    ///
491    /// # Arguments
492    ///
493    /// * `register` - The register to read from
494    ///
495    /// # Returns
496    ///
497    /// The 32-bit value read from the register
498    fn read32_register(&self, register: Register) -> u32 {
499        let addr = self.get_base_addr() + register.offset();
500        unsafe { core::ptr::read_volatile(addr as *const u32) }
501    }
502
503    /// Write a 32-bit value to a device register
504    ///
505    /// # Arguments
506    ///
507    /// * `register` - The register to write to
508    /// * `value` - The 32-bit value to write
509    fn write32_register(&self, register: Register, value: u32) {
510        let addr = self.get_base_addr() + register.offset();
511        unsafe { core::ptr::write_volatile(addr as *mut u32, value) }
512    }
513
514    /// Read a 64-bit value from a device register
515    ///
516    /// # Arguments
517    ///
518    /// * `register` - The register to read from
519    ///
520    /// # Returns
521    ///
522    /// The 64-bit value read from the register
523    fn read64_register(&self, register: Register) -> u64 {
524        let addr = self.get_base_addr() + register.offset();
525        unsafe { core::ptr::read_volatile(addr as *const u64) }
526    }
527
528    /// Write a 64-bit value to a device register
529    ///
530    /// # Arguments
531    ///
532    /// * `register` - The register to write to
533    /// * `value` - The 64-bit value to write
534    fn write64_register(&self, register: Register, value: u64) {
535        let addr = self.get_base_addr() + register.offset();
536        unsafe { core::ptr::write_volatile(addr as *mut u64, value) }
537    }
538
539    // Required methods to be implemented by specific device types
540
541    fn get_base_addr(&self) -> usize;
542    fn get_virtqueue_count(&self) -> usize;
543    fn get_virtqueue(&self, queue_idx: usize) -> &VirtQueue;
544}
545
546
547/// Device type enum for Virtio devices
548/// 
549/// This enum represents the different types of Virtio devices.
550/// Each variant corresponds to a specific device type.
551/// The types are defined in the Virtio specification.
552pub enum VirtioDeviceType {
553    Invalid = 0,
554    Net = 1,
555    Block = 2,
556    Console = 3,
557    Rng = 4,
558}
559
560impl VirtioDeviceType {
561    /// Convert from u32 to VirtioDeviceType
562    /// 
563    /// This method converts a u32 value to the corresponding VirtioDeviceType variant.
564    /// 
565    /// # Arguments
566    /// 
567    /// * `device_type` - The u32 value to convert.
568    /// 
569    /// # Returns
570    /// 
571    /// Returns the corresponding VirtioDeviceType variant.
572    pub fn from_u32(device_type: u32) -> Self {
573        match device_type {
574            0 => VirtioDeviceType::Invalid,
575            1 => VirtioDeviceType::Net,
576            2 => VirtioDeviceType::Block,
577            3 => VirtioDeviceType::Console,
578            4 => VirtioDeviceType::Rng,
579            _ => panic!("Not supported device type"),
580        }
581    }
582}
583
584/// Virtio Common Device
585/// 
586/// Only use this struct for checking the device info.
587/// It should not be used for actual device operations.
588/// 
589struct VirtioDeviceCommon {
590    base_addr: usize,
591}
592
593impl VirtioDeviceCommon {
594    /// Create a new Virtio device
595    ///
596    /// # Arguments
597    ///
598    /// * `base_addr` - The base address of the device
599    ///
600    /// # Returns
601    ///
602    /// A new instance of `VirtioDeviceCommon`
603    pub fn new(base_addr: usize) -> Self {
604        Self { base_addr }
605    }
606}
607
608impl VirtioDevice for VirtioDeviceCommon {
609    fn init(&mut self) -> Result<(), &'static str> {
610        // Initialization is not required for the common device
611        Ok(())
612    }
613
614    fn get_base_addr(&self) -> usize {
615        self.base_addr
616    }
617
618    fn get_virtqueue_count(&self) -> usize {
619        // This should be overridden by specific device implementations
620        0
621    }
622
623    fn get_virtqueue(&self, _queue_idx: usize) -> &VirtQueue {
624        // This should be overridden by specific device implementations
625        unimplemented!()
626    }
627}
628
629fn probe_fn(device: &PlatformDeviceInfo) -> Result<(), &'static str> {
630    let res = device.get_resources();
631    if res.is_empty() {
632        return Err("No resources found");
633    }
634
635    // Get memory region resource (res_type == PlatformDeviceResourceType::MEM)
636    let mem_res = res.iter()
637        .find(|r| r.res_type == PlatformDeviceResourceType::MEM)
638        .ok_or("Memory resource not found")?;
639    
640    let base_addr = mem_res.start as usize;
641
642    // Create a new Virtio device
643    let virtio_device = VirtioDeviceCommon::new(base_addr);
644    // Check device type
645    let device_type = VirtioDeviceType::from_u32(virtio_device.get_device_info().0);
646    
647    match device_type {
648        VirtioDeviceType::Block => {
649            let dev: Box<dyn Device> = Box::new(VirtioBlockDevice::new(base_addr));
650            DeviceManager::get_mut_manager().register_device(dev);
651        }
652        _ => {
653            // Unsupported device type
654            return Err("Unsupported device type");
655        }
656    }
657
658    Ok(())
659}
660
661fn remove_fn(_device: &PlatformDeviceInfo) -> Result<(), &'static str> {
662    Ok(())
663}
664
665fn register_driver() {
666    let driver = PlatformDeviceDriver::new(
667        "virtio-mmio",
668        probe_fn,
669        remove_fn,
670        vec!["virtio,mmio"],
671    );
672    // Register the driver with the kernel
673    DeviceManager::get_mut_manager().register_driver(Box::new(driver))
674}
675
676driver_initcall!(register_driver);
677
678#[cfg(test)]
679mod tests;