user_driver/lib.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//! Infrastructure for implementing PCI drivers in user mode.
// UNSAFETY: Manual memory management around buffers and mmap.
#![expect(unsafe_code)]
#![expect(missing_docs)]
use inspect::Inspect;
use interrupt::DeviceInterrupt;
use memory::MemoryBlock;
use std::sync::Arc;
pub mod backoff;
pub mod interrupt;
pub mod lockmem;
pub mod memory;
pub mod page_allocator;
pub mod vfio;
/// An interface to access device hardware.
pub trait DeviceBacking: 'static + Send + Inspect {
/// An object for accessing device registers.
type Registers: 'static + DeviceRegisterIo + Inspect;
/// Returns a device ID for diagnostics.
fn id(&self) -> &str;
/// Maps a BAR.
fn map_bar(&mut self, n: u8) -> anyhow::Result<Self::Registers>;
/// DMA Client for the device.
fn dma_client(&self) -> Arc<dyn DmaClient>;
/// Returns the maximum number of interrupts that can be mapped.
fn max_interrupt_count(&self) -> u32;
/// Maps a MSI-X interrupt for use, returning an object that can be used to
/// wait for the interrupt to be signaled by the device.
///
/// `cpu` is the CPU that the device should target with this interrupt.
///
/// This can be called multiple times for the same interrupt without disconnecting
/// previous mappings. The last `cpu` value will be used as the target CPU.
fn map_interrupt(&mut self, msix: u32, cpu: u32) -> anyhow::Result<DeviceInterrupt>;
}
/// Access to device registers.
pub trait DeviceRegisterIo: Send + Sync {
/// Returns the length of the register space.
fn len(&self) -> usize;
/// Reads a `u32` register.
fn read_u32(&self, offset: usize) -> u32;
/// Reads a `u64` register.
fn read_u64(&self, offset: usize) -> u64;
/// Writes a `u32` register.
fn write_u32(&self, offset: usize, data: u32);
/// Writes a `u64` register.
fn write_u64(&self, offset: usize, data: u64);
}
/// Device interfaces for DMA.
pub trait DmaClient: Send + Sync + Inspect {
/// Allocate a new DMA buffer. This buffer must be zero initialized.
///
/// TODO: string tag for allocation?
fn allocate_dma_buffer(&self, total_size: usize) -> anyhow::Result<MemoryBlock>;
/// Attach to a previously allocated memory block.
fn attach_dma_buffer(&self, len: usize, base_pfn: u64) -> anyhow::Result<MemoryBlock>;
}