安全引导功能及ATF的启动过程(四)

ATF中bl31的启动

在bl2中触发安全监控模式调用后会跳转到bl31中执行,bl31最主要的作用是建立EL3运行态的软件配置,在该阶段会完成各种类型的安全监控模式调用ID的注册和对应的ARM核状态的切换,bl31运行在EL3。bl31的执行流程如图所示。

在这里插入图片描述

bl31_entrypoint函数

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

/root/optee/trusted-firmware-a/bl31/bl31.ld.S

OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
ENTRY(bl31_entrypoint)

/root/optee/trusted-firmware-a/bl31/aarch64/bl31_entrypoint.S

func bl31_entrypoint/* ---------------------------------------------------------------* Stash the previous bootloader arguments x0 - x3 for later use.* ---------------------------------------------------------------*///保存x0/x1/x2/x3寄存器中的值 mov     x20, x0mov     x21, x1mov     x22, x2mov     x23, x3#if !RESET_TO_BL31//根据是否启用了RESET_TO_BL31参数为el3_entrypoint_common传入不同参数// RESET_TO_BL31=y 系统复位后直接进入 BL31// RESET_TO_BL31=n BL31 是由前一级(如 BL2)加载并跳转进来的/* ---------------------------------------------------------------------* 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 initialised the* SCTLR_EL3, including the endianness, and has initialised the memory.* ---------------------------------------------------------------------*///  不进行初始化类操作el3_entrypoint_common                                   \_init_sctlr=0                                   \_warm_boot_mailbox=0                            \_secondary_cold_boot=0                          \_init_memory=0                                  \_init_c_runtime=1                               \//设置 EL3 异常向量               _exception_vectors=runtime_exceptions           \_pie_fixup_size=BL31_LIMIT - BL31_BASE
#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                                   \_init_sctlr=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           \_pie_fixup_size=BL31_LIMIT - BL31_BASE
#endif /* RESET_TO_BL31 *//* --------------------------------------------------------------------* Perform BL31 setup* --------------------------------------------------------------------*///恢复x0/x1/x2/x3数据,配置bl31mov     x0, x20mov     x1, x21mov     x2, x22mov     x3, x23bl      bl31_setup#if ENABLE_PAUTH/* --------------------------------------------------------------------* Program APIAKey_EL1 and enable pointer authentication* --------------------------------------------------------------------*///执行指针认证初始化 bl      pauth_init_enable_el3
#endif /* ENABLE_PAUTH *//* --------------------------------------------------------------------* Jump to main function* --------------------------------------------------------------------*/// 执行bl31_mainbl      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.* --------------------------------------------------------------------*///清理数据段和 未初始化的全局变量和静态变量段adrp    x0, __DATA_START__add     x0, x0, :lo12:__DATA_START__adrp    x1, __DATA_END__add     x1, x1, :lo12:__DATA_END__sub     x1, x1, x0bl      clean_dcache_rangeadrp    x0, __BSS_START__add     x0, x0, :lo12:__BSS_START__adrp    x1, __BSS_END__add     x1, x1, :lo12:__BSS_END__sub     x1, x1, x0bl      clean_dcache_rangeb       el3_exit
endfunc bl31_entrypoint         

bl31_main函数

该函数主要完成必要的初始化操作,注册EL3中各种安全监控模式调用的处理函数,以便在启动完成后响应在REE侧和TEE侧产生的安全监控模式调用。该函数的内容如下:

/root/optee/trusted-firmware-a/bl31/bl31_main.c

