预计阅读本页时间:-
5.1.4 直接存储器存取
无论一个CPU是否具有内存映射I/O,它都需要寻址设备控制器以便与它们交换数据。CPU可以从I/O控制器每次请求一个字节的数据,但是这样做浪费CPU的时间,所以经常用到一种称为直接存储器存取(Direct Memory Access,DMA)的不同方案。只有硬件具有DMA控制器时操作系统才能使用DMA,而大多数系统都有DMA控制器。有时DMA控制器集成到磁盘控制器和其他控制器之中,但是这样的设计要求每个设备有一个单独的DMA控制器。更加普遍的是,只有一个DMA控制器可利用(例如,在主板上),由它调控到多个设备的数据传送,而这些数据传送经常是同时发生的。
无论DMA控制器在物理上处于什么地方,它都能够独立于CPU而访问系统总线,如图5-4所示。它包含若干个可以被CPU读写的寄存器,其中包括一个内存地址寄存器、一个字节计数寄存器和一个或多个控制寄存器。控制寄存器指定要使用的I/O端口、传送方向(从I/O设备读或写到I/O设备)、传送单位(每次一个字节或每次一个字)以及在一次突发传送中要传送的字节数。

为了解释DMA的工作原理,让我们首先看一下没有使用DMA时磁盘如何读。首先,控制器从磁盘驱动器串行地、一位一位地读一个块(一个或多个扇区),直到将整块信息放入控制器的内部缓冲区中。接着,它计算校验和,以保证没有读错误发生。然后控制器产生一个中断。当操作系统开始运行时,它重复地从控制器的缓冲区中一次一个字节或一个字地读取该块的信息,并将其存入内存中。
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
使用DMA时,过程是不同的。首先,CPU通过设置DMA控制器的寄存器对它进行编程,所以DMA控制器知道将什么数据传送到什么地方(图5-4中的第1步)。DMA控制器还要向磁盘控制器发出一个命令,通知它从磁盘读数据到其内部的缓冲区中,并且对校验和进行检验。如果磁盘控制器的缓冲区中的数据是有效的,那么DMA就可以开始了。
DMA控制器通过在总线上发出一个读请求到磁盘控制器而发起DMA传送(第2步)。这一读请求看起来与任何其他读请求是一样的,并且磁盘控制器并不知道或者并不关心它是来自CPU还是来自DMA控制器。一般情况下,要写的内存地址在总线的地址线上,所以当磁盘控制器从其内部缓冲区中读取下一个字的时候,它知道将该字写到什么地方。写到内存是另一个标准总线周期(第3步)。当写操作完成时,磁盘控制器在总线上发出一个应答信号到DMA控制器(第4步)。于是,DMA控制器步增要使用的内存地址,并且步减字节计数。如果字节计数仍然大于0,则重复第2步到第4步,直到字节计数到达0。此时,DMA控制器将中断CPU以便让CPU知道传送现在已经完成了。当操作系统开始工作时,用不着将磁盘块复制到内存中,因为它已经在内存中了。
DMA控制器在复杂性方面的区别相当大。最简单的DMA控制器每次处理一路传送,如上面所描述的。复杂一些的DMA控制器经过编程可以一次处理多路传送,这样的控制器内部具有多组寄存器,每一通道一组寄存器。CPU通过用与每路传送相关的参数装载每组寄存器而开始。每路传送必须使用不同的设备控制器。在图5-4中,传送每一个字之后,DMA控制器要决定下一次要为哪一设备提供服务。DMA控制器可能被设置为使用轮转算法,它也可能具有一个优先级规划设计,以便让某些设备受到比其他设备更多的照顾。假如存在一个明确的方法分辨应答信号,那么在同一时间就可以挂起对不同设备控制器的多个请求。出于这样的原因,经常将总线上不同的应答线用于每一个DMA通道。
许多总线能够以两种模式操作:每次一字模式和块模式。某些DMA控制器也能够以这两种模式操作。在前一个模式中,操作如上所述:DMA控制器请求传送一个字并且得到这个字。如果CPU也想使用总线,它必须等待。这一机制称为周期窃取(cycle stealing),因为设备控制器偶尔偷偷溜入并且从CPU偷走一个临时的总线周期,从而轻微地延迟CPU。在块模式中,DMA控制器通知设备获得总线,发起一连串的传送,然后释放总线。这一操作形式称为突发模式(burst mode)。它比周期窃取效率更高,因为获得总线占用了时间,并且以一次总线获得的代价能够传送多个字。突发模式的缺点是,如果正在进行的是长时间突发传送,有可能将CPU和其他设备阻塞相当长的周期。
在我们一直讨论的模型——有时称为飞越模式(fly-by mode)中,DMA控制器通知设备控制器直接将数据传送到主存。某些DMA控制器使用的其他模式是让设备控制器将字发送给DMA控制器,DMA控制器然后发起第2个总线请求将该字写到它应该去的任何地方。采用这种方案,每传送一个字需要一个额外的总线周期,但是更加灵活,因为它可以执行设备到设备的复制甚至是内存到内存的复制(通过首先发起一个到内存的读,然后发起一个到不同内存地址的写)。
大多数DMA控制器使用物理内存地址进行传送。使用物理地址要求操作系统将预期的内存缓冲区的虚拟地址转换为物理地址,并且将该物理地址写入DMA控制器的地址寄存器中。在少数DMA控制器中使用的一个替代方案是将虚拟地址写入DMA控制器,然后DMA控制器必须使用MMU来完成虚拟地址到物理地址的转换。只有在MMU是内存的组成部分(有可能,但罕见)而不是CPU的组成部分的情况下,才可以将虚拟地址放到总线上。
我们在前面提到,在DMA可以开始之前,磁盘首先要将数据读入其内部的缓冲区中。你也许会产生疑问:为什么控制器从磁盘读取字节后不立即将其存储在主存中?换句话说,为什么需要一个内部缓冲区?有两个原因。首先,通过进行内部缓冲,磁盘控制器可以在开始传送之前检验校验和。如果校验和是错误的,那么将发出一个表明错误的信号并且不会进行传送。
第二个原因是,一旦磁盘传送开始工作,从磁盘读出的数据就是以固定速率到达的,而不论控制器是否准备好接收数据。如果控制器要将数据直接写到内存,则它必须为要传送的每个字取得系统总线的控制权。此时,若由于其他设备使用总线而导致总线忙(例如在突发模式中),则控制器只能等待。如果在前一个磁盘字还未被存储之前下一个磁盘字到达,控制器只能将它存放在某个地方。如果总线非常忙,控制器可能需要存储很多字,而且还要完成大量的管理工作。如果块被放入内部缓冲区,则在DMA启动前不需要使用总线,这样,控制器的设计就可以简化,因为对DMA到内存的传送没有严格的时间要求。(事实上,有些老式的控制器是直接存取内存的,其内部缓冲区设计得很小,但是当总线很忙时,一些传送有可能由于超载运行错误而被终止。)