twizzler_driver/dma/
pin.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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use std::ops::Index;

use crate::arch::DMA_PAGE_SIZE;

#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq, Hash)]
/// A physical address. Must be aligned on [DMA_PAGE_SIZE].
pub struct PhysAddr(u64);

#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq, Hash)]
/// Information about a page of DMA memory, including it's physical address.
pub struct PhysInfo {
    addr: PhysAddr,
}

/// An iterator over DMA memory pages, returning [PhysInfo].
pub struct DmaPinIter<'a> {
    pin: &'a [PhysInfo],
    idx: usize,
}

/// A representation of some pinned memory for a region.
pub struct DmaPin<'a> {
    backing: &'a [PhysInfo],
}

impl<'a> DmaPin<'a> {
    pub(super) fn new(backing: &'a [PhysInfo]) -> Self {
        Self { backing }
    }

    pub fn len(&self) -> usize {
        self.backing.len()
    }
}

impl PhysInfo {
    pub(crate) fn new(addr: PhysAddr) -> Self {
        Self { addr }
    }

    /// Get the address of this DMA memory page.
    pub fn addr(&self) -> PhysAddr {
        self.addr
    }
}

impl From<PhysAddr> for u64 {
    fn from(p: PhysAddr) -> Self {
        p.0
    }
}

impl TryFrom<u64> for PhysAddr {
    type Error = ();

    fn try_from(value: u64) -> Result<Self, Self::Error> {
        if value & (DMA_PAGE_SIZE as u64 - 1) != 0 {
            return Err(());
        }
        Ok(Self(value))
    }
}

impl<'a> IntoIterator for DmaPin<'a> {
    type Item = PhysInfo;

    type IntoIter = DmaPinIter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        DmaPinIter {
            pin: self.backing,
            idx: 0,
        }
    }
}

impl<'a> Iterator for DmaPinIter<'a> {
    type Item = PhysInfo;

    fn next(&mut self) -> Option<Self::Item> {
        if self.idx >= self.pin.len() {
            None
        } else {
            let ret = self.pin[self.idx];
            self.idx += 1;
            Some(ret)
        }
    }
}

impl<'a> Index<usize> for DmaPin<'a> {
    type Output = PhysInfo;

    fn index(&self, index: usize) -> &Self::Output {
        &self.backing[index]
    }
}

#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq, Hash)]
/// Possible failure modes for pinning memory.
pub enum PinError {
    /// An internal error occurred.
    InternalError,
    /// Kernel resources are exhausted.
    Exhausted,
}

#[cfg(test)]
mod tests {
    use twizzler_abi::syscall::{BackingType, LifetimeType};
    use twizzler_object::CreateSpec;

    use crate::dma::{Access, DmaOptions, DmaPool};

    #[test]
    fn pin_kaction() {
        let pool = DmaPool::new(
            CreateSpec::new(LifetimeType::Volatile, BackingType::Normal),
            Access::BiDirectional,
            DmaOptions::default(),
        );
        let mut reg = pool.allocate(0u32).unwrap();
        let pin = reg.pin().unwrap();
        for phys in pin {
            let addr = phys.addr();
            let addr: u64 = addr.into();
            assert!(addr & 0xfff == 0);
            assert_ne!(addr, 0);
        }
    }
}