2.1 设备驱动的角色
设备驱动是介于应用软件和硬件设备(或其他虚拟设备)之间的程序,驱动完成对硬件设备(或其他虚
拟设备)的管理,应用软件对硬件的访问通过驱动程序来完成。当环境变得复杂,各式各样的硬件设备和硬
件接口会让应用软件对硬件设备的操作变成一团乱麻,此时操作系统的介入,提供一套统一的对硬件设备访
问的接口:一方面,应用程序通过操作系统定义的统一接口间接调用设备驱动程序,而不是直接调用驱动程
序;另一方面,设备驱动程序必须遵从操作系统提供的接口规范来实现、提供自己的功能。我们用图2.1.1
描述无操作系统时的驱动程序和图2.1.2描述有操作系统时驱动程序:
图2.1.1 无操作系统时的设备驱动 图2.1.2 有操作系统的设备驱动
上面两图中体现的最大差异是有无一套统一的硬件设备访问接口,这是我们在操作系统介入时,给应用程序的编写带来的最大益处。当然,操作系统介入的好处不止如此,操作系统的统一内存管理、并发机制等
为编写更为强大、安全的设备驱动带来了便利。
值得一提的是,操作系统提供设备统一访问接口以及设备驱动按照该统一接口实现自己功能的模型,就
是我们经常说到的机制(操作系统提供的接口规范)与策略(设备驱动的具体实现),有时也称机制与策略
为接口与实现,其中机制对应于接口,而策略对应于实现。
2.2 Linux内核划分
前面一节统而论之的描述了设备驱动在流行操作系统中扮演角色,这节开始具体到Linux内核来谈论设
备驱动。
首先看一下我们Linux内核的简单划分,如图2.2所示。
图2.2 Linux内核的划分
进程管理(Process management):负责创建和销毁进程,以及进程的输入和输出、进程间通信。此
外,控制进程如何对CPU共享的调度器,也是进程管理的一部分。
内存管理(Memory management):内核的不同部分通过一组函数调用与内存管理子系统交互,这些函
数调用包括简单的malloc/free以及更多更复杂的功能函数。
文件系统(Filesystems):Linux在硬件之上建立了文件系统的抽象,系统中几乎所有设备都可以看成
一个文件。Linux支持多种文件系统,如ext3,ext,FAT等。
设备控制(Device control):几乎所有的系统操作最终都要映射到物理设备。除处理器、内存以及很
少的实体外,几乎所有的设备控制操作都有设备代码完成,这些代码成为设备驱动。内核在设备控制方面的
功能是我们主要感兴趣的部分。
网络(Networking):因为大部分的网络操作并非特定于某个进程,所以必须由操作系统来管理。
2.2.1 可加载模块
可以在运行时扩展是Linux内核提供的众多优良特性之一。可以在运行时添加到内核的代码,被称为一
个模块,这些模块代码可以通过insmod、modprobe等工具动态链接到内核,通过rmmod从内核移除。
2.3 设备和模块分类
Linux分为字符模块、块模块、网络模块3种基本类型,对应于字符设备、块设备、网络接口。分别对3
种设备做出简单解释。
字符设备:字符设备是可以按字节流方式来访问的设备,/dev/ttyS0是字符设备一个例子。字符设备就
像一个普通文件,但不同于普通文件的是并非每个字符设备都可以在文件内前后移动。
块设备:块设备是指可以驻留文件系统的设备。块设备驱动有着完全不同于字符设备驱动的内核接口和管理方式,不过这些差异对于用户是透明的,用户使用相同的方式访问块设备和字符设备。
网络接口:网络接口是能够在主机间交换数据的设备。网络接口通常是指硬件,但也可能是如loopback
的纯软件设备。网络接口由内核网络子系统驱动,负责收发数据包(data packet)。
网络接口设备难以简单的映射文件系统节点,虽然Linux系统会为每个网络接口提供一个唯一的名称,
如eth0,但这些名称没有对应的文件系统入口。与字符设备和块设备使用read/write与设备通信不同的是,
Linux系统使用面向数据包传送的套接字接口与网络接口通信。
除以上3种类型的设备外,还有FireWire和I2O,它们以同样的方式处理USB和SCSI设备。
2.4 安全问题
系统内的任何安全都由内核代码强制执行。如果内核存在漏洞,那么整个系统就有了漏洞。在内核的官
方发布版本中,只有授权的用户才能加载模块,系统调用init_module检查调用京城是否被授权加载模块。
技术上来讲,只有拥有CAP_SYS_MODULE能力的用户才可以加载模块。
驱动代码要细心的处理安全问题,避免引入安全漏洞。一些为更好的处理驱动中的安全问题的通用规则
如下:
. 尽量不要在自己的驱动代码中引入安全策略,这些最好交由内核去处理;
. 避免一些常见的C语言陷阱如缓冲长度溢出;
. 对来自用户空间的数据总是持怀疑态度;
. 总是对数据进行初始化,将数据置于已知的状态;
2.5 版本号
了解一些关于Linux内核版本号的常识对编写设备驱动也是有帮助的。驱动本身也需要版本的管理。
2.6 版权条款
驱动的代码编写涉及到版权的声明、管理。
2.7 加入到Linux内核开发社区
linux-kernel邮件列表。
参考资料:
《Linux Device Drivers》第3版。