历经一年多时间的系统整理合补充,《手机安全和可信应用开发指南:TrustZone与OP-TEE技术详解 》一书得以出版,书中详细介绍了TEE以及系统安全中的所有内容,全书按照从硬件到软件,从用户空间到内核空间的顺序对TEE技术详细阐述,读者可从用户空间到TEE内核一步一步了解系统安全的所有内容,同时书中也提供了相关的示例代码,读者可根据自身实际需求开发TA。目前该书已在天猫、京东、当当同步上线,链接如下(麻烦书友购书时能给予评论,多谢多谢)

京东购买地址

当当购买地址

天猫购买地址

非常感谢在此期间大家的支持以及各位友人的支持和帮助!!!。

为方便和及时的回复读者对书中或者TEE相关的问题的疑惑,也为了大家能有一个统一的交流平台。我搭建了一个简单的论坛,网址如下:

https://www.huangtengxq.com/discuz/forum.php

关于您的疑问可在“相关技术讨论“”中发帖,我会逐一回复。也欢迎大家发帖,一起讨论TEE相关的一些有意思的feature。共同交流。同时该论坛中也会添加关于移动端虚拟化的相关技术的板块,欢迎各位共同交流学习

  

在bl2中通过调用smc指令后会跳转到bl31中进行执行,bl31最终主要的作用是建立EL3 runtime software,在该阶段会建立各种类型的smc调用注册并完成对应的cortex状态切换。该阶段主要执行在monitor中。

1. bl31_entrypoint

通过bl31.ld.S文件可知, bl31的入口函数是:bl31_entrypoint函数,该函数的内容如下:

func bl31_entrypoint
#if !RESET_TO_BL31/* ---------------------------------------------------------------* Preceding bootloader has populated x0 with a pointer to a* 'bl31_params' structure & x1 with a pointer to platform* specific structure* ---------------------------------------------------------------*/mov    x20, x0mov  x21, x1/* ---------------------------------------------------------------------* For !RESET_TO_BL31 systems, only the primary CPU ever reaches* bl31_entrypoint() during the cold boot flow, so the cold/warm boot* and primary/secondary CPU logic should not be executed in this case.** Also, assume that the previous bootloader has already set up the CPU* endianness and has initialised the memory.* ---------------------------------------------------------------------*/
/* el3初始化操作,该el3_entrypoint_common函数在上面已经介绍过,其中runtime_exceptions为el3 runtime software的异常向量表,内容定义在bl31/aarch64/runtime_exceptions.S文件中 */el3_entrypoint_common                 \_set_endian=0                 \_warm_boot_mailbox=0              \_secondary_cold_boot=0                \_init_memory=0                    \_init_c_runtime=1             \_exception_vectors=runtime_exceptions/* ---------------------------------------------------------------------* Relay the previous bootloader's arguments to the platform layer* ---------------------------------------------------------------------*/mov   x0, x20mov  x1, x21
#else/* ---------------------------------------------------------------------* For RESET_TO_BL31 systems which have a programmable reset address,* bl31_entrypoint() is executed only on the cold boot path so we can* skip the warm boot mailbox mechanism.* ---------------------------------------------------------------------*/el3_entrypoint_common                  \_set_endian=1                 \_warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS    \_secondary_cold_boot=!COLD_BOOT_SINGLE_CPU    \_init_memory=1                    \_init_c_runtime=1             \_exception_vectors=runtime_exceptions/* ---------------------------------------------------------------------* For RESET_TO_BL31 systems, BL31 is the first bootloader to run so* there's no argument to relay from a previous bootloader. Zero the* arguments passed to the platform layer to reflect that.* ---------------------------------------------------------------------*/mov x0, 0mov    x1, 0
#endif /* RESET_TO_BL31 *//* ---------------------------------------------* Perform platform specific early arch. setup* ---------------------------------------------*/
/* 平台架构相关的初始化设置 */bl    bl31_early_platform_setupbl bl31_plat_arch_setup/* ---------------------------------------------* Jump to main function.* ---------------------------------------------*/bl bl31_main   //跳转到bl31_main函数,执行该阶段需要的主要操作/* -------------------------------------------------------------* Clean the .data & .bss sections to main memory. This ensures* that any global data which was initialised by the primary CPU* is visible to secondary CPUs before they enable their data* caches and participate in coherency.* -------------------------------------------------------------*/adr x0, __DATA_START__adr   x1, __DATA_END__sub x1, x1, x0bl    clean_dcache_rangeadr   x0, __BSS_START__adr    x1, __BSS_END__sub  x1, x1, x0bl    clean_dcache_rangeb el3_exit    //执行完成将跳转到bl33中执行,即执行bootloader
endfunc bl31_entrypoint  //执行完成将跳转到bl33中执行,即执行bootloader
endfunc bl31_entrypoint

2. bl31_main

该函数主要完成必要初始化操作,配置EL3中的各种smc操作,以便在后续顺利响应在CA和TA中产生的smc操作

