无论你是备考408,还是912,亦或只是一个单纯的操作系统爱好者,我们都会在各种操作系统的教材上看到这么一句表达:操作系统是管理计算机硬件和软件资源的计算机程序。可是,操作系统究竟是如何工作的呢?中断的具体过程又是什么样的?对于很多读者来说,你可能已经学习了很多进程调度算法、地址虚拟化算法、文件系统特征等,但是对于这些最基本的问题,你可能依然感觉隔着一层朦胧的纱。今天,我们就能揭开这层神秘面纱,看一下一些操作系统最基本的问题。
在谈操作系统之前,我们必须先大致描述一些硬件知识,我们必须知道哪些事情是硬件来做的。在我们的CPU中,有这么一些引脚,它为CPU传递中断信号。这里,我们提及了一个大家都很熟悉的名词”中断“,没错,中断,它并不是操作系统规定出来的概念,而是一台计算机刚被造出来,就被赋予的硬件功能。那么我们来看看,中断发生的时候,硬件又会进行哪些工作呢?
中断的触发原因多种多样,比如鼠标或键盘所引发的”外部中断“,运算器在执行触发运算时发现除数为0,还有应用程序使用的”系统调用“等。而每一类中断,都是硬件计划好的,每一种中断都有一个中断号(指向中断向量),请记住,某种中断提供给CPU哪一个中断号,是硬件决定的,而不是操作系统。
在x86下,CPU收到了引脚传来的中断号后,它会做什么呢?它会查看我们内存中的IDT表,而这个表的基址存储在一个叫做IDTR的寄存器中,而查看表里的哪一项则取决于我们的中断号,与此同时,CPU进入内核态。例如,如果中断原因为除数为0,它便会给我们一个0中断号,我们便取出了IDT表中的第0项。取出IDT表项后,其中含有中断服务程序的段基址和段内偏移,依据这两个信息,我们便可以寻找到中断服务程序的具体地址,执行中断服务程序了。所以,我们经常会看到这样的论述:”中断向量地址是中断服务例程的地址的地址“。
但是要完整执行一个中断,只找到中断服务程序显然无法做到,因为我们还需要传入参数。例如我们需要读一个内存,那么只告诉CPU我们需要一个系统调用是远远不够的,因为内核要完成它还需要知道其他信息:例如对应的系统调用号(注意区分系统调用号与中断号,所有的系统调用都是同一个中断号进入同一个中断服务程序,根据系统调用号来决定具体执行哪一个系统调用)、要读的内存地址、缓冲区地址等。由于陷入内核态后会产生堆栈和虚拟空间的切换,所以我们能够用来传递这些信息的只有寄存器。这个时候,我们只需要做好一个约定 ,例如,系统调用执行前,我们把系统调用号压入到AX寄存器中,并且和内存约定好从AX中取走系统调用号,就可以完成系统调用号的跨特权级传递。
所以,在这个过程中,哪些工作是由操作系统来做的呢?我们可以看到,CPU会根据中断去查IDT,但是IDT中的内容却是由我们的os来填写的,也就是说操作系统可以决定每一类中断需要跳转到哪里去执行中断服务程序,也可以决定中断服务程序的具体内容,也就是规定每一类中断后计算机所要进行的行为。与此同时,信息如何传递的具体约定也是由系统程序员来决定的。
为什么要说这么多中断的内容?因为,中断是操作系统工作的基石。我们的操作系统在完成初始的配置之后,便开始进入一种空转的状态,它等待着响应各种各样的中断。所以,可以说,操作系统程序其实是一个很被动的存在,只有发生中断时它才会跳出来执行”管理者”的功能。所以,操作系统其实是中断响应的。
理解了上述过程,我们便理解了操作系统运行的一些最基本的逻辑,也能够更充分的理解教材中一些看起来很莫名其妙的表达。以上表达,均基于ucore操作系统和x86,符合408和912考察的操作系统的特征,可能与现代操作系统的特点有所偏差,希望有更高要求的读者能够理解。
![e8d5a820f8e64fe53d231585d133bbfa.png](https://i-blog.csdnimg.cn/blog_migrate/abcba0cce5c5c722c6a26b233e9564a8.jpeg)