计算机体系结构 29:CPU 怎样与设备交换数据
计算机体系结构 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 已发生 |






