10.OP-TEE OS启动(一)
历经一年多时间的系统整理合补充,《手机安全和可信应用开发指南:TrustZone与OP-TEE技术详解 》一书得以出版,书中详细介绍了TEE以及系统安全中的所有内容,全书按照从硬件到软件,从用户空间到内核空间的顺序对TEE技术详细阐述,读者可从用户空间到TEE内核一步一步了解系统安全的所有内容,同时书中也提供了相关的示例代码,读者可根据自身实际需求开发TA。目前该书已在天猫、京东、当当同步上线,链接如下(麻烦书友购书时能给予评论,多谢多谢):
京东购买地址
当当购买地址
天猫购买地址
非常感谢在此期间大家的支持以及各位友人的支持和帮助!!!。
为方便和及时的回复读者对书中或者TEE相关的问题的疑惑,也为了大家能有一个统一的交流平台。我搭建了一个简单的论坛,网址如下:
https://www.huangtengxq.com/discuz/forum.php
关于您的疑问可在“相关技术讨论“”中发帖,我会逐一回复。也欢迎大家发帖,一起讨论TEE相关的一些有意思的feature。共同交流。同时该论坛中也会添加关于移动端虚拟化的相关技术的板块,欢迎各位共同交流学习
如果个系统有ATF(ARM Trusted Frimware)(ARF的部分,请参考ATF的相关文档),OP-TEE OS属于bl32阶段被启动,通过在bl31阶段调用opteed_enter_sp函数跳转到OP-TEE OS中执行启动操作。而在使用qemu+OP-TEE的环境中,运行时,如果启动OP-TEE OS请参考《7.OP-TEE+qemu的启动过程分析--加载optee_os和rootfs》。
以qemu+OP-TEE的方式运行TEE时,OP-TEE的image的链接文件是:optee_os/core/arch/arm/kernel/kern.ld.S,在该文件中中可以得知TEE image启动的时的入口函数是_start函数,代码如下:
_start函数被定义在core/arch/arm目录中的不同文件中,根据不同的板级拥有不同的.S文件。在qemu中使用的时候,使用的是ARM32,故本例子中使用QEMU+OPTEE运行TEE时,使用的是ARM32,所以入口函数被定义在core/arch/arm/kernel/generic_entry_a32.S文件中。整个启动的大致流程图如下(只考虑主CPU的启动):
该文件的主要内容如下,整个流程从_start函数开始,然后跳转到reset操作,最重要的是执行reset_primary函数:
.section .data
.balign 4#ifdef CFG_BOOT_SYNC_CPU
.equ SEM_CPU_READY, 1
#endif#ifdef CFG_PL310
.section .rodata.init
panic_boot_file:.asciz __FILE__/** void assert_flat_mapped_range(uint32_t vaddr, uint32_t line)*/
.section .text.init
/* __assert_flat_mapped_range 函数,判定MMU中虚拟地址和物理地址的映射关系是否正常 */
LOCAL_FUNC __assert_flat_mapped_range , :
UNWIND( .fnstart)
UNWIND( .cantunwind)push { r4-r6, lr }mov r4, r0mov r5, r1bl cpu_mmu_enabledcmp r0, #0beq 1fmov r0, r4bl virt_to_physcmp r0, r4beq 1f/** this must be compliant with the panic generic routine:* __do_panic(__FILE__, __LINE__, __func__, str)*/ldr r0, =panic_boot_filemov r1, r5mov r2, #0mov r3, #0bl __do_panicb . /* should NOT return */
1: pop { r4-r6, pc }
UNWIND( .fnend)
END_FUNC __assert_flat_mapped_range/* panic if mmu is enable and vaddr != paddr (scratch lr) */
/* assert_flat_mapped_range宏,如果MMU使能但虚拟地址和物理地址不匹配则引起panic */.macro assert_flat_mapped_range va, lineldr r0, =(\va)ldr r1, =\linebl __assert_flat_mapped_range.endm
#endif /* CFG_PL310 */.weak plat_cpu_reset_early
/* CPU重置 */
FUNC plat_cpu_reset_early , :
UNWIND( .fnstart)bx lr
UNWIND( .fnend)
END_FUNC plat_cpu_reset_early
KEEP_PAGER plat_cpu_reset_early.section .text.boot
/* _start函数,跳转到reset执行 */
FUNC _start , :b resetb . /* Undef */b . /* Syscall */b . /* Prefetch abort */b . /* Data abort */b . /* Reserved */b . /* IRQ */b . /* FIQ */
END_FUNC _start/* 准备非主CPU进入ready */.macro cpu_is_ready
#ifdef CFG_BOOT_SYNC_CPUbl get_core_poslsl r0, r0, #2ldr r1,=sem_cpu_syncldr r2, =SEM_CPU_READYstr r2, [r1, r0]dsbsev
#endif.endm/* 等待主CPU */.macro wait_primary
#ifdef CFG_BOOT_SYNC_CPUldr r0, =sem_cpu_syncmov r2, #SEM_CPU_READYsev
1:ldr r1, [r0]cmp r1, r2wfenebne 1b
#endif.endm/* 等待从CPU */.macro wait_secondary
#ifdef CFG_BOOT_SYNC_CPUldr r0, =sem_cpu_syncmov r3, #CFG_TEE_CORE_NB_COREmov r2, #SEM_CPU_READYsev
1:subs r3, r3, #1beq 3fadd r0, r0, #4
2:ldr r1, [r0]cmp r1, r2wfenebne 2bb 1b
3:
#endif.endm/** Save boot arguments* entry r0, saved r4: pagestore* entry r1, saved r7: (ARMv7 standard bootarg #1)* entry r2, saved r6: device tree address, (ARMv7 standard bootarg #2)* entry lr, saved r5: non-secure entry address (ARMv7 bootarg #0)*/
/* 保存启动的时候传入的参数:page table, dta, linux kernel entry address, bootarg */.macro bootargs_entry
#if defined(CFG_NS_ENTRY_ADDR)ldr r5, =CFG_NS_ENTRY_ADDR
#elsemov r5, lr
#endif
#if defined(CFG_PAGEABLE_ADDR)ldr r4, =CFG_PAGEABLE_ADDR
#elsemov r4, r0
#endif
#if defined(CFG_DT_ADDR)ldr r6, =CFG_DT_ADDR
#elsemov r6, r2
#endifmov r7, r1.endm/* reset函数定义,执行主要启动操作 */
LOCAL_FUNC reset , :
UNWIND( .fnstart)
UNWIND( .cantunwind)bootargs_entry //保存传入的启动参数/* Enable alignment checks and disable data and instruction cache. */
/* 使能对齐检查并禁用cache */read_sctlr r0orr r0, r0, #SCTLR_Abic r0, r0, #SCTLR_Cbic r0, r0, #SCTLR_Iwrite_sctlr r0isb/* Early ARM secure MP specific configuration */
/* 重置CPU的特殊配置 */bl plat_cpu_reset_earlyldr r0, =_startwrite_vbar r0#if defined(CFG_WITH_ARM_TRUSTED_FW)b reset_primary //当支持ATF的时候只执行reset_primary完成OP-TEE的启动
#elsebl get_core_pos //获取当前cpu的ID,用来判定当前执行的cortex是否是主CPUcmp r0, #0beq reset_primary //如果当前CPU是主CPU,则执行reset_primary来完成OP-TEE的启动b reset_secondary //执行其他CPU的初始化操作,主CPU不会执行到这里
#endif
UNWIND( .fnend)
END_FUNC reset/** Setup sp to point to the top of the tmp stack for the current CPU:* sp is assigned stack_tmp + (cpu_id + 1) * stack_tmp_stride -* stack_tmp_offset*/
/* 设置SP的值为栈顶 */.macro set_spbl get_core_poscmp r0, #CFG_TEE_CORE_NB_CORE/* Unsupported CPU, park it before it breaks something */bge unhandled_cpuadd r0, r0, #1ldr r2, =stack_tmp_strideldr r1, [r2]mul r2, r0, r1ldr r1, =stack_tmpadd r1, r1, r2ldr r2, =stack_tmp_offsetldr r2, [r2]sub sp, r1, r2.endm/** Cache maintenance during entry: handle outer cache.* End address is exclusive: first byte not to be changed.* Note however arm_clX_inv/cleanbyva operate on full cache lines.** Use ANSI #define to trap source file line number for PL310 assertion*/.macro __inval_cache_vrange vbase, vend, line
#ifdef CFG_PL310assert_flat_mapped_range (\vbase), (\line)bl pl310_baseldr r1, =(\vbase)ldr r2, =(\vend)bl arm_cl2_invbypa
#endifldr r0, =(\vbase)ldr r1, =(\vend)bl arm_cl1_d_invbyva.endm.macro __flush_cache_vrange vbase, vend, line
#ifdef CFG_PL310assert_flat_mapped_range (\vbase), (\line)ldr r0, =(\vbase)ldr r1, =(\vend)bl arm_cl1_d_cleanbyvabl pl310_baseldr r1, =(\vbase)ldr r2, =(\vend)bl arm_cl2_cleaninvbypa
#endifldr r0, =(\vbase)ldr r1, =(\vend)bl arm_cl1_d_cleaninvbyva.endm#define inval_cache_vrange(vbase, vend) \__inval_cache_vrange (vbase), ((vend) - 1), __LINE__#define flush_cache_vrange(vbase, vend) \__flush_cache_vrange (vbase), ((vend) - 1), __LINE__#ifdef CFG_BOOT_SYNC_CPU
#define flush_cpu_semaphores \flush_cache_vrange(sem_cpu_sync, \(sem_cpu_sync + (CFG_TEE_CORE_NB_CORE << 2)))
#else
#define flush_cpu_semaphores
#endif/* reset_primary函数,执行主CPU的主要初始化操作 */
LOCAL_FUNC reset_primary , :
UNWIND( .fnstart)
UNWIND( .cantunwind)/* preserve r4-r7: bootargs */#ifdef CFG_WITH_PAGER/** Move init code into correct location and move hashes to a* temporary safe location until the heap is initialized.** The binary is built as:* [Pager code, rodata and data] : In correct location* [Init code and rodata] : Should be copied to __text_init_start* [Hashes] : Should be saved before initializing pager**/
/* 拷贝init section 到RAM中 */ldr r0, =__text_init_start /* dst */ldr r1, =__data_end /* src */ldr r2, =__tmp_hashes_end /* dst limit *//* Copy backwards (as memmove) in case we're overlapping */sub r2, r2, r0 /* len */add r0, r0, r2add r1, r1, r2ldr r2, =__text_init_start
copy_init:ldmdb r1!, {r3, r8-r12, sp}stmdb r0!, {r3, r8-r12, sp}cmp r0, r2bgt copy_init
#endif#ifdef CFG_CORE_SANITIZE_KADDRESS/* First initialize the entire shadow area with no access */ldr r0, =__asan_shadow_start /* start */ldr r1, =__asan_shadow_end /* limit */mov r2, #ASAN_DATA_RED_ZONE
shadow_no_access:str r2, [r0], #4cmp r0, r1bls shadow_no_access/* Mark the entire stack area as OK */ldr r2, =CFG_ASAN_SHADOW_OFFSETldr r0, =__nozi_stack_start /* start */lsr r0, r0, #ASAN_BLOCK_SHIFTadd r0, r0, r2ldr r1, =__nozi_stack_end /* limit */lsr r1, r1, #ASAN_BLOCK_SHIFTadd r1, r1, r2mov r2, #0
shadow_stack_access_ok:strb r2, [r0], #1cmp r0, r1bls shadow_stack_access_ok
#endifset_sp/* complete ARM secure MP common configuration */bl plat_cpu_reset_late //完成ARM安全内存保护的基本配置/* Enable Console */bl console_init //初始化串口#ifdef CFG_PL310bl pl310_basebl arm_cl2_config
#endif/** Invalidate dcache for all memory used during initialization to* avoid nasty surprices when the cache is turned on. We must not* invalidate memory not used by OP-TEE since we may invalidate* entries used by for instance ARM Trusted Firmware.*/
/* 无效cache操作 */
#ifdef CFG_WITH_PAGERinval_cache_vrange(__text_start, __tmp_hashes_end)
#elseinval_cache_vrange(__text_start, __end)
#endif#ifdef CFG_PL310/* Enable PL310 if not yet enabled */bl pl310_basebl arm_cl2_enable
#endifbl core_init_mmu_map //初始化MMU的内存映射表bl core_init_mmu_regs //初始化MMU中的寄存器映射bl cpu_mmu_enable //使能MMUbl cpu_mmu_enable_icache //使能指令cachebl cpu_mmu_enable_dcache //使能data cachemov r0, r4 /* pageable part address */mov r1, r5 /* ns-entry address */mov r2, r6 /* DT address */
/* 执行主要初始化操作,带入page part 地址,linux kernel入口地址, DT地址 */bl generic_boot_init_primary mov r4, r0 /* save entry test vector *//** In case we've touched memory that secondary CPUs will use before* they have turned on their D-cache, clean and invalidate the* D-cache before exiting to normal world.*/
/* 清空cache */
#ifdef CFG_WITH_PAGERflush_cache_vrange(__text_start, __init_end)
#elseflush_cache_vrange(__text_start, __end)
#endif/* release secondary boot cores and sync with them */
/* 同步从核的启动 */cpu_is_readyflush_cpu_semaphoreswait_secondary#ifdef CFG_PL310_LOCKED/* lock/invalidate all lines: pl310 behaves as if disable */bl pl310_basebl arm_cl2_lockallwaysbl pl310_basebl arm_cl2_cleaninvbyway
#endif/** Clear current thread id now to allow the thread to be reused on* next entry. Matches the thread_init_boot_thread() in* generic_boot.c.*/bl thread_clr_boot_thread //清空当前线程的ID值,以备被重新使用#if defined(CFG_WITH_ARM_TRUSTED_FW)/* Pass the vector address returned from main_init */mov r1, r4
#else/* realy standard bootarg #1 and #2 to non secure entry */mov r4, #0mov r3, r6 /* std bootarg #2 for register R2 */mov r2, r7 /* std bootarg #1 for register R1 */mov r1, #0
#endif /* CFG_WITH_ARM_TRUSTED_FW *//* 触发smc调用,如果支持ATF,则返回TEESMC_OPTEED_RETURN_ENTRY_DONE的值到EL3中,通知ATF OPTEE已经启动完成。如果不支持ATF,则同样触发smc调用,切换到no-secure world状态进行linux kernel的启动 */mov r0, #TEESMC_OPTEED_RETURN_ENTRY_DONEsmc #0b . /* SMC should not return */
UNWIND( .fnend)
END_FUNC reset_primaryLOCAL_FUNC unhandled_cpu , :
UNWIND( .fnstart)wfib unhandled_cpu
UNWIND( .fnend)
END_FUNC unhandled_cpu#if defined(CFG_WITH_ARM_TRUSTED_FW)
FUNC cpu_on_handler , :
UNWIND( .fnstart)
UNWIND( .cantunwind)mov r4, r0mov r5, r1mov r6, lrread_sctlr r0orr r0, r0, #SCTLR_Awrite_sctlr r0ldr r0, =_startwrite_vbar r0mov r4, lrset_spbl core_init_mmu_regsbl cpu_mmu_enablebl cpu_mmu_enable_icachebl cpu_mmu_enable_dcachemov r0, r4mov r1, r5bl generic_boot_cpu_on_handlerbx r6
UNWIND( .fnend)
END_FUNC cpu_on_handler#else /* defined(CFG_WITH_ARM_TRUSTED_FW) *//* 从核的启动函数 */
LOCAL_FUNC reset_secondary , :
UNWIND( .fnstart)
UNWIND( .cantunwind)wait_primaryset_spbl plat_cpu_reset_late#if defined (CFG_BOOT_SECONDARY_REQUEST)/* if L1 is not invalidated before, do it here */bl arm_cl1_d_invbysetway
#endifbl core_init_mmu_regsbl cpu_mmu_enablebl cpu_mmu_enable_icachebl cpu_mmu_enable_dcachecpu_is_ready#if defined (CFG_BOOT_SECONDARY_REQUEST)/* generic_boot_core_hpen return value (r0) is ns entry point */bl generic_boot_core_hpen
#elsemov r0, r5 /* ns-entry address */
#endifbl generic_boot_init_secondarymov r0, #TEESMC_OPTEED_RETURN_ENTRY_DONEmov r1, #0mov r2, #0mov r3, #0mov r4, #0smc #0b . /* SMC should not return */
UNWIND( .fnend)
END_FUNC reset_secondary
#endif /* defined(CFG_WITH_ARM_TRUSTED_FW) */
10.OP-TEE OS启动(一)相关推荐
- Android手机启动流程与TEE OS
2019独角兽企业重金招聘Python工程师标准>>> 转载:https://cloud.tencent.com/developer/article/1043659 一个移植了TEE ...
- 【CA-TA实战系列六】CA与TA背后的故事一:TEE OS
一.前言 TEE OS就是可信环境的操作系统,这里我们的参考资料是前辈的<手机安全和可信应用开发指南>,因此这里我们的TEE OS就是OP TEE. 那么为什么在搞TA CA的设计实现要关 ...
- TEE OS中断篇(五):FIQ的事件处理
到上一篇的时候,CPU已经具备了执行下一步handler的上下文,推出了EL3,进军了EL1,这里来看看在tee os里面到底干了啥? 1 OP-TEE对FIQ事件的处理 OP-TEE启动时会调用th ...
- 《深入理解Spark:核心思想与源码分析》——3.10节创建和启动ExecutorAllocationManager...
本节书摘来自华章社区<深入理解Spark:核心思想与源码分析>一书中的第3章,第3.10节创建和启动ExecutorAllocationManager,作者耿嘉安,更多章节内容可以访问云栖 ...
- uboot启动流程概述_Alibaba Cloud Linux 2 LTS OS 启动优化实践
Alibaba Cloud Linux 2 (原Aliyun Linux 2)是阿里云操作系统团队基于社区版 4.19 LTS 内核打造的一款针对云产品优化的下一代 Linux 操作系统发行版,不仅提 ...
- 在linux oracle 10g/11g x64bit环境中,goldengate随os启动而自己主动启动的脚本
在linux oracle 10g/11g x64bit环境中,goldengate随os启动而自己主动启动的脚本 在linux.oracle 10g/11g x64bit环境中,goldengate ...
- 10.2.0.5启动enterprise manager
10.2.0.5启动enterprise manager OEM作为一个实用工具,随着10g和11g的普及,OEM功能越来越强大,oem也应用越来越广泛.但是如果是10.2.0.5的版本,并且安装时间 ...
- 修改weblogic(10.3)域的启动JDK
修改weblogic(10.3)域的启动JDK 说明: 1.D:\bea为笔者weblogic安装目录 2.D:\bea\user_projects\domains\base_domain为笔者域创建 ...
- Windows 10和Linux脚本启动jar包服务器,并设置开机启动
Windows 10和Linux脚本启动jar包服务器,并设置开机启动 现在好多Java服务和应用都是用jar启动,jar打包成的里面会直接带有tomcat,所以可以直接启动,但是如何通过脚本启动并且 ...
最新文章
- 再见了SpringMVC,这个框架有点厉害,甚至干掉了Servlet!
- 安装Mysql提示1045错误解决方法
- 软考广东有哪几个考点
- JavaScript面向对象——封装及相关原理解析
- matlab207a,MATLAB教程R2012a课后习题答案
- 使用 ExecuteMultiple 提高批量数据加载的性能
- linux指令ls -1,linux命令1--ls
- 云单元架构,如何赋能数字化转型呢?
- 想将有色彩的视频进行去色处理就这样做
- 优质文章推荐(第一期)
- php 公众号推送图片尺寸,微信公众号推送文图片什么尺寸最佳?
- Select at least one project的解决方法
- Pytorch报错解决:The size of tensor a (4) must match the size of tensor b (3) at non-singleton dimensio
- jQuery-放大镜
- 【转】韩寒:跳出棋盘的棋子
- NodeBB – 基于 Node.js 的开源论坛系统
- 花式登录正方教务系统
- 数学乐 --- 科学计数法(个人学习笔记)
- Nacos微服务注册发现、配置和管理微服务
- 单片机c语言p1口转弯灯实验,单片机p1口转弯灯实验程序
热门文章
- ipad wifi信号测试软件,真香!平板Ipad无线投屏在电视上视频教程分享,无需装软件,支持任何显示设备...
- Vert.x -- web的介绍(三)
- mysql数据库 二次开发_Dedesql数据库类详解(二次开发必备教程)
- (一)老毛桃U盘启动盘制作
- 可以帮我做一个python的3D飞机小游戏吗
- 【融职培训】Web前端学习 第3章 JavaScript基础教程18 BOM概述
- MFC关于进程使用:创建、关闭及查询进程
- adobe air 工程师_基于HTML的Adobe AIR应用程序的新窗口
- String你真的会吗?不会还不进来!!!是等我胖虎锤各位呢?!!!
- 汇编语言 | 基础知识