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

📅 2026/6/25 17:55:27
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_tableentry_a64.SS-EL1 本地硬件异常向量表写入VBAR_EL1由 CPU 硬件识别处理 S-EL1 内部的同步异常、IRQ、FIQ、SError启动初期配置OP-TEE 运行全程生效thread_vector_tablethread_optee_smc_a64.S交付给 ATF 的软件约定向量表纯函数跳转表是 EL3 切入 OP-TEE 业务的统一入口冷启动完成后交付 ATF运行时业务调用、电源管理、中断处理使用_startentry_a64.S主 CPU 冷启动唯一入口完成完整内核环境搭建系统上电后仅执行 1 次cpu_on_handlerentry_a64.S次级 CPU 热启动入口仅完成 CPU 本地硬件初始化每个次级 CPU 上电时执行 1 次简单说冷启动全链路的reset_vect_table“把 OP-TEE 从无到有跑起来”线程向量表负责“跑起来之后处理日常业务”。一、主 CPU 冷启动全链路OPTEED ↔ OP-TEE 双向完整流程冷启动是 EL3 主动发起的一次性全量初始化流程ATF BL31 构造异常现场通过 ERET 跳入 OP-TEE 的 _startOP-TEE 完成从裸机到完整内核的所有初始化最终通过 SMC 交付向量表回到 EL3 建立运行时调用通路。阶段 1OPTEED 侧构造异常现场发起跳转对应 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~x33.执行 eret 指令硬件自动将上下文恢复到寄存器特权级从 EL3 降到 S-EL1PC 跳转到 _start。「伪造异常现场」ERET 硬件语义是“返回异常发生前的状态”但冷启动时没有真实异常发生软件手动填充 ELR_EL3/SPSR_EL3 模拟出异常现场骗过硬件实现降权跳转。阶段 2OP-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~x22callee-saved 寄存器C 函数不会破坏后续传递给 C 初始化函数。配置 S-EL1 本地硬件异常向量表 reset_vect_table 到 VBAR_EL1。此时向量表中所有入口都是死循环b .仅做异常兜底防止启动早期异常导致 CPU 跑飞后续内核初始化完成后会替换为完整异常处理。2.2 早期系统寄存器与安全特性配置#ifdef CFG_PAN init_pan #endif set_sctlr_el1 isbinit_pan开启 ARMv8.1 PANPrivileged 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_RELOCATABLEOP-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 ... #endifset_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_mapboot_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_mmuenable_mmu 函数的核心执行逻辑写入 TCR_EL1、MAIR_EL1、TTBR0_EL1 等内存管理寄存器加载页表基地址。无效化 TLB保证旧的地址翻译全部失效。置位 SCTLR_EL1.M 开启 MMU此时 PC 仍在恒等映射段物理地址虚拟地址不会触发缺页。更新 VBAR_EL1加上虚拟地址偏移修正异常向量表的虚拟地址。无效化指令缓存与分支预测器保证指令流一致性。开启指令缓存与数据缓存。修正栈指针与返回地址SP_EL0、SP_EL1、LR 全部加上虚拟地址偏移完成从物理栈到虚拟栈的切换。返回此时 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初始化收尾交付向量表返回 EL35.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_thread5.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 分支。阶段 6OPTEED 侧完成绑定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 本地硬件与上下文初始化。阶段 1OPTEED 侧触发与路由非安全世界发起 PSCI_CPU_ON SMCATF PSCI 模块校验参数调用 OPTEED 的 cpu_on 电源管理钩子。OPTEED 为目标 CPU 构造 S-EL1 上下文ELR_EL3 设置为向量表中 cpu_on_entry 的物理地址配置 SPSR 为 S-EL1。给目标 CPU 上电、释放复位CPU 从复位向量进入 EL3 暖启动入口完成 EL3 基础初始化后eret 切入 S-EL1 的 cpu_on_handler。阶段 2OP-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与冷启动的核心差异无全局初始化不拷贝镜像、不清 BSS、不构建页表、不初始化内存分配器、不初始化内核子系统——这些全局资源主 CPU 已经完成次级 CPU 直接复用。仅做本地初始化配置本 CPU 的系统寄存器、异常向量表开启本 CPU 的 MMU、缓存、MTE、PAUTH 等硬件特性初始化本 CPU 的私有栈与 thread_core_local 结构初始化本 CPU 的 GIC 中断接口、缓存一致性收尾返回boot_cpu_on_handler 完成后返回 SMC 号 TEESMC_OPTEED_RETURN_ON_DONE陷入 EL3。阶段 3OPTEED 侧收尾OPTEED 收到返回后切换到非安全上下文次级 CPU 跳转到 Linux 指定的入口进入非安全世界启动流程。三、运行时 SMC 唤醒服务全链路冷启动完成后OP-TEE 处于空闲挂起状态非安全世界发起 Trusted OS 范围的 SMC 时会经过 EL3 转发通过线程向量表唤醒 OP-TEE 处理业务全程不会再走_start或cpu_on_handler。完整调用链路1.非安全 SMC 陷入 EL3非安全世界执行 smc #0硬件陷入 EL3ATF 根据 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() * hasnt 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_rpcvoid 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; };函数的最后一步真正完成线程恢复的位置清除临时栈标志THREAD_CLF_TMP表示当前 CPU 使用临时栈即将恢复业务线程要切换到线程私有栈因此先清除该标志。执行线程恢复调用汇编函数thread_resume传入线程的寄存器上下文结构体。该函数会完成从上下文中恢复所有通用寄存器、系统寄存器、栈指针恢复 SPSR 程序状态寄存器执行ERET异常返回跳转到线程被挂起的指令位置继续执行后续代码。不可达兜底thread_resume不会返回直接 ERET 回到线程现场因此后面的panic()是不可达代码如果程序执行到这里说明上下文恢复逻辑出现严重异常直接触发系统崩溃防止异常流继续执行带来安全风险。3.OP-TEE 侧业务处理执行 readjust_pc 修正 ASLR 地址偏移若开启Fast SMC原子执行快速调用处理函数全程关中断、无线程切换Std SMC分配线程、切换线程栈执行 TA 调用、加密运算等耗时操作支持中断抢占与 RPC 回调4.结果返回处理完成后执行 smc #0 陷入 EL3OPTEED 将结果写回非安全上下文eret 返回非安全世界。为什么运行时不走_start_start 是一次性启动入口负责从裸机搭建完整运行环境环境搭建完成后重复执行会破坏已初始化的全局状态、内存布局、线程调度器。运行时 OP-TEE 已经处于 S-EL1 虚拟地址空间MMU、栈、中断、调度器全部就绪只需通过线程向量表直接进入业务处理即可无需重复初始化。核心设计总结Android 安全视角分层解耦启动入口与运行时入口分离全局初始化与本地初始化分离既保证启动流程清晰也避免热启动重复初始化带来的安全风险与性能损耗。安全左移MTE、PAUTH、PAN、WXN、BTI 等安全特性在启动最早期就开启从第一条指令开始就处于安全防护状态最大程度缩小攻击窗口。恒等映射平滑过渡所有启动早期代码放在 .identity_map 段保证 MMU 开启前后地址连续实现无断点的物理地址→虚拟地址切换是嵌入式操作系统启动的经典设计。严格 ABI 约定与 ATF 仅通过 SMC 号、寄存器传参、固定偏移向量表交互无编译期符号依赖完美适配 Android 碎片化的平台与版本差异。