谈谈对中断的理解

一.中断的理解

中断是指CPU在执行过程中,出现了突发事件,CPU必须暂停当前程序的运行,保持现场,转而处理突发事件,处理完毕之后,恢复现场继续执行。

中断按照来源可以分为:

  • 内部中断:来自CPU内部,通常由软件中断指令和一些异常错误触发
  • 外部中断:来自CPU外部,通常由外设触发,经由中断控制器转发请求到CPU,然后进行处理

二.单片机的中断

在玩单片机的时候,中断用的最多的就是外设触发中断了基本就是:

  1. 中断源的优先级与打开使能中断通道
  2. 绑定EXIT与GPIO,配置中断触发方式,引脚是浮空输入
  3. 编写中断服务程序

这个阶段对中断的理解还停留在:外设触发中断、CPU响应中断、执行中断服务程序。

STM32-中断详解

三.ARM的异常中断

在ARM的学习过程中,对异常中断又有了更深入的理解,涉及到ARM的工作模式、异常中断、中断向量表、环境保存与恢复等

ARM工作模式&&异常中断&&中断向量表

ARM-异常中断处理

从ARM的工作模式到异常中断:
image

image

以及ARM的中断向量表,一般是32Bytes,一个异常中断占4Bytes,一般是一个跳转指令:

image

其中,中断优先级的划分如下:

image

可以看出:

  • 复位就是直接去0x0000_0000地址执行
  • FIQ放在中断向量表最后面,可以直接在中断向量表后编写FIQ处理程序,呼应了快速中断
  • FIQ的优先级比IRQ高,可以打断IRQ
  • 系统调用就是利用SWI(软件中断)进行处理的

进入中断和退出中断的操作

image

  1. 将下一条指令地址保存在lr寄存器中,具体是pc+4还是pc+8取决于异常的种类
  2. 将当前的CPSR拷贝到对应的SPSR
  3. 根据异常修改CPSR的值
  4. 根据向量表跳转到中断处理程序执行,在中断处理程序中进行环境保存与恢复

image

退出异常中断时的情况:

image

  1. 将lr寄存器减去相应的偏移,赋值给pc
  2. 将SPSR中的值赋值给CPSR
  3. 清除中断标志位(如果在进入中断是设置了)

中断异常服务程序

中断中断服务程序一般要做的是:

/* und异常处理,进入异常前,硬件完成的事情:将CPSR拷贝到SPSR,将被中断指令的地址存储在lr中 */
do_und:
    ldr sp, =0x34000000          /* und的栈指针,指向64M 的SDRAM的最高地址,为C函数分配空间 */
    stmdb sp!, {r0-r12,lr}      /* 保存现场 */

    mrs r0, cpsr                /* mrs读出寄存器的值,通过r0寄存器向下面的函数传参 */
    bl Und_Process

    ldmia sp!, {r0-r12, pc}^     /* 恢复现场,注意:一定要加!来保存sp的改变 */
  1. 设置栈,通过sp_und来设置
  2. 保存现场,包括r0~r12寄存器、lr寄存器,保存lr也是必须的,因为lr中的是异常处理完之后的返回地址
  3. 调用C处理函数
  4. 恢复现场,利用ldmia sp!, {r0-r12,pc}^ 恢复各个寄存器的值,将lr寄存器的值赋值给pc寄存器(有待考证,ia是先 后 ),^顺便把SPSR中的值恢复到CPSR中

所谓保持现场与恢复现场就是对r0~r12寄存器进行入栈和出栈

ARM-und异常

中断控制器

image

在初始化中断控制器的时候,主要是打开使能位即可,SRCPND和INTPND是在中断处理函数里使用的,判断是哪一个中断请求的

ARM-按键中断

四.Linux的中断

Linux中接触操作系统之后,有了中断、异常、系统调用的概念,

中断、异常、系统调用

image

硬件上的处理:在CPU初始化的时候设置中断使能标志,这个中断使能标志对异常、中断、系统调用都是等效的。然后根据内部或者外部事件设置中断标志位,根据中断向量表调用相应的中断服务例程。

所以,无论是中断、异常、系统调用,都会在中断向量表中进行跳转处理,接下来就是针对性的服务了

如果是中断,直接进入设备驱动中,反馈(鼠标、键盘的输入);

如果是异常,直接转到异常服务例程来做处理;

如果是系统调用,由于系统调用的量很大,不同的系统调用在系统调用表中区分,选择不同的系统调用实现;

当然,在处理异常中断的时候,要注意保护现场和恢复现场,可以参考ARM来理解。

Kernel的中断处理机制

由于中断会打断进程的正常调度与运行,势必要求中断服务程序尽量短小精悍,然而大多数中断处理程序中的工作量不会很小。

Linux内核的中断处理框架是将中断的处理分为了上半部和下半部:

image

当然,可以在/proc/interrupts中查看系统中断的统计信息,包括每个中断号上的中断在CPU上发生的次数。

Linux设备驱动中使用中断的设备需要申请和释放中断,使用内核提供的request_irq()和free_irq()接口。

中断下半部的实现

Linux实现中断下半部的机制主要有tasklet、工作队列、软中断、线程化irq。

tasklet的执行上下文是软中断,执行的时机是上半部返回的时候,只需要定义tasklet及其处理函数,并关联两者就可以。关于tasklet的调度,在需要调度tasklet的时候引用一个tasklet_schedule()函数就可以。

工作队列的执行上下文是内核线程,所以是可以调度和睡眠的。

软中断是一种传统的下半部处理机制,执行时机通常是上半部返回的时候。

五.中断作为计算机系统中必要的存在

从UBoot、STM32等的启动代码中也可以看出,中断向量表为计算机系统的一种基础服务存在。

posted @ 2021-08-22 21:42  Aspirant-GQ  阅读(1273)  评论(0编辑  收藏  举报