IO系统基本结构
CPU 并不直接和设备打交道,它们中间有一个叫作设备控制器
所有设备都在 /dev/ 文件夹下面创建一个特殊的设备文件。这个设备特殊文件也有 inode,但是它不关联到硬盘或任何其他存储介质上的数据,而是建立了与某个设备驱动程序的连接。
对于设备文件,ls 出来的内容如果是字符设备文件,则以 c 开头,如果是块设备文件,则以 b 开头。
输入输出设备分类
-
块设备
块设备将信息存储在固定大小的块中,每个块都有自己的地址。硬盘就是常见的块设备。
一般处理时,需要用到缓冲区
-
字符设备
字符设备发送或接收的是字节流。而不用考虑任何块结构,没有办法寻址。鼠标就是常见的字符设备。
中断
- 软中断 代码调用 INT 指令触发
- 硬件中断 硬件通过中断控制器触发的
驱动程序
设备驱动程序属于操作系统的一部分。操作系统的内核代码可以像调用本地代码一样调用驱动程序的代码。
可以通过
lsmod <device>.ko
来加载驱动
-
/sys/devices 是内核对系统中所有设备的分层次的表示;
- /sys/dev 目录下一个 char 文件夹,一个 block 文件夹,分别维护一个按字符设备和块设备的主次号码 (major:minor) 链接到真实的设备 (/sys/devices 下) 的符号链接文件;
- /sys/block 是系统中当前所有的块设备;
- /sys/module 有系统中所有模块的信息。
字符设备
- 设备安装以后,用户态执行insmod,将驱动程序加载到内核
- 驱动程序提供初始化函数、中断处理函数、设备操作函数,并注册该设备到 cdev_map ,并通过mknod在/dev下新建一个设备文件
- 当进程需要用到设备时,进程通过struct file中设备文件的inode来实现对设备的控制
ioctl IO设备除了读写以外,提供对特殊的 I/O 操作的支持。fd 是这个设备的文件描述,cmd 是传给这个设备的命令,arg 是命令的参数。其中,对于命令和命令的参数,使用 ioctl 系统调用的用户和驱动程序的开发人员约定好行为即可。其实 cmd 看起来是一个 int。
硬件中断
中断是从外部设备发起的,会形成外部中断。
外部中断会到达中断控制器,中断控制器会发送中断向量 Interrupt Vector 给 CPU。
对于每一个 CPU,都要求有一个 idt_table,里面存放了不同的中断向量的处理函数。中断向量表中已经填好了前 32 位,外加一位 32 位系统调用,其他的都是用于设备中断。
硬件中断的处理函数是 do_IRQ 进行统一处理,在这里会让中断向量,通过 vector_irq 映射为 irq_desc。
irq_desc 是一个用于描述用户注册的中断处理函数的结构,为了能够根据中断向量得到 irq_desc 结构,会把这些结构放在一个基数树里面,方便查找。irq_desc 里面有一个成员是 irqaction,指向设备驱动程序里面注册的中断处理函数。
# 查看cpu中断
cat /proc/interrupts
块设备
块设备的 I/O 操作分为两种
-
直接 I/O
-
缓存 I/O
无论是哪种 I/O,最终都会调用 submit_bio 提交块设备 I/O 请求。