目录
1,异常等级(Exception Level)
2,Execution states,执行状态
AArch64的异常等级
AArch32的异常等级
3,异常等级切换
4,执行状态切换(AArch64 <=> AArch32)
1,异常等级(Exception Level)
在ARMv8中,存在4级异常等级(Exception Level),程序需要跑在这四级异常等级中的一个。在AArch64下,异常等级近似于ARMv7中的特权等级(Privilege Level),异常等级定义了每个等级的特权等级,所以可以认为ELn 对应这 PLn。n (0到3)越大,说明特权等级越高。
对于适用于ARMv8架构的所有操作状态,异常级别提供了软件执行权限的逻辑分离。它类似于并支持计算机科学中常见的分层保护域(hierarchical protection domains)的概念。
以下是软件跑在每个异常等级下的用例:
EL0 | 普通的用户程序 |
EL1 | 操作系统内核,通常被描述为具有特权的程序 |
EL2 | 管理员,切换操作系统时可以进入该状态。比如需要从Win切到Linux,需要先进入EL2 Hypervisor模式,然后再切到EL1下的Linux。 |
EL3 | 底层硬件, 包括 Secure Monitor。 |
通常情况下,软件(应用程序,操作系统内核,或者hypervisor)只在某一个异常等级下工作。但是 虚拟机管理程序不适用于这个规则,比如KVM,或者VMware等内核虚拟机监控程序(in-kernel hypervisors),它们可以跨EL2和EL1工作,因为需要进入EL2来管理不同的虚拟机程序(切换操作系统)。
在ARMv8-A系列中,存在两种安全状态:Secure 和 Non-secure。Non-secure状态也可称为Normal World。Secure 和 Non-secure的区分使操作系统(OS)能够与受信任的操作系统(trusted OS)在同一硬件上并行运行,并提供针对某些软件攻击和硬件攻击的保护。
ARM TrustZone技术使系统之间可以被分成Normal world和Secure world。与ARMv7-A体系结构一样,Secure monitor充当在Normal world和Secure world之间移动的网关,即通过Secure monitor可以在Normal world和Secure world之间切换。
ARMv8-A同样支持虚拟化,但是只针对Normal World,这意味着hypervisor或者是VMM(Virtual Machine Manager,虚拟机管理器)程序可以在系统中运行,并且可以管理多个 客户机操作系统(Guest OS)。每一个客户机操作系统都跑在一个虚拟机。然而,每个操作系统都不知道它正在与其他客户机操作系统共享系统上的时间 。
处于Non-secure状态下的Normal world,具有以下具有特权的组件:
- Guest OS kernels,客户机操作系统内核,比如Windows和Linux等,跑在Non-Secure EL1状态。当跑在hypervisor状态时,富操作系统内核(rich OS kernels)可以作为客户机或主机运行,具体取决于系统hypervisor程序模型。
- Hypervisor,跑在EL2状态,总是处于Non-Secure,虚拟化管理程序(hypervisor)在存在并启用时,为富操作系统内核提供虚拟化服务。
处于Secure状态下的Normal world,具有以下具有特权的组件:
Secure firmware,安全固件,在一个应用处理器上,这个固件必须是处理器在启动(boot)时,跑的第一个模块。它可以提供:平台初始化,受信任的操作系统的安装,以及Secure Monitor调用路由等服务。
Trusted OS,受信任的操作系统为Normal world提供安全服务,并为执行安全或受信任的应用程序提供运行时环境。
ARMv8架构中的Secure monitor处于更高的Exception级别,并且比所有其他级别拥有更多特权。这提供了一个软件特权的逻辑模型。
2,Execution states,执行状态
ARMv8架构定义了两种执行状态:AArch64和AArch32。AArch64状态使用64-bit宽的通用寄存器,而AArch32使用32-bit宽的通用寄存器。ARMv8 AArch32保留了ARMv7的特权级别,在AArch64状态,特权等级被描述为异常等级。因此,可以认为ELn对应PLn。
在AArch64状态下,处理器使用A64指令集。而在AArch32状态下,处理器可以使用A32或者T32(Thumb)指令集
AArch64的异常等级
AArch32的异常等级:
在AArch32状态下,Trusted OS软件执行在安全的EL3下,而在AArch64状态下,Trusted OS可以跑在Secure EL1下。
3,异常等级切换
在ARMv7体系结构中,处理器模式可以在具有特权的软件控制下改变,也可以在发生异常时自动改变。当发生异常时,处理器会保存当前执行状态和返回地址,进入所需模式,并可能禁用硬件中断。
- 应用程序执行在最低的特权等级,PL0,即无特权模式。
- 操作系统跑在PL1.
- 支持虚拟化扩展的系统中的Hypervisor跑在PL2.
- Secure monitor,充当secure和non-secure世界的网关,同样跑在PL1.
- SVC,当处理器进入reset(若默认启动状态为AArch32,则处理器启动后的默认异常等级为SVC),或者执行SVC指令时进入。
总结如下表,
-
用户模式(USR):ARM处理器正常的程序执行状态。
-
快速中断模式(FIQ):用于高速数据传输或通道处理。
-
外部中断模式(IRQ):用于通用的中断处理。
-
管理模式(SVC):操作系统使用的保护模式。
-
中止模式(ABT):当数据或指令预取终止时进入该模式,用于虚拟存储及存储保护。
-
未定义指令模式(UND):当未定义的指令执行时进入该模式,用于支持硬件协处理器的软件仿真。
-
系统模式(SYS):运行具有特权的操作系统任务。
-
Monitor(MON):执行SMC(Secure Monitor Call)指令,或者当处理器出现为安全处理而配置的异常时。
-
Hyp(HYP):当处理器出现为安全处理而配置的异常时。
从中也可以发现,只有HYP 模式处于PL2 异常等级(Non-secure only),只有USR模式处于PL0等级,其余模式都处于PL1:
在AArch64状态下,处理器的模式用异常等级表示,如下图所示,显示了AArch32的异常模式与AArch64的对应关系。
异常等级之间的切换,需要遵守一下规则:
-
移动到更高的异常等级,例如从EL0到EL1,表明增加了软件的执行权限
-
异常不能切换到更低的等级
-
EL0没有异常处理,异常只有在更高的异常等级(大于EL0)中才会被处理
-
异常会改变程序的正常执行流程,异常处理器(Exception handler)在大于EL0的异常等级下开始执行,从一个先前被定义好的,与该异常相关的异常向量开始,异常包括:
-
中断,比如 IRQ 和FIQ.
-
内存系统中止
-
未定义的指令。
-
系统调用。一些异常调用的指令允许不具有特权的软件,通过系统调用指令,进入操作系统权限。
-
Secure Monitor或者hypervisor 陷阱。
-
-
可以操作ERET指令来终止异常处理并且返回上一个异常等级
-
从异常返回可以保持相同的异常级别,或者变成较低的异常级别。但不能转移到更高的异常级别。
-
除非从EL3返回到非安全状态,否则安全状态不会随着Exception级别的更改而更改
4,执行状态切换(AArch64 <=> AArch32)
用户有时候需要改变系统的执行状态,比如在一个64-bit的系统下,想跑一个在EL0下32-bit的应用程序。为了实现这种需求,系统需要切换到AArch32状态。当32-bit应用 程序执行完毕,或者执行返回到OS时,系统可以切换回AArch64。下图说明了AArch64的操作系统可以跑AArch32和AArch64的应用程序,反之不行。同样,AArch64的hypervisor支持AArch64和AArch32操作系统的切换,反之也不行。
要在同一Exception级别的执行状态之间进行更改,必须切换到更高级别异常级别,然后返回到原始异常级别。例如,用可能在64位操作系统下运行32位和64位应用程序。在这种情况下,32位应用程序可以执行并生成一个Supervisor Call (SVC)指令,或者接收一个中断,从而切换到EL1和AArch64。然后,操作系统可以在AArch64中执行任务切换并返回EL0。实际上,这意味着用户不能拥有32位和64位的混合应用程序,因为在它们之间没有直接调用的方法。
用户通过更改Exception级别来进行执行状态的切换。引发异常可能从AArch32更改为AArch64,从异常返回可能从AArch64更改为AArch32。
另一种执行状态切换的方式是 reset ,通过配置RMR寄存器,来配置reset后,处理器的执行状态,并产生一个warm reset。
以下是一些AArch32 和 AArch64状态之间切换的总结:
- AArch64和AArch32的执行状态都有异常级别,它们通常是相似的,但是在安全操作和非安全操作之间存在一些差异。生成异常时处理器所处的执行状态可以限制其他执行状态可用的exception级别。
- 从AArch 64 切换到 AArch32, 需要从 高 (higher) 异常等级 切换到 低 (lower)的异常等级。当 执行完 ERET 指令后,异常处理器 退出,状态将切换完成。
- 从 AArch32 切换到 AArch64,则需要从 低 (lower)异常等级 切换到 高 (higher)异常等级。这个异常可以是某些指令的执行结果,或者是一个外部信号。
- 如果,从一个异常切换到另一个异常,但是异常等级没有变,是相同的,这样是无法改变 执行状态的。
- 对于ARMv8处理器,在AArch32执行在某个异常级别,使用与ARMv7中相同的异常模型来处理进入该异常级别的异常。
因此,这两种执行状态之间的交互是在安全监视器(Secure monitor,EL3)、管理员程序(hypervisor,EL2)或操作系统级别(EL1)执行的。在AArch64状态下执行的hypervisor或操作系统可以在较低的权限级别上支持AArch32操作。这意味着一个操作系统正在运行AArch64可以同时承载AArch32和AArch64应用程序。类似地,AArch64 hypervisor可以同时托管AArch32和AArch64客户机操作系统。但是,32位操作系统不能承载64位应用程序,32位hypervisor不能承载64位客户机操作系统。
对于实现的最高异常级别(Cortex-A53和Cortex-A57处理器上的EL3),在获取异常时,每个异常级别使用的执行状态是固定的。异常级别只能通过重置处理器来改变。