//BL31 负责为启动 CPU 设置运行时服务,然后将控制权移交给引导加载程序或操作系统。
//该函数调用 runtime_svc_init(),该函数会初始化所有已注册的运行时服务。
//这些运行时服务会为处理器核心切换到下一个异常级别建立足够的上下文环境。
//当该函数返回后,核心将通过 ERET 指令切换到已设定的异常级别。
void bl31_main(void)
{/* Init registers that never change for the lifetime of TF-A *///初始化在 TF-A 生命周期内永不更改的寄存器。cm_manage_extensions_el3(plat_my_core_pos());/* Init per-world context registers for non-secure world */// 设置那些会在 安全世界(Secure)与非安全世界之间切换时需要恢复的寄存器manage_extensions_nonsecure_per_world();NOTICE("BL31: %s\n", build_version_string);NOTICE("BL31: %s\n", build_message);#if FEATURE_DETECTION/* Detect if features enabled during compilation are supported by PE. *///检测在编译期间启用的功能是否被处理器单元(PE)所支持detect_arch_features();
#endif /* FEATURE_DETECTION */#if ENABLE_RUNTIME_INSTRUMENTATION//运行时性能检测PMF_CAPTURE_TIMESTAMP(bl_svc, BL31_ENTRY, PMF_CACHE_MAINT);
#endif#ifdef SUPPORT_UNKNOWN_MPID//处理未知的 MPID(多核标识)if (unsupported_mpid_flag == 0) {NOTICE("Unsupported MPID detected!\n");}
#endif/* Perform platform setup in BL31 *///平台相关设置bl31_platform_setup();#if USE_GIC_DRIVER/** Initialize the GIC driver as well as per-cpu and global interfaces.* Platform has had an opportunity to initialise specifics.*///初始化 GIC unsigned int core_pos = plat_my_core_pos();gic_init(core_pos);   //初始化 GIC 分发器gic_pcpu_init(core_pos);   //初始化当前 CPU 的中断接口gic_cpuif_enable(core_pos);     //使能当前 CPU 的中断接收
#endif /* USE_GIC_DRIVER *//* Initialise helper libraries *///初始化辅助库bl31_lib_init();#if EL3_EXCEPTION_HANDLING//初始化异常处理框架(EXCEPTION_HANDLING_FRAMEWORK) INFO("BL31: Initialising Exception Handling Framework\n");ehf_init();
#endif/* Initialize the runtime services e.g. psci. *///初始化运行时服务,如PSCI// PSCI(Power State Coordination Interface):负责 CPU 启动、关闭、挂起等// SPD(Secure Payload Dispatcher):调度 OP-TEE(BL32)// SPMC(Secure Partition Manager Component):用于 FF-A 架构// RMM(Realm Management Monitor):用于 CCA(Confidential Compute Architecture)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 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 initialize bl32 where it takes responsibility of entering* S-EL1 and returning control back to bl31_main. Similarly, if RME is* enabled and a function is registered to initialize RMM, control is* transferred to RMM in R-EL2. After RMM initialization, control is* returned back to bl31_main. Once this is done we can prepare entry* into BL33 as normal.*///所有在主 CPU 上的冷启动操作已经完成。//我们现在需要决定下一个要运行的镜像以及如何执行它。//如果存在 SPD(Secure Payload Dispatcher)运行时服务,//它会希望先将控制权交给运行在 S-EL1 的 BL32。//在这种情况下,SPD 会注册一个用于初始化 BL32 的函数,//该函数负责进入 S-EL1 并在完成后将控制权交还给 bl31_main。//同样地,如果启用了 RME(Realm Management Extension)//并注册了用于初始化 RMM(Realm Management Monitor)的函数,//则会将控制权转移到运行在 R-EL2 的 RMM。RMM 初始化完成后,//控制权也会返回到 bl31_main。完成这些步骤后,我们就可以像往常一样准备进入 BL33。// S-EL安全世界 中运行的异常等级。// R-EL普通世界 中运行的异常等级。/** If SPD had registered an init hook, invoke it.*/if (bl32_init != NULL) {INFO("BL31: Initializing BL32\n");console_flush();int32_t rc = (*bl32_init)();if (rc == 0) {WARN("BL31: BL32 initialization failed\n");}}/** If RME is enabled and init hook is registered, initialize RMM* in R-EL2.*/
#if ENABLE_RMEif (rmm_init != NULL) {INFO("BL31: Initializing RMM\n");console_flush();int32_t rc = (*rmm_init)();if (rc == 0) {WARN("BL31: RMM initialization failed\n");}}
#endif/** We are ready to enter the next EL. Prepare entry into the image* corresponding to the desired security state after the next ERET.*///我们已经准备好进入下一个异常级别。//请准备在下一次 ERET 指令后,进入对应目标安全状态的镜像 bl31_prepare_next_image_entry();/** Perform any platform specific runtime setup prior to cold boot exit* from BL31*/// 在从 BL31 冷启动退出之前,执行任何必要的平台特定运行时设置bl31_plat_runtime_setup();#if ENABLE_RUNTIME_INSTRUMENTATIONconsole_flush();  //运行时性能检测PMF_CAPTURE_TIMESTAMP(bl_svc, BL31_EXIT, PMF_CACHE_MAINT);
#endif//切换控制台状态并刷新输出console_flush();console_switch_state(CONSOLE_FLAG_RUNTIME);  //将控制台切换到“运行时”模式
}

