pci_driver/iommu.rs
1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3/* ---------------------------------------------------------------------------------------------- */
4
5use std::io;
6use std::ops::Range;
7
8use crate::regions::Permissions;
9
10/* ---------------------------------------------------------------------------------------------- */
11
12/// Represents an IOMMU that controls DMA done by some PCI function, device, or group of devices.
13///
14/// You'll probably need [`std::sync::atomic::fence`] or use types like
15/// [`AtomicU32`](std::sync::atomic::AtomicU32) somewhere to synchronize accesses properly with the
16/// device.
17pub struct PciIommu<'a> {
18 pub(crate) internal: &'a dyn PciIommuInternal,
19}
20
21impl PciIommu<'_> {
22 /// Both `iova` and process `address` must be aligned to this value.
23 ///
24 /// This is always a power of 2, and never less than the system's page size.
25 pub fn alignment(&self) -> usize {
26 self.internal.alignment()
27 }
28
29 /// IOVA ranges given to [`PciIommu::map`] must be contained in one of the ranges that this
30 /// method returns.
31 pub fn valid_iova_ranges(&self) -> &[Range<u64>] {
32 self.internal.valid_iova_ranges()
33 }
34
35 /// The maximum number of mappings that may be in effect simultaneously.
36 pub fn max_num_mappings(&self) -> u32 {
37 self.internal.max_num_mappings()
38 }
39
40 /// Add the given mapping to the IOMMU.
41 ///
42 /// - `iova` is the start address of the region in the device's address space.
43 /// - `size` is the length of the region.
44 /// - `address` is a pointer (in the current process' address space) to the start of the region
45 /// to be mapped.
46 ///
47 /// TODO: Alignment constraints?
48 ///
49 /// # Safety
50 ///
51 /// Must make sense.
52 pub unsafe fn map(
53 &self,
54 iova: u64,
55 length: usize,
56 address: *const u8,
57 device_permissions: Permissions,
58 ) -> io::Result<()> {
59 unsafe { self.internal.map(iova, length, address, device_permissions) }
60 }
61
62 /// Remove the given mapping from the IOMMU.
63 ///
64 /// TODO: Alignment constraints?
65 ///
66 /// Must unmap exactly a full range that was previously mapped using [`PciIommu::map`], or
67 /// several full ranges as long as they are contiguous. Otherwise, this fails.
68 pub fn unmap(&self, iova: u64, size: usize) -> io::Result<()> {
69 self.internal.unmap(iova, size)
70 }
71}
72
73/* ---------------------------------------------------------------------------------------------- */
74
75pub(crate) trait PciIommuInternal {
76 fn alignment(&self) -> usize;
77
78 fn valid_iova_ranges(&self) -> &[Range<u64>];
79
80 fn max_num_mappings(&self) -> u32;
81
82 unsafe fn map(
83 &self,
84 iova: u64,
85 length: usize,
86 address: *const u8,
87 device_permissions: Permissions,
88 ) -> io::Result<()>;
89
90 fn unmap(&self, iova: u64, length: usize) -> io::Result<()>;
91}
92
93/* ---------------------------------------------------------------------------------------------- */