ARM模式(处理器所在的模式)和寄存器总结
本文介绍了ARM V7架构下的处理器的模式、状态以及通用寄存器和部分CP15 bank
1-1:ARM处理器模式
- USR:大多数应用运行的模式,非特权模式,运行在PL0
- FIQ:快中断异常模式,运行在PL1
- IRQ:普通中断模式,运行在PL1
- SVC:当处理器复位或者执行特权指令的时候处理器进入此模式,运行在PL1
- MON:MON模式在ARM V6之前是没有的,此模式主要作用就是实现安全拓展,运行在PL1
- ABT:进行内存访问的时候处理器进入此模式,运行在PL1
- HYP:主要为虚拟化拓展用,运行在PL2
- UND:当执行一个未定义指令时,处理器进入此模式,运行在PL1
- SYS:OS运行的模式,运行在PL1
CPU当前的模式和运行状态可以由CPSR得知
ARM特权等级
- PL0:应用程序处于的模式(User mode),此模式下不能改变一些配置设置,并且此模式下的只能进行非特权的内存访问
- PL1:大多数软件在PL1下执行,只要不是在User mode和Hyp mode的模式都工作在此特权等级下
- PL2:HYP mode就在PL2下,工作中一般用不到
ARM通用寄存器概述
ARM架构包含16个32位的通用寄存器(R0-R15),R0-R14可以用来一般的数据存储,但**R15存储了当前程序执行计数指针的值(PC)**,手动往R15里写值的话会改变程序执行流。R13一般被用来存储栈指针SP,R14用来存储函数的返回值LR

3-1:ARM通用寄存器
上图的R0-15在不同处理器模式下一些寄存器的作用是不同的,其中有一些物理寄存器在所有模式下是共用的,也有一些寄物理寄存器在不同的处理器模式下独自拥有:

3-2:ARM Bank register
由上图可以看出,所有的模式下R0-R7是共用的,也就是在User、Sys、FIQ…..等模式下访问到的R0-R7的寄存器值是都是相同的。但同时也不难看出比如在IRQ模式下,访问R13寄存器,那实际访问的是SP_svc寄存器,如果在FIQ模式下访问R13寄存器,那么实际访问到的是SP_fiq寄存器。
需要注意的是:软件不会指定访问哪个模式下的哪个寄存器,而是由此时软件处于的处理器模式决定的,比如当前软件运行于User mode,那么此时访问R13,就实际访问SP_svc
R13:在所有的模式下都是OS的栈指针
R14:一般用来保存进入子程序的返回地址;当异常发生时,该异常模式对应的 R14 寄存器被设置成该异常模式将要返回的地址
R15:程序计数器,保存着当前程序的指令地址加上8个字节,也就是PC指针。原因是因为ARM的三级流水钱机制:Fetech->Decode->Execute,比如现在有三条指令inst1,inst2,inst2,当前正在执行的指令是inst1,那么执行inst1的过程也会对inst2进行Decode,inst3也同时在Fetech。对于32位的ARM处理器,那么一条指令为4字节,我们可以得到:
1
R15(PC) = 当前执行的程序位置 + 8个字节
CPSR:程序当前状态寄存器
- 保存着当前的处理器模式
- 中断标志
- 处理器的状态,比如处于ARM还是Thumb等
- 大小端
- 执行状态
我们知道当前中断执行完成之后需要恢复现场,那从图3.2可以看出,所有模式下的CPSR都是公用,那么显然会产生冲突。所以除了User和Sys模式,其他的7个模式在exception下都有各自的备份状态寄存器(SPSR),当exception发生时,CPSR的值会自动拷贝到SPSR,当exception退出时,可以使用SPSR来恢复CPSR。

