在传统的Linux启动流程中,系统上电后的执行顺序如下。
BootROM => U-Boot => Linux Kernel => System Rootfs
各部分说明如下。
典型的按照这个流程启动的芯片,整理表格如下。
Boot stage number | Terminology #1 | Actual program name | Image Name |
---|---|---|---|
1 | Primary Program Loader | ROM code | BootRom |
2 | - | U-Boot | U-Boot.bin |
3 | - | Kernel | zImage/*.dtb |
4 | - | rootfs | rootfs |
进一步详细的说明如下所示。
注: Linux内核中定义的起始进程为”/sbin/init,/etc/init,/bin/init,/bin/sh”中任选一个,需要在文件系统中包含,否则系统会加载失败。
早期的芯片,例如I.MX6ULL就是按照这个流程设计。对于嵌入式Linux的SOC来说,虽然支持EMMC,SDCard,Nand FLASH等多种存储介质存储代码,但这些空间不能直接执行命令,需要将数据加载到内存中才能执行。这里的内存主要指内部的SRAM和外部的DRAM,内部SRAM容量很小,一般不超过256KB,只能运行少量的代码(特殊情况),外部DRAM则一般容量较大,例如I.MX6ull最大可以支持3GB。
如果启动BootROM直接加载U-Boot,那么容量远远超过SRAM的大小,只能将U-Boot加载到DRAM中执行,这就需要在ROM中集成外部DRAM驱动的实现。理论上这也能满足需求,毕竟直接加载U-Boot的方式,在中低端SOC仍然有大量的市场。不过对于性能更强的芯片,适用DRAM的型号五花八门,特别是部分即使ROM也只能做到部分兼容,这就限制了芯片的使用场景。
那么有解决办法吗?当然有,前面提到内部SRAM也可以执行代码,不过容量很小只能运行少量的代码,那么裁剪U-Boot代码,只实现外部DRAM初始化和搬运数据的功能,容量就可以做到很小,能够在内部SRAM控制执行,这就是我们提到了U-Boot SPL启动方式,全志的T113_i就是这类芯片。通过将U-Boot SPL固件加载到内部SRAM中,在SPL固件中执行DRAM的初始化,以及U-Boot从存储到DRAM的搬运工作,然后跳转U-Boot执行后续动作,启动流程就扩展如下所示。
BootRom => U-Boot SPL => U-Boot => Linux Kernel => System Rootfs
按照这个框架启动流程如下。
Boot stage number | Terminology #1 | Actual program name | Image Name |
---|---|---|---|
1 | Primary Program Loader | ROM code | BootRom |
2 | - | U-Boot SPL | U-Boot-spl.bin |
3 | - | U-Boot | U-Boot.bin |
4 | - | Kernel | zImage/*.dtb |
5 | - | rootfs | rootfs |
整个流程和上面类似,只不过在BootROM和U-Boot执行中间多了个步骤,整理起来如下所示。
U-Boot SPL可以将BootROM实现的DRAM驱动转换为由固件U-Boot SPL实现,这样就可以随时修改适配DRAM驱动,增加了灵活性和兼容性,例如全志的T113_i芯片就是这样的启动设计方式。官方SDK中也提供SPL的部分源码,大部分实现以静态库的方式链接实现(可在brandy/brandy2.0/spl-pub)中查看。这当然也额外增加了U-Boot SPL的开发,相应提高了开发难度,不过这部分一般由芯片厂商实现,用户可以很少或者不需要关注。可以看到,U-Boot SPL是对旧有启动流程的优化,只是在U-Boot之前单独实现DRAM等必要驱动的固件,这样就不需要固化在芯片ROM中,厂商可通过升级版本随时更新迭代,这就降低了产品的风险。
U-Boot SPL的主要功能包括如下。
U-Boot SPL是优化启动流程的一种方式,可以降低产品ROM代码异常的风险,因此目前应用也越来越广泛。另外U-Boot SPL也是实现安全加密应用的必要一环,通过内部SRAM执行U-Boot SPL进行后续文件的加载和鉴权,可以避免外部监听和大部分干扰操作。不过参考了各大厂家的SDK,即使使用了U-Boot SPL方案,大部分还是以库或二进制文件的方式提供,如瑞芯微的RK35xx系列就是提供的二进制文件,全志的t113x系列则提供的是库配合部分代码,不提供直接的源码,可能这部分属于厂商独立的开发,涉及到底层的实现,未选择开源。当然,这里U-Boot SPL和Trust Zone并没有直接关联,不过理解U-Boot SPL有助于去理解TrustZone执行流程,下面详细进行说明。
在智能手机,智能家居飞速发展的当下,指纹,面部识别,虹膜识别成为现代电子产品功能的一部分。如何存储管理这些个人身份数据信息,保证安全就成了迫切需求。为了再复杂形式下确保设备的安全性,ARM在ARMv7-A架构后提供了TrustZone硬件解决方案。TrustZone在概念上将SoC的硬件和软件资源划分为安全(Secure World)和非安全(Normal World)两个世界,所有需要保密的操作在安全世界执行(如指纹识别、密码处理、数据加解密、安全认证等),其余操作在非安全世界执行(如用户操作系统、各种应用程序等),安全世界和非安全世界通过一个名为Monitor Mode的模式进行转换,通过隔离的方式来确保应用在非授权的情况下不能访问到系统级的保密信息。
那么什么是TF-A呢,TF-A总称Trust Firmware-A,是支持启动TrustZone功能的固件。它规定了启动TrustZone的工作流程,提供启动对应的固件,从而保证硬件安全功能。ARM TrustZone技术是硬件范围的安全方法,针对高性能计算平台上的大量应用,包括安全支付、数字版权管理 (DRM)、企业服务和基于 Web 的服务。TrustZone 技术与 Cortex-A 处理器紧密集成,并通过 AMBA AXI 总线和特定的TrustZone硬件IP块在系统中进行扩展,所以ARM TrustZone技术是从硬件层次上提供的安全机制,此系统方法意味着可以保护安全内存、加密块、键盘和屏幕等外设,从而可确保它们免遭软件攻击。
上面这些是arm推出TrustZone技术的功能宣讲的说明,事实上TrustZone最重要的目的是防止消费者从软硬件层面对产品的关键系统进行读写、调试等高权限的操作。可以参考这篇博文。
https://blog.csdn.net/lpwsw/article/details/123903397
会对TrustZone有更深刻的认知。这里展示ARM提供TrustZone启动的执行框架。
看到这个图,上来肯定是迷惑的,毕竟这张图有很多知识点可以讲,我们先从每一块的名字讲解。
详细整理表格如下所示。
简称 | 完整名称 | 功能说明 |
---|---|---|
BL1 | Boot stage 1 | 启动第一阶段,一般为BootROM |
BL2 | Boot stage 2 | 启动第二阶段,对应BootLoader SPL |
BL31 | Boot stage 3_1 | 启动第三阶段(第一部分),提供安全的Runtime |
BL32 | Boot stage 3_2 | 启动第三阶段(第二部分),提供安全的系统固件(Trust OS) |
BL33 | Boot stage 3_3 | 启动第三阶段(第三部分),系统启动流程(U-Boot加载) |
理解了这几个参数,图上执行流程就比较简单简答了。
可以看到,每个阶段都有着相应的执行意义,BL1,BL2可以看作系统启动的预处理流程,执行必要的CPU,FLASH,SDRAM初始化,安全系统的基础初始化,保证系统的运行。BL31,BL32,BL33虽然流程上启动有先后顺序,但在启动后是并行执行的,分别执行在不同的CPU环境中,这样就从硬件上实现了隔离,具有更高的安全性。在系统最终运行中,BL31,BL32与BL33后续启动的Linux Kernel并行运行,主要提供安全相关的服务。
从CPU的视角看,如下是一个标准的启用了ARM TrustZone技术后的CPU特权模式等级架构图。对于AARCH64的CPU,它的特权等级分为EL0、EL1、EL2、EL3,其中根据 CPU 所处的世界又分为安全EL0、安全EL1或者非安全EL0、非安全EL1。如果是 32 位 CPU,它的特权等级分为 Mon、Hyp、SVC、ABT、IRQ、FIQ、UND、SYS、USER 模式,其中 SVC、ABT、IRQ、FIQ、UND、SYS、USER 也如64位一样有安全和非安全模式之分,在此图中,ARM Trust Firmware对应BL31,Trust-OS对应BL32。
不过这里有个注意点,TrustZone是硬件支持的特性,只有需要启动此特性时,才需要TF-A的流程来保证硬件的安全性。如果不启动,理论上不需要BL2,BL31,BL32的启动流程,但BL33表示U-Boot启动,是必须存在的。当不支持TrustZone时,启动流程就回归了上面的U-Boot/U-Boot SPL启动流程。
关于TF-A的源码,参考地址如下。
git clone https://github.com/ARM-software/arm-trusted-firmware.git
这里以RockChip官网的启动选项来展示TF-A的实际运行流程,具体网址:rockchip官网启动说明
按照流程来说,详细理解这张图对应关系如下。
另外上面也提到了,阶段1始终在ROM中,它可以加载阶段2,也可以直接加载阶段3,如果加载阶段3,按照注释的说明,就会执行trust.img,这就和最初的U-Boot启动流程一致。
BootROM => U-Boot => Linux Kernel => System Rootfs
如果启用TrustZong机制,则必须加载阶段2,此时流程如下。
在运行过程中,loader(BL1,BL2),Trust-OS(BL32)运行在安全世界,BL31则是非安全世界和安全世界切换的桥梁(Secure Monitor),U-Boot(BL33),Kernel,Rootfs运行在非安全世界。
至此,关于U-Boot SPL启动流程,以及ARM的TF-A机制进行了部分讲解,当然这部分只涉及启动的部分,主要用于芯片移植中需要,大部分开发者并不需要接触。不过理解了这个机制,就可以理解更新的芯片如全志H618,RockChip的RK3568,RK3588,ST的STM32MP1这类芯片的启动流程,可以更好的理解SDK的编译流程,事半功倍。
直接开始下一章节说明: 异构多核芯片工作处理