先分清三个地址空间
CPU 虚拟地址供软件使用,系统物理地址描述内存位置,DMA 地址供设备使用。它们可能数值相同,也可能经过 IOMMU 或平台映射而完全不同。
01
三个地址空间分别服务谁
应用和驱动通常通过 CPU 虚拟地址访问内存;处理器页表把它转换为系统物理地址。设备则使用由 DMA 子系统返回的设备地址。
当平台没有额外转换时,DMA 地址有时可能与物理地址数值相近;一旦存在 IOMMU、总线窗口或设备寻址限制,这个假设就不再可靠。代码不应依赖偶然相等。
02
IOVA 如何连接设备与内存
驱动向操作系统提交一个缓冲区和传输方向,DMA 子系统建立设备可以使用的映射,并返回 DMA 地址。IOMMU 可以把该 IOVA 转换到一页或多页实际内存,同时执行访问权限检查。
映射只应覆盖当前操作需要的范围和时长。完成传输后释放映射,是避免失效地址继续被设备使用的重要部分。
03
为什么需要 Scatter/Gather
一个逻辑连续的网络包或文件缓冲区,在物理内存中可能由多段不连续页面组成。Scatter/Gather 列表向设备描述这些可传输片段,避免为了连续物理内存而进行额外复制。
Windows 的 map registers 和 Linux DMA API 都把这类地址转换交给平台 DMA 层。驱动应使用返回的列表和长度,而不是自行把 CPU 指针当作设备地址。
04
方向、所有权与缓存一致性
DMA 映射还包含传输方向和缓冲区所有权。CPU 与设备在错误时机同时修改同一缓冲区,或忽略平台缓存一致性要求,可能得到旧数据、部分更新或内存损坏。
正确实现会在提交设备前完成必要同步,在硬件完成后再把缓冲区交回软件,并保留可复核的错误与超时路径。
05
评审驱动时应检查什么
检查设备地址是否全部来自受支持的 DMA API,映射和取消映射是否配对,Scatter/Gather 长度是否受硬件限制约束,以及错误恢复后是否仍引用旧描述符。
日志应固定操作系统、IOMMU 状态、驱动、设备固件和硬件版本。单次传输成功只能证明一条路径工作,不能证明所有边界条件安全。
- 不把普通指针或未经映射的物理地址直接交给设备
- 不在设备仍拥有缓冲区时释放或复用内存
- 在映射失败、取消、超时和复位路径同样回收资源
FAQ
常见问题
01IOVA 一定不同于物理地址吗?
不一定。某些平台可能产生相同数值,但驱动必须把它视为独立的设备地址,不能依赖数值相等。
02应用程序的指针可以直接写进 DMA 描述符吗?
不可以这样假定。应用指针属于进程虚拟地址空间,必须经过操作系统和驱动的固定、授权与 DMA 映射流程。
03Scatter/Gather 是否会绕过 IOMMU?
不会。它描述多个可传输片段;每个设备地址仍应受平台 DMA 映射和权限控制。
04映射完成后可以永久复用 DMA 地址吗?
只有专门设计的长期一致性映射才有相应生命周期。流式映射在取消后不得继续使用。
SOURCES
