kernel/drivers/virtio/device/
mod.rs

1//! Virtio device driver interface module.
2//! 
3
4use core::result::Result;
5
6use alloc::{boxed::Box, sync::Arc, vec};
7
8use crate::{device::{manager::{DeviceManager, DriverPriority}, 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        // Get queue addresses directly - safer than closures
359        let desc_addr = self.get_queue_desc_addr(queue_idx);
360        let driver_addr = self.get_queue_driver_addr(queue_idx);
361        let device_addr = self.get_queue_device_addr(queue_idx);
362        
363        if desc_addr.is_none() || driver_addr.is_none() || device_addr.is_none() {
364            return false;
365        }
366        
367        let desc_addr = desc_addr.unwrap();
368        let driver_addr = driver_addr.unwrap();
369        let device_addr = device_addr.unwrap();
370        
371        // Set the queue descriptor address
372        let desc_addr_low = (desc_addr & 0xffffffff) as u32;
373        let desc_addr_high = (desc_addr >> 32) as u32;
374        self.write32_register(Register::QueueDescLow, desc_addr_low);
375        self.write32_register(Register::QueueDescHigh, desc_addr_high);
376
377        // Set the driver area (available ring) address
378        let driver_addr_low = (driver_addr & 0xffffffff) as u32;
379        let driver_addr_high = (driver_addr >> 32) as u32;
380        self.write32_register(Register::DriverDescLow, driver_addr_low);
381        self.write32_register(Register::DriverDescHigh, driver_addr_high);
382
383        // Set the device area (used ring) address
384        let device_addr_low = (device_addr & 0xffffffff) as u32;
385        let device_addr_high = (device_addr >> 32) as u32;
386        self.write32_register(Register::DeviceDescLow, device_addr_low);
387        self.write32_register(Register::DeviceDescHigh, device_addr_high);
388
389        // Check the status of the queue
390        let status = self.read32_register(Register::Status);
391        if DeviceStatus::Failed.is_set(status) {
392            return false; // Queue setup failed
393        }
394        
395        // Mark queue as ready
396        self.write32_register(Register::QueueReady, 1);
397
398        // Check the status of the queue
399        let status = self.read32_register(Register::Status);
400        if DeviceStatus::Failed.is_set(status) {
401            return false; // Queue setup failed
402        }
403        
404        true
405    }
406    
407    /// Read device-specific configuration
408    ///
409    /// This method reads configuration data from the device-specific configuration space.
410    ///
411    /// # Arguments
412    ///
413    /// * `offset` - The offset within the configuration space
414    ///
415    /// # Returns
416    ///
417    /// The configuration value of type T
418    fn read_config<T: Sized>(&self, offset: usize) -> T {
419        let addr = self.get_base_addr() + Register::DeviceConfig.offset() + offset;
420        unsafe { core::ptr::read_volatile(addr as *const T) }
421    }
422    
423    /// Write device-specific configuration
424    ///
425    /// This method writes configuration data to the device-specific configuration space.
426    ///
427    /// # Arguments
428    ///
429    /// * `offset` - The offset within the configuration space
430    /// * `value` - The value to write
431    fn write_config<T: Sized>(&self, offset: usize, value: T) {
432        let addr = self.get_base_addr() + Register::DeviceConfig.offset() + offset;
433        unsafe { core::ptr::write_volatile(addr as *mut T, value) }
434    }
435    
436    /// Get device and vendor IDs
437    ///
438    /// # Returns
439    ///
440    /// A tuple containing (device_id, vendor_id)
441    fn get_device_info(&self) -> (u32, u32) {
442        let device_id = self.read32_register(Register::DeviceId);
443        let vendor_id = self.read32_register(Register::VendorId);
444        (device_id, vendor_id)
445    }
446    
447    /// Get interrupt status
448    ///
449    /// # Returns
450    ///
451    /// The interrupt status register value
452    fn get_interrupt_status(&self) -> u32 {
453        self.read32_register(Register::InterruptStatus)
454    }
455    
456    /// Process interrupts (polling method)
457    ///
458    /// This method checks for interrupts and acknowledges them.
459    ///
460    /// # Returns
461    ///
462    /// The interrupt status before acknowledgment
463    fn process_interrupts(&mut self) -> u32 {
464        let status = self.get_interrupt_status();
465        if status != 0 {
466            self.write32_register(Register::InterruptAck, status & 0x03);
467        }
468        status
469    }
470    
471    /// Memory barrier for ensuring memory operations ordering
472    fn memory_barrier(&self) {
473        core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
474    }
475    
476    /// Notify the device about new buffers in a specified virtqueue
477    ///
478    /// This method notifies the device that new buffers are available in the specified virtqueue.
479    /// It selects the queue using the QueueSel register and then writes to the QueueNotify register.
480    ///
481    /// # Arguments
482    ///
483    /// * `virtqueue_idx` - The index of the virtqueue to notify
484    ///
485    /// # Panics
486    ///
487    /// Panics if the virtqueue index is invalid
488    fn notify(&self, virtqueue_idx: usize) {
489        if virtqueue_idx >= self.get_virtqueue_count() {
490            panic!("Invalid virtqueue index");
491        }
492        // Insert memory barrier before notification
493        self.memory_barrier();
494        self.write32_register(Register::QueueNotify, virtqueue_idx as u32);
495    }
496
497    /// Read a 32-bit value from a device register
498    ///
499    /// # Arguments
500    ///
501    /// * `register` - The register to read from
502    ///
503    /// # Returns
504    ///
505    /// The 32-bit value read from the register
506    fn read32_register(&self, register: Register) -> u32 {
507        let addr = self.get_base_addr() + register.offset();
508        unsafe { core::ptr::read_volatile(addr as *const u32) }
509    }
510
511    /// Write a 32-bit value to a device register
512    ///
513    /// # Arguments
514    ///
515    /// * `register` - The register to write to
516    /// * `value` - The 32-bit value to write
517    fn write32_register(&self, register: Register, value: u32) {
518        let addr = self.get_base_addr() + register.offset();
519        unsafe { core::ptr::write_volatile(addr as *mut u32, value) }
520    }
521
522    /// Read a 64-bit value from a device register
523    ///
524    /// # Arguments
525    ///
526    /// * `register` - The register to read from
527    ///
528    /// # Returns
529    ///
530    /// The 64-bit value read from the register
531    fn read64_register(&self, register: Register) -> u64 {
532        let addr = self.get_base_addr() + register.offset();
533        unsafe { core::ptr::read_volatile(addr as *const u64) }
534    }
535
536    /// Write a 64-bit value to a device register
537    ///
538    /// # Arguments
539    ///
540    /// * `register` - The register to write to
541    /// * `value` - The 64-bit value to write
542    fn write64_register(&self, register: Register, value: u64) {
543        let addr = self.get_base_addr() + register.offset();
544        unsafe { core::ptr::write_volatile(addr as *mut u64, value) }
545    }
546
547    // Required methods to be implemented by specific device types
548
549    fn get_base_addr(&self) -> usize;
550    fn get_virtqueue_count(&self) -> usize;
551    
552    /// Get the descriptor address for a virtqueue
553    fn get_queue_desc_addr(&self, queue_idx: usize) -> Option<u64>;
554    
555    /// Get the driver area address for a virtqueue
556    fn get_queue_driver_addr(&self, queue_idx: usize) -> Option<u64>;
557    
558    /// Get the device area address for a virtqueue
559    fn get_queue_device_addr(&self, queue_idx: usize) -> Option<u64>;
560}
561
562
563/// Device type enum for Virtio devices
564/// 
565/// This enum represents the different types of Virtio devices.
566/// Each variant corresponds to a specific device type.
567/// The types are defined in the Virtio specification.
568pub enum VirtioDeviceType {
569    Invalid = 0,
570    Net = 1,
571    Block = 2,
572    Console = 3,
573    Rng = 4,
574}
575
576impl VirtioDeviceType {
577    /// Convert from u32 to VirtioDeviceType
578    /// 
579    /// This method converts a u32 value to the corresponding VirtioDeviceType variant.
580    /// 
581    /// # Arguments
582    /// 
583    /// * `device_type` - The u32 value to convert.
584    /// 
585    /// # Returns
586    /// 
587    /// Returns the corresponding VirtioDeviceType variant.
588    pub fn from_u32(device_type: u32) -> Self {
589        match device_type {
590            0 => VirtioDeviceType::Invalid,
591            1 => VirtioDeviceType::Net,
592            2 => VirtioDeviceType::Block,
593            3 => VirtioDeviceType::Console,
594            4 => VirtioDeviceType::Rng,
595            _ => panic!("Not supported device type"),
596        }
597    }
598}
599
600/// Virtio Common Device
601/// 
602/// Only use this struct for checking the device info.
603/// It should not be used for actual device operations.
604/// 
605struct VirtioDeviceCommon {
606    base_addr: usize,
607}
608
609impl VirtioDeviceCommon {
610    /// Create a new Virtio device
611    ///
612    /// # Arguments
613    ///
614    /// * `base_addr` - The base address of the device
615    ///
616    /// # Returns
617    ///
618    /// A new instance of `VirtioDeviceCommon`
619    pub fn new(base_addr: usize) -> Self {
620        Self { base_addr }
621    }
622}
623
624impl VirtioDevice for VirtioDeviceCommon {
625    fn init(&mut self) -> Result<(), &'static str> {
626        // Initialization is not required for the common device
627        Ok(())
628    }
629
630    fn get_base_addr(&self) -> usize {
631        self.base_addr
632    }
633
634    fn get_virtqueue_count(&self) -> usize {
635        // This should be overridden by specific device implementations
636        0
637    }
638
639    fn get_queue_desc_addr(&self, _queue_idx: usize) -> Option<u64> {
640        // This should be overridden by specific device implementations
641        None
642    }
643    
644    fn get_queue_driver_addr(&self, _queue_idx: usize) -> Option<u64> {
645        // This should be overridden by specific device implementations
646        None
647    }
648    
649    fn get_queue_device_addr(&self, _queue_idx: usize) -> Option<u64> {
650        // This should be overridden by specific device implementations
651        None
652    }
653}
654
655fn probe_fn(device: &PlatformDeviceInfo) -> Result<(), &'static str> {
656    let res = device.get_resources();
657    if res.is_empty() {
658        return Err("No resources found");
659    }
660
661    // Get memory region resource (res_type == PlatformDeviceResourceType::MEM)
662    let mem_res = res.iter()
663        .find(|r| r.res_type == PlatformDeviceResourceType::MEM)
664        .ok_or("Memory resource not found")?;
665    
666    let base_addr = mem_res.start as usize;
667
668    // Create a new Virtio device
669    let virtio_device = VirtioDeviceCommon::new(base_addr);
670    // Check device type
671    let device_type = VirtioDeviceType::from_u32(virtio_device.get_device_info().0);
672    
673    match device_type {
674        VirtioDeviceType::Block => {
675            let dev: Arc<dyn Device> = Arc::new(VirtioBlockDevice::new(base_addr));
676            DeviceManager::get_mut_manager().register_device(dev);
677        }
678        _ => {
679            // Unsupported device type
680            return Err("Unsupported device type");
681        }
682    }
683
684    Ok(())
685}
686
687fn remove_fn(_device: &PlatformDeviceInfo) -> Result<(), &'static str> {
688    Ok(())
689}
690
691fn register_driver() {
692    let driver = PlatformDeviceDriver::new(
693        "virtio-mmio",
694        probe_fn,
695        remove_fn,
696        vec!["virtio,mmio"],
697    );
698    // Register the driver with the kernel
699    DeviceManager::get_mut_manager().register_driver(Box::new(driver), DriverPriority::Standard)
700}
701
702driver_initcall!(register_driver);
703
704#[cfg(test)]
705mod tests;