背景
ARMv8和ARMv9架构是ARM公司推出的先进处理器架构,被广泛应用于移动设备、服务器和嵌入式系统。这两个架构的设计旨在提供更高的性能、更好的能效以及更强大的安全性。其中,不同特权程序之间的跳转模型是这一架构中关键的组成部分,对于系统的整体安全性和可靠性具有深远的影响。
在计算机系统中,特权等级是用于区分不同执行上下文权限的机制。ARMv8和ARMv9引入了四个特权等级(EL0、EL1、EL2和EL3),使得系统能够在用户态、内核态、hypervisor态和secure monitor态之间进行切换。这为实现多任务处理、虚拟化和安全关键任务提供了灵活性。
此外,安全状态的引入进一步增加了系统的复杂性。安全状态可用于支持加密、认证和其他安全功能,从而保障系统的安全性。不同特权程序需要在特权等级和安全状态之间进行切换,形成了复杂而严密的跳转模型。
在系统启动时,镜像加载和初始化也是跳转模型的一部分。引导加载程序负责在系统启动时进行初始化,加载操作系统内核,并确保系统能够平稳过渡到运行时状态。这个过程涉及到不同特权程序之间的协同工作,以确保系统能够正确启动和运行。
本文观 【周贺贺,baron,代码改变世界ctw,Arm精选, armv8/armv9,trustzone/tee,secureboot,资深安全架构专家,11年手机安全/SOC底层安全开发经验。擅长trustzone/tee安全产品的设计和开发。】文章有感而发。
引用:
思考:
1、我们知道arm有2个执行状态:aarch32/aarch64,他们之间是如何跳转,如何切换的/
2、我们知道arm有4个安全状态:secure security/non-secure security/ Root/ Realm,他们之间是如何跳转,如何切换的?
3、我们知道arm有4个特权级别:secure security/non-secure security,他们之间是如何跳转,如何切换的?
4、在开机启动是,有着不同的阶段,如bootrom、bootloader、kernel,他们都是64位的? 他们之间都是怎样跳转和切换的?
5、uboot怎样切换到Linux Kernel的?
说明:
1、以下知识点,看似简单和清晰,实则零散在整个10000多页的ARM TRM之中,另外也有许多理论知识在实践中不常见。所以也许会有描述不准确的地方(但但致都是准确的),精确的学习还是请以ARM TRM官方文档为准。
2、本文注重讲解基础原理。实战经验中,真的没办法去说,因为很多SOC厂家会视为他们的启动流程为机密吧,受到NDA保护。
1、前言
ARM架构作为一种广泛应用于移动设备、服务器和嵌入式系统的处理器架构,其特权级别的设计影响着系统的安全性和可靠性。ARMv8和ARMv9架构引入了更多的特权等级和安全状态,为系统提供了更多的灵活性和安全性。本文将探讨在ARMv8/ARMv9架构中,不同特权程序之间的跳转模型。
注意本文标题所说的“程序之间的跳转模型”,主要讲解如下这么样子的大系统大程序之中:
- 启动时镜像之间是如何跳转的
- runtime是镜像之间是如何跳转的
阅读本文需要一点点基础,请自行补习:
- 4个特权等级、4个安全状态、2个执行状态
- 启动模型中的BL1 BL2 BL31 BL32 BL33的概念
小结:
在总体概述中,我们了解到ARM架构在移动设备、服务器和嵌入式系统中的广泛应用,并明白了特权级别设计对系统安全性和可靠性的关键影响。ARMv8和ARMv9架构引入了更多特权等级和安全状态,为系统提供了更大的灵活性和安全性。进一步,我们将深入研究ARMv8/ARMv9架构中不同特权程序之间的跳转模型,聚焦于系统启动时镜像之间和运行时程序之间的跳转机制。
在系统启动阶段,我们将探讨如何实现从引导加载程序到操作系统内核的跳转模型。具体而言,我们将研究BL1、BL2、BL31、BL32和BL33等启动模型中的概念,深入解析它们之间的协同工作,以确保系统在启动时能够顺利切换不同特权程序。
在运行时,我们将关注镜像之间的跳转模型,特别是在应用程序、操作系统内核和hypervisor之间的交互。我们将探究在用户态、内核态和hypervisor态之间的切换,了解系统在运行时如何处理系统调用、虚拟化需求以及其他特权操作。
通过对这两个关键方面的深入研究,我们将能够更好地理解ARMv8/ARMv9架构中不同特权程序之间跳转模型的复杂性和灵活性。这些理解将为系统开发者提供有力的指导,以构建性能卓越、安全可靠的计算机系统。
2、4个特权等级/4个安全状态之间的跳转模型
ARMv8/ARMv9架构定义了四个特权等级,分别是EL0(用户态)、EL1(内核态)、EL2(hypervisor态)和EL3(secure monitor态)。这四个等级之间的跳转模型主要通过异常处理机制实现。当从低特权等级跳转到高特权等级时,触发异常,处理器进入相应的异常处理例程。反之,当从高特权等级返回到低特权等级时,通过异常返回指令实现。
安全状态主要包括安全状态和非安全状态,其中安全状态可用于支持更加安全的系统操作,如加密、认证等。特权等级和安全状态之间的组合形成了复杂的跳转模型,通过对不同组合的处理,实现了系统在不同安全场景下的灵活运行。
先弄懂最最最基础的本质原理,10000多页的ARM TRM文档散装了很多场景, 我们总结之后再总结,最后浓缩成了下面这一张框图,通常我们也只要理解下面这张图就可以了:
其中:
- EL0的所有异常(同步异常和异步异常)都可以将core切到EL1中
- EL1的所有异步异常、hvc/smc指令 都可以将core切到EL2中
- EL2的所有异步异常、smc指令 都可以将core切到EL3中
- 所有的返回指令,都是ERET
其实呢,下面这种情况也是可以出现的,(只不过呢查略大多数代码,我都没有找到这样使用的例子)
另外呢svc也是可以被trapped到EL2的,EL3调用ERET返回EL1时,也是可以被EL2 trapped的,即下面这种情况也是可以出现的, (只不过呢查略大多数代码,我也没有找到这样使用的例子)
小结:
在ARMv8/ARMv9架构中,特权等级的划分以及异常处理机制构成了系统中不同特权程序之间的关键跳转模型。这模型通过四个特权等级(EL0、EL1、EL2、EL3)和异常处理机制来管理,确保系统在各种操作和安全场景下能够灵活运行。
基本原理包括:
-
特权等级划分: 四个特权等级分别对应用户态(EL0)、内核态(EL1)、hypervisor态(EL2)和secure monitor态(EL3)。EL0为最低特权,EL3为最高特权。这种划分允许系统在不同的执行上下文中进行切换。
-
异常处理机制: 当从低特权等级跳转到高特权等级时,触发异常,处理器跳转到相应的异常处理例程。反之,当从高特权等级返回到低特权等级时,使用异常返回指令实现。这一机制通过异常向量表的方式实现,确保在不同的异常情况下执行相应的处理代码。
-
安全状态: 安全状态包括安全状态和非安全状态,用于支持更安全的系统操作,如加密和认证。特权等级和安全状态的组合形成了复杂的跳转模型,系统通过处理不同组合的跳转,实现在不同安全场景下的运行。
此外,上述基本原理的框图清晰地展示了在不同特权等级之间的跳转关系。理解这一模型为系统开发者提供了基础,使其能够更好地管理和配置系统,构建出性能卓越、安全可靠的计算机系统。虽然在实际应用中可能存在一些较为罕见的跳转情况,但上述框图提供了对于基本特权等级划分和异常处理机制的清晰理解。
3、启动时镜像之间的跳转模型
在系统启动阶段,不同特权程序之间的跳转模型涉及到引导加载程序(Boot Loader)、操作系统内核以及其他启动时镜像。引导加载程序通常运行在较低的特权等级(如EL2或EL3),负责初始化系统环境并加载操作系统。当引导加载程序准备就绪后,通过异常跳转到操作系统内核的入口点(通常是EL1),切换到内核态,开始执行操作系统的初始化和运行。
由于这些底层的东西,都会和具体的SOC厂家的设计强相关,所以我们也就只好介绍***mon的场景。
很多人都学习过Secure Boot或是即将学习Secure boot,他们的重点也许都放在了如何签名验签的地方。
那么你知道BL1到BL2是怎样跳转? uboot到kernel是怎样跳转的吗?
以下是参在TF-A代码做出的总结,当然了也是比较理想的场景:
可是在你的实际使用中:
- BL32可能不是S-EL1,也是有可能是S-EL2的
- BL33可能不是EL1,也是有可能是EL2的
- BL1 BL2 BL33 BL32 BL33 每一级镜像,也许不是aarch64的,也许是aarch32的
如上的场景中,看似也就那么回事吧,无非就是不同特权等级之间,调用同步异常指令或返回指令,切来切去而已。那么如果是相同的特权等级,那么如何切换呢?
如uboot(EL1)到kernel(EL1), 至少有以下三种方式(其实我还能列出第4种第5种,这里留给大家思考):
如下再展示了一个稍微复杂的场景,aarch64和aarch32掺杂地使用,也许你的SOC就是这样设计的哦:
小结:
在系统启动阶段,不同特权程序之间的跳转模型涉及到引导加载程序(Boot Loader)、操作系统内核以及其他启动时镜像。引导加载程序通常运行在较低的特权等级(如EL2或EL3),其任务是初始化系统环境并加载操作系统。一旦引导加载程序准备就绪,通过异常跳转到操作系统内核的入口点(通常是EL1),切换到内核态,开始执行操作系统的初始化和运行。
在实际应用中,不同特权程序之间的跳转模型可能会更为复杂,具体取决于硬件平台和SOC厂家的设计。在Secure Boot等安全性方面的学习中,很多关注点可能放在签名验签等方面,而对于底层的特权程序之间的跳转可能略显抽象。
在常见的场景中,特权程序的跳转可以理想地用一个简单的框图表示,如TF-A代码所总结的情况。然而,在实际使用中,需要考虑更多的变数,例如BL32可能不仅仅是S-EL1,还有可能是S-EL2;BL33可能不仅仅是EL1,还有可能是EL2。此外,每个镜像的特权等级和执行状态也可能不是固定的,可能是aarch32或aarch64。
在相同特权等级的情况下,例如uboot(EL1)到kernel(EL1)的跳转,存在多种方式,包括直接跳转、通过异常切换、通过硬件相关的机制实现等。这种灵活性使得开发者能够根据需求选择最合适的方式。
特权程序之间的跳转模型是系统启动阶段至关重要的一部分。在学习和实际应用中,了解各种可能的场景和跳转方式,对理解底层机制和解决实际问题都具有重要意义。
4、runtime程序之间的跳转模型
在运行时,不同特权程序之间的跳转模型涉及到应用程序、操作系统内核和可能存在的hypervisor。当用户态应用程序需要进行系统调用时,会触发从EL0到EL1的特权级别切换,将控制权交给操作系统内核执行相应的系统服务。hypervisor则在需要切换虚拟机或执行特权操作时介入,通过从EL1到EL2的特权级别切换进行处理。
在runtime模型中,你的cpu可能会同时在aarch32和aarch64之间运行,aarch32和aarch64之间的切换,其实也很好理解,模型如下所示,就是进入高特权等级,切换一下cpu context而已。
燃鹅,以上依然是最理想的场景吧。在实际使用中,也许你会有各种各样的需求,例如:我不想跳转特权等级,但还想切换执行状态。
比如你的SOC实现定义了EL3,你的EL3既aarch32的程序,也有aarch64的程序,那么两个程序是如何切换的呢?
这个时候,利用同步异常/异步异常的知识点已经无法满足需求了,可能就得利用架构中的warm reset技术了。
例如,你可以在aarch32的程序中去写RMR_EL3的相关比特,触发warm reset, cpu复位进入提前设置好的RVBAR_EL3的地址出,进入aarch64程序。 其实还真有很多厂家,使用这种方式完成的镜像之间的跳转。
小结:
在运行时,不同特权程序之间的跳转模型涉及到了应用程序、操作系统内核以及可能存在的hypervisor。这模型的核心是在处理系统调用、虚拟机切换或执行其他特权操作时进行特权级别的切换。
当用户态应用程序需要进行系统调用时,会触发从EL0到EL1的特权级别切换,将控制权交给操作系统内核执行相应的系统服务。这种切换是通过异常处理机制实现的,确保在处理系统调用时,操作系统能够获得足够的特权执行相应的服务。
另一方面,如果存在hypervisor,它在需要切换虚拟机或执行其他特权操作时会介入。这时,从EL1到EL2的特权级别切换被触发,将控制权交给hypervisor进行处理。这种切换使得hypervisor能够管理虚拟化环境,执行特权操作,然后再切回到EL1或EL0。
在runtime模型中,ARM架构可能会同时在aarch32和aarch64之间运行。这涉及到aarch32和aarch64之间的切换,一般通过进入高特权等级,切换CPU context来实现。然而,实际应用中可能存在各种需求,例如,不想跳转特权等级,但仍然想切换执行状态。这时,可能需要利用架构中的warm reset技术,通过触发warm reset并设置相应的寄存器来实现aarch32和aarch64之间的切换,从而完成镜像之间的跳转。
不同特权程序之间的跳转模型在ARMv8/ARMv9架构中通过异常处理机制和特权级别的切换实现,为系统提供了灵活性和可扩展性。在实际应用中,开发者可以根据需求选择合适的切换方式,确保系统能够在各种场景下高效运行。
推荐
ARMv8/ARMv9架构从入门到精通 --博客专栏
《Armv8/Armv9架构从入门到精通 第二期》 --大课程
8天入门ARM架构 --入门课程