SOC- armv8 启动流程和安全启动

一、启动的软件架构,即bootloader 有哪几部分

(1)芯片的bootrom 固件,每个芯片厂家不一样;

(2)ATF 固件,即 arm-trusted-firmware; 有一个开源的ATF:TF-A/trusted-firmware-a.git - TrustedFirmware Git 浏览器

(3)uboot;

(4) kernel;(不算bootloader 的范畴)

二、启动流程

Armv8的启动流程包含多个阶段,典型地有BL1、BL2、BL31、BL32、BL33,根据需求的不同,这些阶段可以适当地裁剪或添加。为了方便描述,后面我们的讨论将基于以上这些官方定义的标准阶段,它们的源码会被编译成独立的启动镜像,并被保存到特定的存储介质中。由于一般的存储介质(如spi flash、nand flash、emmc、ssd等)都不支持代码的直接执行,因此需要在启动时先将镜像加载到可直接执行代码的存储介质,如SRAM或DDR中,然后运行相关代码。其典型的加载流程如下:

  1. BL1是启动的第一阶段,该镜像必须要存储在可直接执行的介质中。若芯片支持XIP启动方式,其可被存储在片外可直接执行的介质中(如norflash)。若不支持XIP,则需要存储在芯片的片内ROM中,此时在芯片出厂后该部分代码就将被固化,后续再也不能被修改和升级。若芯片要支持安全启动,则需要将bootrom作为启动时的信任根,此时除调试阶段外,SOC必须禁用XIP。关于安全启动我们在第三部分介绍;
  2. BL2镜像由BL1加载,此时DDR还没有被初始化,因此它需要被加载到片内的SRAM中执行,一般在这个阶段会完成DDR的初始化,因此后面的镜像都可以被加载到DDR中。从上图可知,BL31、BL32和BL33都是由BL2加载的,其中BL31和BL32是可选的,若系统不支持TRUST OS,则可去掉BL32,若不支持EL3异常等级及secure monitor,则可去掉BL31
  3. BL33一般指uboot,一般通过它最终启动操作系统内核

Armv8架构典型的启动流程如下:

以上流程中我们假定系统支持的最高异常等级为EL3,且支持secure monitor和TRUST OS,同时BL2运行在secure EL1,BL33运行在non secure EL1或non secure EL2状态

(1)由于armv8架构规定,arm核复位后默认会进入当前系统支持的最高异常等级,因此BL1运行在EL3,它执行完成后会通过异常返回ERET的方式跳转到BL2

(2 - 3)BL2执行完成后需要跳转到BL31,由于BL31运行在EL3异常等级,而BL2根据需求不同可能运行于secure EL1或EL3。当BL2运行于EL3时可直接通过ERET方式跳转到BL31中,但若其运行在secure EL1时,则只能通过smc异常触发进入EL3异常等级。

显然,此时BL31由于尚未设置其自身的smc异常处理程序而无法直接处理该异常,因此,为了完成跳转流程,BL1需要先代理该异常的处理。因此BL1在退出之前先设置smc异常处理函数,BL2触发smc启动BL31时,BL1捕获该异常并根据BL2传入的参数设置BL31的入口地址和系统初始状态,并通过ERET跳转到BL31的入口地址处执行

(4)BL32阶段会运行TRUST OS,它运行于secure EL1异常等级,BL31可根据其镜像加载信息设置入口地址以及其它状态,并完成跳转

(5 - 6)BL32加载完成后将通过SMC返回到BL31,然后由BL31跳转到non secure EL1或non secure EL2以执行BL33

上面这部分总结就是:如何通过异常处理,来启动整个 bl1,bl2, bl31,bl32,bl33;

三、TF-A 安全启动

在Armv8架构里,ARM为安全引入了Trust Firmware作为整体解决方案,开源库地址:TF-A/trusted-firmware-a.git - TrustedFirmware Git 浏览器

根据官网介绍,TF为Armv8-A和Armv8-M提供了安全软件的参考实现,为SoC开发人员和oem提供了符合相关Arm规范的参考可信代码库。,各家厂商基于这个进行DIY。

其中,

TF-A (Trusted Firmware-A,也叫ATF)是专门为Armv7\v8-A架构内核设计的参考安全固件;

TF-M则是为Armv8-M、Armv8.1-M架构(如Cortex-M33、M55等)提供了安全处理环境(SPE,Secure Processing Environment)的参考实现。

TF-A(AArch64)的启动引导过程一共分为5个单独启动阶段,每个阶段运行在不同的内核异常等级,流程如下:

