首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

ARM的安全启动—ATF TF-A以及它与UEFI的互动_atf runtime spmd

  • 25-02-18 11:41
  • 4164
  • 6391
blog.csdn.net

ARMv8 提供了两种安全状态:Secure 和 Non-secure,也就是安全和非安全,Non-secure 也就是正常世界(NormalWorld)。我们可以在 Non-secure 运行通用操作系统,比如 Linux,在 Secure 运行可信操作系统,比如OP-TEE,这两个操作系统可以同时运行,这个需要处理器支持 ARM 的 TrustZone 功能。在 Normal world 和 Secure world下,ARMv8 个 EL 等级对应的内容和在 ARMv8 的 AArch32 模式下,处理器模式如图所示:

图片

在 AArch32 模式下,EL0~LE3 对应 ARMv7 的不同工作模式:

  1. EL0:对应 ARMv7 的 User 工作模式
  2. EL1:对应 ARMv7 的 SVC、ABT、IRQ、IRQ、UND 和 SYS 这 6 中工作模式
  3. EL2:对应 ARMv7 的 Hyp 工作模式
  4. EL3:对应 ARMv7 的 Mon 工作模式

可以看出,只有 EL3 是用于安全监视器的,所以 TF-A 主要工作在 EL3 下,在看 TF-A源码的时候会看到大量的“EL3”字样的文件或代码。

ATF带来最大的变化是信任链的建立(Trust Chain),整个启动过程包括从EL3到EL0的信任关系的打通,过程比较抽象。NXP的相关文档[2]比较充分和公开,它的源代码也是开源的[3]。我们结合它的文档和源代码来理解一下。

ATF启动流程

ARM开源了ATF的基本功能模块,大家可以在这里下载:

git clone  https://github.com/ARM-software/arm-trusted-firmware.git
  • 1

里面已经包含了不少平台,但这些平台的基础代码有些是缺失的,尤其是和芯片部分和与UEFI联动部分。这里我推荐它的一个分支:NXP的2160A芯片的实现。

ARM推出了System Ready计划,效果相当不错,关于它我们今后再单独讲。2020年底,ARM在OSFC推出新的一批System Ready机型[4],NXP 2160A名列其中:

来源:参考资料4

ATF代码下载可以用:

git clone https://source.codeaurora.org/external/qoriq/qoriq-components/atf -b LX2160_UEFI_ACPI_EAR3
  • 1

UEFI代码下载可以用图片上的地址。我们可以把参考资料2和这些代码对照来看,加深理解。
支持ATF的ARM机器,启动过程如下

来源:参考资料2

注意蓝色箭头上的数字,它是启动顺序。一切起源于在EL3的BL1。

BL1:Trusted Boot ROM

启动最早的ROM,它可以类比Boot Guard的ACM,

老狼:什么是Boot Guard?电脑启动中的信任链条解析269 赞同 · 44 评论文章​编辑

不过它是在CPU的ROM里而不是和BIOS在一起,是一切的信任根。它的代码在这里:

代码很简单(略去不重要内容):

func bl1_entrypoint
        ....
	bl	bl1_early_platform_setup
	bl	bl1_plat_arch_setup
        ....
	bl	bl1_main
        ....
	b	el3_exit
endfunc bl1_entrypoint
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

bl1_main()开始就是c程序了,那c运行依靠的堆和栈空间在哪里呢?在CPU内部的SRAM里。SRAM一启动就已经可以访问了,bl1_plat_arch_setup()简单地在其中划分出来一块作为Trusted SRAM给c程序用,而不用像x86在cache里面扣一块出来,简单了很多。

BL1主要目的是建立Trusted SRAM、exception vector、初始化串口console等等。然后找到并验证BL2(验签CSF头),然后跳过去。

BL2:Trusted Boot Firmware

同样运行在EL3上的BL2和BL1一个显著的不同是它在Flash上,作为外置的一个Firmware,它的可信建立在BL1对它的验证上。它也有完整的源代码:

它也会初始化一些关键安全硬件和软件框架。更主要的是,也是我希望大家下载NXP 2160A的分支的重要原因,BL2会初始化很多硬件,而这些硬件初始化在x86中是BIOS完成的(无论是在PEI中还是包在FSP/AGESA中),而在ARM的ATF体系中,很多种CPU是在BL2中完成的。2160A在Plat目录下提供了很多开源的硬件初始化代码,供ATF BL2框架代码调用。比较重要的是bl2_main()

