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

核心问题

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

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

范围与证据等级

附件:状态与反例、协议源码。

证据等级为功能执行。题设限定为非一致性平台上的 streaming DMA,设备写缓冲区后,CPU 消费前必须执行 sync_for_cpu。模型依次进入 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 填好并映射,题设 IOMMU 把 CPU 物理地址 0x1000 映射为设备 DMA 地址 0x9000;这两个数只是模型输入。所有权随后交给设备;设备向 DMA 地址写入值 42 并报告 completion。模型仍要求 synced_for_cpu,然后才允许 CPU 读到 42;跳过同步会被拒绝。

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

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

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

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

验收结果

python3 examples/computer-architecture/run_batch.py 29-33 退出 0;代码实际执行六次状态转换,拒绝交接前的读取和跳过同步后的读取,完成同步后读到设备写入的 42。输出保留 real_device_transfer=false。当前没有 PCIe 设备、IOMMU 映射日志、真实中断或 DMA 带宽数据。

练习

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

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

模式速查

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

一手参考资料