dma_api/dma/
mod.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
use crate::{flush, invalidate, map, unmap, Direction};
use alloc::vec::Vec;
use core::{
    alloc::Layout,
    mem::{self, align_of, size_of},
    ptr::NonNull,
};

pub mod r#box;
pub mod slice;
pub mod vec;

struct DCommon<T> {
    addr: NonNull<T>,
    bus_addr: u64,
    layout: Layout,
    direction: Direction,
}

impl<T> DCommon<T> {
    pub fn zeros(layout: Layout, direction: Direction) -> Option<Self> {
        unsafe {
            let addr = NonNull::new(alloc::alloc::alloc_zeroed(layout))?;
            let bus_addr = map(addr, layout.size(), direction);
            flush(addr, layout.size());
            Some(Self {
                bus_addr,
                addr: addr.cast(),
                layout,
                direction,
            })
        }
    }

    pub fn from_vec(mut value: Vec<T>, direction: Direction) -> Self {
        unsafe {
            let layout = Layout::from_size_align_unchecked(
                value.capacity() * size_of::<T>(),
                align_of::<T>(),
            );

            let addr = NonNull::new(value.as_mut_ptr()).unwrap();

            mem::forget(value);

            let bus_addr = map(addr.cast(), layout.size(), direction);
            flush(addr.cast(), layout.size());
            Self {
                bus_addr,
                addr: addr.cast(),
                layout,
                direction,
            }
        }
    }

    pub fn preper_read(&self, ptr: NonNull<u8>, size: usize) {
        self.direction.preper_read(ptr, size);
    }

    pub fn confirm_write(&self, ptr: NonNull<u8>, size: usize) {
        self.direction.confirm_write(ptr, size);
    }
}

impl<T> Drop for DCommon<T> {
    fn drop(&mut self) {
        if self.layout.size() > 0 {
            unmap(self.addr.cast(), self.layout.size());

            unsafe { alloc::alloc::dealloc(self.addr.as_ptr() as _, self.layout) };
        }
    }
}

impl Direction {
    pub fn preper_read(self, ptr: NonNull<u8>, size: usize) {
        if matches!(self, Direction::FromDevice | Direction::Bidirectional) {
            invalidate(ptr, size);
        }
    }
    pub fn confirm_write(self, ptr: NonNull<u8>, size: usize) {
        if matches!(self, Direction::ToDevice | Direction::Bidirectional) {
            flush(ptr, size)
        }
    }
}