void bl31_main(void)
{NOTICE("BL31: %s\n", version_string);NOTICE("BL31: %s\n", build_message);/* Perform platform setup in BL31 */bl31_platform_setup();    //初始化相关驱动,时钟等/* Initialise helper libraries */bl31_lib_init();   //用于执行bl31软件中相关全局变量的初始化/* Initialize the runtime services e.g. psci. */INFO("BL31: Initializing runtime services\n");runtime_svc_init();  //初始化el3中的service,通过在编译时指定特定的section来确定哪些service会被作为el3 service/** 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.*/
/* 如果注册了TEE OS支持,在调用完成run_service_init之后会使用TEE OS的入口函数初始化bl32_init变量,然后执行对应的Init函数,以OP-TEE为例,bl32_init将会被初始化成opteed_init,到此将会执行 opteed_init函数来进入OP-TEE OS的Image,当OP-TEE image OS执行完了image后,将会产生一个TEESMC_OPTEED_RETURN_ENTRY_DONE的smc来通过bl31已经完成了OP-TEE的初始化*/if (bl32_init) {INFO("BL31: Initializing BL32\n");(*bl32_init)();}/** 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();        //准备跳转到bl33,在执行runtime_service的时候会存在一个spd service,该在service的init函数中将会去执行bl32的image完成TEE OS初始化console_flush();/** Perform any platform specific runtime setup prior to cold boot exit* from BL31*/bl31_plat_runtime_setup();
}

3. runtime_svc_init

该函数主要用来建立smc索引表并执行EL3中提供的service的初始化操作

void runtime_svc_init(void)
{int rc = 0, index, start_idx, end_idx;/* Assert the number of descriptors detected are less than maximum indices */
/*判定rt_svc_descs段中的是否超出MAX_RT_SVCS条*/assert((RT_SVC_DESCS_END >= RT_SVC_DESCS_START) &&(RT_SVC_DECS_NUM < MAX_RT_SVCS));/* If no runtime services are implemented then simply bail out */if (RT_SVC_DECS_NUM == 0)return;/* Initialise internal variables to invalid state */
/* 初始化 t_svc_descs_indices数组中的数据成-1,表示当前所有的service无效*/memset(rt_svc_descs_indices, -1, sizeof(rt_svc_descs_indices));/* 获取第一条EL3 service在RAM中的起始地址,通过获取RT_SVC_DESCS_START的值来确定,该值在链接文件中有定义 */rt_svc_descs = (rt_svc_desc_t *) RT_SVC_DESCS_START;/* 遍历整个rt_svc_des段,将其call type与rt_svc_descs_indices中的index建立对应关系 */for (index = 0; index < RT_SVC_DECS_NUM; index++) {rt_svc_desc_t *service = &rt_svc_descs[index];/** An invalid descriptor is an error condition since it is* difficult to predict the system behaviour in the absence* of this service.*/
/* 判定在编译的时候注册的service是否有效 */rc = validate_rt_svc_desc(service);if (rc) {ERROR("Invalid runtime service descriptor %p\n",(void *) service);panic();}/** The runtime service may have separate rt_svc_desc_t* for its fast smc and standard smc. Since the service itself* need to be initialized only once, only one of them will have* an initialisation routine defined. Call the initialisation* routine for this runtime service, if it is defined.*/
/* 执行当前service的init的操作 */if (service->init) {rc = service->init();if (rc) {ERROR("Error initializing runtime service %s\n",service->name);continue;}}/** Fill the indices corresponding to the start and end* owning entity numbers with the index of the* descriptor which will handle the SMCs for this owning* entity range.*/
/* 根据该service的call type以及start oen来确定一个唯一的index,并且将该service中支持的所有的call type生成的唯一表示映射到同一个index中 */start_idx = get_unique_oen(rt_svc_descs[index].start_oen,service->call_type);assert(start_idx < MAX_RT_SVCS);end_idx = get_unique_oen(rt_svc_descs[index].end_oen,service->call_type);assert(end_idx < MAX_RT_SVCS);for (; start_idx <= end_idx; start_idx++)rt_svc_descs_indices[start_idx] = index;}
}

4. DECLARE_RT_SVC

该宏用来在编译的时候将EL3中的service编译进rt_svc_descs段中,该宏定义如下:

#define DECLARE_RT_SVC(_name, _start, _end, _type, _setup, _smch) \static const rt_svc_desc_t __svc_desc_ ## _name \__section("rt_svc_descs") __used = { \.start_oen = _start, \.end_oen = _end, \.call_type = _type, \.name = #_name, \.init = _setup, \.handle = _smch }

start_oen:该service的起始内部number

end.oen: 该service的末尾number

call_type: 调用的smc的类型

name: 该service的名字

init: 该service在执行之前需要被执行的初始化操作

handle: 当触发了call type的调用时调用的handle该请求的函数

5.以OP-TEE为例从bl31跳转到OP-TEE

实现从bl31到OP-TEE的跳转是通过执行opteed_setup函数来实现的,该函数在执行runtime_svc_int中对各service做service->init()函数来实现,而OPTEE这个service就是通过DECALARE_RT_SVC被注册到tr_svc_descs段中,代码存在service/spd/opteed/opteed_main.c文件中,内容如下:

