一、ARM系统的异常与中断

参考文章:https://www.jianshu.com/p/4ae912d468ac?utm_campaign=maleskine...&utm_content=note&utm_medium=seo_notes

1、赋予了中断号并使能中断的外设,发生中断(这些中断属于一种异常)时,发出信号给中断控制器(GIC、ICTL等),中断控制器再发送信号给CPU;

2、指令不对,数据访问有问题,reset信号,这些都可以中断CPU。

二、CPU模式与寄存器

1、ARM CPU模式

usr :正常模式。除了该模式,其他都叫特权模式

und :未定义模式

svc :管理模式

abt :终止模式

IRQ :中断模式

FIQ :快中断模式

sys :系统模式

2、ARM CPU state,两种指令集

ARM state

Thumb state

3、ARM CPU寄存器:

(1)通用寄存器,其中3个特殊的:

程序计数器(PC)用的寄存器是R15,用于保存处理器要取的下一条指令地址

堆栈指针(SP)用的是R13,用于保存当前处理器工作模式下堆栈的栈顶地址。栈一般是从高地址往下增长的,详细可看下文解析:

https://blog.csdn.net/u011124985/article/details/81529808

链接寄存器(LR)用的是R14,用于保存子程序的返回地址,当子程序的返回地址保存在堆栈中时,R14也可作为通用寄存器。

(2)备份寄存器(banked register)

(3)当前程序状态寄存器(Current Program Status Register);CPSR

(4)CPSR的备份寄存器:SPSR(Save Program Status Register)

注:usr用户模式可以编程操作CPSR,进入其他模式

寄存器如下图,其中灰色的三角形,表示该模式下的专属寄存器;其他为各个模式共用的寄存器。

可以看到,五种异常模式中每个模式都有自己专属的R13 R14寄存器,R13用作SP(栈) R14用作LR(返回地址):

引申介绍一下存储空间中的数据存放

text段(代码段),存放运行的指令数据;

data段(数据段),存放初始化非0的全局变量;

bss段,存放未初始化的和初始化为0的全局变量;

堆段,由用户申请和释放。申请时至少分配虚存,当真正写数据时才分配对应的实存,释放时也并不是马上释放实存,而是可能被反复利用;

栈段,由系统负责申请释放,其操作方式类似数据结构的栈,用于存储參数变量及局部变量,函数的运行也是栈的方式,所以才有了递归;

参数和全局环境变量区,存储程序运行时从shell中传入的参数和环境变量。

4、ARM三级流水线介绍

ARM处理器使用流水线来增加处理器指令流的速度:以下三个流程是一直在同时执行的:

(1)取指(从存储器装载一条指令);(第三条指令)

(2)译码(识别将要被执行的指令);(第二条指令)

(3)执行(处理指令并将结果写回寄存器)。(正在执行,第一条指令)

R15(PC)总是指向“正在取指”的指令。

习惯性将“执行”的指令称为当前第一条指令,因此PC总是指向第三条指令。

即:PC值=当前程序执行地址+8。(ARM指令集下)

当中断发生时,保存的是pc的值,那么中间就有一个指令没有执行(译码)!

所以中断返回是:SUB pc lr-irq #4。(中断返回在后文有讲)

三、arm对异常(中断)处理过程

1、初始化:

a 、设置中断源,让它可以产生中断(TIMER)

b 、设置中断控制器(屏蔽使能某个中断,设置优先级)

c 、设置CPU总开关(使能中断)

2、产生中断:

按下按键--->中断控制器--->CPU

对于不同的异常,CPU跳去不同的地址执行程序。

ldr pc, irq_addr/* vector 0x18 : irq */

该地址是一条跳转指令,最终跳去执行异常处理函数,这个就是异常向量。

注意:

异常发生后,CPSR的值保存到SPSR_xxx、切换到xxx模式、CPU跳到异常向量,例如0x00000008,都是硬件决定的;

中断向量跳到哪个处理函数,是软件决定的。

3、处理过程:

a 、保存现场(各种寄存器)

发生中断时,需要把R0 ~ R14这些寄存器全部保存下来,然后处理异常,最后恢复这些寄存器。