runtime_svc_init函数会将各种安全监控模式调用的处理函数的指针注册到EL3中,并通过service init函数来进行初始化,将TEE OS镜像的入口函数赋值给bl32_init,通过执行bl32_init指向的函数进入到TEE OS的启动过程。待TEE OS启动完成之后就会去查找bl33的镜像文件,即REE侧的镜像文件,开始进入REE侧镜像的启动。

runtime_svc_init函数

该函数主要用来建立安全监控模式调用处理函数的索引表,并执行EL3中提供的服务项的初始化操作,获取TEE OS的入口地址并赋值给bl32_init变量,以备启动TEE OS。而这些处理函数是通过DECLARE_RT_SVC宏定义被编译到镜像文件的rt_svc_descs段中的。

/root/optee/trusted-firmware-a/common/runtime_svc.c

void __init runtime_svc_init(void)
{int rc = 0;uint8_t index, start_idx, end_idx;rt_svc_desc_t *rt_svc_descs;/* Assert the number of descriptors detected are less than maximum indices *///检查是否描述符的结束地址 ≥ 开始地址//检查是否注册的服务数量 < 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 == 0U) {return;}/* Initialise internal variables to invalid state *///初始化内部变量为无效状态(void)memset(rt_svc_descs_indices, -1, sizeof(rt_svc_descs_indices));//获取服务描述符数组指针rt_svc_descs = (rt_svc_desc_t *) RT_SVC_DESCS_START;for (index = 0U; 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.*///检查描述符是否合法rc = validate_rt_svc_desc(service);if (rc != 0) {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 yielding 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.*///调用服务初始化函数(如果存在) if (service->init != NULL) {rc = service->init();if (rc != 0) {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.*/// 为每个服务分配一个OEN范围,用来处理所有的SMC调用start_idx = (uint8_t)get_unique_oen(service->start_oen,service->call_type);end_idx = (uint8_t)get_unique_oen(service->end_oen,service->call_type);assert(start_idx <= end_idx);assert(end_idx < MAX_RT_SVCS);//填充查找表for (; start_idx <= end_idx; start_idx++) {rt_svc_descs_indices[start_idx] = index;}}
}                

DECLARE_RT_SVC

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

/root/optee/trusted-firmware-a/include/common/runtime_svc.h

/** Convenience macros to declare a service descriptor*/
// ##:将 __svc_desc_ 和 _name 拼接成一个唯一变量名。
// #:将 __svc_desc_ 和 _name 拼接成一个唯一变量名。 
// .rt_svc_descs: 将该变量放入名为 .rt_svc_descs 的自定义链接段(section)中。
// __used:告诉编译器“这个变量虽然可能没被显式引用,但也别优化掉”
#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的起始内部编号
  • end.oen:该service的末尾编号
  • call_type:调用的smc的类型
  • name:该service的名字
  • init:该service在执行之前需要被执行的初始化操作
  • handle:当触发了call type的调用时调用的处理该请求的函数

REE侧镜像文件的启动

在bl31_main中启动完TEE OS之后通过调用bl31_prepare_next_image_entry函数来获取下一个阶段需要被加载的镜像文件,即REE侧的镜像文件,并配置好REE侧镜像的运行环境。bl31_main执行完成之后会跳转到bl31_entrypoint中继续执行,计算出需要被加载的镜像文件的数据段大小和起始地址并清空BSS端中的数据,从EL3进入到EL1-NS开始执行REE侧的代码。

TEE侧的加载在bl31_prepare_next_image_entry前,通过runtime_svc_init初始化的函数进行加载,将在下一节进行介绍。

