设备驱动 · 外设 · 操作系统 · 硬件 · CPU
整体交互原理

上一篇讲了"机制"(MMIO、DMA、中断)。这一篇把它们串成一张网:从应用按下 read(),到数据经由五方之手回到用户,完整的协作过程与分工边界。

分层架构 请求向下·完成向上 生命周期 控制面/数据面 通信矩阵

1五方角色:谁负责什么(边界)

整体交互之所以复杂,是因为五方各有"责任田",谁也不该越界。先看清边界,后面的协作才不乱。

应用 App 用户态·提需求 操作系统内核 调度·抽象·安全 设备驱动 懂硬件·翻译 硬件控制器 寄存器+缓冲+DMA (网卡芯片/磁盘控制等) 外设 Peripheral 真正干活:收发信号 网线/磁盘盘片/键帽 CPU + 内存 执行驱动代码·数据落点 (运行 OS/驱动的内核态)

🧑 应用 App

用户态。只知道"我想要数据",用 read/open/write 表达,不碰硬件、不知设备型号。

🛡️ 操作系统

内核态。统一抽象("一切皆文件")、权限检查、进程调度、缓冲管理,是应用与驱动的"中间商 + 保安"。

🔧 设备驱动

住在内核态、紧贴硬件。把 OS 的通用指令翻译成"该设备寄存器的一串特定操作"。一款硬件一份驱动。

⚙️ 硬件控制器

设备自带芯片。寄存器和缓冲区在此;执行驱动命令、负责 DMA 搬数据、就绪后发中断。

🔌 外设

真正产生/消费数据的物理实体:网线信号、磁盘盘片、键帽。它"听不懂"CPU,只跟控制器对话。

🧠 CPU + 内存

CPU 在内核态执行驱动与 OS 代码;内存是数据最终落脚点(DMA 直接写这里)。

🧭 一条铁律:应用绝不直接碰驱动或硬件。所有请求都必须经 OS 这层" Syscall 门"进出内核。这是安全隔离的基石,也是理解整体交互的入口。

2分层架构:请求向下、完成向上

把五方摞成五层,就得到经典的 I/O 软件栈。请求总是一层一层"向下"递交,而数据与完成信号则"向上"回流。点任意一层,看它在交互里的职责。

① 应用程序(用户态) ② 操作系统内核(系统调用 / I/O 子系统) ③ 设备驱动(翻译硬件命令) ④ 硬件控制器(寄存器 / DMA) ⑤ 外设(物理信号 / 数据) 请求向下 完成向上

👆 点击任意一层查看职责。整体规律:请求自上而下传递,数据/中断自下而上回流。两条箭头方向相反,正是"调用"与"返回"的写照。

点击上图查看每一层在"向下递交 / 向上回流"中的具体角色。

3I/O 请求的完整生命周期

把"一次 read"拆开看,会经过 递交 → 排队 → 下发 → 硬件执行 → 中断 → 唤醒 → 返回 七个阶段。下面用分步动画演示,并同步展示发起进程的状态变化

运行 Running 阻塞 Blocked 就绪 Ready

✅ 留意第 5 步之后进程从"运行"变"阻塞"——这正是 I/O 不浪费 CPU 的核心:等硬件的这段时间,CPU 去跑别的进程了,直到中断把它重新唤醒。

4控制面 vs 数据面:统一视角

把所有交互按"性质"一分为二,瞬间清晰:控制面是"下命令"(小而频繁,走寄存器/中断),数据面是"搬数据"(量大,靠 DMA 绕开 CPU)。

🎛️ 控制面(Control Plane)

  • 内容:启动/停止、设置模式、读状态、中断号
  • 通道:CPU ↔ 控制器 的寄存器(MMIO)IRQ 中断线
  • 特点:数据量极小、必须 CPU 亲自参与
  • 类比:项目经理发的"开工/验收"指令

