news 2026/6/25 17:55:17

TEE-OS学习轨迹第十九篇:OP-TEE OS的启动流程:从冷热启动到SMC服务

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
TEE-OS学习轨迹第十九篇:OP-TEE OS的启动流程:从冷热启动到SMC服务
OP-TEE OS AArch64 架构的复位入口与早期启动核心(对应源码路径 core/arch/arm/kernel/entry_a64.S),它定义了所有 CPU 进入 OP-TEE 的第一站:主 CPU 冷启动走 _start 全量初始化,次级 CPU 热启动走 cpu_on_handler 本地初始化,同时包含 S-EL1 本地硬件异常向量表、MMU 开启、地址重定位、安全特性初始化等底层能力。
下面结合这份源码,联动ATF OPTEED侧逻辑,分主 CPU 冷启动全链路、次级 CPU 热启动全链路、运行时 SMC 服务唤醒全链路三条路径,做源码级逐阶段拆解。

前置核心区分:两套向量表的分工

在进入流程前,先彻底厘清两份汇编文件的定位与分工,这是理解所有跳转的基础:
向量表/入口
所在文件
作用
调用时机
reset_vect_table
entry_a64.S
S-EL1 本地硬件异常向量表,写入VBAR_EL1,由 CPU 硬件识别,处理 S-EL1 内部的同步异常、IRQ、FIQ、SError
启动初期配置,OP-TEE 运行全程生效
thread_vector_table
thread_optee_smc_a64.S
交付给 ATF 的软件约定向量表,纯函数跳转表,是 EL3 切入 OP-TEE 业务的统一入口
冷启动完成后交付 ATF,运行时业务调用、电源管理、中断处理使用
_start
entry_a64.S
主 CPU 冷启动唯一入口,完成完整内核环境搭建
系统上电后仅执行 1 次
cpu_on_handler
entry_a64.S
次级 CPU 热启动入口,仅完成 CPU 本地硬件初始化
每个次级 CPU 上电时执行 1 次
简单说:冷启动全链路的reset_vect_table“把 OP-TEE 从无到有跑起来”,线程向量表负责“跑起来之后处理日常业务”

一、主 CPU 冷启动全链路(OPTEED ↔ OP-TEE 双向完整流程)

冷启动是 EL3 主动发起的一次性全量初始化流程:ATF BL31 构造异常现场,通过 ERET 跳入 OP-TEE 的 _start,OP-TEE 完成从裸机到完整内核的所有初始化,最终通过 SMC 交付向量表,回到 EL3 建立运行时调用通路。

阶段 1:OPTEED 侧构造异常现场,发起跳转

对应 ATF 代码:opteed_setup()opteed_init()opteed_synchronous_sp_entry()

1.BL2 已将 OP-TEE 镜像加载到安全物理内存,BL31 通过 bl31_plat_get_next_image_ep_info 拿到 OP-TEE 的入口物理地址(即 _start 的物理地址)。

2.OPTEED 调用 opteed_init_optee_ep_state 构造 S-EL1 上下文:

  • 将 _start 物理地址写入安全上下文的 ELR_EL3
  • 配置 SPSR_EL3 为 S-EL1 特权级、AArch64 模式、中断屏蔽
  • 启动参数(架构位数、内存范围、DTB 地址)写入 x0~x3

3.执行 eret 指令:硬件自动将上下文恢复到寄存器,特权级从 EL3 降到 S-EL1,PC 跳转到 _start。

「伪造异常现场」:ERET 硬件语义是“返回异常发生前的状态”,但冷启动时没有真实异常发生,软件手动填充 ELR_EL3/SPSR_EL3 模拟出异常现场,骗过硬件实现降权跳转。

阶段 2:OP-TEE 汇编级最早期初始化(_start前半段,MMU 开启前)