但如果是快中断FIQ,那么我就不需要保存 系统/用户模式下的R8 ~ R12这几个寄存器,在FIQ模式下有自己专属的R8 ~ R12寄存器,省略保存寄存器的时间,加快处理速度,但是在Linux中并不会使用FIQ模式。

b 、处理异常(中断):分辨中断源,再调用不同的处理函数

c 、恢复现场

ldr pc, irq_addr/* vector 0x18 : irq */

irq_addr:
.word do_irq /*注:.align 4 是让该指令下面的代码进行4字节对齐!不是上面 */
.align 4
do_irq:
/*设置该模式的栈顶,每个模式栈不同、不重叠,例如0x33FF0000、0x33FE0000*/
ldr sp, =0x33FD0000
/* 在und异常处理函数中有可能会修改r0-r12, 所以先保存 */
/* lr是异常处理完后的返回地址, 也要保存 */
sub lr, lr, #4
stmdb sp!, {r0-r12, lr}
/* 处理irq */
bl handle_irq_c
/* 恢复现场,会把spsr的值恢复到cpsr里 */
ldmia sp!, {r0-r12, pc}^

CRSR当前程序状态寄存器,这是一个特别重要的寄存器,格式如下:

M0-M4代表的模式:

Bit5 State bits表示CPU用的指令集是什么

Bit6 FIQ disable当bit6等于1时,禁止所有的FIQ中断,这个位是FIQ的总开关

Bit7 IRQ disable当bit5等于1时,禁止所有的IRQ中断,这个位是IRQ的总开关

Bit8 ~ Bit27是保留位

Bite28 ~ Bit31是状态位:

28 V :

29 C :

30 Z :比较相等,Z=1

31 N :

SPSR:发生异常时这个寄存器会用来保存被中断的模式下的CPSR

比如程序在sys模式下运行,CPSR值为X,当发生IRQ中断时会进入irq模式,这个SPSR_irq就保存系统模式下的CPSR的值X。

很好理解,因为这样才能从irq模式,恢复到sys模式!

4、我们来看看发生异常时CPU是如何协同工作的:

进入异常的处理流程(CPU硬件)

a、把下一条指令的地址保存在LR寄存器里

b、把CPSR保存在SPSR里面(某种异常模式下SPSR里面的值等于异常前的模式的CPSR)

c、修改CPSR的模式为进入异常模式

d、跳到向量表

5、返回异常前

a 、lr是根据下表取值后赋值给pc:



例如,如果发生的是SWI可以把 R14_svc赋值给PC,如果发生的是IRQ可以把R14_irq的值减去4赋值给PC

b 、把CPSR的值恢复(CPSR 值等于 某一个异常模式下的SPSR)

c 、清中断(如果是中断的话,对于其他异常不用设置)

最新文章

  1. PHP之用户验证和标签推荐的简单使用
  2. 《奥威Power-BI案例应用:带着漫画看报告》腾讯课程开课啦
  3. html5设计原理(转)
  4. vector的erase的用法
  5. POJ 2155 2维线段树 || 2维BIT
  6. MATLAB学习笔记(一)——入门与操作
  7. HBase 安装过程记录
  8. HDU2167+状态压缩DP
  9. 在JS中得到表单中各项的值
  10. MSSQL基础
  11. .NET MVC4 实训记录之六(利用ModelMetadata实现资源的自主访问)
  12. tcp协议栈
  13. poptest老李谈分布式与集群 2
  14. JAVA 的 Date、Calendar的常用用法
  15. centos7 系统安装问题汇总
  16. armlinux下的网路传输(tcp/ip)
  17. turtle文库 ——python
  18. phoenix API服务发布
  19. wdcp lanmp 安装+搭建网站+安全狗安装 详细实用
  20. Codeforces 1086D Rock-Paper-Scissors Champion

热门文章

  1. Git配置多个github账号免密登录
  2. Python实现不带头结点的单链表
  3. Ubuntu20.04 安装MongoDB及其基本使用
  4. PHP实习生面试准备的建议
  5. PHP+mysql真题
  6. 私有化轻量级持续集成部署方案--05-持续部署服务-Drone(上)
  7. CentOS7防火墙firewall
  8. 扫盲贴:2021 CSS 最冷门特性都是些啥?
  9. log4j的替换方案
  10. HTTP攻击与防范-PHP客户端脚本攻击