您的位置:首页 > 运维架构 > Linux

linux 中断 异常详细分析 --- 基于linux 2.6.28

2009-04-15 12:42 417 查看
v
一 基础背景知识
1 中断(广义)会改变处理器执行指令的顺序,通常与CPU芯片内部或外部硬件电路产生的电信号相对应
Ø中断——异步的:
由硬件随机产生,在程序执行的任何时候可能出现
Ø异常——同步的:
在(特殊的或出错的)指令执行时由CPU控制单元产生
我们用“中断信号”来通称这两种类型的中断
2 中断上下文不同于进程上下文

Ø中断或异常处理程序执行的代码不是一个进程
Ø它是一个内核控制路径,代表了中断发生时正在运行的进程执行
Ø作为一个进程的内核控制路径,中断处理程序比一个进程要“轻”(中断上下文只包含了很有限的几个寄存器,建立和终止这个上下文所需要的时间很少)

3 中断分类:

v可屏蔽中断(Maskable interrupt)
ØI/O设备发出的所有中断请求(IRQ)都可以产生可屏蔽中断。
Ø可屏蔽中断可以处于两种状态:屏蔽的(masked)和非屏蔽的(unmasked)
v非屏蔽中断(Nonmaskable interrupt)
Ø只有几个特定的危急事件才引起非屏蔽中断。如硬件故障或是掉电
4 异常分类

v处理器探测异常
Ø由CPU执行指令时探测到一个反常条件时产生,如溢出、除0错等
v编程异常
Ø由编程者发出的特定请求产生,通常由int类指令触发
Ø通常叫做“软中断”

Ø

v对于处理器探测异常,根据异常时保存在内核堆栈中的eip的值可以进一步分为:
Ø故障(fault):eip=引起故障的指令的地址
l通常可以纠正,处理完异常时,该指令被重新执行
l例如缺页异常
Ø陷阱(trap):eip=随后要执行的指令的地址。
Ø异常中止(abort):eip=???

l

5 中断向量
每个中断和异常由0~255之间的一个数(8位)来标识,Intel称其为中断向量。

Ø非屏蔽中断的向量和异常的向量是固定的

Ø
6 中断控制器
(1)监视IRQ线,对引发信号检查(编号小者优先)

(2)如果一个引发信号出现在IRQ线上
a,把此信号转换成对应的中断向量
b,把这个向量存放在中断控制器的一个I/O端口,从而允许CPU通过数据总线读这个向量
c,把引发信号发送到处理器的INTR引脚,即产生一个中断
d,等待,直到CPU应答这个信号;收到应答后,清INTR引脚
(3)返回到第1步
7 IRQ号和中断向量号
中断控制器对输入的IRQ线从0开始顺序编号

ØIRQ0,IRQ1,…
vIntel给中断控制器分配的中断向量号从32开始,上述IRQ线对应的中断向量依次是
Ø32+0、32+1、…
v可以对中断控制器编程:
Ø修改起始中断向量的值,或
Ø有选择的屏蔽/激活每条IRQ线
8 异常

可屏蔽中断的向量可以通过对中断控制器的编程来改变

发生严重的错误。eip值无效,只有强制终止受影响的进程

例如系统调用

vX86处理器发布了大约20种不同的异常。
Ø某些异常通过硬件出错码说明跟异常相关的信息
Ø出错码会在陷入异常处理时,由硬件压入内核栈

v



10 中断描述附表(IDT)

v中断描述符表是一个系统表,它与每一个中断或者异常向量相联系
Ø每个向量在表中有相应的中断或者异常处理程序的入口地址。
Ø每个描述符8个字节,共256项,占用空间2KB
Ø内核在允许中断发生前,必须适当的初始化IDT

v

11 中断或异常的硬件处理
假定:内核已经初始化,CPU在保护模式下运行

vCPU的正常运行: 当执行了一条指令后,cs和eip这对寄存器包含了下一条将要执行的指令的逻辑地址。在执行这条指令之前,CPU控制单元会检查在运行前一条指令时是否发生了一个中断或者异常。 如果发生了一个中断或异常,那么CPU控制单元执行下列操作:

(1) 确定与中断或者异常关联的向量i(0~255)
(2)读idtr寄存器指向的IDT表中的第i项
(3)从gdtr寄存器获得GDT的基地址,并在GDT中查找,以读取IDT表项中的段选择符所标识的段描述符
(4)确定中断是由授权的发生源发出的。
Ø中断:中断处理程序的特权不能低于引起中断的程序的特权(对应GDT表项中的DPL vs CS寄存器中的CPL)

Ø
(5)检查是否发生了特权级的变化,一般指是否由用户态陷入了内核态。
如果是由用户态陷入了内核态,控制单元必须开始使用与新的特权级相关的堆栈

a,读tr寄存器,访问运行进程的tss段
b,用与新特权级相关的栈段和栈指针装载ss和esp寄存器。这些值可以在进程的tss段中找到
c,在新的栈中保存ss和esp以前的值,这些值指明了与旧特权级相关的栈的逻辑地址
(6)若发生的是故障,用引起异常的指令地址修改cs和eip寄存器的值,以使得这条指令在异常处理结束后能被再次执行

7)在栈中保存eflags、cs和eip的内容
8)如果异常产生一个硬件出错码,则将它保存在栈中
9)装载cs和eip寄存器,其值分别是IDT表中第i项门描述符的段选择符和偏移量字段。这对寄存器值给出中断或者异常处理程序的第一条指定的逻辑地址
12 从中断/异常返回
中断/异常处理完后,相应的处理程序会执行一条iret汇编指令,这条汇编指令让CPU控制单元做如下事情:

1)用保存在栈中的值装载cs、eip和eflags寄存器。如果一个硬件出错码曾被压入栈中,那么弹出这个硬件出错码
2)检查处理程序的特权级是否等于cs中最低两位的值(这意味着进程在被中断的时候是运行在内核态还是用户态)。若是,iret终止执行;否则,转入3
3)从栈中装载ss和esp寄存器。这步意味着返回到与旧特权级相关的栈

4)检查ds、es、fs和gs段寄存器的内容,如果其中一个寄存器包含的选择符是一个段描述符,并且特权级比当前特权级高,则清除相应的寄存器。这么做是防止怀有恶意的用户程序利用这些寄存器访问内核空间

以上部分即中断和异常部分的基础知识,我们将在下面的文章中详细介绍中断和异常与代码相关的部分,主要讲解相关的
数据结构以及重要的代码。

编程异常:还需比较CPL与对应IDT表项中的DPL

CPU的idtr寄存器指向IDT表的物理基地址

内核为每个异常提供了一个专门的异常处理程序
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: