carloscn/blog

05_OPTEE-OS_系统集成之(三)ATF启动过程

carloscn opened this issue · 0 comments

05_OPTEE-OS_系统集成之(三)ATF启动过程

ATF作为最底层固件,OP-TEE OS、 BootLoader、Linux内核的加载都是由ATF来完成的,而且ATF实现了安全引导的功能。bl31运行于EL3,待系统启动完成后,在REE侧或TEE侧触发的安全监控模式调用(smc)都会进入bl31中被处理。OP-TEE启动完成后会返回一个包含用于处理各种类型的安全监控模式调用的函数指针结构体变量,该变量会被添加到bl31的handle中,用于处理REE侧触发的安全监控模式调用。bl2启动时通过触发安全监控模式调用通知bl1将CPU控制权限交给bl31,bl31通过解析特定段中是否存在OP-TEE的入口函数指针来确定是否需要加载OP-TEE。OP-TEE启动后会触发安全监控模式调用重新进入到bl31中继续执行。bl31通过查询链表的方式获取下一个需要被加载REE侧的镜像文件,并设定好REE侧运行时CPU的状态和运行环境,然后退出EL3进入REE侧镜像文件的启动,一般第一个REE侧镜像文件为 BootLoader,BootLoader会加载Linux内核。

1. 安全引导原理

安全引导功能的原理就是采用链式验签的方式启动系统,也就是在系统启动过程中,在加载下一个阶段的镜像之前都会对需要被加载的镜像文件进行电子验签,只有验签操作通过后,该镜像才能被加载到内存中,然后系统才会跳转到下一个阶段继续执行,整个验签链中的任何一环验签失败都会导致系统挂死,系统启动过程中的第一级验签操作是由ChipRom(BootROM)来完成的。只要芯片一出厂,用户就无法修改固化在芯片中的这部分代码,因此无法通过修改第一级验签结果来关闭安全引导功能。而且验签操作使用的RSA公钥或者哈希值将会被保存在OTP/efuse中,该区域中的数据一般只有ChipRom(BootROM)和TEE能够读取且无法被修改。RSA公钥或者哈希值将会在产品出厂之前被写入到OTP/efuse中,而且不同厂商使用的密钥会不一样。

在谷歌的安全引导功能白皮书中提出了安全引导功能实现方案的设计建议。谷歌建议将镜像文件 的电子签名信息和验签使用的RSA公钥保存在电子证书中,系统在启动的过程中首先会验证电子证书的合法性,如果验证通过则需从电子证书中获取签名信息和RSA公钥,然后再利用它们对镜像文件进行验证。整个验证过程就是先验证证书,验证证书通过后再去验证镜像文件的合法性。但是在实际实现过程中,大多数芯片厂商是将签名信息与需要被验签的镜像文件打包在一起,而RSA公钥则会被打包到执行验证操作的镜像文件中。

不同厂商可能会对镜像文件进行加密操作,使保存在设备中的镜像文件都是以密文的形式存在。 在启动过程中,首先会验证密文镜像文件的合法性然后再进行解密镜像文件的操作,这些都完成后才会将明文的镜像文件加载到内存中然后再执行跳转操作。

1.1 ARMv7安全引导过程

对于安全引导功能的实现和验证过程各家芯片公司的方案都不一样,这是由该芯片的启动流程以及启动所需镜像文件来决定的,但都会遵循链式验签启动的原则。ARMv7架构并没有使用ATF,系统的启动流程与以前一样使用BootLoader来引导Linux内核和TEE OS。

1.1 ARMv8安全引导过程

ARMv8架构之后ARM提供了ATF, BootLoader、TEE镜像文件、Linux内核镜像文件、 recovery镜像文件都是由ATF来进行引导和加载而不是由ChipRom(BootROM)成的。ChipRom(BootROM)只会去验证ATF中bl1的合法性,后续引导过程同样也是按照链式验签的方式进行,符合TBBR规范。在 ARMv8架构中整个安全引导的流程如图所示。

ARMv8架构中引入了ATF,同时在ATF中提供了安全引导的功能,BootLoader镜像、Linux内核、 recovery镜像和TEE OS镜像文件的签名方式都由ATF决定。当然开发者也可以对ATF进行定制化,修改ATF中的验签过程,但是修改后的验签方案需要符合TBBR规范。

2. ATF启动过程

ATF的启动过程根据ARMv8的运行模式(AArch32/AArch64)会有所不同,但基本一致。在AArch32中是不会去加载bl31而是将EL3或者 Monitor模式的运行代码保存在bl32中执行。在AArch64中,ATF的完整启动流程如图所示。

在上述启动过程中,从一个镜像跳转到另外一个镜像文件执行的方式各不相同,以下为镜像跳转的过程和方式说明。

1.bl1跳转到bl2执行

在bl1完成了将bl2镜像文件加载到RAM中的操作、中断向量表的设定以及其他CPU相关设定后, bl1_main函数会解析出bl2镜像文件的描述信息,获取入口地址,并设定下一个阶段的cpu上下文。这些操作完成之后,调用el3_exit函数来实现bl1到bl2的跳转,进入bl2中开始执行。

2.bl2跳转到bl31执行

在bl2中将会加载bl31、bl32、bl33的镜像文件到对应权限的内存中,并将该三个镜像文件的描述 信息组成一个链表保存起来,以备bl31启动bl32和bl33使用。在AArch64中,bl31为EL3的执行软件, 其运行时的主要功能是对安全监控模式调用(smc)指令和中断处理,运行在ARM的Monitor模式中。

bl32一般为TEE OS镜像文件。 bl33为正常世界状态的镜像文件,例如uboot、EKD2等。当前该部分为BootLoader部分的镜像文件,再由BootLoader来启动Linux内核镜像。

从bl2跳转到bl31是通过带入bl31的入口点信息作为参数,然后调用安全监控模式调用指令,触发 在bl1中设定的安全监控模式调用请求,该请求处理完成后会将**处理器的执行权限交给bl31,并跳转到bl31中去执行。

3.bl31跳转到bl32执行

在bl31中会执行runtime_service_inti函数,该函 数会调用注册到EL3中所有服务的初始化函数,其中有一个服务项就是TEE服务,该服务项的初始化函数会将TEE OS的初始化函数赋值给bl32_init变量,当所有服务项执行完初始化后,在bl31中会调 用bl32_init执行的函数来跳转到TEE OS中并开始执 行TEE OS的启动。

4.bl31跳转到bl33执行

当TEE-OS镜像启动完成后会触发一个ID为 TEESMC_OPTEED_RETURN_ENTRY_DONE的安全监控模式调用,该调用是用来告知EL3 TEE OS镜像已经完成了初始化,然后将CPU的状态恢复到 bl31_init的位置继续执行。

bl31通过遍历在bl2中记录的所有镜像信息的链表来找到需要执行的bl33的镜像。然后通过获取到bl33镜像的信息,设定下一个阶段的CPU上下文,退出el3后进入到bl33镜像中开始执行。

ATF具体过程参考:02_Embedded_ARMv8 ATF Secure Boot Flow (BL1/BL2/BL31)