• 从要做的事情上来说,无论哪种ARM架构的异常/中断都是一样的

    • 每执行完一条指令都会检查有无中断/异常产生
    • 发现有中断/异常产生,开始处理:
      • 保存现场
      • 分辨异常/中断,调用对应的异常/中断处理函数
      • 恢复现场
  • 不同的芯片,不同的架构,在这方面的处理稍有差别:

    • CPU中止当前执行,跳转去执行处理异常的代码:也有差异
      • cortex M3/M4在向量表上放置的是函数地址
      • cortex A7在向量表上放置的是跳转指令
    • 保存/恢复现场:cortex M3/M4是硬件实现的,cortex A7是软件实现的

Cortex M3/M4

image.png

  • M3/M4中有一个_Vectors向量表,其中放着各种异常/中断的处理函数
  • 异常/中断发生时,CPU怎么知道跳过来执行哪一个函数呢?
    • 这应该由硬件决定,硬件上确定了当前发生了哪个异常/中断,CPU由此找到向量表中的某一项,从而跳转过去执行处理函数
  • 编译时,vector向量表会保存在程序的最前面,将会被烧写到片内的flash上
  • 这个flash的地址是多少呢?
    • 在MDK中指定了:image.png
    • ROM地址为:0x8000000,大小为0x80000
  • 注意:虽然flash基地址是0x8000000,但当我们复位后,这个地址将会映射到0地址去
    • 这意味着,我们可以使用0x8000000来访问ROM,也可以使用0地址来访问ROM
  • image.png
  • M3/M4中保存现场(将寄存器保存到栈中)是由硬件自动实现的;硬件保存现场后还要分辨是哪个异常/中断,得到异常/中断号,使用异常/中断号在flash上的vector向量表中找到一项,CPU跳转过去执行其中的函数
  • 处理函数执行完后,就会返回,这个步骤将会触发硬件将之前保存的寄存器值恢复回去,这样之前被中断的程序就会继续运行了

    发生异常/中断时,硬件上实现了这些事情:

    • 保存现场:把被中断瞬间的寄存器的值保存进栈里
    • 根据异常/中断号,从向量表中得到函数地址,跳转过去执行
    • 函数执行完后,从栈中恢复现场

    保存现场、分辨异常/中断、跳转执行,都是硬件实现的。我们只需要在向量表中,把处理函数的地址填进去就可以了。 硬件承包了大部分的工作。

M3/M4的向量表中,存放的是函数地址

Cortex A7

  • A7的向量表与M3/M4不一样,其中存放的是跳转指令
  • Uboot中的异常向量表
    • image.png
    • 目录是:u-boot/arch/arm/lib/vector.S 并不位于某个处理器芯片下面,这表明这个vector应该是通用的
    • image.png
    • 这其中放的是某一种异常的总入口,是一条跳转指令
    • 显然,在跳转到的异常总入口里,应该进行更进一步的异常分辨(如中断_irq中,应该进一步区分是什么中断)
  • image.png
    • A7中,CPU执行完一条指令后检测到发生中断时,由硬件进行异常模式切换_irq,然后跳转执行中断向量表中的跳转指令,进而跳转到异常处理函数的总入口
    • 向量表中直接对PC赋值,那么中断前程序的地址(返回地址)怎么办?硬件自动保存PC值到LR寄存器了吗?
      • 一般异常模式(除FIQ)只有SP和LR两个寄存器是独有的,PC寄存器是公用的
      • 猜测最大可能是PC值自动保存到对应模式的LR寄存器,那么跳转到向量表的指令就应该用的跳转指令B/BL了,只有这样PC值才会自动的被保存在LR寄存器中
    • 保存/恢复现场由软件进行

发生异常/中断时,硬件上实现了这些事情:

  • CPU切换到对应的异常模式,比如IRQ模式、未定义模式、SVC模式
  • 保存被中断时的CPSR到SPSR

    • CPSR:current program status register,当前程序状态寄存器
    • SRSR:saved program status register,保存的程序状态寄存器
  • 跳到这个异常的入口地址去,执行指令,这通常是一条跳转指令

软件要做的事情就比较多了:

  • 保存现场
  • 分辨异常/中断
  • 调用对应的处理函数
  • 恢复现场

A7的向量表中,存放的是跳转指令