深入理解裸机中断一

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mxgsgtc/article/details/72676631
  • 前言
    本文介绍arm9裸机中断的概念(下面介绍寄存器相关配置),即扫盲篇,正确把中断各个方面讲解清楚
  • arm9的工作模式
    这里写图片描述
    上图可知,共有七种工作模式, 其中我们可以看到
    1.用户模式除外,其余都称特权模式
    2.特权模式中,除了系统模式外,都是异常模式
  • 深入理解cpu的工作模式
    ARM处理器共有七种工作模式,在程序执行过程中, 处理器一定处在上述7种工作模式中的一种,每种工作模式都有对应的寄存器, ARM寄存器一共有37个,其中包括31个通用寄存器和6个状态寄存器,这些寄存器都是32位的,如下图
    这里写图片描述
    上图中的知识点如下:
    1.需要了解的寄存器:
    r13:堆栈寄存器(sp)
    r14:连接寄存器, b, bl等指令调用函数,r14用来存放调用函数的返回地址
    r15为程序指针寄存器(PC),由于arm9是5级流水线,PC指向正在执行指令的下两条地址
    这里写图片描述
    2.工作模式间可共用相同的寄存器,也可以有自己独立的寄存器
    比如: 用户模式下的R0–>R7与FIQ模式下的R0–>R7是相同的寄存器,但是R8–>R14是不同的,由此我们可以举个例子说明问题,当在User模式下执行app的过程中来了一个快速中断,ARM会进入FIQ模式(通过中断程序修改CPSR来实现ARM进入FIQ模式)
    ①.因为R0->R7被两个模式共用,为了保证User下的不被破坏, 需要保存R0->R7寄存器,即入栈(为了保护用户模式下的R0->R7的值)
    ②.R8->R14无需保存(FIQ有自己的R8->R14)
    ③.当中断执行完后在将R0->R7出栈
    需要注意的是, 上图FIQ中虽然是R8_fiq–>R14_fiq,但是在写法上还是R8->R14,因为系统会自动识别真实的寄存器, 举个例子:
    在用户模式下: mov R8, 8—>指的是R8
    在FIQ模式下: mov R8, 8—>系统会自动识别为 R8_fiq
    3.从图中也可以看出 快速中断(FIQ)与普通中断(IRQ)的区别,之所以叫快速中断,意思就是反应快,看看就知道,当从User模式切换到FIQ模式下需要保存R0->R7,而切换到IRQ需要保存R0->R12,很显然保存寄存器是需要时间的,所以效率上FIQ要高
    4.在上面的讨论中讨论了切换模式入栈的操作,比如从User模式切换到FIQ模式下,需要将R0->R7入栈保存, 但是这个栈在哪里呢?其实上面已经提到了,R13是sp指针,而且每个模式下都有自己的”R13”, 在User用户下执行程序,程序在R13所在的栈指针下运行,当切换入FIQ后,换成FIQ下的R13(R13_fiq)所指向的堆栈下运行.当然,关于每个模式下的堆栈指针需要在系统刚启动就要设置的

    Reset:                  
        ldr sp, =4096           @ 设置栈指针,以下都是C函数,调用前需要设好栈
        bl  disable_watch_dog   @ 关闭WATCHDOG,否则CPU会不断重启
    
        msr cpsr_c, #0xd2       @ 进入中断模式
        ldr sp, =3072           @ 设置中断模式栈指针
    
        msr cpsr_c, #0xdf       @ 进入系统模式
        ldr sp, =4096           @ 设置系统模式栈指针,
                                @ 其实复位之后,CPU就处于系统模式,
                                @ 前面的“ldr sp, =4096”完成同样的功能,此句可省略

    这里写图片描述
    5.刚上电 ARM处于SVC模式

  • 中断执行流程详解
    在系统启动后, 系统进入管理模式(SVC模式, 这是ARM处理器上电后默认的工作模式),在发生中断后,ARM处理器会自动切换到外部中断模式(这里以IRQ为例),如图
    这里写图片描述
    由上图可知, SVC模式下和IRQ模式寄存器的R0->R12是公用的,当前程序状态寄存器CPSR也是公用的. 下面详解描述一下发生中断后 ARM处理器做了哪些事情, 还有哪些事情需要用户编程来实现
    ・步骤1:发生中断后, ARM处理器需要执行完当前指令(ARM)
    ・步骤2:将CPSR保存到IRQ模式下的SPSR_irq(执行中断返回时,其逆过程不能自动完成)(ARM)
    ・步骤3:将PC(r15)值减4(这个地方要注意),存放到IRQ模式下的链接寄存器R14_irq中,即R14_irq中的值=PC - 4(ARM)
    ・步骤4:将PC强制设置为0x00000018(异常中断向量的入口地址)(ARM)
    ・步骤5:刷新流水线(这里注意的是, 凡ARM发现流水线上出现地址不连续的情况下,都会刷新流水线,比如跳转,中断,还有步骤4中的地址被赋值成不连续的值)(ARM)
    ・步骤6:将R0->R12入栈(user)
    为了更好的对上面的执行步骤更好了理解,下面进行图解,以及顺便带出中断返回的步骤
    这里写图片描述
    上图中,我们注意到, ARM处理器不是马上处理中断,而是现将当前指令执行完, 注意,只要执行完该指令, PC的值也已经更新了, 即PC指向了下一条指令的地址处, 然后自动将PC-4值保存到R14_irq下,从图中可以看到是③的位置, 但是我们中断返回需要从②的位置开始执行,即中断前执行指令的下一条指令, 所以在中断返回时,需要返回的地址是从lr寄存器(R14_irq)在减4(③-4)即为②的位置(发生中断, ③保存入R14_irq是arm自动发生, 但是中断返回是user需编程实现)
    所以,在执行中断处理函数之前,首先要计算好返回地址,并将R0->R12,返回地址都入栈
    sub lr, lr, #4                  @ 计算返回地址 即图中②的位置
    stmdb   sp!,    { r0-r12,lr }   @ 保存使用到的寄存器
    @.........执行中断函数.......
    //之后执行完中断函数后,user需要编码实现中断返回
    ldmia   sp!,    { r0-r12,pc }^  @ 中断返回, ^表示将spsr的值复制到cpsr
    //注意:中断返回时, CPSR需要user手动恢复值

总结一下中断返回执行的操作:
・步骤1:将被中断程序的处理器状态(CPSR的内容)恢复,即从IRQ模式恢复到SVC模式
・步骤2:返回到发生异常中断指令的下一条指令处执行,即从上图中②的位置处执行
思考一个问题: 上图中, 中断执行完之后的返回值应该是下图中的③位置
这里写图片描述
那么我们知道PC的值应该指向要取指令的地址,即上图中③的位置,也就是说现在正在执行的是①的位置,问题来了,中断前指令已经之行完②位置上的指令,中断返回后怎么从①位置处开始执行,不应该从③位置上开始执行吗?
答:还是需要强调一句话:这里注意的是, 凡ARM发现流水线上出现地址不连续的情况下,都会刷新流水线(比如跳转,中断),所以在中断返回时,ARM流水线上只有③,即
这里写图片描述
就是说,再返回时刻,流水线上只有取指部分, 译码执行部分都是空的,也就是说流水线上不存在上图中①、②位置上的指令信息, 之后过了两个指令周期后,③位置上的指令被执行(即中断返回执行的第一条指令),所以从这里也可以看出跳转付出的代价还是挺大的(ARM需要重新排流水)

猜你喜欢

转载自blog.csdn.net/mxgsgtc/article/details/72676631