IO硬件原理
IO设备
IO设备大致可以分为两类:块设备和字符设备。块设备大信息存储在固定大小的块中,每个块有自己的地址。所有传输以一个或过个完整(连续)的块为单位。块设备的基本特征是每个块都能独立于其他块而读写。硬盘,CD-ROM就是块设备。
另一类IO设备是字符设备。字符设备以自负为单位发送或接收一个自负流,而不考虑任何块结构。字符设备是不可寻址的,页没有任何寻道操作。
这种分类方法并不完美,有些设备就没有包括进去。不过块设备和字符设备都具有足够的一般性,可以用作使处理Io设备的某些操作系统软件具有设备无关性的基础。
设备控制器
控制器位于IO设备上
IO设备一半由机械部件和电子部件两部分组成。电子部件称作设备控制器或适配器。控制器卡上通常有一个连接器,通向设备本身的电缆可以到这个连接器中。
控制器于设备之间的接口通常是一个很低层次的接口。实际从驱动器出来的确实一个串行的位(比特)流,它以一个前导符开始,接着是一个山区的4096位,最后一个是校验和,也称为错误验证码。
前导符是对磁盘进行格式化时写上去的,包括柱面数和扇区号等数据,此外海包括同步信息。
控制器的任务是把串醒的位流转换为字节块,并进行必要的错误校正工作。字节块通常首先在控制器内部的一个缓冲区按位进行组装,然后在对校验和进行校验并证明字节块没有错误后,再将它复制到主存。
内存映射IO
每个控制器有几个寄存器用来和CPU进行通信。通过写入这些寄存器,操作系统可以命令设备发送数据,接收数据,开启或关闭,或者执行某些其它操作。通过读取这些寄存器,操作系统可以了解设备的状态,是否准备好接受一个新命令。
除了这些控制寄存器之外,很多设备还有一个曹走系统可以读写的数据缓冲区。
CPU和设备的控制寄存器和数据换从区进行通信的方法:
- 每个控制寄存器分配一个IO端口号(8位或16位证书)。所有IO端口形成IO端口空间,并且收到保护使得普通用户程序不能对其进行访问(只有操作系统可以)
- PDP-11引入,将所有控制寄存器映射到内存空间中。每个控制寄存器被分配唯一的一个内存地址,而且不会有内存被分配这一地址。这样的系统称为内存映射IO。
如果只有内存空间,那么每个内存模块和每个IO设备都会将地址西安和它所服务的地址进行笔记,若干地址落在这一范围之内,那么就会响应这个请求。因为绝对不会有地址既分配给内存又分配给IO设备。
内存映射优点:
- 如果需要特殊的IO指令去读写设备控制寄存器,那么访问这些集群起需要使用汇编代码,而对于内存映射而言控制寄存器只是内存汇总的变量。因此对于内存映射IO,IO设备驱动程序另一完全用C语言编写。
- 不需要特殊的保护机制阻止用户进程执行IO操作。操作系统必须要做的全部事情只是避免把包含控制寄存器的那部分地址空间放入任何用户。操作系统需要做的全部事情只是避免把包含控制寄存器的那部分地址空间放入任何用户的虚拟地址空间之中。还可以使不同的设备驱动程序防止在不同的地址空间中,不但可以减小内核大小,而且可以防止驱动程序之间相互干扰
- 对于内存映射IO,可以引用内存的每一条指令也可以引用控制寄存器
缺点:
大多数计算机都有某种形式的内存子高速缓存,对一个设备控制器的高速缓存可能是灾难性的。
对内存映射IO,为了避免这一情形,硬件必须针对每个页面具备选择性禁用高速缓存的能力。这一特性给操作系统和硬件都增加了复杂性。
在内存映射的及其上具有单独的内存总线的麻烦是IO设备没有办法查看内存地址,因为内存地址旁路到内存总线上,所以没有办法响应。
一种可能的办法是首先将全部内存引用发送到内存,如果内存响应直白,CPU将尝试其它总线。这一设计需要额外的硬件复杂度。
第二种方法是在内存总线上放置一个探查设备,放过所有潜在地指向所关注的IO蛇白的地址。问题在于IO设备可能无法按内存能达到的速度处理请求
第三种是咋iPCI桥芯片中对地址进行过滤。这一设计的缺点是需要在引导时判定那些内存地址不是真正的内存地址。
直接存储器存取
无论一个CPU'是否具有内存映射IO,它都需要和寻址设备控制器以便于他们交换数据。每次一个字节浪费CPu时间,所以使用直接存储器存取(DMA)的不同方案,只有硬件具有DMA控制器时操作系统才能使用DMA,而大多数系统都有DMA控制器。
无论DMA控制器在物理上处于什么位置,它都能独立于CPU而访问系统总线。
在使用正常磁盘读取时控制器从磁盘驱动器串行地一位一位读取一个块,知道整块信息放入控制器的内部缓冲区。紧接着,校验,然后产生中断。当操作系统开始允许时,它重复地从控制器的缓冲区中一次一个字节或一个字得区域该块信息,并存入内存。
而DMA不同,DMA被CPu变成所以DMA知道应该将数据传送到何方。DMA想磁盘发出一个命令,通知它从磁盘读数据到期内部换从区,并进行校验。若数据有效,则在总线上发出一个读请求到磁盘控制器而发起DMA传送。当磁盘控制器从其内部缓冲区中独取下一个字时,它知道该字写到什么地方。写到内存是另一个标准总线周期,当写操作完成后,磁盘控制器在总线上发出一个因大信号到DMA控制器。最后DMA控制器将中断CPU让CPU知道传送以及完成。此时数据已经在内存中了。
DMA则是让磁盘数据知道应当传送到内存何处,本身不处理数据(自)
许多总线能以两种模式操作:每次一字和快模式,某些DMA控制器也可以这样操作。在前者,DMA每次请求传送一字,若CPu也想用总线,则必须等待。这一机制称为周期窃取,因为设备控制器偶尔从CPU偷走一个临时的总线周期,从而轻微延迟CPU。在块模式中,DMA控制器通知设备获得总线,发起一连串的传送,然后释放总线。这一操作模式称为突发模式,这种方法比周期窃取效率更高。而缺点在于,如果正在进行长时间突发操作,有可能将CPU和其他设备阻塞相当长的时间。
还有一种模式称为飞跃模式——DMA通知设备寄存器直接将数据传送到主存,某些DMA则是让设备先将数据传送到DMA控制器,然后DMA发起第二个总线周期,缺点是效率低,优点是灵活。
大多数DMA控制器使用物理内存进行传送。在少数DMA控制器中使用的一个替代方案是将虚拟地址写入DMA控制器,然后DMA控制器必须使用MMU完成虚拟地址到物理地址的转换。只有咋iMMU是内存的组成部分而不是CPU的组成部分(很罕见),才可以将虚拟地址放入总线。
并不是所有计算机都使用DMA,反对的论据是主CPu通常要比DMA控制器快得多。
重温中断
当一个IO设备完成交给它的工作时,就会产生一个中断(假设操作系统以及放开中断),它是通过分配给它第一条总线信号线上置其的信号而产生中断的。该信号被主板上的中断控制器芯片监测到,由中断控制器芯片决定做什么。
设备与中断控制器之间的连接实际上使用的是总线上的中断线而不是专用连线。
如果没有其它中断未解决,中断控制器将立刻对中断进行处理。如果不,则该设备会一直在地址线上置起中断信号,知道得到服务。
中断信号导致CPU停止当前正在做的工作并且开始做其它的事情。地址线上的数字被用作指向一个称为中断向量的表格的索引,以便读取一个新的程序计数器。一般情况下,陷阱和中断从这一点上是使用了相同的机制,并且常常共享相同的向量。
终端服务过程开始运行后,它立刻通过将一个确定的值写到中断控制器的某个IO端口来对中断作出应答,这一应答高速中断控制器可以自由发起另一个中断。通过让CPu延迟这一应答知道它准备好下一个中断可以避免与多个几乎同时发生的中断相牵涉的竞争状态。
在开始服务程序之前,硬件总是要保存一定的信息。作为最低限度,必须保存程序计数器,而另一个极端,所有可见的寄存器和许多内部寄存器都要保存。
大多数CPu在对战中保存信息,但是可能是用户进程的堆栈,海可能指向一个页面的末端。若使用内河堆栈,会存在切换到核心态可能要求改变MMU上下文,并且可能使告诉关村和TLB大部分失效。静态或动态的重新装着所有东西会增加处理一个中断的时间,因而让浪费CPU时间。
在老式机器上,如果一个中断正好发生在某一指令之后,那么这条指令(含该指令)都完整的执行过来,而之后的指令一条也没有运行。在现代计算机上这个假设未必正确。
将及其留在一个明确状态的中断称为精确中断。
对于PC所指向的指令之后的那些指令来说,此处没有禁止他们开始执行,而只是要求在中断发生之前必须撤销它们对寄存器或内存所做的任何修改。
某些超标量计算机具有精确中断。为精确中断付出的代价是CPu内部极其复杂的中断逻辑,这里付出的代价不是在时间上,而是在芯片面积和设计复杂性上。
IO软件原理
IO软件的目标
在设计IO软件时一个关键的概念是设备独立性。其疑似是可以访问任意IO设备而无须实现指明设备。
与设备独立性密切相关的是统一命名——一个文件或设备的名字应该是一个简单的字符串或一个证书,不应该原来设备。
IO软件另外的一个重要问题是错误处理。一般来货,错误应该尽可能地在接近硬件的层面得到处理。在许多情况下,错误恢复可以在可以在低层透明地的得到接近,而高层软件甚至不知道存在这一错误。
另一个关键问题是同步(即阻塞)和异步(中断驱动)传输。大多数物理IO是异步的——CPU启动传输时就去做其它工作,直到中断发生。如果IO操作是同步的,那么程序更容易编写。只是操作系统使实际上是终端驱动的操作变成来用户看开是阻塞式的操作。
IO软件另一个问题是缓冲。数据离开一个设备之后通常并不能直接存放其最终的目的地,因此需要缓冲。缓冲涉及大量的复制工作,并且经常对IO性能有重大影响。
还有一个问题是共享设备和独占式设备的问题。
程序控制IO
IO可以以三种根本不同的方式实现最点的形式是让CPU做全部工作,这一方法称为程序控制IO。
该方法首先在用户空间的一个缓冲区组装字符串。然后操作系统(通常)将字符串缓冲区复制到内核空间中国年的一个数组中,在这里访问更加容易(内核可能要通过修改内存映射才能到达用户空间)。一旦打印机可用,操作系统就复制第一个自负到打印机的数据寄存器中。一旦将第一个字符复制到打印机,操作系统就要查看打印机是否就绪准备接收另一个字符。打印机一般有第二个寄存器用户表明状态。将字符写到数据寄存器的操作导致状态变为非就绪。当打印机完成当前字符时,则通过在状态寄存器中设置某一位或将某个值放在其中来表示可用。
操作系统等待打印机状态再次变为就绪。打印机就绪事件发生时,操作系统就打印下一个字符,这一循环持续进行,直到整个字符串打印完毕。然后,控制返回用户进程。
在输出一个字符之后,CPu要不断地查询设备以了解它是否就绪准备接收另一个字符。这哦一行为通常称为轮询或忙等待。
忙等待是低效的,需要更好的方法
中断驱动IO
这种允许CPU在等待打印机变为就绪的同时做某些其他事情的方式就是使用中断。
CPU要调用调度程序,并且某个其他进程将允许,请求打印字符串的进程将被阻塞,直到整个字符串打印完。
当打印机将字符打印完并且准备好接收下一个字符时,它将长恨恶搞一个中断。这一中断将停止当前进程并且保存其状态。
使用DMA的IO
此处的思路是让DMA控制器一次给打印机提供一个字符,而不打扰CPU。本质上,DMA是程序控制IO,只是由DMA控制器而不是主CPU做全部工作。
DMA重大的成功是将终端次数从打印每个字符一次减少到打印每个缓冲区一次。DMA控制器通常比主CPU慢很多,如果DMA控制器不能以全速驱动设备,或者CPU在等待DMA中断的同时没有其他事情要做,那么采用中断驱动IO甚至采用程序控制IO也许更好