CPU 进入 _start 后,此时 MMU 未开启、栈未就绪、C 语言环境不可用,仅能通过汇编完成最小硬件准备。
2.1 启动参数暂存 + 本地异常向量表配置
LOCAL_FUNC reset_vect_table , :, .identity_map, , nobti /* ----------------------------------------------------- * Current EL with SP0 : 0x0 - 0x180 * ----------------------------------------------------- */ SynchronousExceptionSP0: b SynchronousExceptionSP0 check_vector_size SynchronousExceptionSP0 .align 7 IrqSP0: b IrqSP0 check_vector_size IrqSP0 .align 7 FiqSP0: b FiqSP0 check_vector_size FiqSP0 .align 7 SErrorSP0: b SErrorSP0 check_vector_size SErrorSP0 /* ----------------------------------------------------- * Current EL with SPx: 0x200 - 0x380 * ----------------------------------------------------- */ .align 7 SynchronousExceptionSPx: b SynchronousExceptionSPx check_vector_size SynchronousExceptionSPx .align 7 IrqSPx: b IrqSPx check_vector_size IrqSPx .align 7 FiqSPx: b FiqSPx check_vector_size FiqSPx .align 7 SErrorSPx: b SErrorSPx check_vector_size SErrorSPx /* ----------------------------------------------------- * Lower EL using AArch64 : 0x400 - 0x580 * ----------------------------------------------------- */ .align 7 SynchronousExceptionA64: b SynchronousExceptionA64 check_vector_size SynchronousExceptionA64 .align 7 IrqA64: b IrqA64 check_vector_size IrqA64 .align 7 FiqA64: b FiqA64 check_vector_size FiqA64 .align 7 SErrorA64: b SErrorA64 check_vector_size SErrorA64 /* ----------------------------------------------------- * Lower EL using AArch32 : 0x0 - 0x180 * ----------------------------------------------------- */ .align 7 SynchronousExceptionA32: b SynchronousExceptionA32 check_vector_size SynchronousExceptionA32 .align 7 IrqA32: b IrqA32 check_vector_size IrqA32 .align 7 FiqA32: b FiqA32 check_vector_size FiqA32 .align 7 SErrorA32: b SErrorA32 check_vector_size SErrorA32 END_FUNC reset_vect_table FUNC _start , : /* * Temporary copy of boot argument registers, will be passed to * boot_save_args() further down. */ mov x19, x0 mov x20, x1 mov x21, x2 mov x22, x3 adr x0, reset_vect_table msr vbar_el1, x0 isb #ifdef CFG_PAN init_pan #endif set_sctlr_el1 isb #ifdef CFG_WITH_PAGER
  • 将 ATF 传入的 4 个启动参数暂存到 x19~x22(callee-saved 寄存器,C 函数不会破坏),后续传递给 C 初始化函数。
  • 配置 S-EL1 本地硬件异常向量表 reset_vect_table 到 VBAR_EL1。此时向量表中所有入口都是死循环(b .),仅做异常兜底,防止启动早期异常导致 CPU 跑飞;后续内核初始化完成后会替换为完整异常处理。
2.2 早期系统寄存器与安全特性配置
#ifdef CFG_PAN init_pan #endif set_sctlr_el1 isb
  • init_pan:开启 ARMv8.1 PAN(Privileged Access Never)特权访问永不特性,防止 S-EL1 特权态意外访问用户态内存,阻断权限提升攻击路径。
  • set_sctlr_el1:配置 SCTLR_EL1 系统寄存器,开启:
    • 指令缓存(SCTLR_I)、栈对齐检查(SCTLR_SA)
    • 可选项:WXN 写区域不可执行、地址对齐检查、MTE 内存标签、BTI 分支目标校验从启动最早期就开启内存保护与执行保护,缩小攻击面。
2.3 镜像布局修正与内存清零
这是启动最核心的底层准备之一:OP-TEE 镜像尾部携带了初始化代码、嵌入数据(TA 哈希、重定位表等),需要搬运到正确的内存位置,并清零 BSS 段。
#ifdef CFG_WITH_PAGER /* 带页交换机制:拷贝init段到__init_start,暂存哈希数据 */ adr x0, __init_start /* dst */ adr x1, __data_end /* src */ ... copy_init: ldp x3, x4, [x1, #-16]! stp x3, x4, [x0, #-16]! cmp x0, x2 shtu copy_init #else /* 无页交换:将嵌入数据搬到内核空闲内存尾部 */ ... #endif /* 清零BSS段 */ adr_l x0, __bss_start adr_l x1, __bss_end clear_bss: str xzr, [x0], #8 cmp x0, x1 b.lt clear_bss
  • 镜像编译时,初始化代码、嵌入数据会追加在镜像尾部,启动时必须反向拷贝到链接脚本指定的虚拟地址位置,保证后续 C 代码访问全局变量、调用 init 函数时地址正确。
  • 清零 BSS 段:保证未初始化全局变量初值为 0,符合 C 语言标准,同时避免残留敏感数据。
