保护模式下
8259A芯片编程及中断处理探究(上)
Version 0.02
哈尔滨工业大学 并行计算实验室 谢煜波[1]
简介
中断处理是操作系统必须完成的任务,在IBM PC中,常用一块中断控制芯片(PIC)——8259A来辅助CPU完成中断管理。在实模式下,中断控制芯片(PIC)8259A的初始化是由BIOS自动完成的,然而在保护模式下却需要我们自行编程初始化。本篇拟从操作系统的编写角度详细描述下笔者在此方向上所做的摸索,并在最后通过pyos进行实验验证。此是这部份内容的上篇,将详细描述8259A芯片的编程部份,对于操作系统中的中断处理以及程序验证将在下篇里面详细描述。
此文只是我在进行操作系统实验过程中的一点心得体会,记下来,避免自己忘记。对于其中可能出现的错误,欢迎你来信指证。
一、中断概述
相信大家对于中断一点都不陌生,这里也不准备详细介绍中断的所有内容,只简单做下概要介绍,这样使对中断没有概念的朋友能建立起一点概念。
计算机除了CPU外,还有很多外围设备,然而我们都知道CPU的运行速度是很快的,而外围设备的运行速度却不是很快了。假设我们现在需要从磁盘上读入十个字节,而这需要10秒钟(很夸张,但这只是一个例子),那么在这10秒钟之内,CPU就无所事事,不得不等待磁盘如蜗牛般的读入这十个字节,如果在这10秒钟之内,CPU转去运行其它的程序,不就可以防止浪费CPU的时间了吗?但是这就出现了一个问题,CPU怎么知道磁盘已经读完数据了呢?实际上,这时磁盘的控制器会向CPU发送一个信号,CPU收到信号之后,就知道磁盘已经读完数据了,于是它就中断正在运行的程序,重新回到原先等待磁盘输入的程序上来继续执行。这只是一个很简单的例子,也只是中断应用的一个很简单的方面,但基本上可以说明问题。可以这么认为:中断就是外部设备或程序同CPU通信的一种方式。CPU在接收到中断信号时,会中断正在运行的程序,转到对中断的处理上,而这个对中断的处理程序常常称为中断服务程序,当中断服务程序处理完中断后,CPU再返回到原先被中断的程序上继续执行。整个过程如下图所示:
(图1)
中断有很多类型,比如可屏蔽中断(顾名思义,对此种中断,CPU可以不响应)、不可屏蔽中断;软中断(一般由运行中的程序触发)、硬中断……等很多分类方法。中断可以完成的任务也很多,比如设备准备完毕、设备运行故障、程序运行故障……,这许多突发事件都可以以中断的方式通知CPU进行处理。
二、认识中断号及8259A芯片
我们都知道计算机可以挂接上许多外部设备,比如键盘、磁盘驱动器、鼠标、声卡……等等一系列设备,而这些设备都可能在同一时刻向CPU发出中断信号,那么CPU到底应当响应哪一个设备的中断信号呢?这都通过另外一个芯片来控制,在IBM PC机中,这个芯片常常被称作:可编程中断控制器(PIC)8259A,说它可编程,是因为我们可以通过编程来改变它的功能。比如我可以通过编程设定CPU应当优先响应哪一个中断,屏蔽哪些中断等等一系列事件。
一个8259A芯片共有中断请求(IRQ)信号线:IRQ0~IRQ7,共8根。在PC机中,共有两片8259A芯片,通过把它们联结起来使用,就有IRQ0~IRQ15,共16根中断信号线,每个外部设备使用一根或多个外部设备共用一根中断信号线,它们通过IRQ发送中断请求,8259A芯片接到中断请求后就对中断进行优先级选定,然后对多个中断中具有最高优先级的中断进行处理,将其所对应的中断向量送上通往CPU的数据线,并通知CPU有中断到来。
这里出现了一个中断向量的概念,其实它就是一个被送往CPU数据线的一个整数。CPU给每个IRQ分配了一个类型号,通过这个整数,CPU来识别不同类型的中断。这里可能很多朋友会寻问为什么还要弄个中断向量这么麻烦的东东?为什么不直接用IRQ0~IRQ15就完了?比如就让IRQ0为0,IRQ1为1……,这不是要简单的多么?其实这里体现了模块化设计规则以及节约规则。
首先我们先谈谈节约规则,所谓节约规则就是所使用的信号线数越少越好,这样如果每个IRQ都独立使用一根数据线,如IRQ0用0号线,IRQ1用1号线……这样,16个IRQ就会用16根线,这显然是一种浪费。那么也许马上就有朋友会说:那么只用4根线不就行了吗(24=16)?
对于这个问题,则体现了模块设计规则。我们在前面就说过中断有很多类,可能是外部硬件触发,也可能是由软件触发,然而对于CPU来说中断就是中断,只有一种,CPU不用管它到底是由外部硬件触发的还是由运行的软件本身触发的,因为对于CPU来说,中断处理的过程都是一样的:中断现行程序,转到中断服务程序处执行,回到被中断的程序继续执行。CPU总共可以处理256种中断,而并不知道,也不应当让CPU知道这是硬件来的中断还是软件来的中断,这样,就可以使CPU的设计独立于中断控制器的设计,因为CPU所需完成的工作就很单纯了。CPU对于其它的模块只提供了一种接口,这就是256个中断处理向量,也称为中断号。由这些中断控制器自行去使用这256个中断号中的一个与CPU进行交互。比如,硬件中断可以使用前128个号,软件中断使用后128个号,也可以软件中断使用前128个号,硬件中断使用后128个号,这于CPU完全无关了,当你需要处理的时候,只需告诉CPU你用的是哪个中断号就行,而不需告诉CPU你是来自哪儿的中断。这样也方便了以后的扩充,比如现在机器里又加了一片8259芯片,那么这个芯片就可以使用空闲的中断号,看哪一个空闲就使用哪一个,而不是必须要使用第0号,或第1号中断。其实这相当于一种映射机制,把IRQ信号映射到不同的中断号上,IRQ的排列或说编号是固定的,但通过改变映射机制,就可以让IRQ映射到不同的中断号,也可以说调用不同的中断服务程序,因为中断号是与中断服务程序一一对应的,这一点我们将在随后的内容中详细描述。8259A将中断号通知CPU后,它的任务就完成了,至于CPU使用此中断号去调用什么程序它就不管了。下图就是8259A芯片的结构:
(图2 来源《Linux 0.11 内核完全注释》)
上图就是PC机中两片8259A的联结及IRQ分配示意图。从图中我们可以看到,两片8259A芯片是级联工作的,一个为主片,一个为从片,从片的INT端口与主片的IRQ2相连。主片通过0x20及0x21两个端口访问,而从片通过0xA0及0xA1这两个端口访问。
至于为什么从片的INT需要与主片的IRQ2相连而不是与其它的IRQ相联,很遗憾,我目前无法回答这个问题:(,如果你知道答案,非常希望你能来信指教!不过幸运的是,我们只要知道计算机是的确是这样联的,并且这样连它就可以正常工作就行了!