linux操作系统中断、异常和系统调用

中断、异常和系统调用是操作系统中十分重要的概念,在这里略作介绍,当作一个复习。

首先,中断和异常的联系是十分紧密的,广义的中断既包含中断也包含异常。

中断(广义):会改变处理器执行指令的顺序,通常与CPU芯片内部或外部硬件电路产生的电信号相对应,广义的中断包括以下两类:

1.来自CPU外部的中断称为外部中断,比如键盘事件、鼠标事件等。按照是否导致宕机来划分可细分为可屏蔽中断和不可屏蔽中断。

2.来自CPU内部的中断称为内部中断,比如除以0错误等。按照是否正常来划分,可分为软中断和异常。

而我们常提及的系统调用则是由一个int 0x80的软中断而陷入内核当中,故系统调用属于软中断的一种(当然这里很多人有不同的说法,也不必过于纠结)。

下面介绍中断的具体知识:

1.外部中断

外部中断通过两根线信号线来通知CPU,这两根线分别为INTR和NMI,INTR是用来传输不影响系统运行的中断信号,比如硬盘、网卡等发出的信号,这类信号由于忽略了也不会导致严重的后果而属于可屏蔽中断,NMI则是用来传输表示发生严重性错误、会影响系统运行的中断,这类中断由于不进行出来的话可能计算机就死机了,必须立即处理而属于不可屏蔽中断。

 

2.内部中断

2.1软中断

常见的软中断就是系统调用了,格式是 "int + 8位立即数",相信写汇编的朋友对此比较熟 悉,更多的软中断这里就不介绍了。

2.2异常

异常主要是程序运行过程中出现的运行错误,比如CPU发现除法中的除数为0,更多的知识在这里也不再介绍。

3.中断描述符表

在中断系统中有两个名字很相像的结构,就是中断描述符表和中断描述符数组。这里我们先说说中断描述符表。​

中断描述符表是保护模式下存储中断处理程序的入口(如果是在实模式下则称为中断向量表)。一个系统中的中断和异常加起来一共是256个,它们以向量的形式保存在中断描述符表中,每一个向量是8字节(整个表大小就是8x256=2048字节),其主要保存着权限位和向量对应的中断或异常处理程序的入口地址,在运行中断之前,必须初始化IDT(中断描述符表),当然一般是在系统启动时即初始化。而一般的,linux会将中断描述符表中的0~31用于非屏蔽中断和异常,其他的中断用于32~255之间。这个中断描述符表的基地址保存在一个特定的叫idtr的寄存器中。

 

Intel把中断描述符分三类:任务门、中断门、陷阱门,而Linux则分成五类:

1.中断门:Intel的中断门,DPL = 0,描述中断处理程序

2.系统门:Intel的陷阱门,DPL = 3,用于系统调用

3.系统中断门:Intel的中断门,DPL = 3,能够被用户进程访问的陷阱门

4.陷阱门:Intel陷阱门,DPL = 0,大部分的异常处理

5.任务门:Intel任务门,DPL = 0,对"Double fault"异常处理

如果产生的广义中断是异常,以系统调用为例,根据eax寄存器中存放的子功能号以及实现建立好的子功能表找到对应的服务程序。

而如果产生的是狭义的中断的话则有些麻烦。

狭义中断的处理过程:

能够发出中断请求的硬件设备控制器都有一条称为IRQ(Interrupt ReQuest)的输出线。所有的IRQ线都与一个中断控制器的输入引脚相连,中断控制器与CPU的INTR引脚相连,各硬件通过此来提出中断服务请求。而每个能够产生中断的设备或者模块都会在内核中注册一个中断处理程序,当产生中断时,根据中断向量找到中断描述符,而中断描述符这个结构中包含中断处理程序,通过此可以执行中断处理程序,在中断处理程序中,首先会保存中断向量号和上下文,之后执行中断线对应的中断服务例程。

具体过程如下:

       linux操作系统中断、异常和系统调用