每个阶段功能定义如下:

  • BL1(Boot Loader stage 1):BL1一般指运行存放在芯片内部BootROM的代码,这部分代码由SoC厂商在芯片流程时固化进去,不能再做修改;该阶段运行在Armv8的EL3等级,如果支持安全启动,BootROM在构建信任链的时候就显得尤为关键,主要用于校验BL2 Boot Firmware并完成加载和跳转,这也是和目前接触过的车规MCU安全启动流程最明显的区别;
  • BL2(Boot Loader stage 2:):Boot Firmware由BL1从引导介质中(例如NOR Flash、SD/eMMC)加载运行(例如DDR),它的主要作用是初始化平台所需要存储介质、配置MMU、校验BL31\32\33并完成加载等,值得注意,BL2依旧运行在EL3等级。
  • BL31(Boot Loader Stage 3-1):BL2加载BL31后,并把控制权交由BL31(此时仍旧运行在EL3等级),从上图可以看到BL31仍旧需要运行在可信RAM中,它主要为引导加载程序和操作系统提供初始化服务,例如GIC初始化、电源控制设备初始化、MMU使能和重定向等等;完成上述初始化后,如有BL32 trusted OS镜像,BL31加载BL32并跳转运行;
  • BL32:可信的操作系统,例如OP-TEE(Open source Project Trusted Execution Environment )、安卓Trusty TEE
  • BL33:常见的Bootloader(U-Boot/UEFI),运行在Armv8 EL2等级,完成启动后运行Kernel

在开源库中每个阶段都可以单独进行编译,因此很明显启动流程可以根据需求进行裁剪,

但值得一提的是,上述启动流程有个前提假设:那就是这些镜像文件存储的物理介质一般都不支持xip,所以需要在启动时将上述镜像加载到SRAM或者DDR上运行;这是与带有eFlash的MCU的安全启动流程的另一个明显区别。

其实比较复杂一点的地方就是 BL31 的 secure monitor 和 BL32 的OP-TEE 可信操作系统;这是因为这个两个系统,不会把占用的内存进行回收,是一直占用内存,也是专业一点的名字就是runtime service ,提供运行时的服务。当有异常产生时,会调用里面的函数进行执行。这里不展开具体的代码展示。

提供OP-TEE的搭建说明:

里面有ARM V7ARM V8两个架构的搭建说明,官方部分ARM V8的相关指令如下:

复制代码
$ mkdir optee
$ cd optee
$ repo init -u https://github.com/OP-TEE/manifest.git -m qemu_v8.xml
$ repo sync
$ cd build
$ make toolchains
$ make run

由于国内访问有限制,需要在上面的基础上做一些简单的改动,修改repo默认的镜像源地址,如下即可:

复制代码
Ubuntu 22.04/20.04


$ mkdir optee

$ cd optee
$ curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo -o ~/bin/repo
$ chmod a+x ~/bin/repo

$ export PATH=~/bin:$PATH
$ vim ~/.bashrc

//将以下内容添加到.bashrc的末尾
export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo'

//重新启动终端,继续以下命令
$ repo init -u https://github.com/OP-TEE/manifest.git -m qemu_v8.xml

$ repo sync

$ cd build

$ make toolchains

$ sudo make plat=qemu -j3 run

编译时间会比较长,另外如果是虚拟机的话,建议一开始存储内存就给的稍微多一些

执行完最后的命令后会出现三个终端(Normal World、Secure World、命令行shell终端)

在qemu后面输入c,启动两个系统的运行

其中Normal终端中的打印的为BL1 - BL3启动阶段,非安全部分的LOG,以及从BL3跳转到UBOOT并从UBOOT引导Linux的所有输出

Secure World为OP-TEE OS的输出LOG。

四、镜像跳转方式

前面我们聊到镜像跳转时可能需要使用到ERET或SMC指令,下面我们再看下跳转时的细节

4.1 Smc异常处理流程

smc是armv8支持的异常跳转指令,它用于程序从EL1或EL2跳转到EL3异常等级。其跳转流程如下:

以atf的BL1 smc处理流程为例,EL1调用者通过smc指令陷入到EL3异常,此后CPU将跳转到EL3异常向量表的vector_entry SynchronousExceptionA64入口处,该函数解析esr_el3寄存器的异常原因,若其为smc异常,就跳转到smc处理函数smc_handler64中。smc_handler64解析通过x0 -- x7寄存器传入的参数获取smc命令类型,执行特定的命令处理函数,并通过寄存器x0 -- x4返回处理结果。对于异常向量表跳转入口选择原则可参考以下博文:
lgjjeff:armv8中断路由机制

4.2 ERET跳转流程

ERET指令用于从异常处理流程中返回,在介绍异常返回流程之前,我们先看一下armv8异常跳转的流程。Armv8触发异常或中断后硬件将会执行以下操作:

(1)将PSTATE寄存器的内容保存到SPSR_ELx中,其中x表示异常进入的异常等级,如smc异常将会陷入EL3,因此相应的寄存器就为SPSR_EL3

(2)将异常处理完成后需要返回的地址保存在ELR_ELx中

(3)设置中断和异常掩码DAIF,以关闭所有中断和异常

(4)若异常是同步异常或SError中断,异常状态信息将被保存在ESR_ELx中,该信息可用于分析异常发生的原因

(5)若异常为指令异常、数据异常或对齐错误等,则触发异常对应的内存地址将被保存到FAR_ELx寄存器中

(6)栈指针切换为目标异常等级的栈指针寄存器SP_ELx

