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