dma-api 0.7.0

Trait for DMA alloc and some collections
Documentation
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
# DMA API

用于 Rust 的 DMA(直接内存访问)抽象 API,提供安全的 DMA 内存操作接口,适用于嵌入式和裸机环境。

## 目录

- [快速开始]#快速开始
- [核心概念]#核心概念
- [使用场景指南]#使用场景指南
- [API 方法目录]#api-方法目录
- [完整示例]#完整示例
- [缓存同步详解]#缓存同步详解
- [完整 API 参考]#完整-api-参考

---

## 快速开始

### 1. 实现 `DmaOp` trait

首先需要为你的平台实现 `DmaOp` trait,提供底层 DMA 操作支持:

```rust,ignore
use dma_api::{DmaOp, DmaDirection, 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: DmaDirection,
    ) -> 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!()
    }
}
```

### 2. 选择合适的 DMA 容器

根据你的使用场景选择:

| 需求 | 推荐容器 | 特点 |
|------|---------|------|
| 需要数组类型的 DMA 缓冲区 | `DArray<T>` | 自动缓存同步,固定大小 |
| 需要单个结构体的 DMA 缓冲区 | `DBox<T>` | 自动缓存同步,单个值 |
| 映射现有缓冲区用于 DMA | `SArrayPtr<T>` | 手动缓存同步,单个连续内存区域映射 |

---

## 核心概念

### DMA 传输方向 (`DmaDirection`)

DMA 操作有三种方向,决定了缓存同步的行为:

```rust,ignore
pub enum DmaDirection {
    ToDevice,       // CPU → 设备:CPU 写数据,设备读
    FromDevice,     // 设备 → CPU:设备写数据,CPU 读
    Bidirectional,  // 双向:CPU 和设备都可能读写
}
```

**选择指南**:
- **ToDevice**: 用于发送数据到设备(如网卡发送缓冲区)
- **FromDevice**: 用于接收设备数据(如网卡接收缓冲区)
- **Bidirectional**: 用于双向通信(如驱动程序与设备共享内存)

### 缓存同步

DMA 操作需要处理 CPU 缓存和内存之间的数据一致性:

| 操作 | ToDevice | FromDevice | Bidirectional |
|------|----------|------------|---------------|
| **写数据前** (`confirm_write`) | ✅ 刷新缓存 | ❌ 无操作 | ✅ 刷新缓存 |
| **读数据前** (`prepare_read`) | ❌ 无操作 | ✅ 使缓存失效 | ✅ 使缓存失效 |

