dma_api/
lib.rs

1#![cfg_attr(not(test), no_std)]
2#![doc = include_str!("../README.md")]
3
4#[cfg(feature = "alloc")]
5extern crate alloc;
6
7use core::{ptr::NonNull, sync::atomic::AtomicBool};
8
9mod dma;
10mod osal;
11
12#[cfg(feature = "alloc")]
13pub use dma::alloc::{pool::*, r#box::DBox, vec::DVec, DError};
14
15pub use dma::slice::{DSlice, DSliceMut};
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18#[repr(C)]
19pub enum Direction {
20    ToDevice,
21    FromDevice,
22    Bidirectional,
23}
24
25pub trait Osal {
26    /// map virt address to physical address
27    fn map(&self, addr: NonNull<u8>, size: usize, direction: Direction) -> u64;
28
29    /// unmap virt address
30    fn unmap(&self, addr: NonNull<u8>, size: usize);
31
32    /// write cache back to memory
33    fn flush(&self, addr: NonNull<u8>, size: usize) {
34        osal::arch::flush(addr, size)
35    }
36
37    /// invalidate cache
38    fn invalidate(&self, addr: NonNull<u8>, size: usize) {
39        osal::arch::invalidate(addr, size)
40    }
41
42    /// allocate memory that meets the dma requirement
43    ///
44    /// # Safety
45    /// This function is unsafe because undefined behavior can
46    /// result if the caller does not ensure that the returned pointer is
47    /// properly handled.
48    /// The caller must ensure that the pointer is eventually deallocated
49    ///  using the corresponding `dealloc` method, and that the memory is not accessed after being deallocated.
50    #[cfg(feature = "alloc")]
51    unsafe fn alloc(&self, dma_mask: u64, layout: core::alloc::Layout) -> *mut u8 {
52        let _ = dma_mask;
53        alloc::alloc::alloc(layout)
54    }
55
56    /// deallocate memory
57    ///
58    /// # Safety
59    ///
60    /// This function is unsafe because undefined behavior can result if the caller does not ensure that the `ptr` was allocated by a previous call to the `alloc` method with the same `layout`.
61    /// The caller must ensure that the memory is not accessed after being deallocated.
62    #[cfg(feature = "alloc")]
63    unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) {
64        alloc::alloc::dealloc(ptr, layout)
65    }
66}
67
68static mut OSAL: &'static dyn Osal = &osal::NopOsal;
69static INIT: AtomicBool = AtomicBool::new(false);
70
71pub fn init(osal: &'static dyn Osal) {
72    if INIT.load(core::sync::atomic::Ordering::Acquire) {
73        return;
74    }
75
76    unsafe {
77        OSAL = osal;
78    }
79    INIT.store(true, core::sync::atomic::Ordering::Release);
80}
81
82fn get_osal() -> &'static dyn Osal {
83    if !INIT.load(core::sync::atomic::Ordering::Acquire) {
84        panic!("dma-api not initialized");
85    }
86    unsafe { OSAL }
87}
88
89fn map(addr: NonNull<u8>, size: usize, direction: Direction) -> u64 {
90    get_osal().map(addr, size, direction)
91}
92
93fn unmap(addr: NonNull<u8>, size: usize) {
94    get_osal().unmap(addr, size)
95}
96
97fn invalidate(addr: NonNull<u8>, size: usize) {
98    get_osal().invalidate(addr, size)
99}
100
101fn flush(addr: NonNull<u8>, size: usize) {
102    get_osal().flush(addr, size)
103}
104
105#[cfg(feature = "alloc")]
106fn alloc(dma_mask: u64, layout: core::alloc::Layout) -> *mut u8 {
107    unsafe { get_osal().alloc(dma_mask, layout) }
108}
109
110#[cfg(feature = "alloc")]
111fn dealloc(ptr: *mut u8, layout: core::alloc::Layout) {
112    unsafe { get_osal().dealloc(ptr, layout) }
113}