5. ATF(ARM Trusted firmware)启动---bl31相关推荐

  1. ATF(Arm Trusted Firmware)/TF-A Chapter 02 BL1-ROMCode

    第二章目录: Chapter 02.TF-A(Arm Trusted Firmware, ATF ) BL1-ROMCode(本文) Chapter 02.TF-A(Arm Trusted Firmw ...

  2. ATF(Arm Trusted Firmware)/TF-A Chapter 01. 介绍

    1.TF-A 介绍 TF-A是一套通用的软件架构+特定于平台的实现代码. TF-A满足大多数SoC厂商的CPU设计:单核启动,多核启动,自定义reset vector,可裁剪的启动阶段,bootrom ...

  3. [ATF] ARM Trusted firmware 构建选项

    TF-A 构建系统支持以下构建选项.除非另有说明,这些选项应在构建命令行中指定,并且不会在任何组件生成文件中修改.请注意,构建系统不会跟踪构建选项的依赖性.因此,如果任何构建选项从先前的构建中发生更改 ...

  4. ATF(Arm Trusted Firmware)/TF-A Chapter 04 Authentication Framework

    4.1. 代码分析 首先,重新分析之前忽略掉的 TRUSTED_BOARD_BOOT =1 的情况,bl1_platform_setup->arm_bl1_platform_setup-> ...

  5. QEMU模拟器启arm64 ATF(arm trust firmware) BL1, uboot方法

    目的: 使用QEMU(3.0版本以上)模拟一个arm64 virt平台,在virt平台上配置两个cfi flash. Flash0当作BootRom使用,"烧录"ATF(arm t ...

  6. PC的ARM的安全启动

    其实还是很不习惯将PC和ARM联系起来,当然主要是因为我刚刚接触嵌入式没有多久,更别说服务器.PC端了. 脑子里固化了的X86. 于是这一篇学习一下,基于ARM的PC,是怎么利用这个ATF框架,进行安 ...

  7. 移动终端安全-ATF中bl1可信启动源码分析

    一.目标 本报告分析ATF中bl1可信启动的源代码,源代码位于arm-trusted-firmware-master\bl1和arm-trusted-firmware-master\include\a ...

  8. [ATF][Power]ARMv8 arm trust firmware

    ARM 全Trustzone解决方案,软件架构有ARM TBBR规范,在构建运行TEE环境时,ATF与TrustOS构成基本TEE执行环境. 本文主要介绍arm trust firmware组件. # ...

  9. [ATF]-ARM级别/异常/状态切回时候的寄存器保存与恢复

    文章目录 1.save/restore函数的定义 (1).el1_sysregs_context_save //保存系统寄存器 (2).el1_sysregs_context_restore //恢复 ...

  10. ARM裸机篇---启动代码分析

    ARM裸机篇---启动代码分析 先搞清楚启动代码和Bootloader的区别,启动代码是指CPU复位后到进入C语言的main函数之前需要执行的那段汇编代码. 下面的代码先暂且这样吧,没啥注释的,时间关 ...

最新文章

  1. C++ 预编译的时候使用defined 的含义
  2. 高校10余位博士抱着孩子参加授位仪式萌翻全场!科研人抱娃毕业成趋势?
  3. Docker(一):这可能是最为详细的Docker入门总结
  4. 互补性:从不同的角度思考同一个事物时,发现它同时具有不同甚至相互矛盾的性质...
  5. Linux 命令 - od
  6. 神策 FM | 我绝对想要那个 VS 我可能想要那个
  7. C++自定义非极大值抑制(Canny边缘检测,亚像素方法)
  8. JAVA---DOS命令学习
  9. LeetCode 967. 连续差相同的数字(BFS/DFS)
  10. 数据结构研究 ----单链表的按序号查找
  11. Cache 和 Buffer 有什么区别?
  12. ES6中的React生命周期详解
  13. 奇怪吸引子---Rucklidge
  14. qq互联android sdk,qq互联.Android_SDK_V2.0使用说明.doc
  15. 04741<计算机网络原理> 之第二章 网络应用
  16. events插件的使用
  17. 提速降费再发力 中国联通推出八项惠民便民措施
  18. 区块链技术入门,涉及哪些编程语言?
  19. 解决微信ios端+sendReq: not found
  20. 验证input和textarea的输入是否有效,也就是不为空,也不都是空格

热门文章

  1. spyder指定python环境
  2. 数据分析师的薪资大约有多少?
  3. the JDBC Driver has been forcibly unregistered.
  4. onenote打开闪退平板_win10系统下OneNote打不开或闪退怎么解决
  5. Android Studio与夜神模拟器联合调试
  6. MAC快捷键还原最小化的(cmd+M)程序窗口
  7. 非常好用的节假日查询接口
  8. 律师视角下网络爬虫技术的罪与罚
  9. web编辑器——百度UEditor编辑器使用教程与使用方法
  10. 数字ic前端设计工程师是做什么的?就业前景如何?