参考资料:

  • 《手机安全和可信应用开发指南:TrustZone与OP-TEE技术详解》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/92584.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/92584.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/92584.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从手工到智能决策,ERP让制造外贸企业告别“数据孤岛“降本增效

在全球化竞争加剧的当下&#xff0c;制造型外贸企业正面临订单碎片化、供应链复杂化、合规风险上升等多重挑战。数字化转型已成为企业突破增长瓶颈、构建核心竞争力的必选项。然而&#xff0c;许多企业在推进过程中因选型不当陷入“系统孤岛”“数据失真”“流程低效”等困境。…

DMETL简单介绍、安装部署和入门尝试

一、DMETL的介绍1.1 概述我们先来简单了解一下DMETL。DMETL是什么&#xff1f;说的简单一点&#xff0c;DMETL一款数据处理与集成平台&#xff1b;从功能来说&#xff0c;那DMETL就是对数据同步、数据处理以及数据交换共享提供一站式支持的平台&#xff1b;从它的意义来说&…

NLP 人工智能 Seq2Seq、K-means应用实践

基于Java和人工智能的Web应用 以下是基于Java和人工智能的Web应用实例,涵盖自然语言处理、计算机视觉、数据分析等领域。这些案例结合了沈七星AI或其他开源框架(如TensorFlow、Deeplearning4j)的实现思路,供开发参考: 自然语言处理(NLP) 1. 智能客服系统 使用Java的Op…

Docker 从入门到实战(一):全面解析容器化革命 | 2025 终极指南

2025 年,全球容器市场规模突破 200 亿美元,超过 80% 的企业生产环境运行在容器之上。掌握 Docker 已成为开发、运维乃至架构师的核心竞争力。本文带你彻底搞懂 Docker 的底层逻辑与核心价值! 一、Docker 是什么?为什么它能改变世界? 想象一下:你开发时运行完美的 Pytho…

Lazada东南亚矩阵营销破局:指纹手机如何以“批量智控+数据中枢”重构运营生态

在Lazada以“超级APP”战略渗透东南亚6国市场的进程中&#xff0c;商家正陷入一个结构性矛盾&#xff1a;如何用有限人力高效管理10个国家账号&#xff0c;却不被数据孤岛拖垮营销效率&#xff0c;更不因账号关联风险引发平台封禁&#xff1f;传统多账号运营依赖“人手一台设备…

操作系统: 线程(Thread)

目录 什么是线程&#xff08;Thread&#xff09;&#xff1f; 线程与进程之间的关系 线程调度与并发执行 并发&#xff08;Concurrency&#xff09;与并行&#xff08;Parallelism&#xff09; 多线程编程的四大核心优势&#xff08;benefits of multithreaded programmin…

Uber的MySQL实践(一)——学习笔记

MySQL 是Uber数据基础设施的核心支柱&#xff0c;支撑着平台上大量关键操作。Uber 拥有一套庞大的 MySQL 集群&#xff0c;如何构建一个控制平面来管理如此大规模的 MySQL 集群&#xff0c;并同时确保零宕机、零数据丢失是一个十分有挑战性的问题。下面重点介绍 Uber 的 MySQL …

腾讯云EdgeOne产品深度分析报告

一、产品概述腾讯云EdgeOne是腾讯云推出的新一代边缘安全加速平台&#xff0c;集成内容分发网络&#xff08;CDN&#xff09;、Web应用防火墙&#xff08;WAF&#xff09;、DDoS防护、Bot管理、API安全及边缘计算能力&#xff0c;致力于为企业提供一站式安全加速解决方案。该平…

Spring Boot 优雅配置InfluxDB3客户端指南:@Configuration + @Bean + yml实战

前言 想用Java玩转InfluxDB 3?要是还靠写main函数硬编码配置,那就像穿着睡衣开正式会议,实在有点不靠谱。现代Spring开发套路讲究配置和代码分离,讲究优雅和灵活。用@Configuration配合@Bean注解,再加上yml配置文件集中管理连接信息,简直是为代码打扮一身西装,既整洁又…

记录:rk3568适配开源GPU驱动(panfrost)

