1731bc2b3SLoGin use core::ptr::NonNull; 2731bc2b3SLoGin 3731bc2b3SLoGin use alloc::sync::Arc; 4731bc2b3SLoGin use fdt::node::FdtNode; 5*2eab6dd7S曾俊 use log::info; 6731bc2b3SLoGin use system_error::SystemError; 7731bc2b3SLoGin use virtio_drivers::transport::{ 8731bc2b3SLoGin mmio::{MmioTransport, VirtIOHeader}, 9731bc2b3SLoGin Transport, 10731bc2b3SLoGin }; 11731bc2b3SLoGin 12731bc2b3SLoGin use crate::{ 13731bc2b3SLoGin arch::MMArch, 14731bc2b3SLoGin driver::base::device::DeviceId, 15731bc2b3SLoGin exception::HardwareIrqNumber, 16731bc2b3SLoGin libs::align::page_align_up, 17731bc2b3SLoGin mm::{ 18731bc2b3SLoGin mmio_buddy::{mmio_pool, MMIOSpaceGuard}, 19731bc2b3SLoGin MemoryManagementArch, PhysAddr, 20731bc2b3SLoGin }, 21731bc2b3SLoGin }; 22731bc2b3SLoGin 23731bc2b3SLoGin pub struct VirtIOMmioTransport { 24731bc2b3SLoGin mmio_transport: MmioTransport, 25731bc2b3SLoGin _mmio_guard: MMIOSpaceGuard, 26731bc2b3SLoGin irq: HardwareIrqNumber, 27731bc2b3SLoGin device_id: Arc<DeviceId>, 28731bc2b3SLoGin } 29731bc2b3SLoGin 30731bc2b3SLoGin impl VirtIOMmioTransport { new(node: FdtNode) -> Result<Self, SystemError>31731bc2b3SLoGin pub fn new(node: FdtNode) -> Result<Self, SystemError> { 32731bc2b3SLoGin let reg = node 33731bc2b3SLoGin .reg() 34731bc2b3SLoGin .ok_or(SystemError::EINVAL)? 35731bc2b3SLoGin .next() 36731bc2b3SLoGin .ok_or(SystemError::EINVAL)?; 37731bc2b3SLoGin let paddr = reg.starting_address as usize; 38731bc2b3SLoGin let size = reg.size.unwrap_or(0); 39731bc2b3SLoGin let page_offset = paddr % MMArch::PAGE_SIZE; 40731bc2b3SLoGin let paddr = paddr - page_offset; 41731bc2b3SLoGin let size = page_align_up(size + page_offset); 42731bc2b3SLoGin let irq = node 43731bc2b3SLoGin .interrupts() 44731bc2b3SLoGin .ok_or(SystemError::EINVAL)? 45731bc2b3SLoGin .next() 46731bc2b3SLoGin .ok_or(SystemError::EINVAL)?; 47731bc2b3SLoGin 48731bc2b3SLoGin let device_id = DeviceId::new(None, Some(format!("virtio_mmio_{:#X}", paddr))).unwrap(); 49731bc2b3SLoGin 50731bc2b3SLoGin let mmio_guard = mmio_pool().create_mmio(size)?; 51731bc2b3SLoGin unsafe { mmio_guard.map_phys(PhysAddr::new(paddr), size) }?; 52731bc2b3SLoGin 53731bc2b3SLoGin let vaddr = mmio_guard.vaddr() + page_offset; 54731bc2b3SLoGin let header = NonNull::new(vaddr.data() as *mut VirtIOHeader).unwrap(); 55731bc2b3SLoGin 56731bc2b3SLoGin match unsafe { MmioTransport::new(header) } { 57731bc2b3SLoGin Ok(mmio_transport) => { 58*2eab6dd7S曾俊 info!( "Detected virtio MMIO device with vendor id {:#X}, device type {:?}, version {:?}, hw irq: {}", 59731bc2b3SLoGin mmio_transport.vendor_id(), 60731bc2b3SLoGin mmio_transport.device_type(), 61731bc2b3SLoGin mmio_transport.version(), 62731bc2b3SLoGin irq as u32 63731bc2b3SLoGin ); 64731bc2b3SLoGin 65731bc2b3SLoGin Ok(Self { 66731bc2b3SLoGin mmio_transport, 67731bc2b3SLoGin _mmio_guard: mmio_guard, 68731bc2b3SLoGin irq: HardwareIrqNumber::new(irq as u32), 69731bc2b3SLoGin device_id, 70731bc2b3SLoGin }) 71731bc2b3SLoGin } 72731bc2b3SLoGin Err(_) => { 73*2eab6dd7S曾俊 // warn!("MmioTransport::new failed: {:?}", e); 74731bc2b3SLoGin Err(SystemError::EINVAL) 75731bc2b3SLoGin } 76731bc2b3SLoGin } 77731bc2b3SLoGin } 78731bc2b3SLoGin 79731bc2b3SLoGin #[allow(dead_code)] 80731bc2b3SLoGin #[inline] irq(&self) -> HardwareIrqNumber81731bc2b3SLoGin pub fn irq(&self) -> HardwareIrqNumber { 82731bc2b3SLoGin self.irq 83731bc2b3SLoGin } 84731bc2b3SLoGin device_id(&self) -> Arc<DeviceId>85731bc2b3SLoGin pub fn device_id(&self) -> Arc<DeviceId> { 86731bc2b3SLoGin self.device_id.clone() 87731bc2b3SLoGin } 88731bc2b3SLoGin } 89731bc2b3SLoGin 90731bc2b3SLoGin impl Transport for VirtIOMmioTransport { device_type(&self) -> virtio_drivers::transport::DeviceType91731bc2b3SLoGin fn device_type(&self) -> virtio_drivers::transport::DeviceType { 92731bc2b3SLoGin self.mmio_transport.device_type() 93731bc2b3SLoGin } 94731bc2b3SLoGin read_device_features(&mut self) -> u6495731bc2b3SLoGin fn read_device_features(&mut self) -> u64 { 96731bc2b3SLoGin self.mmio_transport.read_device_features() 97731bc2b3SLoGin } 98731bc2b3SLoGin write_driver_features(&mut self, driver_features: u64)99731bc2b3SLoGin fn write_driver_features(&mut self, driver_features: u64) { 100731bc2b3SLoGin self.mmio_transport.write_driver_features(driver_features) 101731bc2b3SLoGin } 102731bc2b3SLoGin max_queue_size(&mut self, queue: u16) -> u32103731bc2b3SLoGin fn max_queue_size(&mut self, queue: u16) -> u32 { 104731bc2b3SLoGin self.mmio_transport.max_queue_size(queue) 105731bc2b3SLoGin } 106731bc2b3SLoGin notify(&mut self, queue: u16)107731bc2b3SLoGin fn notify(&mut self, queue: u16) { 108731bc2b3SLoGin self.mmio_transport.notify(queue) 109731bc2b3SLoGin } 110731bc2b3SLoGin get_status(&self) -> virtio_drivers::transport::DeviceStatus111731bc2b3SLoGin fn get_status(&self) -> virtio_drivers::transport::DeviceStatus { 112731bc2b3SLoGin self.mmio_transport.get_status() 113731bc2b3SLoGin } 114731bc2b3SLoGin set_status(&mut self, status: virtio_drivers::transport::DeviceStatus)115731bc2b3SLoGin fn set_status(&mut self, status: virtio_drivers::transport::DeviceStatus) { 116731bc2b3SLoGin self.mmio_transport.set_status(status) 117731bc2b3SLoGin } 118731bc2b3SLoGin set_guest_page_size(&mut self, guest_page_size: u32)119731bc2b3SLoGin fn set_guest_page_size(&mut self, guest_page_size: u32) { 120731bc2b3SLoGin self.mmio_transport.set_guest_page_size(guest_page_size) 121731bc2b3SLoGin } 122731bc2b3SLoGin requires_legacy_layout(&self) -> bool123731bc2b3SLoGin fn requires_legacy_layout(&self) -> bool { 124731bc2b3SLoGin self.mmio_transport.requires_legacy_layout() 125731bc2b3SLoGin } 126731bc2b3SLoGin queue_set( &mut self, queue: u16, size: u32, descriptors: virtio_drivers::PhysAddr, driver_area: virtio_drivers::PhysAddr, device_area: virtio_drivers::PhysAddr, )127731bc2b3SLoGin fn queue_set( 128731bc2b3SLoGin &mut self, 129731bc2b3SLoGin queue: u16, 130731bc2b3SLoGin size: u32, 131731bc2b3SLoGin descriptors: virtio_drivers::PhysAddr, 132731bc2b3SLoGin driver_area: virtio_drivers::PhysAddr, 133731bc2b3SLoGin device_area: virtio_drivers::PhysAddr, 134731bc2b3SLoGin ) { 135731bc2b3SLoGin self.mmio_transport 136731bc2b3SLoGin .queue_set(queue, size, descriptors, driver_area, device_area) 137731bc2b3SLoGin } 138731bc2b3SLoGin queue_unset(&mut self, queue: u16)139731bc2b3SLoGin fn queue_unset(&mut self, queue: u16) { 140731bc2b3SLoGin self.mmio_transport.queue_unset(queue) 141731bc2b3SLoGin } 142731bc2b3SLoGin queue_used(&mut self, queue: u16) -> bool143731bc2b3SLoGin fn queue_used(&mut self, queue: u16) -> bool { 144731bc2b3SLoGin self.mmio_transport.queue_used(queue) 145731bc2b3SLoGin } 146731bc2b3SLoGin ack_interrupt(&mut self) -> bool147731bc2b3SLoGin fn ack_interrupt(&mut self) -> bool { 148731bc2b3SLoGin self.mmio_transport.ack_interrupt() 149731bc2b3SLoGin } 150731bc2b3SLoGin config_space<T: 'static>(&self) -> virtio_drivers::Result<core::ptr::NonNull<T>>151731bc2b3SLoGin fn config_space<T: 'static>(&self) -> virtio_drivers::Result<core::ptr::NonNull<T>> { 152731bc2b3SLoGin self.mmio_transport.config_space() 153731bc2b3SLoGin } 154731bc2b3SLoGin finish_init(&mut self)155731bc2b3SLoGin fn finish_init(&mut self) { 156731bc2b3SLoGin self.mmio_transport.finish_init() 157731bc2b3SLoGin } 158731bc2b3SLoGin } 159