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内存

相关推荐
Claus-31 分钟前
进程间通信—system v标准
linux·运维·jvm
土豆198910211 小时前
简记_单片机硬件最小系统设计
单片机·嵌入式硬件
musk12121 小时前
ubuntu 安装 g++
linux·运维·ubuntu
@小张要努力1 小时前
第十三届蓝桥杯国赛电子类单片机学习记录(客观题)
单片机·嵌入式硬件·mcu·学习·蓝桥杯·51单片机·proteus
徐小黑ACG1 小时前
Ubuntu下载docker、xshell
linux·ubuntu·docker
vortex52 小时前
如何为 Debian 和 Kali 系统更换软件源并更新系统
linux·运维·网络·网络安全·渗透测试·debian·kali
大明者省2 小时前
Xshell远程登录腾讯云高性能应用服务
linux·服务器·腾讯云
程序猿本员2 小时前
1.深入浅出gcc/g++编译链接过程
linux·c++
阿瑾06183 小时前
【网络】Socket套接字
linux·网络·c++·网络协议
带电的小王3 小时前
VSCode:Linux下安装使用
linux·ide·vscode