2.4 物理重定位(可选)
若开启 CFG_CORE_PHYS_RELOCATABLE,OP-TEE 支持加载到任意物理地址,此时需要执行第一次重定位:
adr_l x2, core_mmu_tee_load_pa adr x1, _start str x1, [x2] mov_imm x0, TEE_LOAD_ADDR sub x0, x1, x0 cbz x0, 1f bl relocate 1:
  • 计算实际加载物理地址与编译默认地址的偏移,调用 relocate 函数遍历重定位表,修正所有绝对地址符号,保证物理地址下访问全局变量正确。
2.5 栈与线程核心本地结构初始化
C 语言运行必须有栈,这一步为当前 CPU 初始化两套栈与核心本地结构:
#if defined(CFG_DYN_CONFIG) /* 动态配置:分配临时栈与thread_core_local */ ... #else set_sp /* 初始化thread_core_local字段 */ bl thread_get_abt_stack ... #endif
  • set_sp 宏为每个 CPU 分配独立的栈:
    • SP_EL0:临时运行栈,用于早期 C 函数调用
    • SP_EL1:指向 thread_core_local 结构体,异常发生时自动切换到 SP_EL1,保存异常上下文,实现异常栈与业务栈隔离
  • 初始化 thread_core_local:标记当前无运行线程、设置临时栈标志,为后续线程调度做准备。
2.6 缓存与控制台初始化
/* 清理初始化内存的缓存一致性 */ adr_l x0, __text_start adr_l x1, boot_cached_mem_end ldr x1, [x1] sub x1, x1, x0 bl dcache_cleaninv_range /* 开启串口控制台 */ bl console_init /* 保存启动参数到C语言全局变量 */ mov x0, x19 mov x1, x20 mov x2, x21 mov x3, x22 mov x4, #0 bl boot_save_args
  • 刷写数据缓存:保证后续开启 MMU 后,内存与缓存数据一致,避免出现一致性问题。
  • 初始化调试串口:此后可以输出启动日志,进入可调试阶段。
  • 保存启动参数:将 x19~x22 暂存的参数写入全局变量,后续内核初始化全程使用。

阶段 3:内存管理初始化与 MMU 开启

这是冷启动的核心分界点:从物理地址恒等映射,切换到虚拟地址空间,开启完整内存保护。
3.1 内存布局与页表构建
bl boot_mem_init /* 初始化内存分配器,划分安全内存区域 */ #ifdef CFG_MEMTAG bl boot_init_memtag /* 初始化MTE内存标签框架 */ #endif /* 生成ASLR随机偏移 */ #ifdef CFG_CORE_ASLR bl get_aslr_seed ... #endif /* 构建S-EL1页表 */ adr x1, boot_mmu_config bl core_init_mmu_map
  • boot_mem_init:初始化内核内存分配器,划分代码段、数据段、堆、栈的内存范围,配置安全内存属性。
  • core_init_mmu_map:构建完整的 MMU 页表,配置各内存段的权限(只读、可读写、不可执行)、安全属性、缓存属性;若开启 ASLR,会随机化内核虚拟地址基址。
3.2 虚拟地址重定位(ASLR 场景)
若开启 ASLR,在 MMU 开启前先执行第二次重定位,修正虚拟地址偏移:
ldr x0, boot_mmu_config + CORE_MMU_CONFIG_MAP_OFFSET cbz x0, 1f bl relocate 1:
  • 读取页表中的虚拟地址偏移,再次调用 relocate 修正所有绝对地址,保证 MMU 开启后虚拟地址访问正确。
