用设备控制器屏蔽设备差异
CPU 并不直接和设备打交道,它们中间有一个叫作设备控制器(Device Control Unit)的组件,例如硬盘有磁盘控制器、USB 有 USB 控制器、显示器有视频控制器等。
控制器其实有点儿像一台小电脑。它有它的芯片,类似小 CPU,执行自己的逻辑。它也有它的寄存器。这样 CPU 就可以通过写这些寄存器,对控制器下发指令,通过读这些寄存器,查看控制器对于设备的操作状态。
输入输出设备我们大致可以分为两类:块设备(Block Device)和字符设备(Character Device):
- 块设备将信息存储在固定大小的块中,每个块都有自己的地址。硬盘就是常见的块设备。
- 字符设备发送或接收的是字节流。而不用考虑任何块结构,没有办法寻址。鼠标就是常见的字符设备。
CPU 如何同控制器的寄存器和数据缓冲区进行通信呢?
- 每个控制寄存器被分配一个 I/O 端口,我们可以通过特殊的汇编指令(例如 in/out 类似的指令)操作这些寄存器。
- 数据缓冲区,可内存映射 I/O,可以分配一段内存空间给它,就像读写内存一样读写数据缓冲区。如果你去看内存空间的话,有一个原来我们没有讲过的区域 ioremap,就是做这个的。
当你给设备发了一个指令,让它读取一些数据,它读完的时候,怎么通知你呢?
- 控制器的寄存器一般会有状态标志位,可以通过检测状态标志位,来确定输入或者输出操作是否完成。
- 第一种方式就是轮询等待
- 第二种方式,就是可以通过中断的方式
为了响应中断,我们一般会有一个硬件的中断控制器,当设备完成任务后触发中断到中断控制器,中断控制器就通知 CPU,一个中断产生了,CPU 需要停下当前手里的事情来处理中断。
DMA 功能, 允许设备在 CPU 不参与的情况下,能够自行完成对内存的读写。实现 DMA 机制需要有个 DMA 控制器帮你的 CPU 来做协调
- DMA 自动处理好数据, 利用中断通知 CPU, CPU 可直接使用准备好的数据了 (内存中)
用驱动程序屏蔽设备控制器差异
类似公司的渠道管理部门。
设备控制器不属于操作系统的一部分,但是设备驱动程序属于操作系统的一部分。
**
设备驱动程序应该有统一的接口:
中断处理在设备驱动里面完成.
操作系统也要有一个统一的流程来处理中断:
- 一个设备驱动程序初始化的时候,要先注册一个该设备的中断处理函数。
- 对于块设备来讲,在驱动程序之上,文件系统之下,还需要一层通用设备层。
- 将与块设备相关的通用逻辑放在这一层,维护与设备无关的块的大小,然后通用块层下面对接各种各样的驱动程序
用文件系统接口屏蔽驱动程序的差异
然我们操作设备,都是基于文件系统的接口,也要有一个统一的标准:
- 首先要统一的是设备名称。所有设备都在 /dev/ 文件夹下面创建一个特殊的设备文件。这个设备特殊文件也有 inode,但是它不关联到硬盘或任何其他存储介质上的数据,而是建立了与某个设备驱动程序的连接。
硬盘设备这里有一点绕。假设是 /dev/sdb,这是一个设备文件。这个文件本身和硬盘上的文件系统没有任何关系。这个设备本身也不对应硬盘上的任何一个文件,/dev/sdb 其实是在一个特殊的文件系统 devtmpfs 中。但是当我们将 /dev/sdb 格式化成一个文件系统 ext4 的时候,就会将它 mount 到一个路径下面。例如在 /mnt/sdb 下面。这个时候 /dev/sdb 还是一个设备文件在特殊文件系统 devtmpfs 中,而 /mnt/sdb 下面的文件才是在 ext4 文件系统中,只不过这个设备是在 /dev/sdb 设备上的。
$ ls -l /dev
c
字符设备文件b
块设备文件- 主设备号: 定位设备驱动程序
- 次设备号: 作为参数传给启动程序,选择相应的单元。
cat /dev/urandom | od -x
如果 Linux 操作系统新添加了一个设备,应该做哪些事情呢?
- 安装驱动
- Linux 的驱动程序已经被写成和操作系统有标准接口的代码,可以看成一个标准的内核模块。在 Linux 里面,安装驱动程序,其实就是加载一个内核模块。
# lsmod, 查看内核模块
Module Size Used by
iptable_filter 12810 1
bridge 146976 1 br_netfilter
vfat 17461 0
fat 65950 1 vfat
ext4 571716 1
cirrus 24383 1
crct10dif_pclmul 14307 0
crct10dif_common 12595 1 crct10dif_pclmul
# 安装模块
insmod openvswitch.ko
# 创建设备文件
mknod filename type major minor
- filename 就是 /dev 下面的设备名称
- type 就是 c 为字符设备,b 为块设备
- major 就是主设备号
- minor 就是次设备号。
一旦执行了这个命令,新创建的设备文件就和上面加载过的驱动关联起来,这个时候就可以通过操作设备文件来操作驱动程序,从而操作设备。
总结
精彩评论
刘強
老师,可不可以这么理解。假设硬盘被格式化为ext 文件系统。如果我们直接读写裸设备,相当于绕过ext文件系统的这部分代码直接让驱动程序指挥硬盘。当然这种指挥由于没有一定的规则,没有什么意义。而把文件系统挂载到某个目录下后,我们访问这个目录,相当于特定于ext文件系统的这部分代码代替我们刚才的“瞎指挥”,还是通过驱动程序操作裸设备,现在由于有了特定文件系统的规则,所以就能读写文件了。 这么理解文件系统 驱动程序 裸设备之间的关系,对吗?
作者回复: 是的,裸写肯定会写坏