第7章 输入/输出组织(I/O 系统)
一、导读
1.1 本章学习目标
理解 I/O 系统在计算机中的角色:掌握 I/O 系统作为计算机与外部世界交互桥梁的核心功能,理解 I/O 设备与 CPU 和内存之间在速度、数据格式和工作方式上的巨大差异。
掌握 I/O 的编址与传输方式:理解 I/O 独立编址和内存映射编址两种方案,掌握程序控制 I/O、中断驱动 I/O 和 DMA 三种数据传输方式的工作原理和适用场景。
深入理解中断机制:掌握中断的分类、处理流程和优先级管理机制,理解中断在异步事件处理中的核心作用。
掌握 DMA 传输原理:理解 DMA 控制器如何管理外设与内存之间的数据传输,掌握周期窃取和块传输模式。
理解总线结构与标准:掌握总线仲裁和定时方式,了解 PCIe、USB、SATA 等主流总线标准的特点。
了解 I/O 软件结构:理解设备驱动程序的作用和 I/O 软件的分层组织方式。
1.2 为什么本章如此重要
I/O 系统是计算机系统中最复杂、最多样化的组成部分。与处理器和内存的标准化设计不同,I/O 设备种类繁多,从键盘鼠标到图形显示器,从硬盘到网络接口卡,每种设备都有独特的工作方式和通信协议。I/O 系统必须为所有设备提供统一接口,同时保证数据传输的正确性和效率。
从性能角度看,I/O 系统往往是整个系统的瓶颈。处理器速度每两年翻一番,但许多 I/O 设备的速度提升缓慢。当 CPU 等待 I/O 操作完成时,大量计算能力被浪费。中断驱动和 DMA 传输等高效 I/O 组织方式使 CPU 能在等待 I/O 时执行其他任务,显著提高系统利用率。
从系统设计的角度看,I/O 系统处于硬件和软件的交汇点。硬件层面需要设计接口电路和通信协议,软件层面需要编写设备驱动程序和管理 I/O 调度。理解 I/O 系统的工作原理对于开发设备驱动程序、优化 I/O 密集型应用和设计嵌入式系统都至关重要。
从用户体验角度看,I/O 系统是用户与计算机交互的唯一途径。无论是键盘输入、鼠标操作、屏幕显示还是网络通信,都通过 I/O 系统实现。I/O 系统的响应速度、可靠性和兼容性直接影响用户的使用体验。
1.3 核心问题引导
I/O 设备与 CPU/内存之间存在哪些差异?I/O 系统如何协调这些差异?
程序控制 I/O、中断驱动 I/O 和 DMA 三种方式各有什么优缺点?分别适用于什么场景?
中断是如何产生的?CPU 如何响应和处理中断?中断优先级如何管理?
DMA 传输如何在不占用 CPU 的情况下完成数据搬运?DMA 与 Cache 一致性有什么关系?
总线仲裁解决什么问题?常见的仲裁方式有哪些?
为什么现代高速 I/O 总线(如 PCIe)从并行转向串行?串行总线如何达到高带宽?
设备驱动程序的作用是什么?I/O 软件的分层结构如何简化设备管理?
二、核心概念详解
2.1 I/O 编址方式
CPU 与 I/O 设备之间的通信需要通过某种编址方式来标识不同的 I/O 设备或设备内部的寄存器。主要有两种编址方案。
I/O 独立编址(Isolated I/O)使用专门的 I/O 指令(如 IN 和 OUT)和独立的 I/O 地址空间来访问设备寄存器。I/O 地址空间与内存地址空间完全分离,CPU 通过不同的控制信号区分内存访问和 I/O 访问。x86 架构使用这种方案,提供 65536 个 8 位 I/O 端口。优点是 I/O 指令与内存访问指令分离,语义清晰。缺点是增加了专门的 I/O 指令和地址解码电路,且 I/O 地址空间有限。
内存映射 I/O(Memory-Mapped I/O)将设备寄存器映射到内存地址空间中,使用普通的内存访问指令(LOAD 和 STORE)来读写设备寄存器。CPU 不需要专门的 I/O 指令,任何可以访问内存的指令都可以访问设备。ARM、MIPS 等 RISC 架构普遍采用这种方案。优点是指令集简单、编程灵活,可以使用所有内存寻址模式访问设备。缺点是占用了宝贵的内存地址空间,且需要地址解码逻辑区分内存和设备访问。
在现代计算机中,内存映射 I/O 已成为主流选择。PCIe 总线使用内存映射方式暴露设备寄存器和内存区域。操作系统在启动时将各设备的寄存器映射到预定义的物理地址范围,设备驱动程序通过这些映射地址控制设备。
2.2 程序控制 I/O
程序控制 I/O(Programmed I/O, PIO)是最简单的 I/O 方式。CPU 通过执行程序直接控制数据传输的每一步。CPU 向设备发送命令,然后不断轮询(Polling)设备的状态寄存器,等待设备准备好数据,最后读取或写入数据。
PIO 的典型流程如下:CPU 向设备的命令寄存器写入读/写命令。然后进入一个循环,反复读取设备的状态寄存器,检查"就绪"位是否被置位。当设备准备好数据后,CPU 从设备的数据寄存器读取一个数据单元(如一个字节或一个字),并将其存入内存。对于大量数据的传输,这个过程需要重复多次。
PIO 的主要缺点是 CPU 利用率低。在等待设备准备数据的期间,CPU 被完全占用在轮询循环中,无法执行其他任务。对于慢速设备(如键盘),一次操作可能需要数毫秒,而 CPU 在此期间可以执行数百万条指令。PIO 只适用于数据传输量小或对延迟要求极高的场景。
PIO 的一个变体是忙等待(Busy Waiting),CPU 在等待期间执行空循环。另一种变体是轮询与任务切换结合,操作系统在轮询失败时切换到其他任务,稍后再回来检查设备状态。
2.3 中断驱动 I/O
中断驱动 I/O(Interrupt-Driven I/O)解决了 PIO 中 CPU 利用率低的问题。其核心思想是:CPU 向设备发出 I/O 命令后立即返回执行其他任务,当设备准备好数据时通过中断信号通知 CPU,CPU 暂停当前任务执行中断服务程序处理 I/O 事件,然后恢复原任务。
中断驱动 I/O 的流程如下:CPU 向设备发送读/写命令,然后继续执行其他任务。设备完成操作后,通过中断控制器向 CPU 发出中断请求。CPU 检测到中断请求后,保存当前上下文(程序计数器、寄存器等),跳转到对应的中断服务程序(ISR)。ISR 读取或写入设备数据,然后恢复 CPU 上下文,返回被中断的任务。
中断机制的关键组件包括:中断请求线(IRQ),设备通过它向 CPU 发出中断信号;中断控制器(如 8259A 或 APIC),负责收集、优先级排序和转发中断请求;中断向量表(IVT),存储每个中断源对应的 ISR 入口地址。
中断驱动 I/O 显著提高了 CPU 利用率,但仍有局限。对于每个数据单元的传输都需要一次中断,当传输大量数据时,中断处理的开销(上下文保存/恢复、ISR 执行)可能变得显著。例如,以 1MB/s 的速率传输数据,每次传输一个字节就需要每秒处理 100 万次中断,中断开销可能超过数据传输本身。
2.4 DMA 传输
DMA(Direct Memory Access,直接内存访问)技术允许外设在不需要 CPU 参与的情况下直接与内存交换数据。DMA 控制器(DMAC)接管总线控制权,在设备和内存之间直接传输数据块,完成后才通过中断通知 CPU。
DMA 传输的基本流程如下:CPU 向 DMA 控制器发送传输命令,指定源地址、目标地址和传输长度。CPU 随后继续执行其他任务。DMA 控制器向总线仲裁逻辑请求总线控制权,获得授权后接管总线。DMA 控制器在设备和内存之间直接传输数据,每次传输一个数据单元(一个字或一个 Cache 行)。传输完成后,DMA 控制器释放总线并向 CPU 发出中断通知。
DMA 的传输模式主要有两种。周期窃取(Cycle Stealing)模式中,DMA 控制器每传输一个数据单元就申请一次总线,传输完成后释放总线,让 CPU 有机会使用总线。这种模式对 CPU 的影响最小,但传输效率较低。块传输(Block Transfer)模式中,DMA 控制器一次获得总线控制权后连续传输整个数据块,直到传输完毕才释放总线。这种模式传输效率高,但会长时间阻塞 CPU 对内存的访问。
DMA 与 Cache 一致性是一个重要问题。当 DMA 将数据写入内存时,如果 CPU 的 Cache 中有该内存区域的旧副本,Cache 中的数据就与内存不一致。解决方案包括:DMA 传输时使相关 Cache 行无效(Cache Invalidation);使用不缓存的内存区域进行 DMA 传输;在 DMA 完成后由软件显式刷新 Cache。
2.5 总线结构
总线(Bus)是连接计算机各部件的共享通信通道。I/O 总线专门用于连接 CPU、内存和各种外设。总线的性能由带宽(单位时间传输的数据量)和延迟(从请求到响应的时间)决定。
总线按定时方式分为同步总线和异步总线。同步总线中,所有设备共享同一个时钟信号,数据传输在时钟边沿同步进行。同步总线设计简单、速度快,但所有设备必须运行在同一时钟频率下,且总线长度受时钟偏斜限制。异步总线中,设备之间通过握手信号(请求和应答)协调数据传输,不依赖共享时钟。异步总线允许不同速度的设备连接,但握手开销降低了传输效率。
总线按数据传输方式分为并行总线和串行总线。传统并行总线(如 PCI)使用多条数据线同时传输多个位。串行总线(如 PCIe、USB 3.0)使用少量线路逐位传输数据。现代高速总线普遍采用串行方式,因为串行链路可以达到极高的信号频率(数 GHz),通过多通道聚合实现高带宽,同时避免了并行总线在高频下的信号串扰和同步问题。
总线仲裁解决多个设备同时请求总线使用权时的冲突。集中式仲裁使用一个中央仲裁器,根据优先级或轮转策略决定哪个设备获得总线。分布式仲裁中,各设备通过分布式协议自行协商总线使用权。PCIe 使用点对点连接和交换机(Switch)结构,每个设备拥有专用的链路,从根本上消除了总线争用问题。
2.6 I/O 软件结构
I/O 软件的目标是向应用程序提供简洁、统一的设备访问接口,同时隐藏硬件的复杂性。I/O 软件通常采用分层结构,从下到上包括:中断处理程序、设备驱动程序、设备无关软件层和用户空间 I/O 库。
中断处理程序是最底层的 I/O 软件,负责响应硬件中断。它保存上下文、读取设备状态、执行必要的快速处理(如将数据从设备寄存器复制到缓冲区),然后恢复上下文返回。中断处理程序必须尽可能短小快速,复杂的处理推迟到下半部(Bottom Half)或工作队列中执行。
设备驱动程序是特定设备的软件接口,封装了设备的所有硬件细节。每个设备类型对应一个驱动程序,向上层提供标准化的操作接口(如 open、read、write、close)。驱动程序负责初始化设备、管理设备状态、处理错误和中断。
设备无关软件层提供与具体设备无关的通用功能,如缓冲区管理、错误处理、安全检查和资源分配。这一层使得上层应用程序不需要关心底层设备的具体类型和特性。
三、深入分析与讨论
3.1 中断机制的深入设计
中断系统的设计需要处理多个复杂问题。中断优先级管理确保重要的中断优先得到处理。在嵌套优先级方案中,高优先级中断可以打断正在执行的低优先级 ISR,形成中断嵌套。优先级可以通过硬件(如中断控制器的优先级编码器)或软件(如中断屏蔽寄存器)实现。
中断亲和性(Interrupt Affinity)是多处理器系统中的高级特性。操作系统可以将特定中断源绑定到特定的 CPU 核心上处理,避免中断在不同核心之间迁移带来的 Cache 失效开销。合理的亲和性设置可以显著提高 I/O 密集型应用的性能。
中断合并(Interrupt Coalescing)是减少中断开销的技术。网络设备在高流量时可能每秒产生数百万次中断,中断处理开销严重影响性能。中断合并将多个中断事件合并为一次处理——设备或驱动程序等待积累一定数量的事件或经过一定时间后再触发一次中断。这减少了中断次数,但增加了单个事件的响应延迟。
消息信号中断(MSI, Message Signaled Interrupt)是现代总线(如 PCIe)使用的中断机制。与传统的中断线不同,MSI 通过向特定的内存地址写入数据来触发中断。MSI 的优势包括:不需要物理中断线、支持更多中断向量(每个设备可以有多个 MSI 中断)、中断可以路由到特定的 CPU 核心。
3.2 现代 I/O 总线技术
PCIe(Peripheral Component Interconnect Express)是现代计算机中最主要的扩展总线标准。PCIe 使用高速串行点对点连接,每个连接(Lane)由一对差分信号线组成,支持全双工通信。PCIe 的版本不断演进:PCIe 1.0 每通道单向带宽为 250MB/s,PCIe 4.0 达到每通道约 2GB/s,PCIe 5.0 进一步翻倍到约 4GB/s。多个通道可以聚合(x1、x4、x8、x16),一个 x16 的 PCIe 5.0 插槽可提供约 64GB/s 的双向带宽。
PCIe 的架构基于分层协议:事务层处理读写请求和中断消息,数据链路层负责数据包的分装、校验和流量控制,物理层管理串行链路的电气特性。PCIe 设备通过配置空间暴露设备信息和内存/IO 资源,操作系统在启动时枚举总线上的所有设备并分配资源。
USB(Universal Serial Bus)是最普及的外部设备接口。USB 采用主从架构,主机控制所有通信。USB 3.2 的传输速率可达 20Gbps,USB4 基于 Thunderbolt 协议可达 40Gbps。USB 支持四种传输类型:控制传输(设备配置)、批量传输(大数据可靠传输)、中断传输(小数据低延迟传输)和等时传输(实时流媒体)。USB Type-C 接口支持正反插拔、高功率充电和多种替代协议(如 DisplayPort)。
3.3 I/O 性能优化策略
I/O 性能优化是系统设计中的重要课题。缓冲(Buffering)技术在内存中设置数据缓冲区,平滑生产者与消费者之间的速度差异。磁盘操作系统的写缓冲区将多个小的写操作合并为大的顺序写,显著提高磁盘利用率。
预取(Prefetching)技术预测未来的 I/O 请求并提前将数据加载到缓冲区。磁盘预读(Read-Ahead)在读取一个数据块时同时读取后续的几个块,利用磁盘顺序访问远快于随机访问的特性。网络协议栈也使用预取技术,在应用层请求数据之前就开始从网卡接收数据。
I/O 调度算法决定多个 I/O 请求的执行顺序。磁盘调度算法如电梯算法(Elevator/SCAN)按磁道位置排序请求,减少磁头移动距离。现代 SSD 的 I/O 调度则更加简单,因为 SSD 没有机械运动部件,随机访问和顺序访问的性能差异很小。
四、实践案例
4.1 案例分析:键盘输入的完整处理流程
当用户按下键盘上的一个键时,数据经过以下步骤到达应用程序。
首先,键盘硬件检测到按键事件,将按键的扫描码(Scan Code)存入键盘内部的缓冲区,然后通过中断请求线(或 USB 中断传输)通知 CPU。对于传统的 PS/2 键盘,这会触发 IRQ 1 中断;对于 USB 键盘,主机控制器定期轮询设备或使用中断传输接收数据。
CPU 响应中断,保存当前上下文,跳转到键盘中断服务程序。ISR 从键盘控制器的数据端口读取扫描码,将其转换为按键码(Key Code),然后放入操作系统的键盘缓冲区。ISR 完成后恢复上下文,返回被中断的任务。
操作系统的键盘驱动程序从缓冲区取出按键码,根据当前的键盘布局(如 US QWERTY)将其转换为字符码。如果同时按下了 Shift 或 Ctrl 等修饰键,驱动程序进行相应的转换。最终的字符被放入终端的行缓冲区。
应用程序通过系统调用(如 read())从终端缓冲区读取字符。如果缓冲区为空,应用程序可能被阻塞(挂起),直到有新字符到达。当字符可用时,操作系统将字符从内核缓冲区复制到应用程序的用户空间缓冲区,应用程序继续处理。
这个例子展示了 I/O 系统的完整层次结构:硬件中断、ISR、设备驱动、操作系统 I/O 子系统和系统调用接口。每一层都为上层提供更高级别的抽象,最终使应用程序能够以简单的方式获取用户输入。
4.2 案例分析:DMA 在磁盘读写中的应用
考虑一个从磁盘读取 4KB 数据到内存的场景。使用 DMA 传输的流程如下。
首先,CPU 向磁盘控制器发送读命令,指定要读取的磁盘扇区号和数据长度。同时,CPU 配置 DMA 控制器:设置目标内存地址、传输方向和传输长度(4KB)。配置完成后,CPU 返回执行其他任务。
磁盘控制器开始机械操作:移动磁头到目标磁道,等待目标扇区旋转到磁头下方。当数据开始从磁盘表面读出时,磁盘控制器将数据暂存到内部缓冲区。
DMA 控制器向总线仲裁逻辑请求总线控制权。获得授权后,DMA 控制器从磁盘控制器的数据缓冲区读取数据,通过总线直接写入内存的目标地址。在周期窃取模式下,每传输一个字就释放一次总线;在块传输模式下,连续传输整个 4KB 数据块。
传输完成后,DMA 控制器释放总线并向 CPU 发出中断。CPU 响应中断,磁盘 ISR 检查传输状态(是否成功、是否有错误),然后通知等待数据的进程。
在这个流程中,CPU 只参与了初始配置和最终的中断处理两个阶段,中间的数据传输完全由 DMA 控制器和磁盘控制器自动完成。与 PIO 方式相比,CPU 的参与度大幅降低,可以将时间用于执行其他任务。
五、常见误区与注意事项
5.1 误区一:DMA 传输完全不需要 CPU
DMA 确实接管了数据传输的过程,但 CPU 仍然需要在传输开始前配置 DMA 控制器(源地址、目标地址、传输长度等),并在传输完成后处理中断(检查传输状态、通知等待的进程)。DMA 减少的是数据传输过程中 CPU 的参与度,而非完全消除 CPU 的角色。
5.2 误区二:中断越多系统性能越好
中断虽然使 CPU 能够在等待 I/O 时执行其他任务,但中断处理本身有开销——上下文保存/恢复、ISR 执行、Cache 失效等。如果中断频率过高(如高速网络设备的每秒百万次中断),中断处理的开销可能超过其带来的收益。中断合并和轮询模式(在高负载时切换回轮询)是应对高频率中断的策略。
5.3 误区三:串行总线一定比并行总线慢
这是一个历史遗留的误解。早期的串行总线(如 RS-232)确实比并行总线(如 LPT)慢,但现代串行总线通过极高的信号频率和多通道聚合实现了远超并行总线的带宽。PCIe 使用串行链路达到每通道数 Gbps 的速率,而传统并行 PCI 总线的带宽仅为 133MB/s。串行技术的优势在于:信号完整性好(差分信号抗干扰)、无需解决多线同步问题、可扩展性强。
5.4 误区四:内存映射 I/O 会浪费大量内存空间
虽然内存映射 I/O 确实占用了一部分物理地址空间,但实际占用的空间通常很小(每个设备只有几 KB 到几 MB 的寄存器空间)。在 64 位地址空间中(256TB),这点占用完全可以忽略。即使在 32 位地址空间中(4GB),通过合理的地址分配也可以有效管理。
5.5 误区五:I/O 设备的速度越来越快,I/O 瓶颈会自然消失
虽然某些 I/O 设备(如 NVMe SSD)的速度已经大幅提升,但 I/O 设备的多样性和复杂性也在增加。网络带宽的需求增长速度超过了单链路速度的提升,存储容量的增长使得数据搬运量持续增加,实时应用对延迟的要求越来越严格。I/O 系统的设计和优化始终是一个重要的工程挑战。
六、本章小结
本章讲解了 I/O 系统的组成和工作原理。I/O 编址方式分为独立编址和内存映射编址,后者因简洁灵活而成为主流。数据传输方式从程序控制 I/O 到中断驱动 I/O 再到 DMA,CPU 的参与度逐步降低,系统效率逐步提高。中断机制使 CPU 能够高效处理异步事件,中断优先级和嵌套管理确保关键事件得到及时处理。DMA 控制器在设备和内存之间直接传输数据,显著减轻了 CPU 的数据搬运负担。总线是连接各部件的通信通道,现代高速总线从并行转向串行,通过高频率和多通道实现高带宽。I/O 软件采用分层结构,设备驱动程序封装硬件细节,为上层提供统一接口。理解 I/O 系统有助于掌握计算机与外部世界的交互方式,也为学习操作系统和设备驱动开发奠定基础。
七、思考题与练习
比较 I/O 独立编址和内存映射编址的优缺点。为什么现代 RISC 处理器普遍采用内存映射 I/O?
比较程序控制 I/O、中断驱动 I/O 和 DMA 三种传输方式的 CPU 利用率。对于一个每秒产生 1000 个字符的键盘和一个传输速率为 100MB/s 的磁盘,分别应该使用哪种传输方式?请说明理由。
描述中断处理的完整流程。中断发生时,CPU 的硬件自动完成哪些操作?哪些操作由软件(ISR)完成?
DMA 传输中的周期窃取和块传输模式有什么区别?在什么场景下应该选择周期窃取模式?
为什么现代高速总线从并行转向串行?串行总线如何在信号频率受限的情况下实现高带宽?
解释 DMA 与 Cache 一致性问题。当 DMA 设备向内存写入数据时,CPU 的 Cache 中可能出现什么问题?有哪些解决方案?
什么是中断合并?为什么高速网络设备需要中断合并技术?中断合并会带来什么副作用?
描述一个文件从磁盘读取到应用程序的完整数据路径,标注每个阶段涉及的硬件组件和软件层。