(7)程序跳转到对应的异常处理入口,执行异常处理程序

在异常执行完成后,可通过ERET指令返回被异常中断程序的断点处继续执行,该指令将使硬件执行以下操作:

(1)用SPSR_ELx寄存器的内容恢复PSTATE寄存器

(2)用ELR_ELx寄存器的内容恢复PC值

从以上流程可以看到,执行ERET指令后程序的执行流将由SPSR_ELx和ELR_ELx决定。因此,我们在执行镜像之间的跳转,只要在ERET之前将ELR_ELx设置为待跳转镜像的入口地址,并设置正确的SPSR_ELx即可完成

五、内存规划

5.1 内存规划原则

嵌入式系统的内存一般包含ROM、SRAM和DDR,其中ROM和SRAM位于SOC片内,DDR位于芯片外部。它们的特点如下:

(1)ROM中的内容断电后不会消失,不仅可用于代码执行,还可以用于镜像存储,但其只有只读权限

(2)SRAM和DDR中的内容在断电后都会消失,因此只能被用于代码的动态执行,而不能用于镜像存储

(3)ROM和SRAM都是直接连接总线上,系统上电后即可直接执行。而DDR需要通过DDR phy和DDR controller连接到总线上,因此使用之前必须要先对其执行初始化操作

根据上述各种内存的特点和前面镜像加载启动流程的需求,在内存规划中我们需要考虑以下几个问题:

(1)由于BL1需要固化到ROM中,且是系统最先执行的,因此ROM地址需要被映射到cpu的重启地址处

(2)由于ROM是只读的,BL1镜像除了代码段和只读数据段之外还包含可读写数据段,这部分数据在BL1启动时需要从ROM重定位到SRAM中

(3)由于BL1被固化在ROM中,芯片出产后就不能更改,因此DDR初始化代码不能集成到BL1中。故BL2需要被加载到SRAM中执行,且在BL2中执行DDR初始化流程

(4)BL2之后的其它镜像既可以运行于SRAM中,也可以运行于DDR中

(5)从前面的镜像启动流程可知,若BL2运行于secure EL1下,当其执行完成后,需要通过smc再次陷入BL1去执行BL31流程,因此BL2和BL1的地址不能有重叠

(6)BL31除了执行启动流程外,在系统运行过程中还会以secure monitor的方式驻留,为normal空间的smc异常提供服务历程,以及为normal os和trust os之间提供消息转发、中断路由转发等功能。因此,BL31镜像需要永久驻留内存,在系统启动完成后不能被回收

(7)与BL31类似,BL32在启动后需要驻留内存为系统提供安全相关服务,因此为其所分配的内存也不能被回收(8)除此之外,BL1、BL2和BL33(一般为uboot)的内存在系统启动完成后都可以被释放给操作系统使用。

5.2 qemu virt平台内存规划示例

根据以上内存规划原则,qemu virt machine各启动阶段的内存规划如下:

|------|------------|-------------|------|------------|--------------|
| 类型 | 起始地址 | 结束地址 | 长度 | 是否secure内存 | 作用 |
| ROM | 0x00000000 | 0x00020000 | 128k | Yes | BL1(bootrom) |
| SRAM | 0x0e04e000 | 0x0e060000 | 72k | Yes | Bl1(rw data) |
| SRAM | 0x0e000000 | 0x0e001000 | 4k | Yes | Shared ram |
| SRAM | 0x0e01b000 | 0x0e040000 | 148k | Yes | BL2 |
| SRAM | 0x0e040000 | 0x0e060000 | 128k | Yes | BL31 |
| SRAM | 0x0e001000 | 0x0e040000 | 252k | YES | BL32 |
| DDR | 0x60000000 | 0x100000000 | 2.5G | NO | BL33 |

从上面的BL31和BL32的内存规划,是占用的SRAM空间,不是占用DDR空间,也就是OP-TEE系统(BL32)和sercure monitor (BL31)是占用SRAM内存,不是DDR内存

相关推荐
IC 见路不走26 分钟前
LeetCode 第91题:解码方法
linux·运维·服务器
翻滚吧键盘38 分钟前
查看linux中steam游戏的兼容性
linux·运维·游戏
小能喵43 分钟前
Kali Linux Wifi 伪造热点
linux·安全·kali·kali linux
汀沿河1 小时前
8.1 prefix Tunning与Prompt Tunning模型微调方法
linux·运维·服务器·人工智能
zly35001 小时前
centos7 ping127.0.0.1不通
linux·运维·服务器
小哥山水之间2 小时前
基于dropbear实现嵌入式系统ssh服务端与客户端完整交互
linux
ldj20202 小时前
2025 Centos 安装PostgreSQL
linux·postgresql·centos
翻滚吧键盘2 小时前
opensuse tumbleweed上安装显卡驱动
linux
宇钶宇夕2 小时前
针对工业触摸屏维修的系统指南和资源获取途径
单片机·嵌入式硬件·自动化
和风化雨3 小时前
stm32的三种开发方式
stm32·单片机·嵌入式硬件