void bl2_main(void)
{
        ...
	bl2_arch_setup();
        ...
	/* initialize boot source */
	bl2_plat_preload_setup();
	/* Load the subsequent bootloader images. */
	next_bl_ep_info = bl2_load_images();
        ...
	bl2_run_next_image(next_bl_ep_info);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

最重要的两步都在这个函数中完成:初始化硬件和找到BL31。

bl2_plat_preload_setup()中会初始化一堆硬件,包括读取RCW初始化Serdes等,对内存初始化感兴趣的人(比如我)也可以在里面找到初始化DDR4的代码:dram_init(),它在Plat\nxp\drivers\ddr\nxp-ddr下。比较遗憾的是DDR4 PHY的代码是个Binary,不含源码,这里对DDR4的初始化仅仅聚焦设置timing寄存器和功能寄存器,而没有内存的Training过程。

Anyway,x86带内初始化硬件的很多代码ARM ATF体系都包括在BL2中,而不在UEFI代码中,这是和x86 UEFI代码的一个显著区别。部分原因这些代码都要求是Secure的。更加糟糕的是,很多ARM平台,BL1和BL2,甚至后面的BL31都是以二进制的形式提供,让定制显得很困难。BL2能否提供足够的信息和定制化选择给固件厂商和提供足够信息给UEFI代码,考验BL2的具体设计实现。NXP在两个方面都做的不错,不但提供RCW等配置接口,还开源了大部分代码,十分方便。

BL2在初始化硬件后,开始寻找BL3的几个小兄弟:BL31,BL32和BL33。它先找到BL31,并验签它,最后转入BL31。

BL31:EL3 Runtime Firmware

BL31作为EL3最后的安全堡垒,它不像BL1和BL2是一次性运行的。如它的runtime名字暗示的那样,它通过SMC为Non-Secure持续提供设计安全的服务。关于SMC的调用calling convention我们今后再详细介绍,这里只需要知道它的服务主要是通过BL32。它负责找到BL32,验签,并运行BL32。

BL32:OPTee OS + 安全app

BL32实际上是著名的Open Portable Trusted Execution Enveiroment[5] OS,它是由Linaro创立的。它是个很大的话题,我们今后再细聊。现在仅需要知道OPTee OS运行在 S-EL1,而其上的安全APP运行在S-EL0。OPTee OS运行完毕后,返回EL3的BL31,BL31找到BL33,验签它并运行。

BL33: Non-Trusted Firmware

BL33实际上就是UEFI firmware或者uboot,也有实现在这里直接放上Linux Kernel。2160A的实现是UEFI和uboot都支持。我们仅仅来看UEFI的路径。

第一次看到UEFI居然是Non-Trusted,我是有点伤心的。UEFI运行在NS_EL2,程序的入口点在ARM package

edk2/ArmPlatformPkg/PrePi/AArch64/ModuleEntryPoint.S
  • 1

做了一些简单初始化,就跳到C语言的入口点CEntryPoint( )。其中ArmPlatformInitialize()做了一些硬件初始化,调用了

edk2-platforms/Silicon/NXP/

的代码。重要的是PrimaryMain()。

PrimaryMain()有两个实例,2160A NXP选择的是PrePI的版本(edk2/ArmPlatformPkg/PrePi/MainUniCore.c),说明它跳过了SEC的部分,直接进入了PEI的后期阶段,在BL2已经干好了大部分硬件初始化的情况下,这个也是正常选择。PrePI的实例直接调用PrePiMain()(仅保留重要部分)

VOID
PrePiMain (
  IN  UINTN                     UefiMemoryBase,
  IN  UINTN                     StacksBase,
  IN  UINT64                    StartTimeStamp
  )
{
  ....
  ArchInitialize ();
  SerialPortInitialize ();
  InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, NULL, NULL);
  // Initialize MMU and Memory HOBs (Resource Descriptor HOBs)
  Status = MemoryPeim (UefiMemoryBase, FixedPcdGet32 (PcdSystemMemoryUefiRegionSize));
  BuildCpuHob (ArmGetPhysicalAddressBits (), PcdGet8 (PcdPrePiCpuIoSize));
  BuildGuidDataHob (&gEfiFirmwarePerformanceGuid, &Performance, sizeof (Performance));
  SetBootMode (ArmPlatformGetBootMode ());
  // Initialize Platform HOBs (CpuHob and FvHob)
  Status = PlatformPeim ();
  ....
  Status = DecompressFirstFv ();
  Status = LoadDxeCoreFromFv (NULL, 0);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

从中我们可以看到,这里几乎就是UEFI PEI阶段DXEIPL的阶段了,后面就是直接DXE阶段。

好了,我们来梳理一下,ATF整个信任链条是逐步建立的:

来源:参考资料2

从作为信任根的BL1开始,一步一步验签CSF头中的签名,最后来到BL33,后面就是OS了。那BL33后面怎么就断了呢?其实后面的验签就是UEFI Secure Boot了

老狼:趣话安全启动:迷思与启示152 赞同 · 24 评论文章​编辑

结语

ATF的官网一张图包含了更多的信息:

如果你仅仅对ATF的UEFI启动路径感兴趣,下面这张图可能更加简单明了:

NXP 2160A的开源和良好的文档,让我们可以在一个具体的平台上切片观察ATF的具体实现,建议大家仔细阅读参考资料2和下载代码来看看。

关于ATF启动这里先整个宏观的概念。

这个blog讲的很好,就不重复写了,自己写还写不到这么清晰,图页很漂亮。

原文链接:https://www.cnblogs.com/arnoldlu/p/14175126.html

启动正文

下图划分成不同EL,分别描述BL1、BL2、BL31、BL32、BL33启动流程,以及PSCI、SP处理流程。

1. 冷启动(Cold boot)流程及阶段划分

restart–冷启动
reset–热启动

ATF冷启动实现分为5个步骤:

  • BL1 - AP Trusted ROM,一般为BootRom。
  • BL2 - Trusted Boot Firmware,一般为Trusted Bootloader。
  • BL31 - EL3 Runtime Firmware,一般为SML,管理SMC执行处理和中断,运行在secure monitor中。
  • BL32 - Secure-EL1 Payload,一般为TEE OS Image。
  • BL33 - Non-Trusted Firmware,一般为uboot、linux kernel。

ATF输出BL1、BL2、BL31,提供BL32和BL33接口。
(我想提供的接口就是BL32和BL33的镜像可以是指定的,atf其实是一个启动框架,这其中包含的五个步骤,每个步骤你想要的内容,可以由厂商自己定义。)

启动流程如下:

在这里插入图片描述

1.1 BL1

BL1位于ROM中,在EL3下从reset vector处开始运行。(bootrom就是芯片上电运行的(chip-rom的作用就是跳转到bootrom))

BL1做的工作主要有:

  • 决定启动路径:冷启动还是热启动。
  • 架构初始化:异常向量、CPU复位处理函数配置、控制寄存器设置(SCRLR_EL3/SCR_EL3/CPTR_EL3/DAIF)
  • 平台初始化:使能Trusted Watchdog、初始化控制台、配置硬件一致性互联、配置MMU、初始化相关存储设备。
  • 固件更新处理
  • BL2镜像加载和执行:
    • BL1输出“Booting Trusted Firmware"。
    • BL1加载BL2到SRAM;如果SRAM不够或者BL2镜像错误,输出“Failed to load BL2 firmware.”。
    • BL1切换到Secure EL1并将执行权交给BL2.

1.2 BL2

BL2位于SRAM中,运行在Secure EL1主要工作有:

  • 架构初始化:EL1/EL0使能浮点单元和ASMID。
  • 平台初始化:控制台初始化、相关存储设备初始化、MMU、相关设备安全配置、
  • SCP_BL2:系统控制核镜像加载,单独核处理系统功耗、时钟、复位等控制。
  • 加载BL31镜像:BL2将控制权交给BL1;BL1关闭MMU并关cache;BL1将控制权交给BL31。
  • 加载BL32镜像:BL32运行在安全世界,BL2依赖BL31将控制权交给BL32。SPSR通过Secure-EL1 Payload Dispatcher进行初始化。
  • 加载BL33镜像:BL2依赖BL31将控制权交给BL33。

1.3 BL31

BL31位于SRAM中,EL3模式。除了做架构初始化和平台初始化外,还做了如下工作:

  • PSCI服务初始化,后续提供CPU功耗管理操作。
  • BL32镜像运行初始化,处于Secure EL1模式。
  • 初始化非安全EL2或EL1,跳转到BL33执行。
  • 负责安全非安全世界切换。
  • 进行安全服务请求的分发。

在这里插入图片描述

这两幅图真的不错,棒。

小结

ATF将系统启动从最底层进行了完整的统一划分,将secure monitor的功能放到了bl31中进行,这样当系统完全启动之后,在CA或者TEE OS中触发了smc或者是其他的中断之后,首先是遍历注册到bl31中的对应的service来判定具体的handle,这样可以对系统所有的关键smc或者是中断操作做统一的管理和分配。

在上述启动过程中,每个Image跳转到写一个image的方式各不相同,下面将列出启动过程中每个image跳转到下一个image的过程:

1. bl1跳转到bl2执行

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

2.bl2跳转到bl31执行

在bl2中将会加载bl31, bl32, bl33的image到对应权限的RAM中,并将该三个image的描述信息组成一个链表保存起来,以备bl31启动bl32和bl33使用在AACH64中,bl31位于EL3 runtime software,运行时的主要功能是管理smc指令的处理和中断的主力,运行在secure monitor状态中

bl32一般为TEE OS image,本章节以OP-TEE为例进行说明

bl33为非安全image,例如uboot, linux kernel等,当前该部分为bootloader部分的image,再由bootloader来启动linux kernel.(所以不会这么久就是为了整个bootloader吧,应该是kernel吧)

从bl2跳转到bl31是通过带入bl31的entry point info调用smc指令触发在bl1中设定的smc异常来通过cpu将全向交给bl31并跳转到bl31中执行。(这个handle是再bl1配置的)

3.bl31跳转到bl32执行

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

4.bl31跳转到bl33执行

当TEE_OS image启动完成之后会触发一个ID为TEESMC_OPTEED_RETURN_ENTRY_DONE的smc调用来告知EL3 TEE OS image已经完成了初始化,然后将CPU的状态恢复到bl31_init的位置继续执行。

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

这一步对宏观的步骤有所认识,下一步对每个步骤的细节进行认识。

注:本文转载自blog.csdn.net的2501_90225460的文章"https://blog.csdn.net/2501_90225460/article/details/145191048"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

123
硬件开发
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top