Linux设备驱动程序

第一章 设备驱动程序简介

  设备驱动程序在Linux内核中扮演着特殊的角色。它们是一个个独立的“黑盒子”,使某个特定硬件响应一个定义良好的内部编程接口,这些接口完全隐藏了设备的工作细节。用户的操作通过一组标准化的调用执行,而这些调用独立于特定的驱动程序。将这些调用映射到作用于实际硬件的设备特有操作上,则是设备驱动程序的任务。这个编程接口能够使得驱动程序独立于内核的其他部分而建立,必要的情况下可在运行时“插入”内核。

一、设备驱动程序的作用

  区分机制和策略是Unix设计背后隐含的最好思想之一。大多数编程问题实际上都可以分成两部分:“需要提供什么功能”(机制)和“如何使用这些功能”(策略)。如果这两个问题由程序的不同部分来处理,或者甚至由不同的程序来处理,则这个软件包更易开发,也更容易根据需要来调整。

  驱动程序同样存在机制和策略的分离问题。例如,软驱的驱动程序不带策略,它的作用是将磁盘表示为一个连续的数据块阵列。系统高层负责提供策略,比如谁有权访问软盘驱动器,是直接访问驱动器还是通过文件系统,以及用户是否可以在驱动器上挂装文件系统等等。既然不同的环境通常需要不同的方式来使用硬件,我们应当尽可能做到让要动程序不带策略。

  在编写驱动程序时,程序员应该特别注意下面这个基本概念:编写访问硬件的内核代码时,不要给用户强加任何特定策略,因为不同的用户有不同的需求,驱动程序应该处理如何使硬件可用的问题,而将怎样使用硬件的问题留给上层应用程序。

  因此,当驱动程序只提供了访问硬件的功能而没有附加任何限制时,这个驱动程序就比较灵活。

  如果从另外一个角度来看驱动程序,它还可以看作是应用程序和实际设备之间的一个软件层。

  不带策略的驱动程序包括一些典型的特征:同时支持同步和异步操作、驱动程序能够被多次打开、充分利用硬件特性,以及不具备用来“简化任务”的或提供与策略相关的软件层等。这种类型的驱动程序不仅能很好地服务最终用户,而且易于编写和维护。实际上,不带策略是软件设计者的一个共同目标。

二、内核功能划分

  Unix系统支持多个进程的并发运行,每个进程都请求系统资源,比如运算、内存、网络连接或其他一些资源等。内核负责处理所有这些请求,根据内核完成任务的不同可将内核功能分成如下几部分:进程管理、内存管理、文件系统、设备控制、网络功能。

三、可装载模块

  Linux有一个很好的特性:内核提供的特性可在运行时进行扩展。这意味着当系统启动并运行时,我们可以向内核添加功能(当然也可以移除功能)。

  可在运行时添加到内核中的代码被称为“模块”。Linux内核支持好几种模块类型(或者类),包括但不限于设备驱动程序。每个模块由目标代码组成(没有连接成一个完整的可执行程序),我们可以使用insmod程序将模块连接到正在运行的内核,也可以使用rmmod 程序移除连接。

四、设备和模块的分类

  Linux系统将设备分成三种基本类型,每个模块通常实现为其中某一类:字符模块、块模块或网络模块。

  字符(char)设备是个能够像字节流(类似文件)一样被访问的设备,由字符设备驱动程序来实现这种特性。字符设备驱动程序通常至少要实现openclosereadwrite系统调用。字符终端(/dev/console)和串口(/dev/itys0以及类似设备)就是两个学符设备,它们能够很好地说明“流”这种抽象概念。字符设备可以通过文件系统节点来访同,比如/dev/ty1/dev/lp0等。

  块设备和字符设备类似,块设备也是通过/dev目录下的文件系统节点来访问。块设备(例如磁盘)上能够容纳文件系统。

  网络接口,许多网络连接(尤其是使用TCP协议的连接)是面向流的,但网络设备却围绕数据包的传输和接收而设计。网络驱动程序不需要知道各个连接的相关信息,它只要处理数据包即可。

  还有另外一种划分驱动程序模块类型的方法。一般而言,某些驱动程序类型用内核用来支持某种给定类型设备的附加层一起工作。比如,通用串行总线(USB)模块、串行模块、SCSI模块,等等。每个USB设备由一个USB模块驱动,而该USB模块和USB子系统一同工作,但设备本身在系统中表现为一个宇符设备(比如USB串口)、一个块设备(比如USB存储卡读取器)或者一个网络设备(比如USB以太网接口)。

  除了设备驱动程序外,内核中其他一些功能(不管是硬件还是软件功能)也都模块化了。一个常见的例子是文件系统。一个文件系统类型决定了如何在块设备上组组数据,以表示目录和文件形成的树。文件系统并不是设备驱动程序,因为没有任何实际物理设备同这种信息组织方式相关联。相反,文件系统类型是个软件驱动程序,他将底层数据结构映射到高层数据结构,决定文件名可以有多长以及在目录项中存储文件的哪些信息等等。

  由于Unix系统严重依赖于底层的文件系统,因此文件系统概念对系统操作具有重要意义。

五、安全问题

  驱动程序编写者应当尽量避免在代码中实现安全策略。安全策略问题最好在系统管理员的控制之下,由内核的高层来实现。驱动程序编写者还应当避免由于自身原因引入安全方面的缺陷。C编程语言很容易产生几种类型的错误,比如缓冲区溢出就会导致许多安全问题。

  还有其他一些原则性的安全概念值得注意。任何从用户进程得到的输入只有经过内核严格验证后才能使用。我们还必须小心对待未初始化的内存:任何从内核中得到的内存,都必须在提供给用户进程或者设备之前清零或者以其他方式初始化,否则就可能发生信息泄漏(如数据和密码的泄漏等)。

  如果设备要解释和分析发送给它的数据,则必须确保用户不能将可能破坏系统的任何东西发送给它。

  尽管通常我们可以信任发行版本中预先编译的内核,但当使用由一个我们不是非常熟悉的朋友编译的内核时就得当心!就像我们不愿意以root身份运行一个预先编译的二进制文件一样,我们也不应当运行一个预先编译好的内核。例如,一个恶意修改过的内核可能会允许任何人装载模块,这样,一扇通过init module的后门就打开了!

  Linux内核也可编译为不支持模块方式,从而可以关闭任何模块相关的安全漏洞。但在这种情况下,所有所需的驱动程序必须直接编译到内核中。在2.2及以后的内核版本中,我们可以通过权能机制禁止在系统启动后装载内核模块。

2020/03/17


参考资料:
Jonathan Corbet. Linux设备驱动程序(第三版) [M].魏永明 译. 北京: 中国电力出版社,2006.1.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luuyiran

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值