twizzler_driver/dma/
pin.rs

1use std::ops::Index;
2
3use crate::arch::DMA_PAGE_SIZE;
4
5#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq, Hash)]
6/// A physical address. Must be aligned on [DMA_PAGE_SIZE].
7pub struct PhysAddr(pub u64);
8
9#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq, Hash)]
10/// Information about a page of DMA memory, including it's physical address.
11pub struct PhysInfo {
12    addr: PhysAddr,
13}
14
15/// An iterator over DMA memory pages, returning [PhysInfo].
16pub struct DmaPinIter<'a> {
17    pin: &'a [PhysInfo],
18    idx: usize,
19}
20
21/// A representation of some pinned memory for a region.
22pub struct DmaPin<'a> {
23    pub backing: &'a [PhysInfo],
24}
25
26impl<'a> DmaPin<'a> {
27    pub(super) fn new(backing: &'a [PhysInfo]) -> Self {
28        Self { backing }
29    }
30
31    pub fn len(&self) -> usize {
32        self.backing.len()
33    }
34}
35
36impl PhysInfo {
37    pub fn new(addr: PhysAddr) -> Self {
38        Self { addr }
39    }
40
41    /// Get the address of this DMA memory page.
42    pub fn addr(&self) -> PhysAddr {
43        self.addr
44    }
45}
46
47impl From<PhysInfo> for u64 {
48    fn from(p: PhysInfo) -> Self {
49        p.addr.into()
50    }
51}
52
53impl From<&PhysInfo> for u64 {
54    fn from(p: &PhysInfo) -> Self {
55        p.addr.into()
56    }
57}
58
59impl From<PhysAddr> for u64 {
60    fn from(p: PhysAddr) -> Self {
61        p.0
62    }
63}
64
65impl TryFrom<u64> for PhysAddr {
66    type Error = ();
67
68    fn try_from(value: u64) -> Result<Self, Self::Error> {
69        if value & (DMA_PAGE_SIZE as u64 - 1) != 0 {
70            return Err(());
71        }
72        Ok(Self(value))
73    }
74}
75
76impl<'a> IntoIterator for DmaPin<'a> {
77    type Item = PhysInfo;
78
79    type IntoIter = DmaPinIter<'a>;
80
81    fn into_iter(self) -> Self::IntoIter {
82        DmaPinIter {
83            pin: self.backing,
84            idx: 0,
85        }
86    }
87}
88
89impl<'a> Iterator for DmaPinIter<'a> {
90    type Item = PhysInfo;
91
92    fn next(&mut self) -> Option<Self::Item> {
93        if self.idx >= self.pin.len() {
94            None
95        } else {
96            let ret = self.pin[self.idx];
97            self.idx += 1;
98            Some(ret)
99        }
100    }
101}
102
103impl<'a> Index<usize> for DmaPin<'a> {
104    type Output = PhysInfo;
105
106    fn index(&self, index: usize) -> &Self::Output {
107        &self.backing[index]
108    }
109}
110
111#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq, Hash)]
112/// Possible failure modes for pinning memory.
113pub enum PinError {
114    /// An internal error occurred.
115    InternalError,
116    /// Kernel resources are exhausted.
117    Exhausted,
118}
119
120#[cfg(test)]
121mod tests {
122    use crate::dma::{Access, DmaOptions, DmaPool};
123
124    #[test]
125    fn pin_kaction() {
126        let pool = DmaPool::new(
127            DmaPool::default_spec(),
128            Access::BiDirectional,
129            DmaOptions::default(),
130        );
131        let mut reg = pool.allocate(0u32).unwrap();
132        let pin = reg.pin().unwrap();
133        for phys in pin {
134            let addr = phys.addr();
135            let addr: u64 = addr.into();
136            assert!(addr & 0xfff == 0);
137            assert_ne!(addr, 0);
138        }
139    }
140}