dma_api/lib.rs
1#![cfg_attr(target_os = "none", no_std)]
2#![doc = include_str!("../README.md")]
3
4extern crate alloc;
5
6use core::{num::NonZeroUsize, ops::Deref, ptr::NonNull};
7
8mod osal;
9
10mod array;
11mod common;
12mod dbox;
13mod def;
14mod map_single;
15
16pub use array::*;
17pub use dbox::*;
18pub use def::*;
19pub use map_single::*;
20pub use osal::DmaOp;
21
22impl Deref for DmaHandle {
23 type Target = core::alloc::Layout;
24 fn deref(&self) -> &Self::Target {
25 &self.layout
26 }
27}
28
29/// DMA 设备操作接口。
30///
31/// `DeviceDma` 是用于执行 DMA 操作的主要入口点,封装了平台特定的
32/// `DmaOp` 实现,并提供了分配、映射和管理 DMA 内存的方法。
33///
34/// # 创建
35///
36/// 使用 [`DeviceDma::new()`] 创建实例,需要提供:
37/// - `dma_mask`: 设备可寻址的地址掩码(如 `0xFFFFFFFF` 表示 32 位设备)
38/// - `osal`: 实现 `DmaOp` trait 的平台抽象层
39///
40/// # 示例
41///
42/// ```rust,ignore
43/// use dma_api::DeviceDma;
44///
45/// let device = DeviceDma::new(0xFFFFFFFF, &my_dma_impl);
46/// ```
47#[derive(Clone)]
48pub struct DeviceDma {
49 os: &'static dyn DmaOp,
50 mask: u64,
51}
52
53impl DeviceDma {
54 /// 创建新的 DMA 设备实例。
55 ///
56 /// # 参数
57 ///
58 /// - `dma_mask`: 设备 DMA 地址掩码,指定设备可寻址的地址范围
59 /// - `0xFFFFFFFF`: 32 位设备(最多 4GB)
60 /// - `0xFFFFFFFFFFFFFFFF`: 64 位设备(全地址空间)
61 /// - `osal`: 实现 `DmaOp` trait 的平台抽象层引用
62 ///
63 /// # 示例
64 ///
65 /// ```rust,ignore
66 /// use dma_api::DeviceDma;
67 ///
68 /// let device = DeviceDma::new(0xFFFFFFFF, &my_dma_impl);
69 /// ```
70 pub fn new(dma_mask: u64, osal: &'static dyn DmaOp) -> Self {
71 Self {
72 mask: dma_mask,
73 os: osal,
74 }
75 }
76
77 /// 获取设备的 DMA 地址掩码。
78 ///
79 /// # 返回
80 ///
81 /// 返回设备的 DMA 掩码值,表示设备可寻址的最大地址范围。
82 pub fn dma_mask(&self) -> u64 {
83 self.mask
84 }
85
86 /// 刷新 CPU 缓存到内存(clean 操作)。
87 ///
88 /// 将指定地址范围的 CPU 缓存数据写回到内存,确保设备可以读取到最新数据。
89 /// 用于 `ToDevice` 和 `Bidirectional` 方向的 DMA 传输前。
90 ///
91 /// # 参数
92 ///
93 /// - `addr`: 内存起始地址
94 /// - `size`: 内存大小(字节)
95 pub fn flush(&self, addr: NonNull<u8>, size: usize) {
96 self.os.flush(addr, size)
97 }
98
99 /// 使 CPU 缓存失效(invalidate 操作)。
100 ///
101 /// 使指定地址范围的 CPU 缓存失效,强制 CPU 从内存重新读取数据。
102 /// 用于 `FromDevice` 和 `Bidirectional` 方向的 DMA 传输后。
103 ///
104 /// # 参数
105 ///
106 /// - `addr`: 内存起始地址
107 /// - `size`: 内存大小(字节)
108 pub fn invalidate(&self, addr: NonNull<u8>, size: usize) {
109 self.os.invalidate(addr, size)
110 }
111
112 /// 刷新并使 CPU 缓存失效(clean and invalidate 操作)。
113 ///
114 /// 同时执行刷新和失效操作,用于确保缓存和内存完全同步。
115 ///
116 /// # 参数
117 ///
118 /// - `addr`: 内存起始地址
119 /// - `size`: 内存大小(字节)
120 pub fn flush_invalidate(&self, addr: NonNull<u8>, size: usize) {
121 self.os.flush_invalidate(addr, size)
122 }
123
124 /// 获取系统页大小。
125 ///
126 /// # 返回
127 ///
128 /// 返回系统的页大小(字节),通常为 4096。
129 pub fn page_size(&self) -> usize {
130 self.os.page_size()
131 }
132
133 fn prepare_read(
134 &self,
135 handle: &DmaMapHandle,
136 offset: usize,
137 size: usize,
138 direction: DmaDirection,
139 ) {
140 self.os.prepare_read(handle, offset, size, direction)
141 }
142
143 fn confirm_write(
144 &self,
145 handle: &DmaMapHandle,
146 offset: usize,
147 size: usize,
148 direction: DmaDirection,
149 ) {
150 self.os.confirm_write(handle, offset, size, direction)
151 }
152
153 unsafe fn alloc_coherent(&self, layout: core::alloc::Layout) -> Result<DmaHandle, DmaError> {
154 let res = unsafe { self.os.alloc_coherent(self.mask, layout) }.ok_or(DmaError::NoMemory)?;
155 match self.check_handle(&res) {
156 Ok(()) => Ok(res),
157 Err(e) => {
158 unsafe { self.dealloc_coherent(res) };
159 Err(e)
160 }
161 }
162 }
163
164 unsafe fn dealloc_coherent(&self, handle: DmaHandle) {
165 unsafe { self.os.dealloc_coherent(handle) }
166 }
167
168 fn check_handle(&self, handle: &DmaHandle) -> Result<(), DmaError> {
169 let addr: u64 = handle.dma_addr.into();
170
171 let in_mask = if handle.size() == 0 {
172 addr <= self.dma_mask()
173 } else {
174 addr.checked_add(handle.size().saturating_sub(1) as u64)
175 .map(|end| end <= self.dma_mask())
176 .unwrap_or(false)
177 };
178
179 if !in_mask {
180 return Err(DmaError::DmaMaskNotMatch {
181 addr: handle.dma_addr,
182 mask: self.dma_mask(),
183 });
184 }
185
186 let is_aligned = handle
187 .dma_addr
188 .as_u64()
189 .is_multiple_of(handle.align() as u64);
190 if !is_aligned {
191 return Err(DmaError::AlignMismatch {
192 address: handle.dma_addr,
193 required: handle.align(),
194 });
195 }
196
197 Ok(())
198 }
199
200 unsafe fn _map_single(
201 &self,
202 addr: NonNull<u8>,
203 size: NonZeroUsize,
204 align: usize,
205 direction: DmaDirection,
206 ) -> Result<DmaMapHandle, DmaError> {
207 let res = unsafe { self.os.map_single(self.mask, addr, size, align, direction) }?;
208 match self.check_handle(&res) {
209 Ok(()) => Ok(res),
210 Err(e) => {
211 unsafe { self.unmap_single(res) };
212 Err(e)
213 }
214 }
215 }
216
217 unsafe fn unmap_single(&self, handle: DmaMapHandle) {
218 unsafe { self.os.unmap_single(handle) }
219 }
220
221 /// 创建默认对齐的 DMA 数组。
222 ///
223 /// 分配一个指定大小的 DMA 可访问数组,内存初始化为零。
224 /// 数组的对齐方式使用类型 `T` 的默认对齐值。
225 ///
226 /// # 类型参数
227 ///
228 /// - `T`: 数组元素类型,必须是 `Sized` 并且实现了 `Default`
229 ///
230 /// # 参数
231 ///
232 /// - `size`: 数组长度(元素个数)
233 /// - `direction`: DMA 传输方向,决定缓存同步策略
234 ///
235 /// # 返回
236 ///
237 /// 成功时返回 `DArray<T>` 容器,失败时返回 `DmaError`
238 ///
239 /// # 示例
240 ///
241 /// ```rust,ignore
242 /// let dma_array = device.array_zero::<u32>(100, DmaDirection::FromDevice)?;
243 /// ```
244 pub fn array_zero<T>(
245 &self,
246 size: usize,
247 direction: DmaDirection,
248 ) -> Result<array::DArray<T>, DmaError> {
249 array::DArray::new_zero(self, size, direction)
250 }
251
252 /// 创建指定对齐的 DMA 数组。
253 ///
254 /// 分配一个指定大小和对齐要求的 DMA 可访问数组,内存初始化为零。
255 ///
256 /// # 类型参数
257 ///
258 /// - `T`: 数组元素类型,必须是 `Sized` 并且实现了 `Default`
259 ///
260 /// # 参数
261 ///
262 /// - `size`: 数组长度(元素个数)
263 /// - `align`: 对齐字节数(至少等于 `core::mem::align_of::<T>()`)
264 /// - `direction`: DMA 传输方向,决定缓存同步策略
265 ///
266 /// # 返回
267 ///
268 /// 成功时返回 `DArray<T>` 容器,失败时返回 `DmaError`
269 ///
270 /// # 示例
271 ///
272 /// ```rust,ignore
273 /// // 创建 64 字节对齐的数组
274 /// let dma_array = device
275 /// .array_zero_with_align::<u32>(100, 64, DmaDirection::FromDevice)?;
276 /// ```
277 pub fn array_zero_with_align<T>(
278 &self,
279 size: usize,
280 align: usize,
281 direction: DmaDirection,
282 ) -> Result<array::DArray<T>, DmaError> {
283 array::DArray::new_zero_with_align(self, size, align, direction)
284 }
285
286 /// 创建默认对齐的 DMA Box。
287 ///
288 /// 分配一个 DMA 可访问的单值容器,内存初始化为零。
289 /// 适合存储 DMA 描述符、配置结构等单个对象。
290 ///
291 /// # 类型参数
292 ///
293 /// - `T`: 存储的值类型,必须是 `Sized` 并且实现了 `Default`
294 ///
295 /// # 参数
296 ///
297 /// - `direction`: DMA 传输方向,决定缓存同步策略
298 ///
299 /// # 返回
300 ///
301 /// 成功时返回 `DBox<T>` 容器,失败时返回 `DmaError`
302 ///
303 /// # 示例
304 ///
305 /// ```rust,ignore
306 /// #[derive(Default)]
307 /// struct Descriptor {
308 /// addr: u64,
309 /// length: u32,
310 /// }
311 ///
312 /// let dma_desc = device.box_zero::<Descriptor>(DmaDirection::ToDevice)?;
313 /// ```
314 pub fn box_zero<T>(&self, direction: DmaDirection) -> Result<dbox::DBox<T>, DmaError> {
315 dbox::DBox::new_zero(self, direction)
316 }
317
318 /// 创建指定对齐的 DMA Box。
319 ///
320 /// 分配一个指定对齐要求的 DMA 可访问单值容器,内存初始化为零。
321 ///
322 /// # 类型参数
323 ///
324 /// - `T`: 存储的值类型,必须是 `Sized` 并且实现了 `Default`
325 ///
326 /// # 参数
327 ///
328 /// - `align`: 对齐字节数(至少等于 `core::mem::align_of::<T>()`)
329 /// - `direction`: DMA 传输方向,决定缓存同步策略
330 ///
331 /// # 返回
332 ///
333 /// 成功时返回 `DBox<T>` 容器,失败时返回 `DmaError`
334 ///
335 /// # 示例
336 ///
337 /// ```rust,ignore
338 /// let dma_desc = device
339 /// .box_zero_with_align::<Descriptor>(64, DmaDirection::ToDevice)?;
340 /// ```
341 pub fn box_zero_with_align<T>(
342 &self,
343 align: usize,
344 direction: DmaDirection,
345 ) -> Result<dbox::DBox<T>, DmaError> {
346 dbox::DBox::new_zero_with_align(self, align, direction)
347 }
348
349 /// 映射现有缓冲区为 DMA 可访问。
350 ///
351 /// 将已存在的缓冲区(如栈数组或堆分配的 slice)映射为 DMA 可访问区域。
352 /// 返回的 `SArrayPtr` 在离开作用域时自动解除映射。
353 ///
354 /// # 缓存同步
355 ///
356 /// **重要**: 此方法创建的映射**不会**自动同步缓存。
357 /// 你必须手动调用 `SArrayPtr` 的方法进行缓存同步:
358 /// - `to_vec()`: 读取前自动失效整个范围
359 /// - `copy_from_slice()`: 写入后自动刷新整个范围
360 ///
361 /// # 类型参数
362 ///
363 /// - `T`: 数组元素类型
364 ///
365 /// # 参数
366 ///
367 /// - `buff`: 要映射的缓冲区切片
368 /// - `align`: 对齐字节数
369 /// - `direction`: DMA 传输方向,决定手动缓存同步的行为
370 ///
371 /// # 返回
372 ///
373 /// 成功时返回 `SArrayPtr<T>` 映射句柄,失败时返回 `DmaError`
374 ///
375 /// # 示例
376 ///
377 /// ```rust,ignore
378 /// let mut buffer = [0u8; 4096];
379 ///
380 /// // 映射用于 DMA 写入
381 /// let mapping = device.map_single_array(&buffer, 64, DmaDirection::ToDevice)?;
382 ///
383 /// // 必须手动刷新缓存
384 /// mapping.copy_from_slice(&data);
385 ///
386 /// // ... 启动 DMA 传输 ...
387 ///
388 /// // 映射在作用域结束时自动解映射
389 /// ```
390 pub fn map_single_array<T>(
391 &self,
392 buff: &[T],
393 align: usize,
394 direction: DmaDirection,
395 ) -> Result<SArrayPtr<T>, DmaError> {
396 SArrayPtr::map_single(self, buff, align, direction)
397 }
398}