展示代码
/*
* Prepare SCTLR
*/
mov_q x0, SCTLR_EL1_SET
ret // return to head.S
SYM_FUNC_END(__cpu_setup)
分析代码
第1行到第3行是注释,准备寄存器 SCTLR,SCTLR 是什么东东我们继续分析
第4行涉及宏定义 SCTLR_EL1_SET,定义如下
#define SCTLR_EL1_SET (SCTLR_ELx_M | SCTLR_ELx_C | SCTLR_ELx_SA |\
SCTLR_EL1_SA0 | SCTLR_EL1_SED | SCTLR_ELx_I |\
SCTLR_EL1_DZE | SCTLR_EL1_UCT |\
SCTLR_EL1_NTWE | SCTLR_ELx_IESB | SCTLR_EL1_SPAN |\
SCTLR_ELx_ITFSB| SCTLR_ELx_ATA | SCTLR_EL1_ATA0 |\
ENDIAN_SET_EL1 | SCTLR_EL1_UCI | SCTLR_EL1_RES1)
该宏涉及到了寄存器 SCTLR_EL1, System Control Register (EL1)
其作用如下 Provides top level control of the system, including its memory system, at EL1 and EL0.
它是ARM64架构中的一个系统控制寄存器,用于控制处理器的操作和行为。它影响内存管理、缓存、中断处理等多个方面。
代码中涉及的宏定义对应的BIT位定义如下
#define SCTLR_ELx_M (BIT(0))
#define SCTLR_ELx_C (BIT(2))
#define SCTLR_ELx_SA (BIT(3))
#define SCTLR_EL1_SA0 (BIT(4))
#define SCTLR_EL1_SED (BIT(8))
#define SCTLR_ELx_I (BIT(12))
#define SCTLR_EL1_DZE (BIT(14))
#define SCTLR_EL1_UCT (BIT(15))
#define SCTLR_EL1_NTWE (BIT(18))
#define SCTLR_ELx_IESB (BIT(21))
#define SCTLR_EL1_SPAN (BIT(23))
#define SCTLR_ELx_ITFSB (BIT(37))
#define SCTLR_ELx_ATA (BIT(43))
#define SCTLR_EL1_ATA0 (BIT(42))
#ifdef CONFIG_CPU_BIG_ENDIAN
#define ENDIAN_SET_EL1 (SCTLR_EL1_E0E | SCTLR_ELx_EE)
#else
#define ENDIAN_SET_EL1 0
#endif
$ cat .config | grep CONFIG_CPU_BIG_ENDIAN
# CONFIG_CPU_BIG_ENDIAN is not set
#define SCTLR_EL1_UCI (BIT(26))
#define SCTLR_EL1_RES1 ((BIT(11)) | (BIT(20)) | (BIT(22)) | (BIT(28)) | (BIT(29)))
而 BIT 的宏定义如下
#define BIT(nr) (UL(1) << (nr))
我们逐个寄存器bit域分析
M[0]: 使能MMU(内存管理单元)。设置为1时,启用MMU;设置为0时,禁用MMU。
C[2]: 数据缓存使能。设置为1时,启用数据缓存;设置为0时,禁用数据缓存。
SA[3]: 设置/失效指令的栈对齐检查。如果设置了这个位,处理器会检查所有使用set/clear指令的栈地址是否对齐。
SA0[4]: EL0栈对齐检查使能位。与SA位类似,但是专门针对EL0(用户模式)。
SED: 禁止SETEND。在EL0使用AArch32禁止SETEND指令。0 使能,1 禁止。
I: 开启指令缓存,这是在EL0和EL1下的指令缓存的启用位。对可缓存的正常内存的指令访问被缓存。
DZE 位域用于控制当处理器执行在 EL0 权限级别下的 DC ZVA 指令时的行为。DC ZVA 指令是用于实现指针的零化操作,它将指定的指针设置为零值。细节描述如下
DZE: 位域位于 SCTLR_EL1 寄存器的第 14 位。
含义:
0b0: 任何在 EL0 下使用 AArch64 执行 DC ZVA 指令的尝试都会被截获(trapped),并且引发异常,该指令在 EL0 下是不允许执行的。
0b1: 允许在 EL0 下执行 DC ZVA 指令,不会有异常发生。
如果 DZE 位被设置为 0,那么在 EL0 下尝试执行 DC ZVA 指令将导致异常,从而阻止用户级别的代码执行该操作。这可以防止用户级别的代码干预或破坏由操作系统或更高权限级别代码所管理的指针验证过程。
此位域的设计是为了在不同的执行级别之间提供额外的控制和安全性,确保操作系统或虚拟机监视器能够在需要时控制对某些系统指令的访问。
UCT: 此标志为1时,开启AArch64的EL0下访问CTR_EL0寄存器 。
nTWE: 不陷入WFE,此标志为1表示WFE作为普通指令执行
SCTLR_EL1 寄存器的 IESB 位域用于控制是否允许 EL0 权限级别软件执行同步外部障碍(Synchronous External Barrier)操作。IESB 位位于 SCTLR_EL1 寄存器的第 25 位。
IESB: 如果 IESB 位设置为 1,则允许在 EL0 下执行同步外部屏障指令,如 DMB、DSB 和 ISB。如果设置为 0,则在 EL0 下执行这些指令时会触发异常。
这个位域的设计是为了在不同的执行级别之间提供额外的控制和安全性,确保操作系统或虚拟机监视器能够在需要时控制对某些系统指令的访问。
SPAN位是一个控制位,用于处理地址翻译过程中的异常情况。具体来说:
SPAN (Stage 2 Address Translation span): 这一位用来控制第二级地址翻译的范围。当SPAN位设置为0时,处理器只允许在当前的翻译表内进行地址翻译。
这意味着,如果发生地址翻译错误,并且所需的内存当前没有映射在当前的翻译表中,那么这个错误就不能被解决。SPAN位通常与PSTATE寄存器中的PAN位一起使用,以增强系统的安全性 。
SPAN位通常用于确保特定代码或数据的访问限制在特定的内存区域,从而增强系统的安全性。
例如,如果一个程序只能访问特定的内存区域,通过设置SPAN位,可以防止该程序访问未授权的内存区域,即使通过地址翻译错误的方式尝试。
需要注意的是,如果SPAN位被设置为0,并且同时PAN位也被设置为1,那么任何尝试访问未映射内存的操作都会被阻止,即使是特权代码也无法访问。
这可能会使得处理地址翻译错误变得更加困难,因为无法通过映射所需内存到不同的翻译表来解决问题 。
总的来说,SPAN位是一个安全特性,可以用来限制代码的内存访问范围,增加系统的稳定性和安全性。
ITFSB是SCTLR_EL1寄存器中的一个位域,具体位于第37位。当FEAT_MTE2特性被实现时,这个位才存在。ITFSB的作用是控制是否在进入EL1异常时,将所有由于指令执行前产生的标签检查故障(Tag Check Faults)同步到TFSRE0_EL1和TFSR_EL1寄存器中。这些故障通常是异步报告的。
当ITFSB设为0b0时,标签检查故障不会在进入EL1时同步。
当ITFSB设为0b1时,标签检查故障会在进入EL1时同步。
这个位的设置对于确保处理器在异常处理时能正确地处理标签检查故障是有帮助的。
在ARM64架构中,SCTLR_EL1寄存器的ATA(Alignment Trap for data abort)位通常是用来控制数据访问对齐的。
当该位被设置为1时,如果在EL0发生对齐异常,处理器会将异常陷阱(trap)到EL1,而不是默认的更高异常级别。
这允许在EL1级别处理对齐异常,而不是直接进入到更高的异常级别(如EL2或EL3),从而为操作系统提供了更大的灵活性来处理这类异常。
ATA位通常位于SCTLR_EL1寄存器的第28位。当ATA位被设置,并且EL0发生数据访问对齐异常时,异常处理器会将控制权转交给EL1,而不是像通常情况下那样直接进入EL3。
这对于操作系统设计者来说非常有用,因为它允许他们在不牺牲安全性的前提下,更灵活地处理对齐异常。
需要注意的是,ATA位的效果可能会受到其他系统控制寄存器设置的影响,例如HCR_EL2(Hypervisor Configuration Register)中的TAC(Trap ALignment Check)位。
如果TAC位被设置,那么即使ATA位被启用,对齐异常也会被陷阱到EL2而不是EL1。
在ARM64架构中,SCTLR_EL1寄存器的ATA(Allocation Tag Access)位通常是用来控制对内存分配标签的访问权限。具体来说:
ATA (Allocation Tag Access): 当该位设置为0时,对于分配标签的任何访问都会导致未定义指令异常,并且会被陷阱到更高的异常级别(例如EL2或EL3)。
这意味着在EL1和EL0下不允许访问分配标签相关的寄存器,如GCR_EL1, RGSR_EL1, TFSR_EL1, TFSR_EL2 或 TFSRE0_EL1。当ATA位设置为1时,则允许对分配标签的访问 。
这个控制位通常用于在虚拟化环境中或者当需要严格限制对某些内存标签的访问时。通过适当设置ATA位,可以防止在较低的异常级别(如EL0或EL1)下对这些敏感寄存器的未授权访问,从而增强系统的安全性。
在ARM64架构中,SCTLR_EL1寄存器的ATA0位域,也就是bit 42,当FEAT_MTE2特性被实现时,这个位才存在。
ATA0(Allocation Tag Access in EL0)控制着在EL0(异常级别0)对内存访问的分配标签(Allocation Tags)的访问权限以及标签检查操作(Tag Check operations)。
当ATA0设为0b0时,会阻止在EL0访问分配标签,并且EL0的内存访问不会受到标签检查操作的影响。
当ATA0设为0b1时,不会阻止EL0访问分配标签,EL0的标签检查内存访问将受到标签检查操作的影响,这取决于被访问内存的标签类型:对于带有分配标签的内存,会执行分配标签检查操作;如果实现了FEAT_MTE_CANONICAL_TAGS特性,对于规范标签的内存,会执行规范标签检查操作 。
这个位的设置对于确保处理器在不同异常级别下对内存访问的一致性和安全性是有帮助的。
在ARM64架构中,SCTLR_EL1寄存器的UCI(bit 26)位用于控制是否允许在EL0(异常级别0)执行缓存维护指令。当UCI位设置为1时,以下缓存维护指令在EL0执行时不会引发异常,而是正常执行:
DC CIVAC
DC CVAC
DC CVAP
IC IVAU
如果UCI位设置为0,则在EL0执行上述指令会被认为是非法的,并在EL1或EL2(取决于当前安全状态和HCR_EL2.TGE的值)引发异常,异常的ESR_ELx.EC值会是0x18。