用设备控制器屏蔽设备差异

CPU 并不直接和设备打交道,它们中间有一个叫作设备控制器(Device Control Unit)的组件,例如硬盘有磁盘控制器、USB 有 USB 控制器、显示器有视频控制器等。

控制器其实有点儿像一台小电脑。它有它的芯片,类似小 CPU,执行自己的逻辑。它也有它的寄存器。这样 CPU 就可以通过写这些寄存器,对控制器下发指令,通过读这些寄存器,查看控制器对于设备的操作状态。

输入输出设备我们大致可以分为两类:块设备(Block Device)和字符设备(Character Device):

  • 块设备将信息存储在固定大小的块中,每个块都有自己的地址。硬盘就是常见的块设备。
  • 字符设备发送或接收的是字节流。而不用考虑任何块结构,没有办法寻址。鼠标就是常见的字符设备。

CPU 如何同控制器的寄存器和数据缓冲区进行通信呢?

  • 每个控制寄存器被分配一个 I/O 端口,我们可以通过特殊的汇编指令(例如 in/out 类似的指令)操作这些寄存器。
  • 数据缓冲区,可内存映射 I/O,可以分配一段内存空间给它,就像读写内存一样读写数据缓冲区。如果你去看内存空间的话,有一个原来我们没有讲过的区域 ioremap,就是做这个的。

当你给设备发了一个指令,让它读取一些数据,它读完的时候,怎么通知你呢?

  • 控制器的寄存器一般会有状态标志位,可以通过检测状态标志位,来确定输入或者输出操作是否完成。
    • 第一种方式就是轮询等待
    • 第二种方式,就是可以通过中断的方式

为了响应中断,我们一般会有一个硬件的中断控制器,当设备完成任务后触发中断到中断控制器,中断控制器就通知 CPU,一个中断产生了,CPU 需要停下当前手里的事情来处理中断。

image.png

DMA 功能, 允许设备在 CPU 不参与的情况下,能够自行完成对内存的读写。实现 DMA 机制需要有个 DMA 控制器帮你的 CPU 来做协调

  • DMA 自动处理好数据, 利用中断通知 CPU, CPU 可直接使用准备好的数据了 (内存中)

image.png

用驱动程序屏蔽设备控制器差异

类似公司的渠道管理部门。

设备控制器不属于操作系统的一部分,但是设备驱动程序属于操作系统的一部分。
**
设备驱动程序应该有统一的接口:

image.png

中断处理在设备驱动里面完成.

操作系统也要有一个统一的流程来处理中断:

  • 一个设备驱动程序初始化的时候,要先注册一个该设备的中断处理函数。

image.png

  • 对于块设备来讲,在驱动程序之上,文件系统之下,还需要一层通用设备层。
    • 将与块设备相关的通用逻辑放在这一层,维护与设备无关的块的大小,然后通用块层下面对接各种各样的驱动程序

image.png

用文件系统接口屏蔽驱动程序的差异

然我们操作设备,都是基于文件系统的接口,也要有一个统一的标准:

  • 首先要统一的是设备名称。所有设备都在 /dev/ 文件夹下面创建一个特殊的设备文件。这个设备特殊文件也有 inode,但是它不关联到硬盘或任何其他存储介质上的数据,而是建立了与某个设备驱动程序的连接。

硬盘设备这里有一点绕。假设是 /dev/sdb,这是一个设备文件。这个文件本身和硬盘上的文件系统没有任何关系。这个设备本身也不对应硬盘上的任何一个文件,/dev/sdb 其实是在一个特殊的文件系统 devtmpfs 中。但是当我们将 /dev/sdb 格式化成一个文件系统 ext4 的时候,就会将它 mount 到一个路径下面。例如在 /mnt/sdb 下面。这个时候 /dev/sdb 还是一个设备文件在特殊文件系统 devtmpfs 中,而 /mnt/sdb 下面的文件才是在 ext4 文件系统中,只不过这个设备是在 /dev/sdb 设备上的。

  1. $ ls -l /dev
  • c 字符设备文件
  • b 块设备文件
  • 主设备号: 定位设备驱动程序
  • 次设备号: 作为参数传给启动程序,选择相应的单元。
  1. cat /dev/urandom | od -x

如果 Linux 操作系统新添加了一个设备,应该做哪些事情呢?

  • 安装驱动
    • Linux 的驱动程序已经被写成和操作系统有标准接口的代码,可以看成一个标准的内核模块。在 Linux 里面,安装驱动程序,其实就是加载一个内核模块。
  1. # lsmod, 查看内核模块
  2. Module Size Used by
  3. iptable_filter 12810 1
  4. bridge 146976 1 br_netfilter
  5. vfat 17461 0
  6. fat 65950 1 vfat
  7. ext4 571716 1
  8. cirrus 24383 1
  9. crct10dif_pclmul 14307 0
  10. crct10dif_common 12595 1 crct10dif_pclmul
  11. # 安装模块
  12. insmod openvswitch.ko
  13. # 创建设备文件
  14. mknod filename type major minor
  • filename 就是 /dev 下面的设备名称
  • type 就是 c 为字符设备,b 为块设备
  • major 就是主设备号
  • minor 就是次设备号。

一旦执行了这个命令,新创建的设备文件就和上面加载过的驱动关联起来,这个时候就可以通过操作设备文件来操作驱动程序,从而操作设备。

总结

image.png

精彩评论

刘強

老师,可不可以这么理解。假设硬盘被格式化为ext 文件系统。如果我们直接读写裸设备,相当于绕过ext文件系统的这部分代码直接让驱动程序指挥硬盘。当然这种指挥由于没有一定的规则,没有什么意义。而把文件系统挂载到某个目录下后,我们访问这个目录,相当于特定于ext文件系统的这部分代码代替我们刚才的“瞎指挥”,还是通过驱动程序操作裸设备,现在由于有了特定文件系统的规则,所以就能读写文件了。 这么理解文件系统 驱动程序 裸设备之间的关系,对吗?

作者回复: 是的,裸写肯定会写坏