Skip to main content

axdriver_virtio/
lib.rs

1//! Wrappers of some devices in the [`virtio-drivers`][1] crate, that implement
2//! traits in the [`axdriver_base`][2] series crates.
3//!
4//! Like the [`virtio-drivers`][1] crate, you must implement the [`VirtIoHal`]
5//! trait (alias of [`virtio-drivers::Hal`][3]), to allocate DMA regions and
6//! translate between physical addresses (as seen by devices) and virtual
7//! addresses (as seen by your program).
8//!
9//! [1]: https://docs.rs/virtio-drivers/latest/virtio_drivers/
10//! [2]: https://github.com/arceos-org/axdriver_crates/tree/main/axdriver_base
11//! [3]: https://docs.rs/virtio-drivers/latest/virtio_drivers/trait.Hal.html
12
13#![no_std]
14#![cfg_attr(doc, feature(doc_cfg))]
15
16#[cfg(feature = "alloc")]
17extern crate alloc;
18
19#[cfg(feature = "block")]
20mod blk;
21
22#[cfg(feature = "gpu")]
23mod gpu;
24
25#[cfg(feature = "net")]
26mod net;
27
28use axdriver_base::{DevError, DeviceType};
29use virtio_drivers::transport::DeviceType as VirtIoDevType;
30pub use virtio_drivers::{
31    BufferDirection, Hal as VirtIoHal, PhysAddr,
32    transport::{
33        Transport,
34        mmio::MmioTransport,
35        pci::{PciTransport, bus as pci},
36    },
37};
38
39#[cfg(feature = "block")]
40pub use self::blk::VirtIoBlkDev;
41#[cfg(feature = "gpu")]
42pub use self::gpu::VirtIoGpuDev;
43#[cfg(feature = "net")]
44pub use self::net::VirtIoNetDev;
45use self::pci::{DeviceFunction, DeviceFunctionInfo, PciRoot};
46
47/// Try to probe a VirtIO MMIO device from the given memory region.
48///
49/// If the device is recognized, returns the device type and a transport object
50/// for later operations. Otherwise, returns [`None`].
51pub fn probe_mmio_device(
52    reg_base: *mut u8,
53    _reg_size: usize,
54) -> Option<(DeviceType, MmioTransport)> {
55    use core::ptr::NonNull;
56
57    use virtio_drivers::transport::mmio::VirtIOHeader;
58
59    let header = NonNull::new(reg_base as *mut VirtIOHeader).unwrap();
60    let transport = unsafe { MmioTransport::new(header) }.ok()?;
61    let dev_type = as_dev_type(transport.device_type())?;
62    Some((dev_type, transport))
63}
64
65/// Try to probe a VirtIO PCI device from the given PCI address.
66///
67/// If the device is recognized, returns the device type and a transport object
68/// for later operations. Otherwise, returns [`None`].
69pub fn probe_pci_device<H: VirtIoHal>(
70    root: &mut PciRoot,
71    bdf: DeviceFunction,
72    dev_info: &DeviceFunctionInfo,
73) -> Option<(DeviceType, PciTransport)> {
74    use virtio_drivers::transport::pci::virtio_device_type;
75
76    let dev_type = virtio_device_type(dev_info).and_then(as_dev_type)?;
77    let transport = PciTransport::new::<H>(root, bdf).ok()?;
78    Some((dev_type, transport))
79}
80
81const fn as_dev_type(t: VirtIoDevType) -> Option<DeviceType> {
82    use VirtIoDevType::*;
83    match t {
84        Block => Some(DeviceType::Block),
85        Network => Some(DeviceType::Net),
86        GPU => Some(DeviceType::Display),
87        _ => None,
88    }
89}
90
91#[allow(dead_code)]
92const fn as_dev_err(e: virtio_drivers::Error) -> DevError {
93    use virtio_drivers::Error::*;
94    match e {
95        QueueFull => DevError::BadState,
96        NotReady => DevError::Again,
97        WrongToken => DevError::BadState,
98        AlreadyUsed => DevError::AlreadyExists,
99        InvalidParam => DevError::InvalidParam,
100        DmaError => DevError::NoMemory,
101        IoError => DevError::Io,
102        Unsupported => DevError::Unsupported,
103        ConfigSpaceTooSmall => DevError::BadState,
104        ConfigSpaceMissing => DevError::BadState,
105        _ => DevError::BadState,
106    }
107}