3.3 开启 MMU,完成地址空间切换
调用恒等映射段中的 enable_mmu 函数,这是从物理地址到虚拟地址的平滑切换核心:
bl __get_core_pos bl enable_mmu
enable_mmu 函数的核心执行逻辑:
  1. 写入 TCR_EL1、MAIR_EL1、TTBR0_EL1 等内存管理寄存器,加载页表基地址。
  2. 无效化 TLB,保证旧的地址翻译全部失效。
  3. 置位 SCTLR_EL1.M 开启 MMU,此时 PC 仍在恒等映射段,物理地址=虚拟地址,不会触发缺页。
  4. 更新 VBAR_EL1:加上虚拟地址偏移,修正异常向量表的虚拟地址。
  5. 无效化指令缓存与分支预测器,保证指令流一致性。
  6. 开启指令缓存与数据缓存。
  7. 修正栈指针与返回地址:SP_EL0、SP_EL1、LR 全部加上虚拟地址偏移,完成从物理栈到虚拟栈的切换。
  8. 返回:此时 PC 已经是虚拟地址,整个 CPU 正式运行在 S-EL1 虚拟地址空间。
这就是上一份代码中 readjust_pc 宏的背景:如果运行时从 EL3 切入时 PC 落在恒等映射地址,就需要修正到运行时虚拟地址;而冷启动是在 enable_mmu 中一次性完成了全量修正。

阶段 4:主 CPU 内核全量初始化(C 语言阶段)

MMU 开启后,OP-TEE 进入完整的 C 语言内核初始化,按分层顺序执行:
bl boot_init_primary_early /* 早期平台硬件初始化:时钟、GPIO、GIC、TZASC */ #ifdef CFG_MEMTAG init_memtag_per_cpu /* 本CPU开启MTE内存标签检查 */ #endif bl boot_init_primary_late /* 核心子系统初始化:调度器、加密框架、安全存储 */ bl boot_init_primary_runtime /* 运行时服务初始化:TA加载器、驱动框架 */ #ifdef CFG_CORE_PAUTH /* 开启指针认证PAUTH */ ... #endif bl boot_init_primary_final /* 收尾初始化:内置TA加载、服务注册 */
这一阶段完成后,OP-TEE 内核所有子系统就绪,可信服务能力全部可用。

阶段 5:初始化收尾,交付向量表,返回 EL3

5.1 收尾清理
/* 刷缓存,保证次级CPU上电时内存数据一致 */ adr_l x0, __text_start adr_l x1, boot_cached_mem_end ldr x1, [x1] sub x1, x1, x0 bl dcache_cleaninv_range /* 释放boot线程,允许后续复用 */ bl thread_clr_boot_thread
5.2 握手 ATF,交付向量表
/* 计算向量表的物理地址(减去虚拟偏移),保证EL3用物理地址能正确索引 */ ldr x0, boot_mmu_config + CORE_MMU_CONFIG_MAP_OFFSET adr x1, thread_vector_table sub x1, x1, x0 /* x0 = 初始化完成SMC号,x1 = 向量表基地址 */ mov x0, #TEESMC_OPTEED_RETURN_ENTRY_DONE smc #0 panic_at_smc_return
  • 核心细节:thread_vector_table 是虚拟地址,但 ATF 侧此时用物理地址跳转,因此需要减去虚拟地址偏移,得到物理地址后再通过 x1 传递给 EL3。
  • 执行 smc #0 陷入 EL3,回到 OPTEED 的 opteed_smc_handler,命中 TEESMC_OPTEED_RETURN_ENTRY_DONE 分支。

阶段 6:OPTEED 侧完成绑定

ATF 侧保存向量表基地址,注册电源管理钩子与中断处理函数,调用 opteed_synchronous_sp_exit 恢复 EL3 调用现场,回到 BL31 启动流程。
至此,冷启动全流程闭环完成,OP-TEE 进入空闲态,等待运行时 SMC 唤醒。

二、次级 CPU 热启动全链路(PSCI CPU_ON)

次级 CPU 上电由非安全世界通过 PSCI CPU_ON 命令触发,对应向量表中的 vector_cpu_on_entry,最终执行本文件的 cpu_on_handler。核心特点:不执行全局初始化,仅做 CPU 本地硬件与上下文初始化

阶段 1:OPTEED 侧触发与路由

  1. 非安全世界发起 PSCI_CPU_ON SMC,ATF PSCI 模块校验参数,调用 OPTEED 的 cpu_on 电源管理钩子。
  2. OPTEED 为目标 CPU 构造 S-EL1 上下文:ELR_EL3 设置为向量表中 cpu_on_entry 的物理地址,配置 SPSR 为 S-EL1。
  3. 给目标 CPU 上电、释放复位,CPU 从复位向量进入 EL3 暖启动入口,完成 EL3 基础初始化后,eret 切入 S-EL1 的 cpu_on_handler。

