前言
中断是十分重要的,我将按照arm异常->中断控制器->通用架构->应用层,来讲解,希望对大家有所帮助,同时也欢迎各位指正。
一、异常
异常是理解CPU运转最重要的一个知识点,几乎每种处理器都支持特定异常处理,中断是异常的一种。有时候我们衡量一个操作系统的时候实时性就是看OS最段响应中断时间以及单位时间内响应中断次数。处理器在正常执行程序的过程中可能会遇到一些不正常的事件发生,这时处理器就要将当前的程序暂停下来转而去处理这个异常的事件,异常事件处理完成之后再返回到被异常打断的点继续执行程序。
二、ARM异常源
导致异常产生的事件称为异常源。ARM异常源分7类:
1.FIQ
2.IRQ
FIQ为快速中断请求引脚有效(快速中断),IRQ为外部中断请求引脚有效(通常的中断)。CPU和外部设备是分别独立的硬件执行单元, CPU对全部设备进行管理和资源调度处理,CPU要想知道外部设备的运行状态,要么CPU定时的去查看外部设备特定寄存器,要么让外部设备在出现需要CPU干涉处理时“打断”CPU,让它来处理外部设备的请求,这里的“打断”操作就叫做中断请求。
根据请求的紧急情况,中断请求分一般中断和快速中断,快速中断具有最高中断优先级和最小的中断延迟,通常用于处理高速数据传输及通道的中数据恢复处理,如DMA等,绝大部分外设使用一般中断请求。大部分外设如传感器,网卡,I2C,SPI等一般为一般中断请求。
FIQ比IRQ快原因
- FIQ在异常向量表位于最末 可直接把异常处理写在异常向量表之后,省去跳转
- FIQ模式有5个私有寄存器(R8-R12) 执行中断处理程序前无需压栈保存寄存器,可直接处理中断
- FIQ的优先级高于IRQ
3.1 两个中断同时发生时先响应FIQ
3.2 FIQ可以打断RIQ,但RIQ不能打断FIQ
附:自行理解。
3.Reset 复位电平有效
(当CPU上电时执行或者按下复位按键之后进入该异常,该异常在管理模式下处理)
4.Software Interrupt 执行swi指令
(当一个软中断指令被执行完的时候执行)该异常是应用程序自己调用时产生的,用户程序申请访问硬件资源时需要调用该指令。例如: printf()打印函数,用户程序要想实现打印必须申请使用显示器,而用户程序又没有外设硬件的使用权,只能通过使用软件中断指令切换到内核态,通过操作系统内核代码来访问外设硬件,内核态是工作在特权模式下,操作系统在特权模式下完成将用户数据打印到显示器上。这样做的目的无非是为了保护操作系统的安全和硬件资源的合理使用,该异常在管理模式(SVC)下处理。
注意:linux中分内核态和用户态两层,所有的应用程序,运行时都是在用户空间运行的,但是运行的时候,如printf需要调用系统资源,调用系统资源部分代码就放到内核态,他们中间要能够关联起来,就需要通过swi异常,应用程序中read,write等接口就是通过swi异常实现调用内核中file_operations的接口的。内核态可以访问所有的硬件资源,用户态访问不了系统资源,只能调用进程间的一些基础资源。
如图,printf通过内核态系统调用最终实现其功能。
5.Data Abort 数据终止
(如果一个预取指令试图存取一个非法的内存单元,这时异常产生)该异常发生在要访问数据地址不存在或者为非法地址时,该异常在中止异常模式下处理。
注意:段错误:指针没有初始化,直接写数据,那么这个指针指向的内存是不确定的(不存在或者不允许修改)就会出现段错误。
6.Prefetch Abort 指令预取终止
(当一个指令被从内存中预取时,由于某种原因失败,如果它能到达运行状态这个异常才会产生)该异常发生在CPU流水线取指阶段,如果目标指令地址是非法地址进入该异常,该异常在中止异常模式下处理。
7.Undefined Instruction 遇到不能处理的指令
(当流水线中的某个非法指令到达执行状态时执行)该异常发生在流水线技术里的译码阶段,如果当前指令不能被识别为有效指令,产生未定义指令异常,该异常在未定义异常模式下处理。
ARM异常是有优先级的,其优先级按下列依次递减:
Reset->Data Abort->FIQ->IRQ->Prefetch Abort->Undefined Instruction/SWI
ARM异常与模式的关系
ARM异常与ARM模式是不一样的,它们之间有对应关系。
ARM异常处理流程
当异常发生的时候,处理器会去处理异常,处理完异常之后会继续回到异常发生时的状态。其完整处理过程分为三个阶段:硬件阶段、异常处理、异常返回。
硬件阶段(4大步3小步)
保存执行状态
当前程序的执行状态是保存在CPSR里面的
异常发生时,要保存当前的CPSR里的执行状态到异常模式里的SPSR里
将来异常返回时,恢复回CPSR,恢复执行状态。
模式切换
硬件自动根据当前的异常类型,将异常码写入CPSR里的M[4:0]模式位,这样CPU就进入了对应异常模式下。
不管是在ARM状态下还是在THUMB状态下发生异常,都会自动切换到ARM状态下进行异常的处理,这是由硬件自动完成的,将CPSR[5] 设置为 0。
CPU会关闭中断IRQ(设置CPSR 寄存器I位),防止中断进入,如果当前是快速中断FIQ异常,关闭快速中断(设置CPSR寄存器F位)。
保存返回地址
当前程序被异常打断,切换到异常处理程序里,异常处理完之后,需要返回当前被打断模式继续执行,因此必须要保存当前执行指令的下一条指令的地址到LR_excep。
由于异常模式不同以及ARM内核采用流水线技术,异常处理程序里要根据异常模式计算返回地址。
跳入异常向量表
该操作是CPU硬件自动完成的,当异常发生时, CPU强制将PC的值修改为一个固定内存地址,这个固定地址叫做异常向量。
异常向量表
跳入异常向量表操作是异常发生时,硬件自动完成的,剩下的异常处理任务完全交给了程序员。
异常向量表的本质是内存中的一段代码。
表中为每个异常源分配了四个字节的存储空间。
遇到异常后处理器自动将PC修改为对应的地址。
因为异常向量表空间有限一般我们不会再这里写异常处理程序,而是在对应的位置写一条跳转指令使其跳转到指定的异常处理程序的入口。
注意:ARM的异常向量表的基地址默认在0x00地址 但可以通过配置协处理器来修改其地址。
当发生IRQ异常的时候用户程序先跳转到异常向量表,再跳转到异常处理程序,最后再返回用户程序。
整个过程CPSR保存的永远是当前程序运行状态SPSR只是异常时对原来的CPSR进行备份。
异常处理
异常处理程序最开始,要保存被打断程序的执行现场,程序的执行现场无非就是保存当前操作寄存器里的数据,可以通过下面的栈操作指令实现保存现场:
STMFD SP_excep!, {R0 – R12, LR_excep}
在跳转到异常处理程序入口时,已经切换到对应异常模式下了,因此这里的SP是异常模式下的SP_excep了,所以被打断程序现场(寄存器数据)是保存在异常模式下的栈里
上述指令将R0~R12全部都保存到了异常模式栈
最后将修改完的被打断程序返回地址入栈保存,后面可以通过类似:MOV PC, LR的指令,返回用户程序继续执行。
异常处理的返回
异常处理完成之后,返回被打断程序继续执行,具体操作如下:
- 恢复被打断程序运行时寄存器数据
- 恢复程序运行时状态CPSR
- 通过进入异常时保存的返回地址,返回到被打断程序继续执行