
目录一、中断信号的起点、中断控制器的产生1中断信号的起点2中断控制器的诞生3中断控制器中的两个关键寄存器IRR、IMR二、中断响应周期CPU与中断控制器的交互1CPU初步检查2CPU向中断控制器索要中断向量编号三、中断周期中断服务函数的处理过程1关闭CPU中断保护栈指针的唯一准确2保存重要信息3查找中断向量表更新 PC 为服务程序入口地址4开启CPU中断支持中断嵌套5根据中断服务函数的地址压入新函数栈帧四、两层中断屏蔽的意义1中断控制器端的屏蔽IMR中断屏蔽寄存器2CPU 端的屏蔽IF 标志位EFLAGS 寄存器中的中断允许位在计算机中中断是软件、硬件协同实现的机制。它的出现让CPU能在执行主程序的同时实时响应外设的紧急请求也是操作系统处理IO事件、硬件异常、信号等的基础。我们往往只知道有中断这个机制的作用但却忽略了它实现的底层原理如何保存上下文保存到哪里中断服务函数又是个什么东西本篇文章将一步步带你揭开中断的神秘面纱。一、中断信号的起点、中断控制器的产生1中断信号的起点中断的起点是外设主动发送的一个电信号请求当一个外设比如磁盘、网卡、键盘等完成任务或遇到异常的时候该硬件系统被设计成会在自己的中断线上发送一个中断请求信号。而前面我们说CPU会在每一个执行周期结束后监测中断线上是否有中断请求如果有则立马针对该请求进行处理。但你有没有发现一个问题随着外设的逐渐增多CPU用于检测中断线的时长也越长因为需要遍历每一根中断线而且还不知道怎么判断各种外设的中断优先级这样会极大的拖慢CPU的性能。2中断控制器的诞生于是人们想能不能有一个人帮CPU做完这些事情呢于是中断控制器应运而生他把CPU从原来的繁琐遍历检测过程合并成一个中断控制器首先对接各种外设只输出一根线给CPU那么CPU每次只用检测一根线运行效率大大提升。现代的中断控制器通常可以分为APIC、NVIC两种。其中APIC主要用在x86架构下的桌面电脑上重点解决多核心之间的中断调度问题不同的调度带来的速度差异是大大不同的而NVIC则多用于ARM架构的单核CPU主打低功耗、高实时性。3中断控制器中的两个关键寄存器IRR、IMR当硬件产生的中断信号倍中断管理器接受后并且没有被屏蔽则进入优先级仲裁中断管理器会筛选出此时优先级最高的中断并向CPU发送中断请求信号INTR。二、中断响应周期CPU与中断控制器的交互这是 CPU 与中断控制器之间的 “握手” 阶段核心目的是获取中断的具体类型。1CPU初步检查CPU在每一个执行周期后都会进入中断周期的检测即采样INTR信号。并对该信号的屏蔽、优先级做出判断若 PSW 中的中断屏蔽位 IF0关中断则忽略该请求若 IF1开中断且当前 CPU 优先级低于中断请求优先级则进入中断响应总线周期。2CPU向中断控制器索要中断向量编号这一步是 CPU 与中断控制器的总线交互不同架构略有差异x86 架构APICCPU 发送 2 个连续的INTA#中断响应信号中断控制器在第二个INTA#时将中断类型码8 位对应 0~255 级中断发送到数据总线。ARM 架构NVICCPU 检测到中断请求后直接向 NVIC 请求向量编号NVIC 通过内部总线将向量编号传递给 CPU无需外部 INTA 信号。核心寄存器动作CPU 将收到的中断类型码 / 向量编号暂存到内部临时寄存器用于后续查找中断向量表。三、中断周期中断服务函数的处理过程1关闭CPU中断保护栈指针的唯一准确虽然我们说中断是可以根据优先级进行嵌套的但是这里是为了保存之前的运行环境信息这一步是万万不能被中断的否则可能上一个函数的栈帧还没有保存好就来了下一个中断最后的结果就是返回时前面的函数无法继续执行了。2保存重要信息由于所有的函数都是在栈帧中执行的所有的数据也都被存放在各自的栈帧中那么当中断来临时只需要让栈帧继续往低地址延伸并保存重要关键的运行数据即可而不用动之前的函数栈帧就相当于保存了原本的数据信息。保存栈顶指针的值等会它来定位回归到原函数CU 发出微命令SPout, MARin将 SP 的值栈顶地址送入 MARCU 发出微命令SPSP-字长修改 SP 的值栈顶指针下移腾出存储单元字长取决于 CPU 架构如 32 位 CPU 字长 4 字节CU 发出微命令PCout, MDRin将 PC 的值断点地址原程序下一条指令地址送入 MDRCU 发出微命令MemWrite将 MDR 中的断点地址写入 MAR 指向的堆栈内存单元完成压栈。而其他信息的保存与这个过程不能说一模一样只能说毫无区别。最为主要的就是PSW寄存器的内容他里面存放了当前函数的执行到的地方等重要数据。3查找中断向量表更新 PC 为服务程序入口地址中断向量表中存放的都是各个中断服务函数的函数指针也可以叫做函数地址且中断向量表本质就是一个指针数组是根据优先级中断号顺序编写的所以可以通过中断向量的编号直接偏移找到对应的中断服务函数地址。4开启CPU中断支持中断嵌套这和最开始关闭中断响应的操作是互补的他们两步骤形成了一个中断屏障保护了中断响应过程中的栈顶指针、函数运行状态参数的安全。而开启后就能支持更高优先级的中断继续打断当前中断咯。5根据中断服务函数的地址压入新函数栈帧当中断服务函数执行结束后会把最上层的函数栈帧销毁根据刚刚保存的数据恢复到上一层函数的具体位置继续执行。四、两层中断屏蔽的意义细心的同学可以发现在上述的过程中中断控制器和CPU都分别有一些寄存器用于中断屏蔽。但他们二者有什么区别呢1中断控制器端的屏蔽IMR中断屏蔽寄存器这是第一层屏蔽属于外设级别的精细控制。IMR 的每一位都对应一个具体的外设中断源比如磁盘、网卡、键盘等。它的作用是 “拦截” 特定外设的中断请求让这些请求无法进入中断控制器的优先级仲裁环节更不会被发送给 CPU。举个例子如果我们屏蔽了键盘中断那么即使你按下键盘这个中断请求也只会被记录在 IRR 里不会被提交给 CPU也就不会触发中断处理。2CPU 端的屏蔽IF 标志位EFLAGS 寄存器中的中断允许位这是第二层屏蔽属于全局级别的总开关。CPU 通过 EFLAGS 寄存器中的 IFInterrupt Flag位来控制是否响应外部可屏蔽中断。当 IF0 时CPU 会忽略所有通过 INTR 信号线发来的中断请求相当于给整个系统的中断响应按下了 “暂停键”。举个例子在执行关键的原子操作或中断服务函数的开头时操作系统会暂时关闭 IF 位避免被其他中断打断保证操作的原子性。这一步主要是用来保护中断响应过程时的各种数据安全性保护犯罪现场。