8259A:掌握中断大权的傲娇女王!👑
![[5fc6160c5f7c8 1.pdf]]
1.0 中断处理基础:一个五步协议
中断处理并非一系列孤立的事件,而是一个基础协议,用于管理异步硬件事件与同步CPU执行之间的交互。该协议确保了CPU能够高效地处理外部请求,同时维持主程序的完整性。整个过程可分解为五个逻辑连贯的阶段。
1.1 步骤一:中断请求 (Interrupt Request)
中断处理的起点是中断源发出的服务请求。中断源可分为内部中断源和外部中断源两大类 1。内部中断源于程序执行过程本身,是同步于程序计数器的事件,例如执行
INT n
指令、发生除零错误或运算溢出 1。外部中断源则由外部硬件设备触发,通过CPU的特定引脚(如NMI或INTR)发出异步信号,其发生时间相对于CPU的指令流是不可预测的 1。
这一步骤的本质是建立了一种“异步契约”。外部设备在需要服务时发出信号,无需关心CPU当前正在执行何种任务。相应地,CPU承诺在满足特定条件时最终会响应此请求。这种解耦的通信机制是现代计算中实现高效I/O和多任务处理的基石。与此相对的是轮询(Polling)机制,CPU需要不断地查询设备状态,这会极大地浪费处理器资源。中断机制则允许CPU在等待I/O操作完成时继续执行其他有用的计算任务,从而显著提升了系统的并行处理能力 1。
1.2 步骤二:中断仲裁与优先级判定 (Interrupt Arbitration and Prioritization)
在现实世界的应用中,多个中断请求可能同时到达。为了确保系统的稳定性和实时性,必须建立一个仲裁机制来决定首先响应哪个请求,这就是中断优先级判定 1。若无优先级管理,一个关键且时效性强的事件(如通过NMI引脚传入的电源故障警告)可能会被一个常规事件(如通过INTR引脚传入的键盘输入)所延迟,从而导致系统崩溃。
8086体系结构在此展现了明确的职责划分。CPU自身负责宏观层面的优先级管理,即在其核心中断类型之间进行裁决。其固有的、不可编程的优先级顺序为:内部中断(如除法错误、INT n
指令)> NMI中断 > INTR中断 > 单步中断 1。然而,8086 CPU只有一个可屏蔽中断请求引脚(INTR),无法直接处理来自多个外部设备的请求 1。因此,它将微观层面的优先级管理——即在多个可屏蔽硬件设备之间进行仲裁——的职责委托给了一个专门的外围芯片,即可编程中断控制器8259A 1。这种设计将复杂的优先级判定逻辑从CPU核心中剥离,转移到一个可编程的专用模块上,不仅简化了CPU的设计,也使得整个中断系统更具模块化和可扩展性。8259A的存在正是为了解决由单一INTR引脚所带来的扇入、优先级排序和中断向量提供等一系列问题 1。
1.3 步骤三:中断响应 (Interrupt Response)
CPU并不会在收到中断请求后立即处理,而是需要满足一系列响应条件。对于可屏蔽中断(INTR),要求当前指令执行完毕、CPU处于开中断状态(即中断允许标志位$IF=1$
),且无更高优先级的中断请求(如NMI)等待处理 1。一旦条件满足,CPU便进入中断响应周期,由其内部微码自动执行一系列硬件操作。
此过程的核心是保存当前程序的执行上下文,以确保中断服务完成后能准确返回。CPU硬件自动完成以下操作:
-
将程序状态字(PSW,即标志寄存器)压入堆栈。
-
将当前代码段寄存器(CS)的内容压入堆栈。
-
将指令指针(IP)的内容压入堆栈 1。
这三者共同构成了被中断程序的“断点”(Breakpoint),即下一条将要执行的指令地址及其执行时的处理器状态 1。
随后,CPU会自动清除中断允许标志位(IF)和陷阱标志位(TF)1。最后,CPU通过特定方式(对于INTR,需要从外部控制器获取)获得中断类型号,并以此为索引在中断向量表中查找中断服务程序的入口地址 1。
CPU硬件的设计体现了“最小必要状态保存”的优化原则。它仅保存了恢复程序执行所必需的绝对最小状态(PSW、CS、IP),而并未保存通用寄存器(如AX、BX等)。这是因为并非所有中断服务程序都会使用到全部通用寄存器,强制保存所有寄存器会给简短的服务程序带来不必要的性能开销。将这部分工作留给软件开发者,可以根据具体情境决定需要保存哪些寄存器,从而实现更高的效率 1。同时,自动清除IF标志位的行为至关重要,它使CPU进入一个临时的“安全模式”,防止新的可屏蔽中断在当前中断服务程序尚未完成初始化时就将其打断,从而避免了潜在的竞态条件和堆栈错误。
1.4 步骤四:中断服务 (Interrupt Servicing)
在获取中断服务程序(Interrupt Service Routine, ISR)的入口地址后,CPU跳转至该地址开始执行。这是中断处理的“有效载荷”阶段,即执行具体任务以响应该中断事件 1。
一个设计良好的ISR通常遵循固定的结构。在其起始部分(prologue),程序会首先保存所有即将被修改的通用寄存器的内容(通常通过PUSH
指令压入堆栈),这被称为“保护现场” 1。随后,执行处理中断事件的核心代码。在程序的结束部分(epilogue),通过
POP
指令从堆栈中恢复之前保存的通用寄存器,称为“恢复现场” 1。这种设计确保了ISR的执行对于被中断的主程序是完全透明的,即主程序在恢复执行时,其所有寄存器状态与被中断前完全一致。
在ISR执行期间,由于IF标志位已被硬件自动清零,默认情况下它不会被其他可屏蔽中断再次打断。然而,为了构建响应更及时的实时系统,有时需要允许更高优先级的中断来打断当前正在执行的低优先级ISR,这即是“中断嵌套”(Interrupt Nesting)1。为实现嵌套,ISR必须在完成现场保护和必要的初始化后,通过执行
STI
(Set Interrupt Flag)指令显式地重新开中断 1。这是一个关键的编程决策,它虽然增加了程序的复杂性,但可以防止一个耗时较长的低优先级服务阻塞一个紧急的高优先级请求。
1.5 步骤五:中断返回 (Interrupt Return)
中断服务程序的最后一步是执行一条特殊的中断返回指令IRET
1。这条指令的功能是将在中断响应阶段压入堆栈的上下文信息恢复到对应的寄存器中,从而使CPU返回到被中断的程序继续执行。
IRET
指令与常规的子程序返回指令RET
有本质区别。IRET
指令以原子的方式执行三个连续的出栈操作:首先将堆栈顶的值弹出到指令指针(IP),然后是代码段寄存器(CS),最后是程序状态字(PSW)1。恢复顺序至关重要,特别是将标志寄存器安排在最后恢复。因为保存在堆栈中的PSW值包含了中断发生
_之前_的IF标志位状态。通过在最后一步恢复PSW,IRET
指令能够自动地将系统的可中断状态恢复到中断前的原样。整个操作的原子性确保了在CS和IP被恢复之后、PSW被恢复之前,不会有任何新的中断插入,从而杜绝了可能导致堆栈损坏或上下文丢失的风险。
2.0 Intel 8086微处理器中断系统
Intel 8086的中断系统是其体系结构的核心组成部分,它定义了处理器如何识别、分类和响应来自软件和硬件的各种中断事件。
2.1 8086中断源的分类
8086的中断源可以根据其触发方式分为内部中断和外部中断 1。
2.1.1 内部(软件)中断
内部中断由CPU内部事件或特定指令的执行而触发,其发生是同步且可预测的 1。主要包括以下几种类型:
-
除法错误中断(类型0): 当执行除法指令时,若除数为0或结果商溢出,CPU会自动产生类型0中断 1。
-
单步中断(类型1): 当标志寄存器中的陷阱标志(TF)被置为1时,CPU在每条指令执行结束后都会自动产生类型1中断。这主要用于程序的调试 1。
-
断点中断(类型3): 由单字节指令
INT 3
触发,通常由调试器用于在代码中设置断点 1。 -
溢出中断(类型4): 当执行
INTO
(Interrupt on Overflow)指令时,如果溢出标志(OF)为1,则会产生类型4中断 1。 -
软件中断指令(
INT n
): 程序员可以通过INT n
指令主动触发一个中断,其中n
是0到255之间的中断类型号。这是一种强大的机制,常用于调用操作系统或BIOS提供的服务,例如DOS系统中的INT 21H
功能调用 1。
2.1.2 外部(硬件)中断
外部中断由CPU外部的硬件设备通过处理器的物理引脚发起,其发生是异步的,可能在任何指令执行的间隙出现 1。8086提供了两个用于接收外部中断的引脚:NMI和INTR 1。
2.2 NMI与INTR的比较分析
NMI(Non-Maskable Interrupt,非可屏蔽中断)和INTR(Interrupt Request,可屏蔽中断请求)为外部设备提供了两种性质截然不同的中断通道,体现了系统设计的核心哲学:为紧急事件提供保障通道,为常规I/O提供灵活通道。
-
NMI(非可屏蔽中断):
-
触发方式: NMI引脚是一个上升沿触发的输入 1。
-
可屏蔽性: 顾名思义,NMI是不可屏蔽的。它的请求不受中断允许标志位(IF)的控制。一旦NMI线上出现有效信号,只要当前指令执行完毕,CPU就必须响应 1。
-
中断类型号: NMI的中断类型号固定为2,由CPU硬件直接产生,无需外部提供 1。
-
应用场景: 由于其强制响应的特性,NMI通常用于处理最紧急、最关键的系统事件,如内存奇偶校验错误、系统电源即将失效等灾难性故障 1。NMI的处理程序必须极其健壮,因为它可能在系统处于不稳定状态时被调用。
-
-
INTR(可屏蔽中断):
-
触发方式: INTR引脚是一个高电平有效的电平触发输入 1。
-
可屏蔽性: INTR是可屏蔽的,其请求能否被CPU响应,完全取决于IF标志位的状态。只有当
$IF=1$
(开中断)时,CPU才会处理INTR请求;若$IF=0$
(关中断),则INTR请求将被忽略 1。 -
中断类型号: INTR本身不携带中断类型信息。当CPU响应INTR请求时,它会执行一个中断响应总线周期,并通过
INTA
(Interrupt Acknowledge)信号通知外部中断控制器(如8259A)将对应的中断类型号放到数据总线上,由CPU读取 1。 -
应用场景: INTR是所有常规I/O设备(如键盘、鼠标、磁盘、定时器)与CPU通信的标准通道。其可屏蔽的特性赋予了软件控制中断处理时机的能力。程序员可以通过
CLI
(Clear Interrupt Flag)指令关中断,进入一个“临界区”(Critical Section)来执行不可被打断的原子操作或时序敏感代码,之后再通过STI
(Set Interrupt Flag)指令开中断。这是操作系统内核和设备驱动程序设计中的一项基本技术。
-
2.3 8086中断优先级体系
8086处理器内部实现了一套固定的、不可编程的优先级仲裁机制,以处理不同来源中断的冲突。这个固定的优先级顺序揭示了其架构设计的内在逻辑和对事件重要性的评估 1。
优先级从高到低的顺序是:
-
内部中断(除法错误、
INT n
、INTO
) -
NMI(非可屏蔽中断)
-
INTR(可屏蔽中断)
-
单步中断
这个排序的背后逻辑如下:
-
内部中断优先级最高:
INT n
指令是程序代码的一部分,代表了程序员的明确意图,必须得到最高优先级的执行。而除法错误等异常是严重的算术错误,必须立即处理以防止数据损坏和程序逻辑崩溃。允许任何外部中断(即便是NMI)来延迟对这些内部程序错误的响应,都可能导致程序状态不一致。 -
NMI次之: NMI代表了最紧急的_硬件_事件,其重要性高于常规的I/O操作,因此它的优先级必须高于INTR。
-
INTR居中: 这是所有标准、非关键I/O设备的通道,其优先级低于紧急硬件事件和程序内部事件。
-
单步中断优先级最低: 单步中断是一个调试功能,其目的是在一条指令_执行完毕后_暂停程序,以便开发者检查系统状态。将其优先级设为最低,可以确保在该指令执行期间可能发生的所有其他中断(如INTR或NMI)都得到处理之后,调试器才获得控制权,从而让开发者能够观察到指令执行的完整效果。
2.4 中断向量表 (Interrupt Vector Table, IVT)
为了将中断类型号与对应的中断服务程序(ISR)地址关联起来,8086采用了一个名为中断向量表的软件结构。IVT是8086中断系统实现间接寻址的核心机制,它将中断源的标识(类型号)与服务程序的物理位置解耦,提供了极大的灵活性 1。
-
位置与结构: 8086系统将内存的最低1024个字节(物理地址
00000H
至003FFH
)固定地保留给IVT 1。该表包含256个表项,对应256个可能的中断类型(0-255)。每个表项占用4个字节,存储一个指向ISR的远指针,即16位的段地址(CS)和16位的偏移地址(IP)1。 -
地址计算: 对于一个给定的中断类型号
n
,其在IVT中对应表项的起始地址可以通过简单的计算$n \times 4$
得到。例如,NMI(类型2)的向量存储在地址$2 \times 4 = 00008H$
处,而类型为1FH
的中断向量则存储在地址$1FH \times 4 = 0007CH$
处 1。 -
作为关键系统资源: IVT的固定位置使其成为系统启动和运行的基石。在系统加电后,BIOS负责初始化IVT中的关键表项(如硬件中断、BIOS功能调用等)。随后,操作系统在加载时会接管并修改IVT,将向量指向其自身的驱动程序和系统服务。由于其关键性和可写性,IVT也成为了一个潜在的安全弱点。恶意软件可以通过篡改IVT中的指针,将中断处理流程重定向到其恶意代码,这是实现系统劫持的一种经典技术。因此,保护IVT的完整性对于确保系统安全与稳定至关重要。
下表总结了8086主要中断类型的特性:
表 2.1:8086中断类型特性对比
特性 | 内部中断 (异常, INT n ) |
NMI (非可屏蔽中断) | INTR (可屏蔽中断) |
---|---|---|---|
触发机制 | 指令执行(如INT n 、除法错) |
外部引脚NMI的上升沿 | 外部引脚INTR的高电平 |
同步性 | 同步于指令流 | 异步于指令流 | 异步于指令流 |
可屏蔽性 | 不可屏蔽 | 不可屏蔽 | 可屏蔽 |
控制标志 | 无 | 无 | 中断允许标志 (IF) |
关联引脚 | 无 | NMI | INTR |
向量获取 | 由指令或CPU硬件直接提供 | 由CPU硬件固定为类型2 | 由外部控制器在INTA 周期提供 |
典型用途 | 系统调用、软件调试、异常处理 | 紧急硬件故障(电源、内存错误) | 常规外部设备I/O(键盘、磁盘) |
3.0 Intel 8259A可编程中断控制器 (PIC)
Intel 8259A是一款功能强大的外围芯片,旨在扩展和增强基于Intel微处理器的中断系统。它作为8086 CPU的INTR输入的智能前端,解决了单个INTR引脚无法管理多个中断源的根本问题 1。
3.1 核心功能与系统集成
8259A的核心使命是作为一个中断的管理者和仲裁者,其主要功能包括 1:
-
中断请求管理: 接收多达8个来自外部设备的中断请求(通过
IR0
至IR7
引脚),并能通过级联方式扩展至管理64个中断源 1。 -
优先级解析: 当多个中断请求同时有效时,根据预设的优先级方案(如固定优先级或循环优先级)进行仲裁,确定当前优先级最高的请求 1。
-
向CPU发信: 在确定最高优先级请求后,通过其
INT
输出引脚向CPU的INTR
引脚发送一个统一的中断请求信号 1。 -
中断向量提供: 在CPU响应中断并发出
INTA
信号后,8259A负责将与该中断源对应的、可编程的中断类型号放置到系统数据总线上,供CPU读取 1。 -
中断嵌套支持: 管理中断服务状态,允许更高优先级的中断打断正在进行的低优先级中断服务,实现中断嵌套 1。
-
中断屏蔽: 允许通过编程,动态地屏蔽或允许任何一个中断请求输入 1。
3.2 内部架构:关键寄存器深度剖析
8259A的强大功能源于其内部精巧的寄存器设计。其中三个8位寄存器——中断请求寄存器(IRR)、服务中寄存器(ISR)和中断屏蔽寄存器(IMR)——协同工作,构成了一个完整的中断处理状态机 1。
3.2.1 中断请求寄存器 (Interrupt Request Register, IRR)
IRR用于锁存来自外部设备的中断请求。当IRi
引脚上出现有效的中断请求信号时,IRR中对应的第i
位将被置为1,表示有一个待处理的中断请求 1。这个寄存器的内容可以被CPU读取,以查询当前有哪些中断源正在请求服务。
3.2.2 服务中寄存器 (In-Service Register, ISR)
ISR用于跟踪当前正在被CPU服务的,或者因被更高优先级中断打断而暂停服务的中断。当CPU响应一个中断请求(例如来自IRi
)后,8259A会自动将ISR中对应的第i
位置为1,同时清除IRR中的相应位。该位置1的状态将一直保持,直到CPU的中断服务程序向8259A发送一个中断结束(End of Interrupt, EOI)命令为止 1。ISR的存在是实现中断嵌套的关键,因为优先级判优器会参考ISR的状态,只允许优先级高于ISR中当前最高有效位的中断请求通过。
3.2.3 中断屏蔽寄存器 (Interrupt Mask Register, IMR)
IMR允许程序员通过软件来选择性地屏蔽或允许各个中断源。IMR是一个8位读/写寄存器,若其第i
位被置为1,则来自IRi
引脚的中断请求将被忽略,无法触发向CPU的INT
信号。若为0,则该中断请求被允许。通过写IMR,可以动态地调整系统的中断响应能力 1。
3.2.4 优先级判优器 (Priority Resolver) 与控制逻辑
优先级判优器是8259A的大脑。它持续监视IRR的内容,并结合IMR的屏蔽状态,确定所有未被屏蔽的待处理请求。然后,它将这些请求的优先级与ISR中正在服务的最高优先级中断进行比较。只有当一个待处理请求的优先级高于所有正在服务的请求时,判优器才会指示控制逻辑向CPU发出INT
信号 1。控制逻辑则负责处理与CPU之间的握手信号(
INT
和INTA
),并解释来自CPU的初始化命令字(ICWs)和操作命令字(OCWs)以配置8259A的工作模式 1。
这三个寄存器共同构成了一个严密的状态机:
-
请求到达: 外部设备在
IR
线上发信号,IRR的对应位置1(状态:“请求待决”)。 -
权限过滤: 优先级判优器检查该位在IMR中是否为0(“权限过滤器”)。
-
优先级比较: 若未被屏蔽,判优器将此请求的优先级与ISR中当前置位的最高优先级进行比较(状态:“正在服务”)。
-
发起中断: 如果新请求的优先级更高,8259A通过
INT
引脚向CPU请求中断。 -
状态转换: CPU响应
INTA
后,8259A将该中断的标志位从IRR中清除,并在ISR中置位(状态转换:“待决” -> “服务中”)。
这个精巧的流程确保了中断处理的有序性和可嵌套性。
表 3.1:8259A内部核心寄存器功能描述
寄存器 | 全称 | 目的 | 位如何置位 | 位如何清除 |
---|---|---|---|---|
IRR | 中断请求寄存器 | 锁存外部设备的中断请求信号 | 由外部IR 引脚的有效信号触发 |
当CPU响应中断时,由8259A内部逻辑清除 |
ISR | 服务中寄存器 | 记录正在被CPU服务的中断 | 当CPU响应中断时,由8259A内部逻辑置位 | 由CPU软件发送EOI(中断结束)命令 |
IMR | 中断屏蔽寄存器 | 允许/禁止特定的中断请求 | 由CPU软件通过写操作置位(屏蔽) | 由CPU软件通过写操作清除(允许) |
3.3 8259A的完整操作流程
从接收请求到服务结束,8259A与CPU的交互遵循一个精确定义的时序 1:
-
请求锁存: 一个或多个外部设备在
IR0-IR7
引脚上产生高电平请求,IRR的相应位置1 1。 -
屏蔽与判优: 优先级判优器检查IRR,忽略被IMR屏蔽的位,并在剩余的请求中确定优先级最高的那个。
-
发出INT: 如果该最高优先级请求的级别高于ISR中任何正在服务的级别,控制逻辑将
INT
引脚置为高电平,向CPU发出中断请求 1。 -
CPU响应(第一次
INTA
): CPU在当前指令结束后,若IF为1,则响应中断。它会执行第一个中断响应总线周期,并发出第一个低电平有效的INTA
脉冲 1。 -
内部状态更新: 收到第一个
INTA
脉冲后,8259A的内部逻辑被“锁定”。它将最高优先级请求对应的位从IRR中清除,并在ISR中置位 1。 -
CPU响应(第二次
INTA
): CPU紧接着执行第二个中断响应总线周期,并发出第二个INTA
脉冲 1。 -
向量发送: 在第二个
INTA
脉冲有效期间,8259A将预先编程好的、与该中断源对应的8位中断类型号放置到数据总线D0-D7
上 1。 -
CPU获取向量并跳转: CPU从数据总线上读取中断类型号,中断响应周期结束。随后,CPU使用该类型号在IVT中查找ISR地址并跳转执行。
-
中断结束(EOI): 中断服务程序在执行完毕、返回主程序(通过
IRET
)之前,必须向8259A发送一个EOI命令。该命令会清除ISR中相应的位,标志着此次中断服务彻底完成,从而允许同级或更低优先级的中断被响应 1。
其中,两次INTA
脉冲的握手协议设计得非常巧妙。第一个INTA
脉冲的作用是“提交”或“锁定”信号,它通知8259A:“中断已被接受,请立即冻结你当前的优先级判优结果。” 这可以防止在CPU响应和获取向量之间到达的更高优先级请求“劫持”本次中断响应周期。第二个INTA
脉冲则是“输出使能”信号,通知8259A:“数据总线已准备好,请将已锁定的中断向量放上来。” 这个两阶段过程确保了CPU最终获取的向量始终对应于最初被响应的那个中断请求,保证了系统的稳定性和确定性。