ARM-处理器模式(二)

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

猜你喜欢

转载自blog.csdn.net/tyustli/article/details/130655444