1 use core::ptr::NonNull; 2 3 use alloc::sync::Arc; 4 use fdt::node::FdtNode; 5 use log::info; 6 use system_error::SystemError; 7 use virtio_drivers::transport::{ 8 mmio::{MmioTransport, VirtIOHeader}, 9 Transport, 10 }; 11 12 use crate::{ 13 arch::MMArch, 14 driver::base::device::DeviceId, 15 exception::HardwareIrqNumber, 16 libs::align::page_align_up, 17 mm::{ 18 mmio_buddy::{mmio_pool, MMIOSpaceGuard}, 19 MemoryManagementArch, PhysAddr, 20 }, 21 }; 22 23 pub struct VirtIOMmioTransport { 24 mmio_transport: MmioTransport, 25 _mmio_guard: MMIOSpaceGuard, 26 irq: HardwareIrqNumber, 27 device_id: Arc<DeviceId>, 28 } 29 30 impl VirtIOMmioTransport { new(node: FdtNode) -> Result<Self, SystemError>31 pub fn new(node: FdtNode) -> Result<Self, SystemError> { 32 let reg = node 33 .reg() 34 .ok_or(SystemError::EINVAL)? 35 .next() 36 .ok_or(SystemError::EINVAL)?; 37 let paddr = reg.starting_address as usize; 38 let size = reg.size.unwrap_or(0); 39 let page_offset = paddr % MMArch::PAGE_SIZE; 40 let paddr = paddr - page_offset; 41 let size = page_align_up(size + page_offset); 42 let irq = node 43 .interrupts() 44 .ok_or(SystemError::EINVAL)? 45 .next() 46 .ok_or(SystemError::EINVAL)?; 47 48 let device_id = DeviceId::new(None, Some(format!("virtio_mmio_{:#X}", paddr))).unwrap(); 49 50 let mmio_guard = mmio_pool().create_mmio(size)?; 51 unsafe { mmio_guard.map_phys(PhysAddr::new(paddr), size) }?; 52 53 let vaddr = mmio_guard.vaddr() + page_offset; 54 let header = NonNull::new(vaddr.data() as *mut VirtIOHeader).unwrap(); 55 56 match unsafe { MmioTransport::new(header) } { 57 Ok(mmio_transport) => { 58 info!( "Detected virtio MMIO device with vendor id {:#X}, device type {:?}, version {:?}, hw irq: {}", 59 mmio_transport.vendor_id(), 60 mmio_transport.device_type(), 61 mmio_transport.version(), 62 irq as u32 63 ); 64 65 Ok(Self { 66 mmio_transport, 67 _mmio_guard: mmio_guard, 68 irq: HardwareIrqNumber::new(irq as u32), 69 device_id, 70 }) 71 } 72 Err(_) => { 73 // warn!("MmioTransport::new failed: {:?}", e); 74 Err(SystemError::EINVAL) 75 } 76 } 77 } 78 79 #[allow(dead_code)] 80 #[inline] irq(&self) -> HardwareIrqNumber81 pub fn irq(&self) -> HardwareIrqNumber { 82 self.irq 83 } 84 device_id(&self) -> Arc<DeviceId>85 pub fn device_id(&self) -> Arc<DeviceId> { 86 self.device_id.clone() 87 } 88 } 89 90 impl Transport for VirtIOMmioTransport { device_type(&self) -> virtio_drivers::transport::DeviceType91 fn device_type(&self) -> virtio_drivers::transport::DeviceType { 92 self.mmio_transport.device_type() 93 } 94 read_device_features(&mut self) -> u6495 fn read_device_features(&mut self) -> u64 { 96 self.mmio_transport.read_device_features() 97 } 98 write_driver_features(&mut self, driver_features: u64)99 fn write_driver_features(&mut self, driver_features: u64) { 100 self.mmio_transport.write_driver_features(driver_features) 101 } 102 max_queue_size(&mut self, queue: u16) -> u32103 fn max_queue_size(&mut self, queue: u16) -> u32 { 104 self.mmio_transport.max_queue_size(queue) 105 } 106 notify(&mut self, queue: u16)107 fn notify(&mut self, queue: u16) { 108 self.mmio_transport.notify(queue) 109 } 110 get_status(&self) -> virtio_drivers::transport::DeviceStatus111 fn get_status(&self) -> virtio_drivers::transport::DeviceStatus { 112 self.mmio_transport.get_status() 113 } 114 set_status(&mut self, status: virtio_drivers::transport::DeviceStatus)115 fn set_status(&mut self, status: virtio_drivers::transport::DeviceStatus) { 116 self.mmio_transport.set_status(status) 117 } 118 set_guest_page_size(&mut self, guest_page_size: u32)119 fn set_guest_page_size(&mut self, guest_page_size: u32) { 120 self.mmio_transport.set_guest_page_size(guest_page_size) 121 } 122 requires_legacy_layout(&self) -> bool123 fn requires_legacy_layout(&self) -> bool { 124 self.mmio_transport.requires_legacy_layout() 125 } 126 queue_set( &mut self, queue: u16, size: u32, descriptors: virtio_drivers::PhysAddr, driver_area: virtio_drivers::PhysAddr, device_area: virtio_drivers::PhysAddr, )127 fn queue_set( 128 &mut self, 129 queue: u16, 130 size: u32, 131 descriptors: virtio_drivers::PhysAddr, 132 driver_area: virtio_drivers::PhysAddr, 133 device_area: virtio_drivers::PhysAddr, 134 ) { 135 self.mmio_transport 136 .queue_set(queue, size, descriptors, driver_area, device_area) 137 } 138 queue_unset(&mut self, queue: u16)139 fn queue_unset(&mut self, queue: u16) { 140 self.mmio_transport.queue_unset(queue) 141 } 142 queue_used(&mut self, queue: u16) -> bool143 fn queue_used(&mut self, queue: u16) -> bool { 144 self.mmio_transport.queue_used(queue) 145 } 146 ack_interrupt(&mut self) -> bool147 fn ack_interrupt(&mut self) -> bool { 148 self.mmio_transport.ack_interrupt() 149 } 150 config_space<T: 'static>(&self) -> virtio_drivers::Result<core::ptr::NonNull<T>>151 fn config_space<T: 'static>(&self) -> virtio_drivers::Result<core::ptr::NonNull<T>> { 152 self.mmio_transport.config_space() 153 } 154 finish_init(&mut self)155 fn finish_init(&mut self) { 156 self.mmio_transport.finish_init() 157 } 158 } 159