**自动同步 vs 手动同步**:
- `DArray<T>``DBox<T>`:每次访问(`read`/`set`/`write`/`modify`**自动**同步对应元素的缓存
- `SingleMap`**不自动**同步,用户必须手动调用 `prepare_read_all()``confirm_write_all()`

### DMA 地址掩码 (`dma_mask`)

`dma_mask` 指定设备可寻址的地址范围:

- `0xFFFFFFFF` (32 位设备,最多 4GB)
- `0xFFFFFFFFFFFFFFFF` (64 位设备,全地址空间)
- 其他值根据设备硬件限制

---

## 使用场景指南

### 场景 1: DMA 数组缓冲区

**用途**:需要固定大小的数组类型 DMA 缓冲区

**推荐**:`DArray<T>`

**特点**:
- ✅ 自动缓存同步(每次 `read`/`set` 时)
- ✅ 固定大小,随机访问
- ✅ 类型安全

**示例**:
```rust,ignore,ignore
let device = DeviceDma::new(0xFFFFFFFF, &DMA_IMPL);

// 创建 100 个 u32 的 DMA 数组
let mut dma_array = device.array_zero_with_align::<u32>(100, 64, DmaDirection::FromDevice)
    .expect("Failed to allocate");

dma_array.set(0, 0x12345678);  // 写入(自动刷新缓存)
let value = dma_array.read(0); // 读取(自动失效缓存)

let dma_addr = dma_array.dma_addr(); // 获取 DMA 地址给硬件
```

**适用场景**:
- 网卡数据包缓冲区
- 音频采样缓冲区
- 图像帧缓冲区

---

### 场景 2: DMA 单值容器

**用途**:需要单个结构体的 DMA 缓冲区

**推荐**:`DBox<T>`

**特点**:
- ✅ 自动缓存同步(每次 `read`/`write`/`modify` 时)
- ✅ 适合配置寄存器、描述符等
- ✅ 类型安全

**示例**:
```rust,ignore,ignore
#[derive(Default)]
struct Descriptor {
    addr: u64,
    length: u32,
    flags: u32,
}

let mut dma_desc = device.box_zero_with_align::<Descriptor>(64, DmaDirection::ToDevice)
    .expect("Failed to allocate");

dma_desc.modify(|d| d.length = 4096); // 修改(自动刷新缓存)
let desc = dma_desc.read();           // 读取(自动失效缓存)
```

**适用场景**:
- DMA 描述符
- 设备配置结构
- 状态寄存器

---

### 场景 3: 映射现有缓冲区

**用途**:将已存在的缓冲区映射用于 DMA

**推荐**:`SingleMap`

**特点**:
- ⚠️ **手动**缓存同步
- ✅ 临时映射,RAII 自动解映射
- ✅ 适用于栈分配或静态缓冲区

**示例**:
```rust,ignore,ignore
let mut buffer = [0u8; 4096];

// 映射现有缓冲区
let mapping = device.map_single_array(&buffer, 64, DmaDirection::ToDevice)
    .expect("Mapping failed");

// ⚠️ 重要:使用前必须手动同步缓存
mapping.confirm_write_all();  // 将 CPU 数据刷到内存
// ... DMA 传输 ...
mapping.prepare_read_all();   // 使 CPU 缓存失效,准备接收设备数据

let dma_addr = mapping.dma_addr();

// 映射在离开作用域时自动解除(不会自动同步缓存)
```

**适用场景**:
- 临时 DMA 操作
- 栈上的小缓冲区
- 重用已分配的内存

---

## API 方法目录

### 📦 创建方法

| 方法 | 用途 | 返回类型 | 缓存同步 |
|------|------|----------|----------|
| [`array_zero<T>(len, dir)`]#device-zeros | 创建默认对齐的 DMA 数组 | `DArray<T>` | 自动 |
| [`array_zero_with_align<T>(len, align, dir)`]#device-zeros | 创建指定对齐的 DMA 数组 | `DArray<T>` | 自动 |
| [`box_zero<T>(align, dir)`]#device-zeros | 创建默认对齐的 DMA Box | `DBox<T>` | 自动 |
| [`box_zero_with_align<T>(align, dir)`]#device-zeros | 创建指定对齐的 DMA Box | `DBox<T>` | 自动 |
| [`map_single_array<T>(buff, align, dir)`]#device-maps | 映射现有缓冲区 | `SArrayPtr<T>` | **手动** |

### 🔍 访问方法(DArray)

| 方法 | 用途 | 缓存同步 | 返回值 |
|------|------|----------|--------|
| [`read(index)`]#darray-access | 读取元素 | 自动失效 | `Option<T>` |
| [`set(index, value)`]#darray-access | 写入元素 | 自动刷新 | `()` |
| [`copy_from_slice(slice)`]#darray-access | 批量复制 | 自动刷新整个范围 | `()` |

### 🔍 访问方法(DBox)

| 方法 | 用途 | 缓存同步 | 返回值 |
|------|------|----------|--------|
| [`read()`]#dbox-access | 读取值 | 自动失效 | `T` |
| [`write(value)`]#dbox-access | 写入值 | 自动刷新 | `()` |
| [`modify(f)`]#dbox-access | 修改值(read-modify-write) | 先失效后刷新 | `()` |

### 🔄 同步方法(SingleMap)

| 方法 | 用途 | 适用方向 |
|------|------|----------|
| [`prepare_read_all()`]#singlemap-sync | 使 CPU 缓存失效 | `FromDevice`, `Bidirectional` |
| [`confirm_write_all()`]#singlemap-sync | 刷新 CPU 缓存到内存 | `ToDevice`, `Bidirectional` |

### 📊 信息方法

| 方法 | 用途 | 返回值 |
|------|------|--------|
| [`dma_addr()`]#info-methods | 获取 DMA 地址 | `DmaAddr` |
| [`len()`]#info-methods | 获取数组长度 | `usize` |

---

## 完整示例

### 示例 1: 网卡接收缓冲区

```rust,ignore,ignore
use dma_api::{DeviceDma, Direction};

// 创建 DMA 设备
let device = DeviceDma::new(0xFFFFFFFF, &DMA_IMPL);

// 分配接收缓冲区(1500 字节数据包)
let mut rx_buffer = device.array_zero_with_align::<u8>(1500, 64, DmaDirection::FromDevice)
    .expect("Failed to allocate RX buffer");

// 配置网卡使用这个 DMA 地址
let dma_addr = rx_buffer.dma_addr();
nic.set_rx_address(dma_addr.as_u64());

// ... 网卡接收数据 ...

// 读取数据(自动使 CPU 缓存失效)
let data = rx_buffer.read(0).unwrap();
```

### 示例 2: DMA 描述符配置

```rust,ignore,ignore
#[derive(Default)]
struct DmaDescriptor {
    buffer_addr: u64,
    length: u32,
    control: u32,
}

// 分配描述符
let mut desc = device.box_zero_with_align::<DmaDescriptor>(64, DmaDirection::ToDevice)
    .expect("Failed to allocate descriptor");

// 配置描述符(自动刷新缓存)
desc.write(DmaDescriptor {
    buffer_addr: 0x12345000,
    length: 4096,
    control: 0x01,
});

// 修改描述符(自动失效 → 修改 → 刷新)
desc.modify(|d| d.length = 2048);

// 获取 DMA 地址给硬件
let desc_addr = desc.dma_addr();
```

### 示例 3: 临时映射栈缓冲区

```rust,ignore,ignore
// 栈上的临时缓冲区
let mut temp_buf = [0u8; 256];

// 映射用于 DMA 写入
let mapping = device.map_single_array(&temp_buf, 64, DmaDirection::ToDevice)
    .expect("Failed to map");

// 准备数据写入设备
temp_buf[0] = 0xAA;
temp_buf[1] = 0xBB;

// ⚠️ 必须手动刷新缓存
mapping.confirm_write_all();

// ... 启动 DMA 传输 ...

// 映射在作用域结束时自动解映射
```

---

## 缓存同步详解

### 自动同步(DArray 和 DBox)

`DArray<T>` 和 `DBox<T>` 在以下操作时**自动**处理缓存同步:

| 操作 | 缓存同步行为 |
|------|--------------|
| `DArray::set(i, v)` | 写入后刷新单个元素 |
| `DArray::read(i)` | 读取前失效单个元素 |
| `DArray::copy_from_slice(s)` | 写入后刷新整个范围 |
| `DBox::write(v)` | 写入后刷新 |
| `DBox::read()` | 读取前失效 |
| `DBox::modify(f)` | 失效 → 执行闭包 → 刷新 |

**优点**:使用简单,不会出错
**缺点**:频繁同步可能影响性能

### 手动同步(SingleMap)

`SingleMap` **不会**在 Drop 时自动同步缓存,必须显式调用:

```rust,ignore,ignore
let mapping = device.map_single_array(&buffer, 64, DmaDirection::ToDevice)?;

// 写入前准备
mapping.confirm_write_all();  // 将 CPU 数据刷到内存

// ... DMA 传输 ...

// 读取前准备
mapping.prepare_read_all();   // 使 CPU 缓存失效

// Drop 时只会解除映射,不会自动同步
```

**为什么这样设计**:
- 与 Linux DMA API 语义一致
- 让用户精确控制缓存同步时机
- 避免不必要的缓存操作

### 缓存同步规则

根据 DMA 方向选择同步操作:

| DMA 方向 | 写入设备前 | 读取设备后 |
|----------|-----------|-----------|
| `ToDevice` | `confirm_write_all()`| ❌ 无需操作 |
| `FromDevice` | ❌ 无需操作 | `prepare_read_all()`|
| `Bidirectional` | `confirm_write_all()`| `prepare_read_all()`|

---

## 完整 API 参考

### 核心类型

#### `DeviceDma`

DMA 设备操作接口。

**构造函数**:
```rust,ignore
pub fn new(dma_mask: u64, osal: &impl DmaOp) -> Self
```
- **用途**:创建 DMA 设备实例
- **参数**  - `dma_mask`: 设备可寻址的地址掩码(如 `0xFFFFFFFF`  - `osal`: 实现 `DmaOp` trait 的操作系统抽象层
- **示例**```rust,ignore
let device = DeviceDma::new(0xFFFFFFFF, &DMA_IMPL);
```

#### <a name="device-zeros"></a>数组创建方法

```rust,ignore
pub fn array_zero<T: Sized + Default>(
    &self,
    len: usize,
    direction: DmaDirection,
) -> Result<DArray<T>, DmaError>

pub fn array_zero_with_align<T: Sized + Default>(
    &self,
    len: usize,
    align: usize,
    direction: DmaDirection,
) -> Result<DArray<T>, DmaError>
```
- **用途**:创建 DMA 可访问的数组,初始化为零
- **参数**  - `len`: 数组长度(元素个数)
  - `align`: 对齐字节数(`array_zero` 默认为 `core::mem::align_of::<T>()`  - `direction`: DMA 传输方向
- **返回**`DArray<T>` 容器
- **缓存同步**:自动
- **示例**```rust,ignore
let array = device.array_zero_with_align::<u32>(100, 64, DmaDirection::ToDevice)?;
```

#### <a name="device-zeros"></a>Box 创建方法

```rust,ignore
pub fn box_zero<T: Sized + Default>(
    &self,
    direction: DmaDirection,
) -> Result<DBox<T>, DmaError>

pub fn box_zero_with_align<T: Sized + Default>(
    &self,
    align: usize,
    direction: DmaDirection,
) -> Result<DBox<T>, DmaError>
```
- **用途**:创建 DMA 可访问的单值容器,初始化为零
- **参数**  - `align`: 对齐字节数(`box_zero` 默认为 `core::mem::align_of::<T>()`  - `direction`: DMA 传输方向
- **返回**`DBox<T>` 容器
- **缓存同步**:自动
- **示例**```rust,ignore
let box_val = device.box_zero_with_align::<MyStruct>(64, DmaDirection::Bidirectional)?;
```

#### <a name="device-maps"></a>映射方法

```rust,ignore
pub fn map_single_array<T: Sized>(
    &self,
    buff: &[T],
    align: usize,
    direction: DmaDirection,
) -> Result<SArrayPtr<T>, DmaError>
```
- **用途**:将现有缓冲区映射为 DMA 可访问
- **参数**  - `buff`: 要映射的缓冲区切片
  - `align`: 对齐字节数
  - `direction`: DMA 传输方向
- **返回**`SArrayPtr<T>` 映射句柄
- **缓存同步****手动**(必须使用 `to_vec()``copy_from_slice()`- **示例**```rust,ignore
let buf = [0u8; 4096];
let mapping = device.map_single_array(&buf, 64, DmaDirection::ToDevice)?;
```

---

#### `DArray<T>`

DMA 可访问的数组容器,支持自动缓存同步。

##### <a name="darray-access"></a>访问方法

```rust,ignore
pub fn read(&self, index: usize) -> Option<T>
```
- **用途**:读取数组中指定索引的元素
- **缓存同步**:读取前自动失效
- **返回**`Some(T)` 如果索引有效,否则 `None`

```rust,ignore
pub fn set(&mut self, index: usize, value: T) -> Option<()>
```
- **用途**:写入数组中指定索引的元素
- **缓存同步**:写入后自动刷新
- **返回**`Some(())` 如果索引有效,否则 `None`

```rust,ignore
pub fn copy_from_slice(&mut self, src: &[T]) where T: Copy
```
- **用途**:从 slice 复制数据到数组
- **缓存同步**:写入后自动刷新整个范围
- **要求**`src.len() <= self.len()`

##### <a name="info-methods"></a>信息方法

```rust,ignore
pub fn dma_addr(&self) -> DmaAddr
```
- **用途**:获取 DMA 地址,用于配置硬件
- **返回**:DMA 地址

```rust,ignore
pub fn len(&self) -> usize
```
- **用途**:获取数组长度
- **返回**:元素个数

---

#### `DBox<T>`

DMA 可访问的单值容器,支持自动缓存同步。

##### <a name="dbox-access"></a>访问方法

```rust,ignore
pub fn read(&self) -> T
```
- **用途**:读取存储的值
- **缓存同步**:读取前自动失效
- **返回**:存储的值

```rust,ignore
pub fn write(&mut self, value: T)
```
- **用途**:写入新值
- **缓存同步**:写入后自动刷新

```rust,ignore
pub fn modify<F: FnOnce(&mut T)>(&mut self, f: F)
```
- **用途**:修改值(read-modify-write 模式)
- **缓存同步**:读取前失效,写入后刷新
- **示例**```rust,ignore
dma_box.modify(|v| v.field += 10);
```

##### 信息方法

```rust,ignore
pub fn dma_addr(&self) -> DmaAddr
```
- **用途**:获取 DMA 地址,用于配置硬件
- **返回**:DMA 地址

---

#### `SArrayPtr<T>`

映射单个连续内存区域的 DMA 数组,RAII 风格自动清理。

**注意**:此类型提供手动缓存同步控制,与 `DArray<T>` 不同,它不会在每次访问时自动同步缓存。

##### 访问方法

```rust,ignore
pub fn read(&self, index: usize) -> Option<T>
```
- **用途**:读取指定索引的元素(**不自动**同步缓存)
- **返回**`Some(T)` 如果索引有效,否则 `None`
- **注意**:读取前需手动使用 `to_vec()` 方法

```rust,ignore
pub fn set(&mut self, index: usize, value: T)
```
- **用途**:写入指定索引的元素(**不自动**同步缓存)
- **注意**:写入后需使用 `copy_from_slice()` 刷新缓存

```rust,ignore
pub fn copy_from_slice(&mut self, src: &[T])
```
- **用途**:从 slice 复制数据到数组
- **缓存同步**:写入后自动刷新整个范围

```rust,ignore
pub fn to_vec(&self) -> Vec<T>
```
- **用途**:将整个数组转换为 Vec
- **缓存同步**:读取前自动失效整个范围

##### 信息方法

```rust,ignore
pub fn dma_addr(&self) -> DmaAddr
```
- **用途**:获取 DMA 地址,用于配置硬件
- **返回**:DMA 地址

```rust,ignore
pub fn len(&self) -> usize
```
- **用途**:获取数组长度(元素个数)
- **返回**:元素个数

```rust,ignore
pub fn is_empty(&self) -> bool
```
- **用途**:检查数组是否为空
- **返回**:如果长度为 0 返回 `true`

---

### 类型定义

#### `DmaDirection`

DMA 传输方向枚举:

```rust,ignore
pub enum DmaDirection {
    ToDevice,       // DMA_TO_DEVICE: CPU 写入,设备读取
    FromDevice,     // DMA_FROM_DEVICE: 设备写入,CPU 读取
    Bidirectional,  // DMA_BIDIRECTIONAL: 双向传输
}
```

#### `DmaError`

DMA 操作错误类型:

```rust,ignore
pub enum DmaError {
    NoMemory,                           // DMA 分配失败
    LayoutError(LayoutError),           // 无效的内存布局
    DmaMaskNotMatch { addr, mask },     // DMA 地址超出设备掩码
    AlignMismatch { required, address }, // 地址对齐不满足要求
    NullPointer,                        // 提供了空指针
    ZeroSizedBuffer,                    // 零大小缓冲区不能用于 DMA
}
```

#### `DmaAddr`

DMA 地址类型:

```rust,ignore
pub struct DmaAddr(u64);

impl DmaAddr {
    pub fn as_u64(&self) -> u64;  // 转换为 u64
    pub fn checked_add(&self, rhs: u64) -> Option<Self>;  // 安全加法
}
```

---

### Linux 等价 API

| Rust API | Linux Equivalent |
|----------|------------------|
| `DeviceDma::map_single_array()` | `dma_map_single()` |
| `SArrayPtr<T>::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 操作通常需要对齐到特定的边界:

- 常见对齐值:64、128、256、512、4096
- `array_zero_with_align()` / `box_zero_with_align()``align` 参数指定对齐字节数
- `map_single_array()``align` 参数也指定对齐要求
- 确保返回的 DMA 地址满足对齐要求,否则返回 `DmaError::AlignMismatch`

### DMA Mask

`DeviceDma::new()` 的 `dma_mask` 参数指定设备可寻址的地址范围:

- `0xFFFFFFFF` (32 位设备,最多 4GB)
- `0xFFFFFFFFFFFFFFFF` (64 位设备,全地址空间)
- 其他值根据设备硬件限制
- 如果分配的 DMA 地址超出掩码范围,返回 `DmaError::DmaMaskNotMatch`