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