Chinaunix首页 | 论坛 | 博客
  • 博客访问: 51649
  • 博文数量: 75
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2013-04-12 12:32
文章分类

全部博文(75)

文章存档

2013年(75)

我的朋友

分类: LINUX

2013-04-12 13:03:19

原文地址:linux中断异常分析 作者:liujunwei1234

一 基础背景知识
1 中断(广义)会改变处理器执行指令的顺序,通常与CPU芯片内部或外部硬件电路产生的电信号相对应
Ø中断——异步的:
由硬件随机产生,在程序执行的任何时候可能出现
Ø异常——同步的:
在(特殊的或出错的)指令执行时由CPU控制单元产生
我们用中断信号来通称这两种类型的中断
断上下文不同于进程上下文
Ø中断或异常处理程序执行的代码不是一个进程
Ø它是一个内核控制路径,代表了中断发生时正在运行的进程执行
Ø作为一个进程的内核控制路径,中断处理程序比一个进程要(中断上下文只包含了很有限的几个寄存器,建立和终止这个上下文所需要的时间很少)
中断分类:

 

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开始顺序编号
ØIRQ0IRQ1
vIntel给中断控制器分配的中断向量号从32开始,上述IRQ线对应的中断向量依次是
Ø32+032+1
v可以对中断控制器编程
Ø修改起始中断向量的值,或
Ø有选择的屏蔽/激活每条IRQ线
8 异常
可屏蔽中断的向量可以通过对中断控制器的编程来改变
发生严重的错误。eip值无效,只有强制终止受影响的进程
例如系统调用
 
vX86处理器发布了大约20种不同的异常。
Ø某些异常通过硬件出错码说明跟异常相关的信息
Ø出错码会在陷入异常处理时,由硬件压入内核栈
v
10 中断描述附表(IDT)
 
v中断描述符表是一个系统表,它与每一个中断或者异常向量相联系
Ø每个向量在表中有相应的中断或者异常处理程序的入口地址
Ø每个描述符8个字节,共256项,占用空间2KB
Ø内核在允许中断发生前,必须适当的初始化IDT
v
11 中断或异常的硬件处理
假定:内核已经初始化,CPU在保护模式下运行
vCPU的正常运行: 当执行了一条指令后,cseip这对寄存器包含了下一条将要执行的指令的逻辑地址。在执行这条指令之前,CPU控制单元会检查在运行前一条指令时是否发生了一个中断或者异常。 如果发生了一个中断或异常,那么CPU控制单元执行下列操作:
 
(1) 确定与中断或者异常关联的向量i0~255
(2)idtr寄存器指向的IDT表中的第i
(3)gdtr寄存器获得GDT的基地址,并在GDT中查找,以读IDT表项中的段选择符所标识的段描述符
(4)确定中断是由授权的发生源发出的。
Ø中断:中断处理程序的特权不能低于引起中断的程序的特权(对GDT表项中的DPL vs CS寄存器中的CPL
Ø
(5)检查是否发生了特权级的变化,一般指是否由用户态陷入了内核态。
如果是由用户态陷入了内核态,控制单元必须开始使用与新的特权级相关的堆栈
a,读tr寄存器,访问运行进程的tss
b用与新特权级相关的栈段和栈指针装载ssesp寄存器。些值可以在进程的tss段中找到
c,在新的栈中保存ssesp以前的值,这些值指明了与旧特权级相关的栈的逻辑地址
(6)若发生的是故障,用引起异常的指令地址修改cseip寄存器的值,以使得这条指令在异常处理结束后能被再次执行
7)在栈中保存eflagscseip的内容
8)如果异常产生一个硬件出错码,则将它保存在栈中
9)装载cseip寄存器,其值分别是IDT表中第i项门描述符的段选择符和偏移量字段。这对寄存器值给出中断或者异常处理程序的第一条指定的逻辑地址
12  从中断/异常返回
中断/异常处理完后,相应的处理程序会执行一条iret编指令,这条汇编指令让CPU控制单元做如下事情:
1)用保存在栈中的值装载cseipeflags寄存器。如果一个硬件出错码曾被压入栈中,那么弹出这个硬件出错码
2)检查处理程序的特权级是否等于cs中最低两位的值(这意味着进程在被中断的时候是运行在内核态还是用户态)。若是,iret终止执行;否则,转入3
3)从栈中装载ssesp寄存器。这步意味着返回到与旧特权级相关的栈
4)检查dsesfsgs段寄存器的内容,如果其中一个寄存器包含的选择符是一个段描述符,并且特权级比当前特权级高,则清除相应的寄存器。这么做是防止怀有恶意的用户程序利用这些寄存器访问内核空间
以上部分即中断和异常部分的基础知识,我们将在下面的文章中详细介绍中断和异常与代码相关的部分,主要讲解相关的
数据结构以及重要的代码。
编程异常:还需比较CPL与对应IDT表项中的DPL
CPUidtr寄存器指向IDT表的物理基地址
内核为每个异常提供了一个专门的异常处理程序
阅读(182) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~