阶段 2:OP-TEE 侧cpu_on_handler本地初始化

FUNC cpu_on_handler , : mov x19, x0 mov x20, x1 mov x21, x30 /* 1. 设置本地异常向量表 */ adr x0, reset_vect_table msr vbar_el1, x0 isb /* 2. 配置SCTLR_EL1与PAN */ set_sctlr_el1 isb #ifdef CFG_PAN init_pan #endif /* 3. 开启异常接收 */ msr daifclr, #DAIFBIT_ABT /* 4. 开启MMU,切换到虚拟地址空间 */ bl __get_core_pos bl enable_mmu /* 5. 初始化本CPU栈与thread_core_local */ #if defined(CFG_DYN_CONFIG) ... #else set_sp #endif /* 6. 初始化本CPU安全特性 */ #ifdef CFG_MEMTAG init_memtag_per_cpu #endif #ifdef CFG_CORE_PAUTH init_pauth_secondary_cpu #endif /* 7. 调用C语言CPU上电处理函数 */ mov x0, x19 mov x1, x20 b boot_cpu_on_handler END_FUNC cpu_on_handler

与冷启动的核心差异

  1. 无全局初始化:不拷贝镜像、不清 BSS、不构建页表、不初始化内存分配器、不初始化内核子系统——这些全局资源主 CPU 已经完成,次级 CPU 直接复用。
  2. 仅做本地初始化
  • 配置本 CPU 的系统寄存器、异常向量表
  • 开启本 CPU 的 MMU、缓存、MTE、PAUTH 等硬件特性
  • 初始化本 CPU 的私有栈与 thread_core_local 结构
  • 初始化本 CPU 的 GIC 中断接口、缓存一致性
  1. 收尾返回:boot_cpu_on_handler 完成后,返回 SMC 号 TEESMC_OPTEED_RETURN_ON_DONE,陷入 EL3。

阶段 3:OPTEED 侧收尾

OPTEED 收到返回后,切换到非安全上下文,次级 CPU 跳转到 Linux 指定的入口,进入非安全世界启动流程。

三、运行时 SMC 唤醒服务全链路

冷启动完成后,OP-TEE 处于空闲挂起状态;非安全世界发起 Trusted OS 范围的 SMC 时,会经过 EL3 转发,通过线程向量表唤醒 OP-TEE 处理业务,全程不会再走_startcpu_on_handler

完整调用链路

1.非安全 SMC 陷入 EL3:非安全世界执行 smc #0,硬件陷入 EL3,ATF 根据 OEN 路由到 opteed_smc_handler。

2.OPTEED 路由转发

  • 保存非安全上下文
  • 根据 SMC 类型(Fast/Yield),从已保存的 optee_vector_table 中取出对应入口地址
  • 将参数拷贝到安全上下文
  • eret 切入 S-EL1,跳转到向量表对应的 vector_fast_smc_entry / vector_std_smc_entry
/* * Vector table supplied to ARM Trusted Firmware (ARM-TF) at * initialization. * * Note that ARM-TF depends on the layout of this vector table, any change * in layout has to be synced with ARM-TF. */ FUNC thread_vector_table , : , .identity_map, , nobti b vector_std_smc_entry b vector_fast_smc_entry b vector_cpu_on_entry b vector_cpu_off_entry b vector_cpu_resume_entry b vector_cpu_suspend_entry b vector_fiq_entry b vector_system_off_entry b vector_system_reset_entry END_FUNC thread_vector_table DECLARE_KEEP_PAGER thread_vector_table LOCAL_FUNC vector_std_smc_entry , : , .identity_map readjust_pc bl thread_handle_std_smc /* * Normally thread_handle_std_smc() should return via * thread_exit(), thread_rpc(), but if thread_handle_std_smc() * hasn't switched stack (error detected) it will do a normal "C" * return. */ mov w1, w0 ldr x0, =TEESMC_OPTEED_RETURN_CALL_DONE smc #0 /* SMC should not return */ panic_at_smc_return END_FUNC vector_std_smc_entry LOCAL_FUNC vector_fast_smc_entry , : , .identity_map readjust_pc sub sp, sp, #THREAD_SMC_ARGS_SIZE store_xregs sp, THREAD_SMC_ARGS_X0, 0, 7 mov x0, sp bl thread_handle_fast_smc load_xregs sp, THREAD_SMC_ARGS_X0, 1, 8 add sp, sp, #THREAD_SMC_ARGS_SIZE ldr x0, =TEESMC_OPTEED_RETURN_CALL_DONE smc #0 /* SMC should not return */ panic_at_smc_return END_FUNC vector_fast_smc_entry

