twizzler_driver/dma/
object.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
use std::sync::Mutex;

use twizzler_abi::{
    kso::{KactionCmd, KactionFlags, KactionGenericCmd},
    object::{MAX_SIZE, NULLPAGE_SIZE},
    syscall::sys_kaction,
};
use twizzler_object::{ObjID, Object};

use super::{Access, DeviceSync, DmaOptions, DmaRegion, DmaSliceRegion};

/// A handle for an object that can be used to perform DMA, and is most useful directly as a way to
/// perform DMA operations on a specific object. For an allocator-like DMA interface, see
/// [crate::dma::DmaPool].
pub struct DmaObject {
    obj: Object<()>,
    pub(crate) releasable_pins: Mutex<Vec<u32>>,
}

impl DmaObject {
    /// TODO: support
    /// Create a [DmaSliceRegion] from the base of this object, where the region represents memory
    /// of type `[T; len]`.
    fn _slice_region<T: DeviceSync>(
        &self,
        len: usize,
        access: Access,
        options: DmaOptions,
    ) -> DmaSliceRegion<T> {
        let nr_bytes = core::mem::size_of::<T>()
            .checked_mul(len)
            .expect("Value of len too large");
        assert!(nr_bytes < MAX_SIZE - NULLPAGE_SIZE * 2);
        DmaSliceRegion::new(
            core::mem::size_of::<T>() * len,
            access,
            options,
            NULLPAGE_SIZE,
            len,
            None,
        )
    }

    /// TODO: support
    /// Create a [DmaRegion] from the base of this object, where the region represents memory
    /// of type `T`.
    fn _region<T: DeviceSync>(&self, access: Access, options: DmaOptions) -> DmaRegion<T> {
        DmaRegion::new(
            core::mem::size_of::<T>(),
            access,
            options,
            NULLPAGE_SIZE,
            None,
        )
    }

    /// Get a reference to the object handle.
    pub fn object(&self) -> &Object<()> {
        &self.obj
    }

    /// Create a new [DmaObject] from an existing object handle.
    pub fn new<T>(obj: Object<T>) -> Self {
        Self {
            obj: unsafe { obj.transmute() },
            releasable_pins: Mutex::new(Vec::new()),
        }
    }
}

pub(crate) fn release_pin(id: ObjID, token: u32) {
    let _ = sys_kaction(
        KactionCmd::Generic(KactionGenericCmd::ReleasePin),
        Some(id),
        token as u64,
        0,
        KactionFlags::empty(),
    );
}

impl Drop for DmaObject {
    fn drop(&mut self) {
        let pins = self.releasable_pins.lock().unwrap();
        for pin in &*pins {
            release_pin(self.object().id(), *pin);
        }
    }
}

impl<T> From<Object<T>> for DmaObject {
    fn from(obj: Object<T>) -> Self {
        Self::new(obj)
    }
}