下面我们来讨论I/O结构
在I/O结构当中呢
我们先从硬件的结构说起
在我们计算机系统当中
我们的CPU为了跟外界相连
实际上在我们的主板上
它是分成了两段
一段是和高速的这些内存 显卡
相连的部分
这时候它的速度通常是若干个G
连的是内存显卡
然后还有一个部分是南桥
它负责跟我们这里的
各种各样的设备相连
比如说像这里的PCI总线
然后你的磁盘
网络都是通过这底下连的
在我们的基本原理里是说
CPU通过总线来连内存和I/O设备
那到这个地方
我们就细化成北桥连高速设备
南桥连I/O设备
这时候在这种结构下我们还需要
进一步来细化CPU到底
如何来识别每一个设备
它们的连接关系是什么样子的
在这儿呢
首先我们在这里头是CPU和I/O设备
设备上面呢有设备控制器
设备控制器的功能
是提供CPU和设备之间的接口
那在这里头就是总线接口
然后有相应的一组寄存器
可以进行数据的交互和
状态和控制的交互
也可以把它映射到内存当中
给一段内存区域
然后对于这段内存区域的访问
对应过来就是我们的I/O设备的访问
这就是我们这里说到的I/O地址
I/O地址通过总线连到我们的CPU上
总线和实际设备之间有总线适配器
在这里头我们映射过来
可能是内存地址
也可能是I/O空间的端口
那我们可以对I/O端口
有相应的I/O指令
如果是内存
那我们直接是访问存储
就对应着对I/O设备的访问
这是从CPU到设备
反过来还有一个从设备到CPU的通道
这就是我们的中断控制器
设备产生中断之后
在中断控制器进行汇总然后送给CPU
CPU就能对外部设备的事件做出响应
这就是我们在这里CPU和设备之间的
通讯的三种方式
轮询那就不用中断控制器
CPU直接访问I/O端口
或者说访问设备所对应的内存地址空间
我也可以采用中断方式
那就是外部设备有事件要通知CPU
就要通过中断到CPU
如果说在这里头
还有一种方式是说
我外部设备需要把数据
直接放到内存当中
你可以通过CPU读然后放到内存
在DMA控制器的控制下
把数据从I/O设备直接到内存单元
这是CPU和设备之间的连接关系
那下面我们进一步来讨论一下
I/O指令和内存映射I/O
I/O指令它是通过I/O端口
来访问设备寄存器
实际上也就是相当于我们通过端口号
来区别我访问的是哪个设备
以及于哪个设备上的哪一项功能
然后CPU上执行out in两个指令
来完成对端口的读写
这些读写不仅仅是数据的访问
也还对应着相应的设备控制
比如说我们有一些控制
就是直接对指定的端口发出写信号
那这个写信号来控制设备的操作
而写的内容有的时候反倒是不重要的
另一种呢是内存映射I/O
它是把设备的寄存器或者存储队列
或者说存储区域
映射到内存的物理地址空间
然后通过load /store
这种存储访问命令来实现I/O操作
在这地方呢
它的地址到底是在哪呢
实际上是在MMU来设置
或者说通过硬件的跳线
来完成相应地址的映射
有了这些讨论之后
那我们就可以给出
操作系统当中I/O子系统的结构
那我们从下往上来讨论
最底下是我们各种各样的设备
比如说存储的SCSI设备
和这边的ATAPI设备
然后还有其它的你比如说鼠标 键盘
然后每一个设备之上
都对应着有一个设备控制器
那不同的设备它的控制器是不一样的
然后在这之上呢
对应着我们就是开始是软件
操作系统里第一层是设备驱动
每一个设备
每一类设备对应着有自己的驱动
在这上头呢是我们的I/O子系统
它用来处理各种设备共同的一些内容
比如说我们的I/O请求
转换成驱动的I/O请求
这是一种细化
然后我也会缓存
设备给出来的一些结果
你比如说我要访问某一个磁盘上的
某一个扇区的数据
那我前面已经做过一次操作了
I/O子系统负责缓存
并且你第二次来访问的时候
我直接给你结果
然后上边是我们内核的其它部分内容
文件系统 那这些都是依赖于I/O子系统
来完成相应数据读写的
在这种结构下我们来看一个
完整的I/O请求的生命周期
跟我们刚才那张图呢
在这地方又有一些细化
这地方的驱动我把它分成两段
设备驱动和底下的中断处理例程
那我们来看一个用户
进行I/O请求它的过程
用户发出I/O请求 这是时间顺序
到这个系统调用返回
我得到相应的数据
或者说我输出数据完成
操作系统里头的I/O子系统
它会做什么事呢
首先判断一下你要进行这个操作
是否有现成的结果
比如说你的磁盘数据的读操作
如果有 那我在这儿呢
直接把我已经缓存的结果给应用
我这个操作就结束了
它实际上没有对实际的设备
进行任何的操作
如果说这个数据没有
它会给驱动发出I/O请求
那这时候我就要去读
指定的区域里的数据了
设备驱动再把这些I/O请求
转换成设备的控制命令
这个设备控制命令呢
直接给硬件进行控制硬件操作
那么这时候设备驱动处于等待状态
等这边处理结束之后
它会产生中断
中断回来我们的中断处理例程
会对它做出响应
这时候响应就是保存相应的结果
并且把结果通知上面的设备驱动层
设备驱动层负责来区分
返回的结果和哪个请求是相对应的
然后把这个结果
给到相应的I/O子系统当中
再把它送给用户的进程
整个一个I/O请求的
完整过程就实现了
这是我们说到的I/O结构