3-3:CPSR寄存器
各个位含义如下:
- N:ALU计算出的结果为负值
- Z:ALU计算出的结果为0
- C:ALU计算有进位产生
- V:ALU计算有溢出产生
- Q:饱和状态,仅ARM v5TE_J 架构支持
- J:ARM core是否处于Jazelle状态
- GE[3:0]:SIMD指令使用
- IT[7:2]:Thumb2指令使用
- E:大小端标志,0为小端,1为大端
- A:disables asynchronous aborts.
- I:是否使能IRQ
- F:是否使能FIQ
- T:ARM core是否处于Thumb状态
- M[4:0]:确定处理器模式,见图1-1:ARM处理器模式
ARM CP15协处理器控制寄存器
功能:CP15一共有16个32位**(c0-c15**)的寄存器,一般用于存储管理和中断管理
4-1:CP15不同的CRn,opc1,opc2,CRm组合对应着不同的寄存器。图4-1:CP15里重要的参数解读如下:
CRn:CP15 协处理器的目标寄存器
CRm:协处理器中附加的目标寄存器或者源操作数寄存器,如果不需要附加信息就将
CRm 设置为 C0,否则结果不可预测opc1:要执行的操作码
opc2:可选的操作码,不用的时候置0
CP15的读写通过MRC与MCR,读写格式为:
1
2MRC p15, Op1, Rt, CRn, CRm, Op2 ; read a CP15 register into an ARM register
MCR p15, Op1, Rt, CRn, CRm, Op2 ; write a CP15 register from an ARM registerRt:ARM源寄存器,要写到CP15的寄存器的值就保存在此寄存器中,对于MRC来说,从CP15指定寄存器读出来的值就会保存在Rt里,对于MCR来说Rt就代表将要写入的寄存器
c0寄存器详细描述:

4-2:c0寄存器
当CRn=0,opc1=0,CRm=0,opc2=0时,就表示此时的c0就代表MIDR,同理当CRn=0,opc1=0,CRm=0,opc2=1时,此时的c0就代表CTR寄存器。当c0代表了MIDR时,MIDR各个位含义如下:

4-2:c0作为MIDR
Bits [31:24] – implementer:处理器厂商编号,如果是0x41就代表ARM
Bits [23:20] – variant:ARM core的主版本号
Bits [19:16] – architecture:ARM架构,0xF代表ARM V7
Bits [15:4] – part number:ARM core版本号,如果是0xC08,就代表了Cotex-A8处理器
Bits [3:0] – revision:ARM core的次版本号
c1寄存器详细描述:

4-3:c1 寄存器组
如图4-3,当CRn=1,opc1=0,CRm=0,opc2=0时,c1即为SCTLR寄存器,SCTLR寄存器就是系统控制寄存器,主要用来控制标准内存、系统一些外设并且提供ARM core的一些状态信息等。SCTLR只能在PL1或者更高的特权等级访问。

4-4:c1—SCTLR寄存器
常用的位有:
EE:定义了异常的大小端
U:定义了内存对齐模型,多少字节对齐
FI:FIQ配置使能
V:中断向量表基地址选择位,如果为0的话中断向量基地址为0x00000000。软件可以使用 VBAR 来重映射此基地址,也就是中断向量表重定位。为 1 的话中断向量表基地址为0XFFFF0000,此基地址不能被重映射 。
I:I cache使能位,为0关闭,1开启
Z:分支预测使能位
C:D Cache 和缓存一致性使能位,为 0 的时候禁止 D Cache 和缓存一致性,为 1 时使能
A:内存对齐检查位,为1是开启内存检查
M:MMU使能位,为0禁止MMU,为1开启MMU
c12寄存器详细描述:
c12常见的功能是作为VBAR寄存器,这样用户就可以通过软件的方式重新设置中断向量表地址

4-5:c12—VBAR
如图4-5,当CRn=12,opcl=0,CRm=0,opc2=0时,c12即为VBAR寄存器。
常见的设置中断向量表地址的示例如下:
1
2ldr r0,=dest addr
MCR p15,0,r0,c12,c0,0c15功能描述:
c15一般用来获取GIC地址,从而配置中断控制器相关功能

4-6:c15—CBAR寄存器
如图4-6,当CRn=15,opc1=4,CRm=0,opc2为0时,c15即为CBAR寄存器,CBAR寄存里保存的是内存映射 GIC 寄存器的物理基地址 。需要注意的是CBAR为只读寄存器,并且访问特权等级为PL1或者更高。
访问CBAR可以使用:
1
MRC p15, 4, <Rt>, c15, c0, 0; Read Configuration Base Address Register
通过上面命令可以获取到GIC的基地址,由于GIC是中断控制器,那我们就可以通过读GIC的一些寄存器来获取中断的一些状态,通过上面的命令我们已经得到了GIC BASE ADDR,由于GIC是CPU接口端寄存器,中断的的ID保存在GICC_IAR里,那只需要找到GICC_IAR相对CPU端接口基址的偏移量即可访问到GICC_IAR。GICC_IAR相对CPU端基地址偏移量是0x000C
1
2
3MRC p15,4,r1,c15,c0,0;把GIC的基地址读到r1里
ARR r1,r1,#0X2000;CPU端基地址为GIC基地址+0x2000
LDR r0,[r1,#0XC];读取GICC_IAR的值,保存到r0
