计算机体系结构 29:CPU 怎样与设备交换数据

核心问题

设备完成一次 DMA 后,CPU 为什么还不能立刻把缓冲区当成普通内存读取?数据移动只是传输链路的一部分。驱动还要处理 DMA 地址映射、缓冲区所有权、完成通知和同步;IOMMU 则可能在设备地址与物理内存之间再加一层翻译和权限检查。

本篇只验证一条六状态协议,不连接真实设备,不产生总线事务,也不测中断延迟。附件:29-dma.json。

范围与证据等级

证据等级为功能执行。模型依次进入 cpu_owned、mapped_for_device、device_owned、completion_visible、synced_for_cpu、cpu_consumed。这些状态用于检查“谁此时可以访问缓冲区”,不能证明某个平台的 DMA 一致性实现,更不能称作真实设备传输。

Linux Dynamic DMA Mapping Guide 区分 CPU 虚拟地址、CPU 物理地址和设备使用的 DMA 地址。驱动应使用 DMA API 建立映射,不能把 CPU 指针直接交给设备。streaming mapping 的同步要求还取决于数据方向和平台一致性规则。

核心案例:完成通知早于 CPU 消费

描述符由 CPU 填好并映射,所有权随后交给设备。设备写完数据并报告 completion,只说明设备侧工作到达约定完成点;模型仍要求 synced_for_cpu,然后才允许 cpu_consumed。如果跳过同步状态,模型拒绝 CPU 消费。

MMIO doorbell、中断或轮询负责推进控制状态,DMA 负责搬运数据。两条路径可能由不同的互联和排序规则承载。驱动必须按设备与平台文档放置 barrier 和 DMA sync,不能用“中断已经到了”替代缓冲区可见性的证明。

模式:数据通路与所有权通路分开记账

1
可消费 = 传输完成 && 所有权归还 && 平台要求的同步完成

网络收包、存储队列和加速器命令缓冲区都能复用这一模式。变动的是设备协议、DMA 一致性属性和通知机制,三个条件本身不能省略。

验收结果

python3 examples/computer-architecture/run_batch.py 29-33 退出 0,并生成六个有序状态。输出显式保留 real_device_transfer=false。验收只确认协议状态完整、边界可追踪;当前没有 PCIe 设备、IOMMU 映射日志、真实中断或 DMA 带宽数据。

练习

若设备只读缓冲区,CPU 在交出所有权后又修改描述符,可能破坏哪个协议条件?

画出轮询替代中断后的状态图。哪些状态不变,哪一条控制边改变?

模式速查

现象 应检查的状态 不能直接下的结论
completion 已到 设备完成点、所有权、同步 CPU 必然可安全消费
地址可由 CPU 访问 DMA 映射与设备地址 设备能使用同一地址
模型状态通过 协议顺序 真实 DMA 已发生

一手参考资料