rk3568采用的GPU是Mali-G52&#xff0c;该型号的GPU已在5.10内核的panfrost驱动中被支持。下面记录下移植过程。 1.内核dts修改&#xff1a; kernel 5.10: arch/arm64/boot/dts/rockchip/rk3568.dtsigpu: gpufde60000 {compatible "rockchip,rk3568-mali", "ar…

SMBIOS详解:系统管理BIOS的工作原理与实现

1. SMBIOS概述 SMBIOS&#xff08;System Management BIOS&#xff09;是由DMTF&#xff08;分布式管理任务组&#xff09;制定的行业标准&#xff0c;旨在为计算机系统提供统一的硬件信息描述框架。它定义了计算机硬件组件&#xff08;如处理器、内存、主板等&#xff09;的标…

8.5 CSS3多列布局

多列布局 CSS3之多列布局columns CSS3中新出现的多列布局(multi-column)是传统HTML网页中块状布局模式的有力扩充。这种新语法能够让WEB开发人员轻松的让文本呈现多列显示。 设置列宽 column-width&#xff1a; | auto 设置对象的宽度&#xff1b;使用像素表示。 auto&#…

Chrome插件快速上手

目录 前言 一、浏览器插件的主要功能 二、插件的工作原理 插件结构 manifest.json icons background.js content-scripts 三、插件例子 popup popup.html popup.js styles.css background.js content-script.js manifest.json 四、其它 前言 本文不做特殊说明…

moment和dayjs

一&#xff1a;moment和dayjs 区别moment 大且可变、维护模式&#xff1b;dayjs 小且不可变、插件化、tree‑shaking 友好。antd v4 用 moment&#xff1b;antd v5 用 dayjs。请在同一项目中统一其一&#xff0c;避免混用导致组件报错。二&#xff1a; antd 4.24.16&#xff08…

Flutter Packge - 组件应用

一、组件创建1. 在工程根目录创建 packages 目录。mkdir packages #创建文件夹 cd packages 2. 创建纯 Dart Package&#xff08;适合工具类/UI组件&#xff09;。flutter create --templatepackage common_network二、组件配置1. 在 common_network 的 pubspec.yaml 中添加…

基于双块轻量级神经网络的无人机拍摄的风力涡轮机图像去雾方法

基于双块轻量级神经网络的无人机拍摄的风力涡轮机图像去雾方法 UAV-Taken Wind Turbine Image Dehazing With a Double-Patch Lightweight Neural Network 我是菜鸡&#xff01;我是菜鸡&#xff01;我是菜鸡&#xff01; 如果老师及学姐学长对该文有任何意见&#xff0c;请…

Spring AI Alibaba 项目接入阿里云百炼平台大模型

1 依赖jdk 21 springboot 3.4.5 spring-ai-alibaba-starter-dashscope 1.0.0.2<properties><java.version>21</java.version><spring-ai.version>1.0.0</spring-ai.version><spring-ai-alibaba.version>1.0.0.2</spring-ai-alibaba.v…

电脑和手机访问网站,自动检测跳转不同网站

自动检测跳转不同网站 自动检测设备手机或电脑来跳转不同网页 开箱即用&#xff0c;不过需要自己修改一下跳转链接 源码截图&#xff1a; 下载地址&#xff1a;电脑和手机访问网站&#xff0c;自动检测跳转不同网站.zip - 蓝奏云

Spring Boot 集成 ShardingSphere 实现读写分离实践

Spring Boot 集成 ShardingSphere 实现读写分离实践 在高并发的业务场景中,数据库往往是系统性能的瓶颈。为了提高系统的吞吐量和稳定性,读写分离是一种常见的优化方案。本文将详细介绍如何使用 Spring Boot 结合 ShardingSphere 实现数据库的读写分离,并提供完整的配置和实…

以rabbitmq为例演示podman导出导入镜像文件

1. 导出镜像为 tar 文件 将镜像保存为压缩包&#xff08;默认格式为 docker-archive&#xff09;&#xff1a; podman save -o rabbitmq_management.tar docker.io/rabbitmq:management-o&#xff1a;指定输出文件名&#xff08;如 rabbitmq_management.tar&#xff09;。镜像名…