| Crates.io | dma-api |
| lib.rs | dma-api |
| version | 0.6.0 |
| created_at | 2024-11-20 09:28:34.187072+00 |
| updated_at | 2026-01-23 07:41:00.677148+00 |
| description | Trait for DMA alloc and some collections |
| homepage | |
| repository | https://github.com/drivercraft/sparreal-os |
| max_upload_size | |
| id | 1454519 |
| size | 37,964 |
用于 Rust 的 DMA(直接内存访问)抽象 API,提供安全的 DMA 内存操作接口,适用于嵌入式和裸机环境。
no_std 支持: 完全支持裸机环境Direction - DMA 传输方向pub enum Direction {
ToDevice, // DMA_TO_DEVICE: CPU 写入,设备读取
FromDevice, // DMA_FROM_DEVICE: 设备写入,CPU 读取
Bidirectional, // DMA_BIDIRECTIONAL: 双向传输
}
DeviceDma - DMA 设备操作DMA 设备的主要操作接口,提供内存分配、映射和缓存操作。
DmaOp trait - 操作系统抽象层需要由平台实现的 trait,用于提供底层的 DMA 操作支持。
DArray<T> - DMA 数组DMA 可访问的数组类型,支持自动缓存同步。
DBox<T> - DMA BoxDMA 可访问的单值容器,支持自动缓存同步。
SingleMapping - 单次映射临时的单缓冲区 DMA 映射,RAII 风格自动清理。
DmaOp traituse dma_api::{DmaOp, Direction, DmaHandle, DmaError};
use core::{alloc::Layout, ptr::NonNull, num::NonZeroUsize};
struct MyDmaImpl;
impl DmaOp for MyDmaImpl {
fn page_size(&self) -> usize {
4096 // 返回系统页大小
}
unsafe fn map_single(
&self,
dma_mask: u64,
addr: NonNull<u8>,
size: NonZeroUsize,
align: usize,
direction: Direction,
) -> Result<DmaHandle, DmaError> {
// 实现虚拟地址到 DMA 地址的映射
// 返回 DmaHandle
todo!()
}
unsafe fn unmap_single(&self, handle: DmaHandle) {
// 解除 DMA 映射
todo!()
}
unsafe fn alloc_coherent(
&self,
dma_mask: u64,
layout: Layout,
) -> Option<DmaHandle> {
// 分配 DMA 一致性内存
todo!()
}
unsafe fn dealloc_coherent(&self, handle: DmaHandle) {
// 释放 DMA 内存
todo!()
}
}
DeviceDma 和 DMA 容器use dma_api::{DeviceDma, Direction};
// 创建 DMA 设备实例
static DMA_IMPL: MyDmaImpl = MyDmaImpl;
let device = DeviceDma::new(0xFFFFFFFF, &DMA_IMPL);
// 创建 DMA 数组 (自动初始化为零)
let mut dma_array = device.new_array::<u32>(100, 64, Direction::FromDevice)
.expect("Failed to allocate DMA array");
// 写入数据 (自动处理缓存同步)
dma_array.set(0, 0x12345678);
dma_array.set(1, 0xABCDEF00);
// 读取数据 (自动处理缓存同步)
let value = dma_array.read(0);
assert_eq!(value, 0x12345678);
// 获取 DMA 地址用于硬件配置
let dma_addr = dma_array.dma_addr();
// 配置 DMA 控制器使用 dma_addr...
// 使用索引访问
let val = dma_array[0]; // 自动处理缓存同步
// 创建 DMA Box (单个值)
let mut dma_box = device.new_box::<MyStruct>(64, Direction::ToDevice)
.expect("Failed to allocate DMA box");
dma_box.write(MyStruct { field1: 42, field2: 100 });
let value = dma_box.read();
// 修改值 (read-modify-write 模式)
dma_box.modify(|v| v.field1 += 10);
SingleMapping 映射现有缓冲区use dma_api::DeviceDma;
use core::{ptr::NonNull, num::NonZeroUsize};
let device = DeviceDma::new(0xFFFFFFFF, &DMA_IMPL);
// 现有缓冲区
let mut buffer = [0u8; 4096];
let addr = NonNull::new(buffer.as_mut_ptr()).unwrap();
let size = NonZeroUsize::new(4096).unwrap();
// 映射缓冲区用于 DMA
let mapping = unsafe {
device.map_single(addr, size, 64, Direction::ToDevice)
.expect("Mapping failed")
};
// 使用映射的 DMA 地址
let dma_addr = mapping.dma_addr();
// ... DMA 传输 ...
// 映射在离开作用域时自动解除
API 遵循 Linux DMA 缓存一致性语义,由 DmaOp trait 的 prepare_read 和 confirm_write 方法自动处理:
prepare_read)invalidate - 使 CPU 缓存失效,准备接收设备数据confirm_write)flush - 将 CPU 数据写回内存DArray<T> 和 DBox<T> 在以下操作时自动处理缓存同步:
read() / set() - 自动同步对应元素index (索引访问) - 自动同步读取的元素write() / modify() - 自动同步写入copy_from_slice() - 写入后自动同步整个范围| 类型 | 说明 |
|---|---|
DeviceDma |
DMA 设备操作接口 |
Direction |
DMA 传输方向枚举 |
DmaOp |
操作系统抽象层 trait |
DmaHandle |
DMA 映射句柄 |
DArray<T> |
DMA 数组容器 |
DBox<T> |
DMA 单值容器 |
SingleMapping |
单次映射 |
| Rust API | Linux Equivalent |
|---|---|
DeviceDma::map_single() |
dma_map_single() |
SingleMapping::drop() |
dma_unmap_single() |
DmaOp::alloc_coherent() |
dma_alloc_coherent() |
DmaOp::dealloc_coherent() |
dma_free_coherent() |
DmaOp::flush() |
dma_cache_sync() (DMA_TO_DEVICE) |
DmaOp::invalidate() |
dma_cache_sync() (DMA_FROM_DEVICE) |
DMA 操作通常需要对齐到特定的边界:
new_array() / new_box() 的 align 参数指定对齐字节数DeviceDma::new() 的 dma_mask 参数指定设备可寻址的地址范围:
0xFFFFFFFF (32 位设备)0xFFFFFFFFFFFFFFFF (64 位设备)