设备驱动程序接口

5.1.3 说驱动程序”与硬件直接相关”,这带来一个工程问题:世界上有成千上万种设备,每种都要写一个驱动程序,而这些驱动程序都要嵌进同一个操作系统里。

如果不加约束,操作系统就得为每一种设备单独适配一次。这一节讲的就是那道约束——操作系统规定一组统一的接口,谁想接进来,谁就按这组接口来实现。

机制

统一接口的两个方向

① 每个设备驱动程序与操作系统之间都有相同或相近的接口形式。 也就是说,操作系统给设备驱动程序规定了一组它必须支持的函数——open、read、write、close、中断处理入口等等。驱动程序作者只需把这组函数按自己设备的特性实现出来。

② 驱动程序与内核之间的接口相同。 内核不需要知道这是磁盘还是打印机,它只按同一张函数表去调用。

此外,操作系统还需要知道每个设备驱动程序需要提供的其他信息,例如设备类型、需要占用的中断号等。

这套机制与 4.3.4 虚拟文件系统中”下层文件系统必须提供 VFS 规定的一组函数”完全同构——都是”向上统一接口、向下规定约定”的分派模式,只是一个用于文件系统,一个用于设备。

驱动程序与普通程序的五点差异

驱动程序属于低级的系统例程,它与一般的应用程序及系统程序有明显差异:

① 它主要是请求 I/O 的进程与设备控制器之间的一个通信程序——它的职责是传递和翻译,不做业务逻辑。

② 它与设备控制器和 I/O 设备的硬件特性紧密相关——寄存器编号、命令字编码、时序要求,全都是这台设备特有的。

③ 它与 I/O 控制方式紧密相关——采用中断驱动还是 DMA,驱动程序的写法完全不同。

④ 由于与硬件紧密相关,其中一部分必须用汇编语言书写——某些寄存器操作和时序控制无法用高级语言精确表达。

⑤ 驱动程序应允许可重入。 这一条最值得解释:同一个驱动程序可能同时被多个进程调用(比如两个进程同时读磁盘),也可能在处理一个请求的过程中被中断、转而处理另一个请求。若驱动程序不可重入,这些并发调用就会互相破坏各自的中间状态。

边界

哪些工作不属于驱动程序

这一条与 5.1.3 的判据完全一致,此处只做归位:

属于驱动程序的:接收并检查针对本设备的 I/O 命令与参数、查询设备状态、把抽象要求翻译成具体要求(如逻辑块号 → 盘面/磁道/扇区)、写控制寄存器启动设备、响应本设备的中断。

不属于驱动程序的:通用的缓冲区管理、设备分配与回收、权限检查、逻辑设备名映射——这些换任何一台设备做法都一样,统统属于设备独立性软件。

判据仍然是那一句:换一台设备,这件事还成不成立。

为什么驱动程序必须可重入

这是本节唯一需要理解而非记忆的点。

可重入意味着:一个函数在执行到一半被打断、又被重新进入执行时,两次执行不会互相干扰。 做到这一点的关键是不使用全局的可变状态,所有中间结果都放在各自的栈或参数里。

驱动程序为什么会被重入,有两个来源:其一是多个进程同时请求同一台设备(磁盘尤其常见);其二是驱动程序执行期间来了本设备的中断,中断处理又要进入驱动程序的代码。

若驱动程序把中间状态存在一个全局变量里,第二次进入就会把第一次的状态覆盖掉,结果是数据读错、设备状态错乱——而且这种错误只在高并发时偶发,极难排查。

这与 2.3 同步与互斥关心的是同一类问题,只不过这里的解法不是加锁,而是从写法上就不留共享状态。

统一接口与设备独立性的关系

两者容易混,但一个面向”驱动程序的作者”,一个面向”用户程序的作者”:

设备驱动程序接口规定的是驱动程序必须向内核提供哪些函数,受益者是操作系统——它因此不必为每种设备单独适配。

设备独立性规定的是用户程序使用逻辑设备名,受益者是用户程序——它因此不必绑定具体设备。

两者一上一下,共同构成了”设备可插拔”这件事的两端。

对照速查

统一接口的两个方向
①每个驱动程序与操作系统之间接口相同或相近
②驱动程序与内核之间接口相同(内核按同一张函数表调用)
驱动程序的五点特殊性
①是请求 I/O 的进程与设备控制器之间的通信程序
②与设备控制器和硬件特性紧密相关
③与 I/O 控制方式紧密相关
④一部分必须用汇编语言书写
⑤必须可重入
是不是驱动程序的职责
接收并检查 I/O 命令和参数是
查询 I/O 设备状态是
发出 I/O 命令、启动设备是
逻辑块号译成盘面/磁道/扇区是
通用缓冲区管理否(设备独立性软件)
设备分配与回收否(设备独立性软件)

考点

  • 统一接口的两个方向:驱动与操作系统之间、驱动与内核之间
  • 驱动程序的五点特殊性,尤其**“一部分必须用汇编”与”必须可重入”**
  • 可重入的原因:多进程并发调用 + 执行中被本设备中断
  • 缓冲区管理不属于驱动程序(高频真题)
  • 驱动接口面向操作系统,设备独立性面向用户程序

链接