diff --git a/Cargo.toml b/Cargo.toml index 2a51dc4d548d5fd10e24b3d2d4b7b5b748e48c2c..02276793c48b87a4f39f02622de8222d1079222a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -136,6 +136,7 @@ net = { path = "drivers/net" } pci = { path = "drivers/pci" } vsock = { path = "drivers/vsock" } virtio = { path = "drivers/virtio" } +virtio-drivers = { version = "0.13.0", default-features = false, package = "kvirtiodrivers" } aarch64-pmuv3 = { path = "drivers/aarch64-pmuv3" } fatfs ={ version = "0.1.0-pre.0", default-features = false, package = "axfatfs"} @@ -153,4 +154,3 @@ kbuild_config = { path = "util/kbuild_config" } kconfig-gen = { path = "xtask/kconfig-gen" } smoltcp = { version = "0.12.0", package = "x-smoltcp", default-features = false } -virtio-drivers = { version = "0.7.4", default-features = false } diff --git a/drivers/kdriver/src/bus/pci.rs b/drivers/kdriver/src/bus/pci.rs index 6fa71c3fe3056578e9ccb2efdaa2b5ef60e2ef77..9d0f1c5d24717f33803802e4a4591840cd1e210e 100644 --- a/drivers/kdriver/src/bus/pci.rs +++ b/drivers/kdriver/src/bus/pci.rs @@ -5,7 +5,8 @@ //! PCI bus probing and BAR configuration. use khal::mem::p2v; use pci::{ - BarInfo, Cam, Command, DeviceFunction, HeaderType, MemoryBarType, PciRangeAllocator, PciRoot, + BarInfo, Cam, Command, ConfigurationAccess, DeviceFunction, HeaderType, MemoryBarType, MmioCam, + PciRangeAllocator, PciRoot, }; use crate::{AllDevices, prelude::*}; @@ -13,14 +14,21 @@ use crate::{AllDevices, prelude::*}; const PCI_BAR_NUM: u8 = 6; /// Configure PCI BARs and enable the device. -fn config_pci_device( - root: &mut PciRoot, +fn config_pci_device( + root: &mut PciRoot, bdf: DeviceFunction, allocator: &mut Option, ) -> DriverResult { let mut bar = 0; while bar < PCI_BAR_NUM { - let info = root.bar_info(bdf, bar).unwrap(); + let info = match root.bar_info(bdf, bar).unwrap() { + Some(info) => info, + None => { + bar += 1; + continue; + } + }; + if let BarInfo::Memory { address_type, address, @@ -44,7 +52,14 @@ fn config_pci_device( } // read the BAR info again after assignment. - let info = root.bar_info(bdf, bar).unwrap(); + let info = match root.bar_info(bdf, bar).unwrap() { + Some(info) => info, + None => { + bar += 1; + continue; + } + }; + let takes_two = info.takes_two_entries(); match info { BarInfo::IO { address, size } => { if address > 0 && size > 0 { @@ -62,7 +77,7 @@ fn config_pci_device( " BAR {}: MEM [{:#x}, {:#x}){}{}", bar, address, - address + size as u64, + address + size, if address_type == MemoryBarType::Width64 { " 64bit" } else { @@ -75,7 +90,7 @@ fn config_pci_device( } bar += 1; - if info.takes_two_entries() { + if takes_two { bar += 1; } } @@ -96,11 +111,13 @@ impl AllDevices { let mut root = { #[cfg(feature = "pci-mmio")] { - unsafe { PciRoot::new(base_vaddr.as_mut_ptr(), Cam::MmioCam) } + let cam = unsafe { MmioCam::new(base_vaddr.as_mut_ptr(), Cam::MmioCam) }; + PciRoot::new(cam) } #[cfg(not(feature = "pci-mmio"))] { - unsafe { PciRoot::new(base_vaddr.as_mut_ptr(), Cam::Ecam) } + let cam = unsafe { MmioCam::new(base_vaddr.as_mut_ptr(), Cam::Ecam) }; + PciRoot::new(cam) } }; diff --git a/drivers/kdriver/src/drivers.rs b/drivers/kdriver/src/drivers.rs index 50118379eab3cfbef7fb2abba1e58d781000a020..ab85a393a90058ca39bff221ed533a2910b4ebb8 100644 --- a/drivers/kdriver/src/drivers.rs +++ b/drivers/kdriver/src/drivers.rs @@ -8,7 +8,7 @@ use driver_base::DeviceKind; #[cfg(feature = "bus-pci")] -use pci::{DeviceFunction, DeviceFunctionInfo, PciRoot}; +use pci::{ConfigurationAccess, DeviceFunction, DeviceFunctionInfo, PciRoot}; pub use super::dummy::*; use crate::DeviceEnum; @@ -30,8 +30,8 @@ pub trait DriverProbe { #[cfg(bus = "pci")] /// Probe a PCI device described by BDF and device info. - fn probe_pci( - _root: &mut PciRoot, + fn probe_pci( + _root: &mut PciRoot, _bdf: DeviceFunction, _dev_info: &DeviceFunctionInfo, ) -> Option { @@ -171,8 +171,8 @@ cfg_if::cfg_if! { register_net_driver!(IxgbeDriver, net::ixgbe::IxgbeNic); impl DriverProbe for IxgbeDriver { #[cfg(bus = "pci")] - fn probe_pci( - root: &mut pci::PciRoot, + fn probe_pci( + root: &mut pci::PciRoot, bdf: pci::DeviceFunction, dev_info: &pci::DeviceFunctionInfo, ) -> Option { diff --git a/drivers/kdriver/src/virtio.rs b/drivers/kdriver/src/virtio.rs index a022241001b4246b1a93074d57fd3caa4e0c6c1e..407fa7d96b882496173be307899b75938d03cdba 100644 --- a/drivers/kdriver/src/virtio.rs +++ b/drivers/kdriver/src/virtio.rs @@ -16,10 +16,10 @@ use crate::{DeviceEnum, drivers::DriverProbe}; cfg_if! { if #[cfg(bus = "pci")] { - use pci::{Cam, PciConfigAccess, PciRoot, DeviceFunction, DeviceFunctionInfo}; + use pci::{Cam, PciConfigAccess, PciRoot, DeviceFunction, DeviceFunctionInfo, ConfigurationAccess}; type VirtIoTransport = virtio::PciTransport; } else if #[cfg(bus = "mmio")] { - type VirtIoTransport = virtio::MmioTransport; + type VirtIoTransport = virtio::MmioTransport<'static>; } } @@ -139,8 +139,8 @@ impl DriverProbe for VirtIoDriver { } #[cfg(bus = "pci")] - fn probe_pci( - root: &mut PciRoot, + fn probe_pci( + root: &mut PciRoot, bdf: DeviceFunction, dev_info: &DeviceFunctionInfo, ) -> Option { @@ -162,11 +162,11 @@ impl DriverProbe for VirtIoDriver { let cam = Cam::MmioCam; #[cfg(not(feature = "pci-mmio"))] let cam = Cam::Ecam; - let base_vaddr = khal::mem::p2v((kbuild_config::PCI_ECAM_BASE).into()); + let base_vaddr = p2v((kbuild_config::PCI_ECAM_BASE).into()); let mut config = unsafe { PciConfigAccess::new(base_vaddr.as_mut_ptr(), cam) }; if let Some((ty, transport, irq)) = - virtio::probe_pci_device::(root, bdf, dev_info, &mut config) + virtio::probe_pci_device::(root, bdf, dev_info, &mut config) && ty == D::DEVICE_TYPE { match D::try_new(transport, Some(irq)) { @@ -221,7 +221,7 @@ unsafe impl VirtIoHal for VirtIoHalImpl { let layout = Layout::from_size_align(size, PAGE_SIZE).unwrap(); let dma_info = kdma::DMAInfo { cpu_addr: vaddr, - bus_addr: kdma::DmaBusAddress::new(paddr as u64), + bus_addr: kdma::DmaBusAddress::new(paddr), }; unsafe { kdma::deallocate_dma_memory(dma_info, layout) }; #[cfg(feature = "crosvm")] @@ -233,7 +233,8 @@ unsafe impl VirtIoHal for VirtIoHalImpl { #[inline] unsafe fn mmio_phys_to_virt(paddr: PhysAddr, _size: usize) -> NonNull { - NonNull::new(p2v(paddr.into()).as_mut_ptr()).unwrap() + let paddr_usize: usize = paddr as usize; + NonNull::new(p2v(paddr_usize.into()).as_mut_ptr()).unwrap() } #[allow(unused_variables)] @@ -283,7 +284,8 @@ unsafe impl VirtIoHal for VirtIoHalImpl { #[cfg(not(any(feature = "crosvm", feature = "sev")))] { let vaddr = buffer.as_ptr() as *mut u8 as usize; - khal::mem::v2p(vaddr.into()).into() + let paddr_usize: usize = khal::mem::v2p(vaddr.into()).into(); + paddr_usize as PhysAddr } } @@ -303,7 +305,8 @@ unsafe impl VirtIoHal for VirtIoHalImpl { // If data flows from device to driver, copy back from shared buffer if direction != BufferDirection::DriverToDevice { - let shared_ptr = p2v(paddr.into()).as_ptr(); + let paddr_usize = paddr as usize; + let shared_ptr = p2v(paddr_usize.into()).as_ptr(); unsafe { core::ptr::copy_nonoverlapping(shared_ptr, buffer.as_ptr() as *mut u8, len); } @@ -321,7 +324,10 @@ unsafe impl VirtIoHal for VirtIoHalImpl { // Free the bounce buffer via kdma let layout = Layout::from_size_align(aligned_size, PAGE_SIZE).unwrap(); let dma_info = kdma::DMAInfo { - cpu_addr: NonNull::new(p2v(paddr.into()).as_mut_ptr()).unwrap(), + cpu_addr: { + let paddr_usize = paddr as usize; + NonNull::new(p2v(paddr_usize.into()).as_mut_ptr()).unwrap() + }, bus_addr: kdma::DmaBusAddress::new(paddr as u64), }; unsafe { kdma::deallocate_dma_memory(dma_info, layout) }; diff --git a/drivers/pci/src/lib.rs b/drivers/pci/src/lib.rs index 6121447c4d337cb4cfc9dcc728d99847c4e63c0d..4d880ff6b457a42720d35eacec7f9de6e2ccad03 100644 --- a/drivers/pci/src/lib.rs +++ b/drivers/pci/src/lib.rs @@ -13,8 +13,8 @@ #![no_std] pub use virtio_drivers::transport::pci::bus::{ - BarInfo, Cam, CapabilityInfo, Command, DeviceFunction, DeviceFunctionInfo, HeaderType, - MemoryBarType, PciError, PciRoot, Status, + BarInfo, Cam, CapabilityInfo, Command, ConfigurationAccess, DeviceFunction, DeviceFunctionInfo, + HeaderType, MemoryBarType, MmioCam, PciError, PciRoot, Status, }; pub mod msix; diff --git a/drivers/pci/src/msix.rs b/drivers/pci/src/msix.rs index db7a2dcb6dad3ed928ef9a2ce6f3839db5302075..29bbc2fb26fa8abdd58ba364fb55fa4faa197577 100644 --- a/drivers/pci/src/msix.rs +++ b/drivers/pci/src/msix.rs @@ -10,7 +10,7 @@ //! - Dynamically allocated, no hardcoded IRQ numbers //! - Direct to CPU, no IO-APIC routing needed -use super::{Command, DeviceFunction, PciConfigAccess, PciRoot}; +use super::{Command, ConfigurationAccess, DeviceFunction, PciConfigAccess, PciRoot}; /// PCI MSI-X capability ID. pub const MSIX_CAP_ID: u8 = 0x11; @@ -79,8 +79,8 @@ impl MsixTableEntry { /// Scans the PCI capability list and returns the parsed MSI-X capability, if present. /// /// Returns `None` if the device does not advertise MSI-X (capability ID 0x11). -pub fn find_msix_capability( - root: &PciRoot, +pub fn find_msix_capability( + root: &PciRoot, config: &PciConfigAccess, bdf: DeviceFunction, ) -> Option { @@ -117,8 +117,8 @@ pub fn find_msix_capability( /// /// Sets the MSI-X Enable bit in Message Control and disables legacy INTx by /// setting `Command::INTERRUPT_DISABLE`. -pub fn enable_msix( - root: &mut PciRoot, +pub fn enable_msix( + root: &mut PciRoot, config: &mut PciConfigAccess, bdf: DeviceFunction, cap: &MsixCapability, diff --git a/drivers/virtio/Cargo.toml b/drivers/virtio/Cargo.toml index 032f97ee43e1813b7eb2327129d2d46595467783..642d91ff03b7c71d41f45901ad0fe3aceb2e26a3 100644 --- a/drivers/virtio/Cargo.toml +++ b/drivers/virtio/Cargo.toml @@ -30,6 +30,7 @@ log = { workspace = true } virtio-drivers = { workspace = true } unittest = { workspace = true } pci = { workspace = true } +zerocopy = "0.8" [target.'cfg(target_arch = "x86_64")'.dependencies] khal = { workspace = true } diff --git a/drivers/virtio/src/input.rs b/drivers/virtio/src/input.rs index 09bba2ef5e0675b3cddd01a1a7e54a125f84e379..deb80818bbb8e65fd9f9f210c75a5ed9a519b622 100644 --- a/drivers/virtio/src/input.rs +++ b/drivers/virtio/src/input.rs @@ -44,9 +44,10 @@ impl VirtIoInputDev { } fn load_event_bits(&mut self, event_type: EventType, out: &mut [u8]) -> DriverResult { - let written = - self.inner - .query_config_select(InputConfigSelect::EvBits, event_type as u8, out); + let written = self + .inner + .query_config_select(InputConfigSelect::EvBits, event_type as u8, out) + .map_err(as_driver_error)?; Ok(written != 0) } } diff --git a/drivers/virtio/src/lib.rs b/drivers/virtio/src/lib.rs index a9cad7684d0fb9c844831d2230a113c138d7f580..28e35a0a64363d5f431ba9e98ca9cf1ea93c1b01 100644 --- a/drivers/virtio/src/lib.rs +++ b/drivers/virtio/src/lib.rs @@ -58,7 +58,7 @@ pub use virtio_drivers::{ #[cfg(feature = "socket")] pub use self::socket::VirtIoSocketDev; -use self::virtio_pci_bus::{DeviceFunction, DeviceFunctionInfo, PciRoot}; +use self::virtio_pci_bus::{ConfigurationAccess, DeviceFunction, DeviceFunctionInfo, PciRoot}; /// Try to probe a VirtIO MMIO device from the given memory region. /// @@ -66,14 +66,14 @@ use self::virtio_pci_bus::{DeviceFunction, DeviceFunctionInfo, PciRoot}; /// for later operations. Otherwise, returns [`None`]. pub fn probe_mmio_device( reg_base: *mut u8, - _reg_size: usize, -) -> Option<(DeviceKind, MmioTransport)> { + reg_size: usize, +) -> Option<(DeviceKind, MmioTransport<'static>)> { use core::ptr::NonNull; use virtio_drivers::transport::mmio::VirtIOHeader; let header = NonNull::new(reg_base as *mut VirtIOHeader).unwrap(); - let transport = unsafe { MmioTransport::new(header) }.ok()?; + let transport = unsafe { MmioTransport::new(header, reg_size) }.ok()?; let dev_kind = as_device_kind(transport.device_type())?; Some((dev_kind, transport)) } @@ -82,8 +82,8 @@ pub fn probe_mmio_device( /// /// If the device is recognized, returns the device type and a transport object /// for later operations. Otherwise, returns [`None`]. -pub fn probe_pci_device( - root: &mut PciRoot, +pub fn probe_pci_device( + root: &mut PciRoot, bdf: DeviceFunction, dev_info: &DeviceFunctionInfo, config: &mut ::pci::PciConfigAccess, @@ -166,7 +166,7 @@ pub fn probe_pci_device( PCI_IRQ_BASE + (bdf.device & 3) as usize }; - let transport = PciTransport::new::(root, bdf).ok()?; + let transport = PciTransport::new::(root, bdf).ok()?; log::info!("PCI virtio device at {:?}: IRQ = {}", bdf, irq); Some((dev_kind, transport, irq)) } @@ -224,9 +224,7 @@ pub(crate) const fn as_driver_error(e: virtio_drivers::Error) -> DriverError { OutputBufferTooShort(_) | BufferTooShort | BufferTooLong(..) => { DriverError::InvalidInput } - UnexpectedDataInPacket | PeerSocketShutdown | NoResponseReceived | ConnectionFailed => { - DriverError::Io - } + UnexpectedDataInPacket | PeerSocketShutdown => DriverError::Io, InsufficientBufferSpaceInPeer => DriverError::WouldBlock, RecycledWrongBuffer => DriverError::BadState, }, diff --git a/drivers/virtio/src/mock_virtio.rs b/drivers/virtio/src/mock_virtio.rs index f8465be6cee3d9604727b5a60932a792e65ae3d7..88730349c35913ec75a7213bd03b1d2214d94dc3 100644 --- a/drivers/virtio/src/mock_virtio.rs +++ b/drivers/virtio/src/mock_virtio.rs @@ -5,9 +5,10 @@ use core::{cell::RefCell, ptr::NonNull}; use virtio_drivers::{ - BufferDirection, Hal, PhysAddr, Result, - transport::{DeviceStatus, DeviceType, Transport}, + BufferDirection, Error, Hal, PhysAddr, Result, + transport::{DeviceStatus, DeviceType, InterruptStatus, Transport}, }; +use zerocopy::{FromBytes, Immutable, IntoBytes}; extern crate alloc; use alloc::alloc::{Layout, alloc, dealloc}; @@ -23,7 +24,7 @@ unsafe impl Hal for MockHal { panic!("MockHal: dma_alloc failed"); } unsafe { ptr.write_bytes(0, pages * 4096) }; // Zero memory - (ptr as usize, NonNull::new(ptr).unwrap()) + (ptr as PhysAddr, NonNull::new(ptr).unwrap()) } unsafe fn dma_dealloc(paddr: PhysAddr, _vaddr: NonNull, pages: usize) -> i32 { @@ -114,14 +115,50 @@ impl Transport for MockTransport { false } - fn ack_interrupt(&mut self) -> bool { - false + fn ack_interrupt(&mut self) -> InterruptStatus { + InterruptStatus::empty() + } + + fn read_config_generation(&self) -> u32 { + 0 } - fn config_space(&self) -> Result> { + fn read_config_space(&self, offset: usize) -> Result { + let size = core::mem::size_of::(); + let config = self.config_space.borrow(); + if offset + .checked_add(size) + .is_none_or(|end| end > config.len()) + { + return Err(Error::ConfigSpaceTooSmall); + } + + let mut value = core::mem::MaybeUninit::::uninit(); unsafe { - let ptr = self.config_space.borrow_mut().as_mut_ptr() as *mut T; - Ok(NonNull::new_unchecked(ptr)) + core::ptr::copy_nonoverlapping( + config.as_ptr().add(offset), + value.as_mut_ptr() as *mut u8, + size, + ); + Ok(value.assume_init()) } } + + fn write_config_space( + &mut self, + offset: usize, + value: T, + ) -> Result<()> { + let bytes = value.as_bytes(); + let mut config = self.config_space.borrow_mut(); + if offset + .checked_add(bytes.len()) + .is_none_or(|end| end > config.len()) + { + return Err(Error::ConfigSpaceTooSmall); + } + + config[offset..offset + bytes.len()].copy_from_slice(bytes); + Ok(()) + } } diff --git a/sync/kspin/src/lock.rs b/sync/kspin/src/lock.rs index c5c50e22c2760760f1244bb6dd14f326d5842706..82bd3d97804316a7069704c2da121e1c78c9acc1 100644 --- a/sync/kspin/src/lock.rs +++ b/sync/kspin/src/lock.rs @@ -55,8 +55,7 @@ pub struct SpinLock { /// Provides mutable access to the protected data and automatically /// releases the lock when dropped. pub struct SpinLockGuard<'a, G: BaseGuard, T: ?Sized + 'a> { - #[allow(dead_code)] - token: &'a PhantomData, + _token: &'a PhantomData, guard_state: G::State, ptr: *mut T, #[cfg(feature = "smp")] @@ -115,7 +114,7 @@ impl SpinLock { } SpinLockGuard { - token: &PhantomData, + _token: &PhantomData, guard_state, ptr: unsafe { &mut *self.storage.get() }, #[cfg(feature = "smp")] @@ -159,7 +158,7 @@ impl SpinLock { if is_unlocked { Some(SpinLockGuard { - token: &PhantomData, + _token: &PhantomData, guard_state, ptr: unsafe { &mut *self.storage.get() }, #[cfg(feature = "smp")] diff --git a/util/klogger/src/lib.rs b/util/klogger/src/lib.rs index 483be1b2b877c45b89171ada79e6584de0e49592..1c1b607ba035ca507b6368e360f33478e7ffa70c 100644 --- a/util/klogger/src/lib.rs +++ b/util/klogger/src/lib.rs @@ -53,6 +53,7 @@ enum AnsiColor { #[repr(u8)] #[allow(dead_code)] +#[allow(clippy::enum_variant_names)] enum AnsiBrightColor { BrightBlack = 90, BrightRed = 91, diff --git a/util/unittest_support/src/lib.rs b/util/unittest_support/src/lib.rs index 82425aac4d317239716b2d69bcf6c1c833d0528b..4808062cc6e0c2418d92d930ef20179b3d3993c9 100644 --- a/util/unittest_support/src/lib.rs +++ b/util/unittest_support/src/lib.rs @@ -121,6 +121,10 @@ impl TestUserBuffer { self.len } + pub fn is_empty(&self) -> bool { + self.len == 0 + } + pub fn as_user_ptr(&self) -> *mut T { assert!(size_of::() <= self.len); self.user_addr as *mut T @@ -208,6 +212,10 @@ impl TestUserArray { N } + pub fn is_empty(&self) -> bool { + N == 0 + } + pub fn as_user_slice(&mut self) -> &mut [T] { unsafe { core::slice::from_raw_parts_mut(self.as_user_ptr(), N) } }