调用到thread_handle_std_smc函数中:

uint32_t thread_handle_std_smc(uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5, uint32_t a6 __unused, uint32_t a7 __maybe_unused) { uint32_t rv = OPTEE_SMC_RETURN_OK; thread_check_canaries(); if (IS_ENABLED(CFG_NS_VIRTUALIZATION) && virt_set_guest(a7)) return OPTEE_SMC_RETURN_ENOTAVAIL; /* * thread_resume_from_rpc() and thread_alloc_and_run() only return * on error. Successful return is done via thread_exit() or * thread_rpc(). */ if (a0 == OPTEE_SMC_CALL_RETURN_FROM_RPC) { thread_resume_from_rpc(a3, a1, a2, a4, a5); rv = OPTEE_SMC_RETURN_ERESUME; } else { thread_alloc_and_run(a0, a1, a2, a3, 0, 0); rv = OPTEE_SMC_RETURN_ETHREAD_LIMIT; } if (IS_ENABLED(CFG_NS_VIRTUALIZATION)) virt_unset_guest(); return rv; }

thread_resume_from_rpc

void thread_resume_from_rpc(uint32_t thread_id, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3) { size_t n = thread_id; struct thread_core_local *l = thread_get_core_local(); bool found_thread = false; assert(l->curr_thread == THREAD_ID_INVALID); thread_lock_global(); if (n < CFG_NUM_THREADS && threads[n].state == THREAD_STATE_SUSPENDED) { threads[n].state = THREAD_STATE_ACTIVE; found_thread = true; } thread_unlock_global(); if (!found_thread) return; l->curr_thread = n; if (threads[n].have_user_map) { core_mmu_set_user_map(&threads[n].user_map); if (threads[n].flags & THREAD_FLAGS_EXIT_ON_FOREIGN_INTR) tee_ta_ftrace_update_times_resume(); } if (is_user_mode(&threads[n].regs)) tee_ta_update_session_utime_resume(); /* * Return from RPC to request service of a foreign interrupt must not * get parameters from non-secure world. */ if (threads[n].flags & THREAD_FLAGS_COPY_ARGS_ON_RETURN) { copy_a0_to_a3(&threads[n].regs, a0, a1, a2, a3); threads[n].flags &= ~THREAD_FLAGS_COPY_ARGS_ON_RETURN; } thread_lazy_save_ns_vfp(); if (threads[n].have_user_map) ftrace_resume(); l->flags &= ~THREAD_CLF_TMP; thread_resume(&threads[n].regs); /*NOTREACHED*/ panic(); }

线程对象结构:

//实际上就是ARM 64的cpu寄存器组 struct thread_ctx_regs { uint64_t sp; uint64_t pc; uint64_t cpsr; uint64_t x[31]; uint64_t tpidr_el0; #if defined(CFG_TA_PAUTH) || defined(CFG_CORE_PAUTH) uint64_t apiakey_hi; uint64_t apiakey_lo; #endif }; //线程上下文对象 struct thread_ctx { struct thread_ctx_regs regs; enum thread_state state; vaddr_t stack_va_end; uint32_t flags; struct core_mmu_user_map user_map; bool have_user_map; #if defined(ARM64) || defined(RV64) vaddr_t kern_sp; /* Saved kernel SP during user TA execution */ #endif #ifdef CFG_CORE_PAUTH struct thread_pauth_keys keys; #endif #ifdef CFG_WITH_VFP struct thread_vfp_state vfp_state; #endif void *rpc_arg; struct mobj *rpc_mobj; struct thread_shm_cache shm_cache; struct thread_specific_data tsd; };

