文章目录
- ARM 处理器模式
- 工作模式
- 模式切换
- 内核寄存器
- R13_mode
- R14_mode
- PC
- 各个模式对应的内核寄存器
- 模式切换代码实现
- 使用 mrs/msr 指令
- 使用 cps 指令
ARM 处理器模式
ARMv7-a 处理器共有 9 种工作模式
工作模式
- User:用户模式,非特权模式,大部分程序运行的时候就处于此模式
- FIQ:快速中断模式,进入 FIQ 中断异常
- IRQ:一般中断模式,进入 IRQ 中断异常
- Supevisor(SVC):超级管理员模式,复位或者一个 Supervisor 指令调用
- Monitor(MON):监听模式,用户安全扩展模式
- Abort(ABT):数据访问中止模式,用户虚拟存储及存储保护
- Hyp(HYP):用于虚拟化扩展
- Undef(UND):未定义的指令终止模式
- System(SYS):系统模式,用于运行特权级的操作系统任务
从上表可以看出,系统一复位就处于 SVC
模式
模式切换
ARM 模式切换由 CPSR( Current Program Status Register) 寄存器控制
需要注意的是,
- User 模式下,操作 bit[4:0],即不能切换处理器模式
- User 模式下,不能操作 A,I 和 F 位
M[4:0] 对应的处理器模式如下表
内核寄存器
一共有 16 个寄存器,R[0-15]
- R13 - SP(stack pointer)
- R14 - LR(link register)
- R15 - PC(program counter)
R13_mode
- 在 ARM 指令集中常用作栈指针,这只是一种习惯的用法,并没有任何指令强制性的使用 R13 作为栈指针。用户也可以使用其他的寄存器作为栈指针;
- 在 Thumb 指令集中,有一些指令强制使用 R13 作为栈指针。
除 User 和 SYS公用 SP 以外,每一种异常模式都有自己的物理 R13,使其指向该异常模式专用的栈地址。
- 当进入异常模式时,可以将需要使用的寄存器保存在 R13 所指的栈中;
- 当退出异常模式时,将保存在 R13 所指的栈中的寄存器值弹出。
这样就使异常处理程序不会破坏被其中断程序的运行现场。
R14_mode
寄存器 R14 又成为链接寄存器(link register)
除 User ,SYS 和 HYP 公用 LR 以外,每一种模式都有自己的物理 R14,并在其中存放当前子程序的返回地址。实现子程序的返回可以有如下两种方式
mov pc, lr
bx lr
PC
由于 ARM 采用了流水线机制,取址 -> 译码 -> 执行,所以当正确的读取了 PC 的值时,该值为当前指令地址加 8 个字节。也就是说,对于 ARM 指令集来说,PC 指向当前指令的下两条指令的地址,由于 ARM 指令时字对齐的(这也是为什么加的是 8),PC 的值第 0 为和第 1 位总为 0。
例如在下面的示例中,将 PC 的值放到 R4 寄存器中
- 执行
mov r4, pc
指令的地址为0x80000024
- 使用
info reg
命令查看 r4 寄存器的值为0x8000002c
各个模式对应的内核寄存器
浅色字体的是与 User 模式所共有的寄存器,蓝绿色背景的是各个模式所独有的寄存器
- 在所有模式中,低寄存器组(R0-R7) 是共享同一组寄存器的
- 一些高寄存器组在不同模式下有自己独有的寄存器,
- FIQ 模式下访问 R12 寄存器,它实际访问的是 R12_fiq
- SVC 模式下访问 SP 寄存器,它实际访问的是 SP_svc
- 除 sys模式外,SP 寄存器都是独立的,所以各个模式需要切换到对应的模式,然后设置自己的栈指针
- Hyp 模式下独有一个 ELR_hyp 寄存器。
模式切换代码实现
使用 mrs/msr 指令
- MRS:将特殊功能寄存器
CPSR/SPSR/CP14/CP15
的值传递到通用寄存器中 - MSR:将通用寄存器的值传递到
CPSR/SPSR/CP14/CP15
特殊功能寄存器中 - 需要注意的是,在 User 模式下,虽然所有的位都是可读的,但是只有 F 位才能被修改,所以在 User 模式下不能进行处理器模式切换
.global _start
_start:
/* 进入 SVC 模式(其实复位之后,系统就处于 SVC 模式,这里也可以不切换,设置 SP 的值) */
mrs r0, cpsr
bic r0, r0, #0x1f /* 将 r0 寄存器中的低 5 位清零,也就是 cpsr 的 M0~M4 */
orr r0, r0, #0x13 /* r0 或上 0x13,表示使用 SVC 模式 */
msr cpsr, r0 /* 将 r0 的数据写入到 cpsr 中 */
ldr sp, =0X80200000 /* 设置栈指针 */
使用 cps 指令
- CPS:Change Processor State 这个指令可以切换处理器模式,或者使能/禁止各自的异常
.global _start
.equ Mode_USR, 0x10
.equ Mode_FIQ, 0x11
.equ Mode_IRQ, 0x12
.equ Mode_SVC, 0x13
.equ Mode_MON, 0x16
.equ Mode_ABT, 0x17
.equ Mode_HYP, 0x1A
.equ Mode_UND, 0x1B
.equ Mode_SYS, 0x1F
.equ Stack_size, 0x400
.equ Stack_Start, 0x80200000
.equ Mode_USR_Stack, Stack_Start + Stack_size
.equ Mode_FIQ_Stack, Mode_USR_Stack + Stack_size
.equ Mode_IRQ_Stack, Mode_FIQ_Stack + Stack_size
.equ Mode_SVC_Stack, Mode_IRQ_Stack + Stack_size
.equ Mode_MON_Stack, Mode_SVC_Stack + Stack_size
.equ Mode_ABT_Stack, Mode_MON_Stack + Stack_size
.equ Mode_HYP_Stack, Mode_ABT_Stack + Stack_size
.equ Mode_UND_Stack, Mode_HYP_Stack + Stack_size
.equ Mode_SYS_Stack, Mode_UND_Stack + Stack_size
_start:
cps #Mode_FIQ
ldr sp, =Mode_FIQ_Stack
cps #Mode_IRQ
ldr sp, =Mode_IRQ_Stack
cps #Mode_SVC
ldr sp, =Mode_SVC_Stack
cps #Mode_MON
ldr sp, =Mode_MON_Stack
cps #Mode_ABT
ldr sp, =Mode_ABT_Stack
cps #Mode_HYP
ldr sp, =Mode_HYP_Stack
cps #Mode_UND
ldr sp, =Mode_UND_Stack
/* sys mode and user have common sp register */
@cps #Mode_SYS
@ldr sp, =Mode_SYS_Stack
/* last enter user mode, and user manipulate cpsr except for F bit */
cps #Mode_USR
ldr sp, =Mode_USR_Stack
/* switch fail cpu run in user mode */
cps #Mode_SVC
ldr r0, =0x01
ldr r1, =0x02
ldr r2, =0x03
ldr r3, =0x04
ldr lr, =0x05
push {r0-r3, lr}
/* nop for debug */
nop
nop
nop
mov r0, #0
mov r1, #0
mov r2, #0
mov r3, #0
mov lr, #0
/* nop for debug */
nop
nop
nop
pop {r0-r3, lr}
/* nop for debug */
nop
nop
nop
stmfd sp!, {r0-r3, lr}
/* nop for debug */
nop
nop
nop
mov r0, #0
mov r1, #0
mov r2, #0
mov r3, #0
mov lr, #0
/* nop for debug */
nop
nop
nop
ldmfd sp!, {r0-r3, lr}
/* nop for debug */
nop
nop
nop
loop:
b loop