📦 数据面(Data Plane)

  • 内容:真正的用户数据(一个包、一块扇区)
  • 通道:外设 ↔ 控制器 ↔ 内存(DMA)不经 CPU
  • 特点:体量巨大、由 DMA 控制器代劳
  • 类比:工人把货直接搬进仓库,不惊动经理
CPU 控制面:CPU ↔ 控制器 寄存器 + IRQ(小、CPU 亲自) 数据面:外设 → 控制器 → 内存 DMA(大、绕开 CPU) 硬件控制器 + 外设
💡 为什么这个区分重要?因为优化方向截然不同:控制面要"低延迟、确定性"(中断快);数据面要"高吞吐、零拷贝"(DMA、绕过 CPU)。现代网卡甚至把整个数据面 offload 到硬件(TSO/LRO),CPU 只管控制面。

5通信频道矩阵:两两之间怎么对话

五方并非两两直连,而是走固定的"频道"。点击右侧任一频道卡片,左侧图中对应的连线会高亮。

应用 OS 驱动 控制器 CPU/内存 外设
📌 注意几个"无直接频道":应用↔外设、应用↔控制器都不存在直连——都必须经 OS 与驱动。这正是"用户态不能乱碰硬件"的安全体现。

6两个真实案例:键盘 vs 磁盘

同样走五层,不同设备差异巨大。切换查看:键盘(极简、每键中断、无 DMA)与磁盘(DMA、I/O 调度、寻道)各自的端到端过程。

键盘为何不用 DMA?

数据量太小(每秒几个字节),DMA 的"建立描述符"开销反而划不来。直接用中断把单个扫描码塞进缓冲区即可。

磁盘为何必须 DMA + 调度?

一次读就是几百 KB~几 MB,且机械盘有寻道延迟。OS 的 I/O 调度器会合并、排序请求以减少寻道,DMA 负责后续大块搬运。

7阻塞 vs 异步:进程何时醒来

同样是"等 I/O",进程可以选择阻塞(睡到数据来)异步(先去干别的,好了再通知我)。两种模式下五方的交互几乎一样,区别仅在 OS 如何处理发起进程。

🔒 阻塞 I/O(最常见)

调用 read() 后进程立刻进入阻塞态,从运行队列移除,CPU 转去跑别的进程。数据到了由中断唤醒,重新进入就绪→运行。

// 简单、直觉,但线程被"卡住"
char buf[1024];
int n = read(fd, buf, 1024); // 卡这里直到有数据
printf("%.*s", n, buf);

⚡ 异步 / 非阻塞 I/O

进程用 O_NONBLOCKio_uring/epollread 立即返回"暂无数据",进程继续干别的;OS 在中断完成后通过回调/事件通知它。

// 一个线程同时盯上千个连接
submit_read(io_uring, fd, buf);
do_other_work();            // 不阻塞
// 稍后 io_uring 告诉你"这块好了"
⚠️ 无论哪种,底层硬件交互完全一致:驱动下发命令、控制器 DMA 搬数据、完成后中断。区别只在"OS 把发起进程放在哪种状态、用何种方式回调"。理解这一点,就不会把"异步"误以为改变了硬件行为。

8一句话模型 & 与上一篇的衔接

应用提需求 → OS 管调度与安全 → 驱动翻译命令 → 控制器执行+DMA 搬数据 → 外设干活;
完成后中断沿原路向上回流,唤醒进程、数据返回。

控制面(CPU↔寄存器/IRQ)小而亲临,数据面(外设→内存 DMA)大而绕开 CPU。

📘 上一篇(机制篇)

深入"怎么做":MMIO/PMIO、DMA、中断、寄存器握手、网卡收包动画。是本文的"零件说明书"。

📗 本篇(架构篇)

讲清"谁和谁、按什么顺序"交互:五方边界、分层、生命周期、控制/数据面、通信矩阵。是上一篇的"装配总图"。

✅ 两篇合起来,你既有微观机制(寄存器、DMA、中断),又有宏观流程(从 read() 到数据回流)。如果再结合具体设备(键盘/磁盘/网卡/GPU)逐一看,就能真正打通"计算机组成 + OS + 网络"的底层认知。