ARMv8
Exception Level
在介绍其他概念前,先要了解 ARMv8 全新的异常级设计。
ARMv8 定义了4个异常级。EL0-EL3,数字越大,权限越高。其中 EL0 用于应用程序,EL1 用于操作系统,EL2 用于虚拟化,EL3 用于安全固件。对于处理器实现而言,EL0和EL1是必须要实现的,EL2和EL3可选,且不必连续,例如可以实现 EL0,EL1和EL3,不实现EL2。
Execution State
ARMv8为了兼容32位指令有两个执行态,分别是 AArch32 和 AArch64,AArch32 兼容 Armv7-A。
各个异常级支持的执行态见下图:可以看到64位的OS可以支持32位和64位的APP,32位的OS只能支持32的APP。
道理很简单,如果64的APP运行在32位的OS上,syscall 的参数将被OS截断。同理 EL2 的 Hypervisor 也是如此。
执行态的切换必须要进入更高的EL。例如,EL0当前运行在AArch32希望切换到AArch64,必须向OS请求来实现执行态的变更。这里没有提到EL3,如果EL3希望切换执行态该怎么办呢?由于EL3是最高的异常级了,所以自己没办法改变执行态,只能通过复位配置来解决。对于其他异常级而言,可以通过System Register来控制。
If, when taking an exception or returning from an exception, the Exception level remains the same, the execution state cannot change.
PSTATE
程序状态字。包含各种标志、进位、溢出等。
In the ARMv8-A architecture, Process state or PSTATE is an abstraction of process state information.
ARMv8 Registers
体系结构提供了两类寄存器,一种用于系统控制和状态呈现,称为系统寄存器。一种用于指令处理,比如算术运算或异常处理。接下来描述一下后者。
- 通用寄存器 R0-R30
- 栈指针寄存器 SP_ELx
- SIMD及浮点寄存器
- 保存程序状态寄存器 SPSR
- 异常链接寄存器 ELRx
General Purpose Registers
ARMv8 提供了31个 64-bit 的通用寄存器。分别是 X0-X30。
每个 64-bit 的寄存器低32位又包含 32-bit 的兼容形式。称作 W0-W30。
读取W不会影响相应X的高32位,写入W会清零相应X的高32位。
Special Registers
In the ARMv8 architecture, when executing in AArch64, the exception return state is held in the
following dedicated registers for each Exception level:
- Exception Link Register (ELR).
- Saved Processor State Register (SPSR).
There is a dedicated SP per Exception level, but it is not used to hold return state.
Zero register
这个寄存器读取值时返回0,写入值时值被忽略。
Stack pointer
在每个实现的 Exception level 上都有相应的SP寄存器。
EL0 只能使用 SP_EL0
作为栈指针。
进入其他异常级后可以选择当前级的 SP_ELx
或者选择 SP_EL0
作为堆栈指针。触发异常时默认选择目标异常级的栈指针,当触发异常时,即使异常级未发生变化,也会切到目标异常级对应的栈指针上,也就是说假如当前在 EL1 使用 SP_EL0,此时触发了异常,依然停留在 EL1,栈指针将切换到 SP_EL1,而不是之前设置的 SP_EL0。
Software executing at the target Exception level can then choose to change the stack pointer to SP_EL0 by updating PSTATE.SP.
我们可以通过在异常级的后缀区分到底用了哪个栈指针。
// The t and h suffixes are based on the terminology of thread and handler.
t Indicates use of the SP_EL0 stack pointer.
h Indicates use of the SP_ELx stack pointer.
SIMD & FP
单指令多数据和浮点指令共享一套寄存器组。
它们是128-bit 的寄存器组,V0-V31。同时可以以不同的长度访问这些寄存器,分别是:
- 64-bit D0-D31
- 32-bit S0-S31
- 16-bit H0-H31
- 8-bit B0-B31
Saved Process Status Register
保存异常发生时的PSTATE值。SPSR在各个异常级同样都有对应的 SPSR_ELx。
Exception Link Register
保存异常发生时的返回地址。ELR在各个异常级同样有对应的 ELR_ELx,异常返回时 PC 的值讲从 ELR 中恢复。异常发生时 ELR_ELx 中保存的值和异常类型息息相关,见下文的 Exception return
。
事实上操作系统就是通过 ELR_EL1 的值来控制返回 EL0 时的指令地址,实现跳转。
System Registers
这些寄存器负责系统配置。且使用MSR, MRS
指令进行控制。通常 EL0 是无法访问这些寄存器的。
The name of a register tells you the lowest Exception level that it can be accessed from.
For example:
- TTBR0_EL1 is accessible from EL1, EL2, and EL3.
- TTBR0_EL2 is accessible from EL2 and EL3.
MRS x0, TTBR0_EL1 // Move TTBR0_EL1 into x0
MSR TTBR0_EL1, x0 // Move x0 into TTBR0_EL1
Exception
Synchronous & Asynchronous exception
异常是指系统发生了需要特权级软件(exception handler)进行处理的状态或事件。它会打断当前指令流,强制跳转到预先定义的位置进行处理。ARMv8 将异常分为了两个大类,分别是同步异常和异步异常。
同步异常是由于执行或尝试执行某条指令触发的。
异步异常包括通常意义上的中断(如外设产生的中断信号,在 ARMv8 上即 FIQ/IRQ 信号)以及系统错误(SError)。
System errors have several possible causes, the most common being asynchronous Data Aborts (for example, an abort that is triggered by write-back of dirty data from a cache line to external memory)
Exception entry
On taking an exception to AArch64 state,发生异常时根据异常的种类,有不同的行为。
程序状态字 SPSR
会保存到异常处理的目标异常级别 SPSR_ELx
返回地址则保存到对应的 ELR_ELx
自动屏蔽中断。All of PSTATE {D, A, I, F} are set to 1.
堆栈指针切换到对应的 SP_ELx
某些异常会保存出错的虚拟地址到 FAR_ELx
• An Instruction Abort exception.
• A Data Abort exception.
• A PC alignment fault exception.
• A Watchpoint exception.
...
之后执行流进入异常向量表里指定的位置开始执行。
Execution moves to the target Exception level, and starts at the address defined by the exception vector. Which exception vector is used is also an indicator of whether the exception came from a lower Exception level or the current Exception level.
Exception return
- For asynchronous exceptions, it is the address of the instruction following the instruction boundary at which the interrupt occurs. Therefore, it is the address of the first instruction that did not execute, or did not complete execution, as a result of taking the interrupt. 由于发生中断而未执行或未完成执行的第一条指令的地址。
- For synchronous exceptions other than system calls, it is the address of the instruction that generates the exception. 不包括 syscall,指令自身地址。
- For exception generating instructions, it is the address of the instruction that follows the exception generating instruction. 对于异常产生指令(svc,hvc,smc),是该指令的下一条指令地址。
Data Model
64-bit Linux使用 LP64
,ARM的A64指令集支持 LP64
和 LLP64
。Procedure Call Standard (PCS)
关于数据模型,更详细的介绍可参看数据模型。
CTLR reg
SCTLR_EL3.NS
Non-secure bit.
0 Indicates that EL0 and EL1 are in Secure state, and so memory accesses from those
Exception levels can access Secure memory.1 Indicates that EL0 and EL1 are in Non-secure state, and so memory accesses from those
Exception levels cannot access Secure memory.EL2 is not supported in the Secure state. When SCR_EL3.NS==0, it is not possible to enter EL2,
and the EL2 state has no effect on execution.
Hypervisor Configuration Register
HCR_EL2.TGE
Trap General Exceptions, from Non-secure EL0.
0 This control has no effect on execution at EL0.
1 When the value of SCR_EL3.NS is 0, this control has no effect on execution at EL0.
When the value of SCR_EL3.NS is 1, in all cases:
• All exceptions that would be routed to EL1 are routed to EL2.
• The SCTLR_EL1.M field, or the SCTLR.M field if EL1 is using AArch32, is
treated as being 0 for all purposes other than returning the result of a direct read
of SCTLR_EL1 or SCTLR.
• All virtual interrupts are disabled.
• Any IMPLEMENTATION DEFINED mechanisms for signaling virtual interrupts are
disabled.
• An exception return to EL1 is treated as an illegal exception return.
When the value of SCR_EL3.NS is 1 and the value of HCR_EL2.E2H is 0, additionally:
• The HCR_EL2.{FMO, IMO, AMO} fields are treated as being 1 for all purposes
other than a direct read or write access of HCR_EL2.
• The MDCR_EL2.{TDRA,TDOSA,TDA, TDE} fields are treated as being 1 for
all purposes other than returning the result of a direct read of MDCR_EL2.
For information on the behavior of this bit when E2H is 1, see Behavior of
HCR_EL2.E2H on page D4-2183.
HCR_EL2.TGE must not be cached in a TLB.
In an implementation that includes EL3, when the value of SCR_EL3.NS is 0 the PE behaves as if
this field is 0 for all purposes other than a direct read or write access of HCR_EL2.