没有合适的资源?快使用搜索试试~ 我知道了~
第三章 中断机制中断控制是计算机发展中一种重要的技术。最初它是为克服对 I/O 接口控制采用程序查询所带来的处理器低效率而产生的。中断控制的主要优点是只有在 I
资源详情
资源评论
资源推荐
– 55 –
第三章 中断机制
中断控制是计算机发展中一种重要的技术。最初它是为克服对 I/O 接口控制采用程序查
询所带来的处理器低效率而产生的。中断控制的主要优点是只有在 I/O 需要服务时才能得到
处理器的响应,而不需要处理器不断地进行查询。由此,最初的中断全部是对外部设备而言
的,即称为外部中断(或硬件中断)。
但随着计算机系统结构的不断改进以及应用技术的日益提高,中断的适用范围也随之扩
大,出现了所谓的内部中断(或叫异常),它是为解决机器运行时所出现的某些随机事件及编
程方便而出现的。因而形成了一个完整的中断系统。
本章主要讨论在 Intel i386 保护模式下中断机制在 Linux 中的实现。如果你曾有过在
DOS 实模式下编写中断程序的经历,那么,你会发现中断在 Linux 中的实现较为复杂,这是
由保护模式的复杂性引起的,因此,必须首先了解硬件机制对中断的支持。不过,不管在实
模式下还是保护模式下,有关中断实现的基本原理是完全相同的。
3.1 中断基本知识
大多数读者可能对 16 位实地址模式下的中断机制有所了解,例如中断向量、外部 I/O
中断以及异常,这些内容在 32 位的保护模式下依然有效。两种模式之间最本质的差别就是在
保护模式引入的中断描述符表。
3.1.1 中断向量
Intel x86 系列微机共支持 256 种向量中断,为使处理器较容易地识别每种中断源,将
它们从 0~256 编号,即赋予一个中断类型码
n
,Intel 把这个 8 位的无符号整数叫做一个向
量,因此,也叫中断向量。所有 256 种中断可分为两大类:异常和中断。异常又分为故障(Fault)
和陷阱(Trap),它们的共同特点是既不使用中断控制器,又不能被屏蔽。中断又分为外部可
屏蔽中断(INTR)和外部非屏蔽中断(NMI),所有 I/O 设备产生的中断请求(IRQ)均引起屏
蔽中断,而紧急的事件(如硬件故障)引起的故障产生非屏蔽中断。
非屏蔽中断的向量和异常的向量是固定的,而屏蔽中断的向量可以通过对中断控制器的
编程来改变。Linux 对 256 个向量的分配如下。
• 从 0~31 的向量对应于异常和非屏蔽中断。
• 从 32~47 的向量(即由 I/O 设备引起的中断)分配给屏蔽中断。
• 剩余的从 48~255 的向量用来标识软中断。Linux 只用了其中的一个(即 128 或 0x80
深入分析
Linux
内核源代码
– 56 –
向量)用来实现系统调用。当用户态下的进程执行一条 int 0x80 汇编指令时,CPU 就切换到
内核态,并开始执行 system_call( )内核函数。
3.1.2 外设可屏蔽中断
Intel x86 通过两片中断控制器 8259A 来响应 15 个外中断源,每个 8259A 可管理 8 个中
断源。第 1 级(称主片)的第 2 个中断请求输入端,与第 2 级 8259A(称从片)的中断输出
端 INT 相连,如图 3.1 所示。我们把与中断控制器相连的每条线叫做中断线,要使用中断线,
就得进行中断线的申请,就是 IRQ(Interrupt ReQuirement ),我们也常把申请一条中断线
称为申请一个 IRQ 或者是申请一个中断号。IRQ 线是从 0 开始顺序编号的,因此,第一条 IRQ
线通常表示成 IRQ0。IRQn 的缺省向量是
n
+32;如前所述,IRQ 和向量之间的映射可以通过中
断控制器端口来修改。
IRQ0(
时钟
)
IRQ1(
键盘
)
IRQ3(tty2)
IRQ4(tty1)
IRQ5(XT Winchester)
IRQ6(
软驱
)
IRQ7(
打印机
)
IRQ8(
实时时钟
)
IRQ9(
重定向的
IRQ2)
IRQ10
IRQ11
IRQ12
IRQ13(FPU
异常
)
IRQ14(AT Winchester)
IRQ15
INT
从中断
控制器
AC
K
INT
主中断
控制器
ACK
系
统
数
据
总
线
INTR
CPU
INTA
中断
中断
确认
图 3.1 级连的 8259A 的中断机构
并不是每个设备都可以向中断线上发中断信号,只有对某一条确定的中断线拥有了控制
权,才可以向这条中断线上发送信号。由于计算机的外部设备越来越多,所以 15 条中断线已
经不够用了。中断线是非常宝贵的资源,只有当设备需要中断的时候才申请占用一个 IRQ,
或者是在申请 IRQ 时采用共享中断的方式,这样可以让更多的设备使用中断。
中断控制器 8259A 执行如下操作。
(1)监视中断线,检查产生的中断请求(IRQ)信号。
(2)如果在中断线上产生了一个中断请求信号。
a. 把接受到的 IRQ 信号转换成一个对应的向量。
b. 把这个向量存放在中断控制器的一个 I/O 端口,从而允许 CPU 通过数据总线读此
向量。
第三章
中断机制
– 57 –
c. 把产生的信号发送到 CPU 的 INTR 引脚——即发出一个中断。
d. 等待,直到 CPU 确认这个中断信号,然后把它写进可编程中断控制器(PIC)的
一个 I/O 端口;此时,清 INTR 线。
(3)返回到第一步。
对于外部 I/O 请求的屏蔽可分为两种情况,一种是从 CPU 的角度,也就是清除 eflag 的
中断标志位(IF),当 IF=0 时,禁止任何外部 I/O 的中断请求,即关中断;一种是从中断控
制器的角度,因为中断控制器中有一个 8 位的中断屏蔽寄存器(IMR),每位对应 8259A 中的
一条中断线,如果要禁用某条中断线,则把 IRM 相应的位置 1,要启用,则置 0。
3.1.3 异常及非屏蔽中断
异常就是 CPU 内部出现的中断,也就是说,在 CPU 执行特定指令时出现的非法情况。非
屏蔽中断就是计算机内部硬件出错时引起的异常情况。从图 3.1 可以看出,二者与外部 I/O
接口没有任何关系。Intel 把非屏蔽中断作为异常的一种来处理,因此,后面所提到的异常
也包括了非屏蔽中断。在 CPU 执行一个异常处理程序时,就不再为其他异常或可屏蔽中断请
求服务,也就是说,当某个异常被响应后,CPU 清除 eflag 的中 IF 位,禁止任何可屏蔽中断。
但如果又有异常产生,则由 CPU 锁存(CPU 具有缓冲异常的能力),待这个异常处理完后,才
响应被锁存的异常。我们这里讨论的异常中断向量在 0~31 之间,不包括系统调用(中断向
量为 0x80)。
Intel x86 处理器发布了大约 20 种异常(具体数字与处理器模式有关)。Linux 内核必
须为每种异常提供一个专门的异常处理程序。这里特别说明的是,在某些异常处理程序开始
执行之前,CPU 控制单元会产生一个硬件错误码,内核先把这个错误码压入内核栈中。
在表 3.1 中给出了 Pentium 模型中异常的向量、名字、类型及简单描述。更多的信息可
以在 Intel 的技术文挡中找到。
表 3.1 异常的简单描述
向量 异常名 类别 描述
0 除法出错 故障 被 0 除
1 调试 故障/陷阱 当对一个程序进行逐步调试时
2 非屏蔽中断(NMI) 为不可屏蔽中断保留
3 断点 陷阱 由 int3(断点指令)指令引起
4 溢出 陷阱 当 into(check for overflow)指令被执行
5 边界检查 故障 当 bound 指令被执行
6 非法操作码 故障 当 CPU 检查到一个无效的操作码
7 设备不可用 故障 随着设置 cr0 的 TS 标志,ESCAPE 或 MMX 指令
被执行
8 双重故障 故障 处理器不能串行处理异常而引起的
深入分析
Linux
内核源代码
– 58 –
续表
向量 异常名 类别 描述
9 协处理器段越界 故障 因外部的数学协处理器引起的问题(仅用在 80386)
10 无效 TSS 故障 要切换到的进程具有无效的 TSS
11 段不存在 故障 引用一个不存在的内存段
12 栈段异常 故障 试图超过栈段界限,或由 ss 标识的段不在内存
13 通用保护 故障 违反了 Intelx86 保护模式下的一个保护规则
14 页异常 故障 寻址的页不在内存,或违反了一种分页保护机制
15 Intel 保留 / 保留
16 浮点出错 故障 浮点单元用信号通知一个错误情形,如溢出
17 对齐检查 故障 操作数的地址没有被正确地排列
18~31 由 Intel 保留,为将来的扩充用。
另外,如表 3.2 所示,每个异常都由专门的异常处理程序来处理(参见本章后面“异常
处理“部分),它们通常把一个 UNIX 信号发送到引起异常的进程。
表 3.2 由异常处理程序发送的信号
向量 异常名 出错码 异常处理程序 信号
0 除法出错 / divide_error( ) SIGFPE
1 调试 / debug( ) SIGTRAP
2 非屏蔽中断(NMI) / nmi( ) None
3 断点 / int3( ) SIGTRAP
4 溢出 / overflow( ) SIGSEGV
5 边界检查 / bounds( ) SIGSEGV
6 非法操作码 / invalid_op( ) SIGILL
7 设备不可用 / device_not_available( ) SIGSEGV
8 双重故障 有 double_fault( ) SIGSEGV
9 协处理器段越界 / coprocessor_segment_overrun
( )
SIGFPE
10 无效 TSS 有 invalid_tss( ) SIGSEGV
11 段不存在 有 segment_not_present( ) SIGBUS
12 栈段异常 有 stack_segment( ) SIGBUS
13 通用保护 有 general_protection( ) SIGSEGV
14 页异常 有 page_fault( ) SIGSEGV
第三章
中断机制
– 59 –
15 Intel 保留 / None None
续表
向量 异常名 出错码 异常处理程序 信号
16 浮点出错 / coprocessor_error( ) SIGFPE
17 对齐检查 / alignment_check( ) SIGSEGV
3.1.4 中断描述符表
在实地址模式中,CPU 把内存中从 0 开始的 1K 字节作为一个中断向量表。表中的每个表
项占 4 个字节,由两个字节的段地址和两个字节的偏移量组成,这样构成的地址便是相应中
断处理程序的入口地址。但是,在实模式下,由 4 字节的表项构成的中断向量表显然满足不
了要求。这是因为,c除了两个字节的段描述符,偏移量必用 4 字节来表示;d要有反映模
式切换的信息。因此,在实模式下,中断向量表中的表项由 8 个字节组成,如图 3.2 所示,
中断向量表也改叫做中断描述符表 IDT(Interrupt Descriptor Table)。其中的每个表项叫
做一个门描述符(Gate Descriptor),“门”的含义是当中断发生时必须先通过这些门,然后
才能进入相应的处理程序。
偏移量
31
…
16
P DPL 0DXXX 000
段选择符
偏移量
15
…
0
31
16
15 12 8 7 5 4 0
31
16
15 0
DPL
段描述符的特权级
偏移量
入口函数地址的偏移量
P
段是否在内存中的标志
段选择符
入口函数所处代码段的选择符
D
标志位,
1=32
位,
0=16
位
XXX 3
位门类型码
图 3.2 门描述符的一般格式
其中类型占 3 位,表示门描述符的类型,这些描述符如下。
1.任务门(Task gate)
其类型码为 101,门中包含了一个进程的 TSS 段选择符,但偏移量部分没有使用,因为 TSS
本身是作为一个段来对待的,因此,任务门不包含某一个入口函数的地址。TSS 是 Intel 所提供
的任务切换机制,但是 Linux 并没有采用任务门来进行任务切换(参见第五章的任务切换)。
2.中断门(Interrupt gate)
其类型码为 110,中断门包含了一个中断或异常处理程序所在段的选择符和段内偏移量。
当控制权通过中断门进入中断处理程序时,处理器清 IF 标志,即关中断,以避免嵌套中断的
剩余43页未读,继续阅读
图像车间
- 粉丝: 21
- 资源: 298
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论0