一、PIO 和 DMA 的定义与区别

1. PIO (Programmed I/O,程序控制 I/O)

定义: CPU 直接负责数据传输。当设备需要读/写时,CPU 用普通的 load/store 指令访问设备寄存器,把数据一个字节(或一批字)搬进搬出。


特点

  • 实现简单,硬件便宜。
  • CPU 开销大:CPU 忙于数据搬运,几乎是“苦力活”,占用大量指令周期。
  • 适合低速设备(如键盘、鼠标、串口 9600bps)。
  • 响应延迟低:CPU 直接参与搬运,不需要复杂控制,适合实时性要求高但数据量小的场景。

引入缓冲区(FIFO buffer)

很多 PIO 设备(如 UART、早期硬盘控制器)内部会带一个 FIFO 缓冲区(几字节到几十字节不等):

  • CPU 一次可以写多个字节到 FIFO,硬件再慢慢从 FIFO 里把数据发送出去。
  • 这样减少了 CPU 与设备交互的次数,性能比“单字节 PIO”要好得多。
  • 例如:UART 16550 芯片有 16 字节 FIFO,可以一次性写多个字符,而不是每个字节都要等硬件发完。

即使有缓冲区,仍然存在的问题

  • CPU 仍然是主动的:CPU 依然要一批批把数据搬到 FIFO,直到整个数据块写完。
    • 例如要传 4KB 数据,FIFO 只有 16 字节 → CPU 要循环写 256 次寄存器
  • 吞吐量受限:CPU 时间被消耗在 I/O 搬运上,无法并行处理别的计算。
  • 扩展性差:当数据量非常大(如磁盘、网卡、显卡内存传输),即使有 FIFO,CPU 也会很快成为瓶颈。

举例

  • uartputc() 在 xv6 里就是典型的 PIO:CPU 把要发的字节写入 UART 的数据寄存器。UART 硬件再去发送,可能带一个小 FIFO。
  • 嵌入式系统的 GPIO、低速串口、简单 I²C/SPI 外设,大多还是 PIO 方式。

🔑 一句话总结: 带缓冲区的 PIO = “批量版 PIO”,能减少一些 CPU 的负担,但本质问题(CPU 仍然负责搬运)没变;一旦数据量大,就会拖慢系统性能 → 这时必须用 DMA 来解放 CPU。


2. DMA (Direct Memory Access,直接内存访问)

定义:由 DMA 控制器(硬件)负责在 内存 ↔ 设备 之间搬运数据,CPU 只需要设置好“任务参数”(源地址、目标地址、传输大小等),然后让 DMA 去跑。

传输完成后,DMA 控制器通常会给 CPU 发一个中断,告诉它“任务完成”。

特点

  • CPU 负担小:CPU 不需要每个字节都搬,只需要发命令、然后处理结果。
  • 适合高速、大批量数据传输(例如网卡收发包、硬盘读写、显卡纹理传输)。
  • 需要额外的 DMA 硬件。
  • 支持异步传输,CPU 可以并行处理其他任务,提高系统整体效率。
  • 某些 DMA 控制器还支持 scatter-gather(分散-聚集)模式,能处理非连续内存块。

举例

  • 网卡(NIC):收到一个以太网帧时,DMA 会把数据直接写进内存里的缓冲区,CPU 只在包到达后被中断唤醒。
  • GPU 上传纹理时,也会走 DMA。
  • 现代硬盘(如 SATA、NVMe)数据传输基本都依赖 DMA。

3. 核心区别总结

特性 PIO DMA
数据搬运者 CPU DMA 控制器
CPU 开销 高,需要循环读写 低,只需设置参数和处理中断
适合设备 低速、简单设备 高速、大数据吞吐设备
硬件需求 简单,寄存器就行 需要 DMA 控制器支持
延迟 小数据可快(少配置) 初始配置略复杂,但适合大批传输
并发能力 差,CPU被占用 好,CPU可并行做其他任务

补充说明

  • 在现代操作系统和硬件中,DMA 已成为主流,尤其是在数据吞吐量要求高的场景(如磁盘、网络、显卡等)。
  • 某些嵌入式或实时系统,仍然会用 PIO 以获得更低的延迟和更高的可控性。
  • DMA 的使用需要注意内存一致性和安全性(如防止 DMA 攻击),通常操作系统会对 DMA 访问做严格管理。