创建时间: | 2022/1/19 11:04 |
更新时间: | 2022/3/6 14:23 |
作者: | gi51wa2j |
标签: | 100ask_IMX6ULL_v11, bingo, 正文 |
保存现场
分辨异常/中断,调用对应的异常/中断处理函数
恢复现场
对于不用的处理器,具体的处理工作有差别:
保存现场:cortex M3/M4里是硬件完成,cortex A7等是软件实现
分辨异常/中断:cortex M3/M4里是硬件完成,cortex A7等是软件实现
调用处理函数:cortex M3/M4里是硬件来调用,cortex A7等是软件自己去调用
恢复现场:cortex M3/M4里是软件触发、硬件实现,cortex A7等是软件实现
不管是硬件还是软件实现,第一步都是保存现场。
这4条指令涉及R0、R1寄存器,程序被打断时、恢复运行时,R0、R1要保持不变
执行完第3条指令时,比较结果保存在程序状态寄存器里,程序被打断时、恢复运行时,程序状态寄存器保持不变
这4条指令,读取a、b内存,程序被打断时、恢复运行时,a、b内存保持不变
内存保持不变,这很容易实现,程序不越界就可以。 所以,关键在于R0、R1、程序状态寄存器要保持不变(当然不止这些寄存器):
在处理异常前,把这些寄存器保存在栈中,这称为保存现场
在处理完异常后,从栈中恢复这些寄存器,这称为恢复现场
R0-R3
调用者和被调用者之间传参数
R4-R11
函数可能被使用,所以在函数的入口保存它们,在函数的出口恢复它们。
R0-R3是用来传参数给函数B的
函数B可以肆意修改R0-R3
函数A不要指望函数B帮你保存R0-R3
保存R0-R3,是函数A的事情
对于LR、PSR也是同样的道理,保存它们是函数A的责任
对于函数B:
我用到R4-R11中的某一个,我都会在函数入口保存、在函数返回前恢复
保证在B函数调用前后,函数A看到的R4-R11保存不变
假设函数B就是异常/中断处理函数,如果函数B本身能保证R4-R11不变,那么保存现场时,只需要保存这些:
调用者保存的寄存器(R0-R3,R12,LR,PSR)
PC
比较值得关注的是FIQ模式,名为"快中断",它有很多"Banked"寄存器:R8-R12,SP,LR。 在FIQ模式下,它既然能使用自己的R8-R12,SP,LR,自然不需要去保存被中断的程序的"R8-R12,SP,LR"了。 省去保存这几个寄存器的时间,处理中断时自然就快很多,所以被称为"FIQ"。
从上图也看到,几乎每个模式下都有自己是SP寄存器,意味着这些模式下有自己的栈。
当发生异常时,以IRQ为例:
CPU会自动切换进入对应的模式,比如进入IRQ模式
并且会把被中断是的CPSR保存到SPSR_irq里
所以发生异常/中断时,在保存现场时,只需要保存:
调用者保存的寄存器(R0-R3,R12,LR)
PC
《ARM体系结构与编程》作者:杜春雷
ARM ArchitectureReference Manual ARMv7-A and ARMv7-R edition.pdf
S3C2440A_UserManual_Rev13.pdf:没错,这个手册里描述得更清晰
ARM9和cortex A7的CPU模式、状态、寄存器,以及发生异常时的处理细节,几乎是一模一样的。
跟ARM9相比,多了2中Mode:Monitor、Hyp。在文中不涉及这两种模式。 除usr模式外,其他模式是特权模式。 usr模式下,无法通过修改CPSR寄存器进入其他模式。 在其他模式下,可以通过修改CPSR寄存器进入其他模式。
usr:用户模式
sys:系统模式
undefined(und):未定义模式
Supervisor(svc):管理模式
Monitor
Abort(abt):中止模式 有两种情况会导致CPU今日中止模式:
指令预取中止(读取某条指令时发生错误)
数据访问终止 (读写某个地址上的数据时,发生错误)
Hyp
IRQ(irq):中断模式
FIQ(fiq):快中断模式
ARM state:每条指令都是32位的,4个字节,高效,但是占空间
Thumb state:每天指令都是16位的,2个字节,节省空间,但是有时候效率不高
对于Cortex A7芯片,还有Thumb2指令集,支持16位、32位指令混合编程。
这个字节数指一个汇编指令转为机器码时占据几个字节
通用寄存器
备份寄存器(banked register)
当前程序状态寄存器(CPSR,Current Program Status Register)
CPSR的备份寄存器(SPSR,Save Program Status Register)
R13用作SP(栈) :所以发生异常时,使用的是该异常模式下的栈
R14用作LR(返回地址):用来保存发生异常时的指令地址,处理完异常后,根据LR的值恢复被中断的程序
保存现场(保存被中断模式的寄存器)
处理异常
最后恢复这些寄存器
假设程序正在系统模式/用户模式下运行, 当发生中断时,需要把R0 ~ R14这些寄存器全部保存下来。 但如果是快中断,那么就不需要保存系统/用户模式下的R8 ~ R12这几个寄存器, 因为在FIQ模式下有自己专属的R8 ~ R12寄存器, 这样可以省略保存寄存器的时间,加快处理速度。
Bit5 State bits:表示CPU工作于Thumb State还是ARM State,用的指令集是什么。
Bit6 FIQ disable:当bit6等于1时,FIQ被禁止。
Bit7 IRQ disable:当bit5等于1时,禁止所有的IRQ中断,这个位是IRQ的总开关
Bite28 ~ Bit31是状态位 什么是状态位,比如说执行这两条指令
硬件确定要进入哪种异常模式
LR寄存器被更新,它表示处理完异常后要返回到哪里,这个值可能需要修改。
SPSR = 被中断时的CPSR
对于"Security Exceptions",……,本课程不涉及
更新异常模式下的CPSR:设置模式位、设置mask bit(屏蔽其他异常)、设置指令集状态位
PC = 异常入口地址
从PC所指示地方执行程序
ARM ArchitectureReference Manual ARMv7-A and ARMv7-R edition.pdf
中,对异常的退出,描述得很复杂。但是很多情况,我们并不涉及。让LR减去某个值,然后赋值给PC(PC = 某个异常LR寄存器减去 offset)
减去什么值呢?
也就是我们怎么返回去继续执行原来的程序,根据下面这个表来取值:
如果发生的是SWI可以把 R14_svc复制给PC,
如果发生的是IRQ可以把R14_irq的值减去4赋值给PC
把CPSR的值恢复(CPSR 值等于 某一个一场模式下的SPSR)
清中断(如果是中断的话,对于其他异常不用设置)