赞
踩
在使用TrustZone技术的嵌入式设备当中,无法避免的需要解决从非安全侧切换到安全侧的问题,而为了完成这个切换,需要一个专用的进行非安全上下文和安全上下文切换的固件,这个固件一般我们称为arm trust firmware,在ARM官方维护的github中我们能够下载到其完整的代码
https://github.com/ARM-software/arm-trusted-firmware
在其github工程的介绍里,有完整的arm trusted firmware的移植和适配的方法,所以可以很方便的将其移植到不同的平台并进行适配,自己的操作系统。
arm trusted firmware的工作方法如下图所示
图中的EL3 Firmware就是BL31,也就是arm trusted firmware,通过其框图我们可以看到其包括多个组成部分,第一级是一个中断处理入口叫做 SMC interface,其用汇编代码写成,用来接收来自非安全侧或者是安全侧的SMC指令造成的陷入到EL3的异常请求,然后SMC Interface根据其SMC 指令中传入的立即数,通过Service Router进行处理函数分发,按照分类主要的处理分发分为非安全世界和安全世界的World Switcher,一些需要在EL3访问的硬件资源的驱动类代码,最后是一大类的PSCI电源管理模块(包括挂起处理器,恢复处理器运行,处理器的上下电等PSCI电源管理的内容)。
其中我们着重分析World Switch和PSCI的部分,个人对特殊的EL3硬件访问接口所知不多,所以不做介绍。
1, World Switch
非安全世界和安全世界的切换,这个是arm trusted firmware的主要功能,其中的主要功能集中在service/spd 目录中然后其根据不同的安全OS的操作系统来进行不同的Dispatch,所以这里的spd是 Secure Payload Dispatch的简写,其根据SMC FID的不同来选择不同的optee_smc_handler, trusty_smc_handler, tspd_smc_handler来对具体的命令来进行处理。
比如 TSP_PREEMPT是当运行在安全侧的时候非安全侧的IRQ中断发生了,从而触发了中断当前安全侧业务,切换到非安全侧执行中断处理函数,然后再返回安全侧的动作。
而 TSP_EL1_INTERRUPT是和TSP_PREEMPT相反的动作。
而在optee_smc_handler这些具体的SMC中断处理函数中有对其具体命令的具体处理。
2, PSCI电源管理
如果不知道PSCI是什么那么请参考
http://infocenter.arm.com/help/topic/com.arm.doc.den0022d/Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf
在标准的Linux操作系统的处理器电源管理通用接口中,对ARM处理器有专用的PSCI模块,来对CPU的上线和离线进行处理,其中包括了对中断的迁移,对处理器状态切换的保存,而在最终的操作硬件的阶段,可以通过对设备树的PSCI模块进行配置从而选择使用什么SMC指令或者HYP指令将当前的处理器进行挂起恢复,上电和下电。
ARM TrustZone技术简介更像是一个简单的介绍和怎样把整个系统串起来的线索,如果对其中的具体实现很感兴趣,可以具体阅读代码,也许后面我会写一些代码分析的博客,来更详细的介绍其中的细节。 (代码分析是写书最快的途径....但是实际上对读者对系统架构的了解作用了了)
在vendor某些厂商的设计中,ATF并不是BOOTROM加载后的第一个启动镜像,可能是这样的:
BOOTROM—>PL—>ATF—>optee—>uboot…, 在PL阶段就已经将ATF/optee/uboot镜像的load到内存了.
由上述背景的原因,我们的ATF就不需要走BL1/BL2阶段load optee/uboot镜像到内存了,直接走BL3即可.
所以bl1和bl2目录也无需编译.
我们的编译方法是在make的时候传入RESET_TO_BL31=1参数:
- make -C $DIRPATH RESET_TO_BL31=1 PLAT=xxxx clean
- make -C $DIRPATH RESET_TO_BL31=1 PLAT=xxx xxxx_VDK=0 xxxxxx=0 xxxxxx=0 HIGHADDR_DEVICE=1 all
从bl31.ld.S文件可知,ATF是从bl31_entrypoint开始启动的
- func bl31_entrypoint
- bl bl31_early_platform_setup
- bl bl31_plat_arch_setup
- bl bl31_main
在bl31_main()函数中:
runtime_svc_init()跳转optee之前的准备,然后再调用bl32_init跳转到optee,optee
os初始化完成后再从此处回来。
bl31_prepare_next_image_entry()跳转uboot之前的准备,返回到bl31_entrypoint后调用b
el3_exit跳转到uboot, PC就不会再回此处了。下次PC再回来就是在REE进行了smc调用,那时是直接跳转到ATF的异常向量表.
- void bl31_main(void)
- {
- NOTICE("BL31: %s\n", version_string);
- NOTICE("BL31: %s\n", build_message);
-
- /* Perform remaining generic architectural setup from EL3 */
- bl31_arch_setup();
-
- /* Perform platform setup in BL31 */
- bl31_platform_setup();
-
- /* Initialise helper libraries */
- bl31_lib_init();
-
- /* Initialize the runtime services e.g. psci */
- INFO("BL31: Initializing runtime services\n");
- runtime_svc_init();
-
- /*
- * All the cold boot actions on the primary cpu are done. We now need to
- * decide which is the next image (BL32 or BL33) and how to execute it.
- * If the SPD runtime service is present, it would want to pass control
- * to BL32 first in S-EL1. In that case, SPD would have registered a
- * function to intialize bl32 where it takes responsibility of entering
- * S-EL1 and returning control back to bl31_main. Once this is done we
- * can prepare entry into BL33 as normal.
- */
-
- /*
- * If SPD had registerd an init hook, invoke it.
- */
- if (bl32_init) {
- INFO("BL31: Initializing BL32\n");
- (*bl32_init)();
- }
-
-
- next_image_type = NON_SECURE;//han han han 也可以是启动non-secure内核
- /*
- * We are ready to enter the next EL. Prepare entry into the image
- * corresponding to the desired security state after the next ERET.
- */
- bl31_prepare_next_image_entry();
-
- /*
- * Perform any platform specific runtime setup prior to cold boot exit
- * from BL31
- */
- bl31_plat_runtime_setup();
- }
bl31_prepare_next_image_entry()可以获取optee/uboot的跳转地址,该地址最终来自于platform_def.h头文件中写死的地址
#define BL32_BASE (PLAT_S_DRAM_BASE + BL31_SIZE + PLAT_TRUSTED_MAILBOX_SIZE)
#define PLAT_NS_IMAGE_BASE 0x80000000
#define PLAT_NS_IMAGE_OFFSET (PLAT_NS_IMAGE_BASE + 0x9000000)
- void bl31_prepare_next_image_entry(void)
- {
- entry_point_info_t *next_image_info;
- uint32_t image_type;
-
- /* Determine which image to execute next */
- image_type = bl31_get_next_image_type();
-
- /* Program EL3 registers to enable entry into the next EL */
- next_image_info = bl31_plat_get_next_image_ep_info(image_type);
- assert(next_image_info);
- assert(image_type == GET_SECURITY_STATE(next_image_info->h.attr));
-
- INFO("BL31: Preparing for EL3 exit to %s world\n",
- (image_type == SECURE) ? "secure" : "normal");
- print_entry_point_info(next_image_info);
- cm_init_my_context(next_image_info);
- cm_prepare_el3_exit(image_type);
- }
- entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
- {
- assert(sec_state_is_valid(type));
- if (type == NON_SECURE)
- return &bl33_image_ep_info;
-
- if (type == SECURE)
- return &bl32_image_ep_info;
-
- return NULL;
- }
-
- void bl31_early_platform_setup(bl31_params_t *from_bl2,
- void *plat_params_from_bl2)
- {
- ......
- bl32_image_ep_info.pc = BL32_BASE;
- ......
- ......
- bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
- bl33_image_ep_info.spsr = plat_get_spsr_for_bl33_entry();
- ......
- }
-
- unsigned long plat_get_ns_image_entrypoint(void)
- {
- return PLAT_NS_IMAGE_OFFSET;
- }
-------------------------------------------------------------------------------------------------------------------------------
ATF将系统启动从最底层进行了完整的统一划分,将secure monitor的功能放到了bl31中进行,这样当系统完全启动之后,在CA或者TEE OS中触发了smc或者是其他的中断之后,首先是遍历注册到bl31中的对应的service来判定具体的handle,这样可以对系统所有的关键smc或者是中断操作做统一的管理和分配。ATF的code boot整个启动过程框图如下:
在上述启动过程中,每个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.
从bl2跳转到bl31是通过带入bl31的entry point info调用smc指令触发在bl1中设定的smc异常来通过cpu将全向交给bl31并跳转到bl31中执行。
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的执行。
https://blog.csdn.net/shuaifengyun/article/details/72468109
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。