函数的最后一步真正完成线程恢复的位置

  1. 清除临时栈标志THREAD_CLF_TMP表示当前 CPU 使用临时栈;即将恢复业务线程,要切换到线程私有栈,因此先清除该标志。

  2. 执行线程恢复调用汇编函数thread_resume,传入线程的寄存器上下文结构体。该函数会完成:

    • 从上下文中恢复所有通用寄存器、系统寄存器、栈指针;
    • 恢复 SPSR 程序状态寄存器;
    • 执行ERET异常返回,跳转到线程被挂起的指令位置,继续执行后续代码。
  3. 不可达兜底thread_resume不会返回(直接 ERET 回到线程现场),因此后面的panic()是不可达代码;如果程序执行到这里,说明上下文恢复逻辑出现严重异常,直接触发系统崩溃,防止异常流继续执行带来安全风险。

3.OP-TEE 侧业务处理

  • 执行 readjust_pc 修正 ASLR 地址偏移(若开启)
  • Fast SMC:原子执行快速调用处理函数,全程关中断、无线程切换
  • Std SMC:分配线程、切换线程栈,执行 TA 调用、加密运算等耗时操作,支持中断抢占与 RPC 回调

4.结果返回:处理完成后执行 smc #0 陷入 EL3,OPTEED 将结果写回非安全上下文,eret 返回非安全世界。

为什么运行时不走_start

  • _start 是一次性启动入口,负责从裸机搭建完整运行环境;环境搭建完成后,重复执行会破坏已初始化的全局状态、内存布局、线程调度器。
  • 运行时 OP-TEE 已经处于 S-EL1 虚拟地址空间,MMU、栈、中断、调度器全部就绪,只需通过线程向量表直接进入业务处理即可,无需重复初始化。

核心设计总结(Android 安全视角)

  1. 分层解耦:启动入口与运行时入口分离,全局初始化与本地初始化分离,既保证启动流程清晰,也避免热启动重复初始化带来的安全风险与性能损耗。
  2. 安全左移:MTE、PAUTH、PAN、WXN、BTI 等安全特性在启动最早期就开启,从第一条指令开始就处于安全防护状态,最大程度缩小攻击窗口。
  3. 恒等映射平滑过渡:所有启动早期代码放在 .identity_map 段,保证 MMU 开启前后地址连续,实现无断点的物理地址→虚拟地址切换,是嵌入式操作系统启动的经典设计。
  4. 严格 ABI 约定:与 ATF 仅通过 SMC 号、寄存器传参、固定偏移向量表交互,无编译期符号依赖,完美适配 Android 碎片化的平台与版本差异。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/25 17:50:41

小红书多账号管理不再难,揭秘高效运营工具

深耕小红书矩阵运营的朋友都清楚&#xff0c;账号数量增多后&#xff0c;最大的难题从来不是内容创作&#xff0c;而是日常运维的繁琐。反复扫码登录、频繁切换设备、消息分散遗漏、账号状态不稳定&#xff0c;大量时间耗费在机械操作上&#xff0c;严重拉低整体运营效率&#…

作者头像 李华
网站建设 2026/6/25 17:49:14

【软工方法论25】持续集成与持续部署CI_CD实战

【软工方法论25】295_持续集成与持续部署CI_CD实战 持续集成与持续部署:CI/CD实战 你有没有遇到过这种情况? 本地代码明明跑得好好的,一上线就出bug。 或者: 代码合并后,等了2天才部署上线,测试反馈"早提测早发现问题"。 持续集成(CI)和持续部署(CD),…

作者头像 李华
网站建设 2026/6/25 17:42:33

机器学习科研信息流操作系统:arXiv高效筛选与靶向精读实战

1. 这不是一份“论文清单”&#xff0c;而是一套可复用的科研信息流操作系统你点开这个标题&#xff0c;大概率是被“Weekly”和“#9”这两个词吸引的——说明你已经意识到&#xff1a;机器学习领域的知识更新不是线性的&#xff0c;而是爆炸式的、非结构化的、带着强烈时效压迫…

作者头像 李华
网站建设 2026/6/25 17:41:58

极端气候对流域水循环及水环境影响系统实践技术

近年来&#xff0c;在全球气候变化加剧的背景下&#xff0c;极端气候事件频发&#xff0c;对流域水循环过程及水生态系统造成显著影响&#xff0c;已成为制约区域经济社会与环境可持续发展的关键因素。为应对这一挑战&#xff0c;亟需引入系统化的模拟技术与创新方法&#xff0…

作者头像 李华