赞
踩
Trusted Firmware Project是一个开源软件项目,最初由ARM管理,后来移交给Linaro管理。Trusted Firmware Project旨在为ARM A-Profile和M-Profile架构处理器提供安全软件的参考实现。
Trusted Firmware Project包括如下项目;TF-A、TF-M、MCUboot、TF-RMM、OP-TEE、
Mbed TLS、Hafnium、Trusted Services、Open CI。
TF-A 是Trusted Firmware-A 的简称,支持的处理器包括 Cortex-A 和 Neoverse系列,为 ARM AProfile 架构(包括 Armv7-A、Armv8-A和Armv9-A)处理器提供了安全软件的参考实现;TF-A支持代码复用,方便移植到不同芯片厂商的模型和硬件平台上,移植工作只需添加平台相关代码;TFA包括了执行在EL3异常级别的Secure Monitor,并支持 AArch32 和 AArch64 执行状态。
TF-A实现了如下ARM 接口标准:
对于AArch64 状态的 Cold boot,从CPU Reset开始,TF-A按如下启动顺序工作:
AP Trusted ROM
;Trusted Boot Firmware
;EL3 Runtime Software
;Secure-EL1 Payload (optional)
;Non-trusted Firmware
;bl1:Bootrom
,BL1
是启动的第一阶段,该镜像必须要存储在可直接执行的介质中。若芯片支持 XIP 启动方式,其可被存储在片外可直接执行的介质中(如norflash
)。若不支持 XIP,则需要存储在芯片的片内 ROM
中,此时在芯片出厂后该部分代码就将被固化,后续再也不能被修改和升级。若芯片要支持安全启动,则需要将 bootrom 作为启动时的信任根。
bl2:BL2
镜像由 BL1
加载,此时 DDR
还没有被初始化,因此它需要被加载到片内的 SRAM
中执行,一般在 BL2 中完成 DDR 的初始化,因此后面的镜像都可以被加载到 DDR 中。BL31、BL32
和 BL33
都是由 BL2 加
载的,其中 BL31
和 BL32
是可选的,若系统不支持 TRUST OS
,则可去掉 BL32
,若不支持 EL3
异常等级及 secure monitor
,则可去掉 BL31。此外 BL2 还会进行完成 USB 配置,PMIC
的配置 UART
配置,另外,BL2
运行在 EL3 级别。
bl2 有的公司叫做
preboot
, 在有的公司称为SPL
b31:称为 ATF
,主要完成双系统切换的工作,有的公司称其为 Sloader
。sloader
对应的 ATF
代码 (也就 arm trust firmware
,现在最新版本已经改名) 。
ATF 代码可以从ARM官网 download,再加入一些自己的特有设计。
ATF
的功能主要是负责 tee\ree
切换;运行在EL3
级别,由 BL2
(有的公司称其为SPL
) 加载并调用初始化。
BL2
执行完成后需要跳转到 BL31
,由于 BL31
运行在 EL3 异常等级,而 BL2根据需求不同可能运行于secure EL1或EL3。当BL2运行于EL3时可直接通过ERET方式跳转到BL31中,但若其运行在secure EL1时,则只能通过smc异常触发进入EL3异常等级。 显然,此时 BL31 由于尚未设置其自身的SMC
异常处理程序而无法直接处理该异常,因此,为了完成跳转流程,BL1 需要先代理该异常的处理。因此 BL1 在退出之前先设置 SMC 异常处理函数,BL2 触发smc启动 BL31 时,BL1 捕获该异常并根据 BL2 传入的参数设置 BL31 的入口地址和系统初始状态,并通过 ERET 跳转到 BL31 的入口地址处执行。
当异常发生时 PE 会根据异常的类型选择一个合适返回地址保存到
ELR_ELn
中,n
的含义和签名SPSR_ELn
类似。等到异常处理完毕、软件主动调用ERET
指令,这个指令会将SPSR_ELn
恢复到 PSATE寄存器 中 (严格来说PSTATE
不是一个寄存器,是一组表示PE状态寄存器的组合)ELR_ELn
的内容更新到PC
指针,实现异常的返回跳转。
b32:包括 TEE OS(OpenTee)
, 其中 TE OS
运行在安全模式下的 EL1级别。BL31
可根据其镜像加载信息设置入口地址以及其它状态,并完成跳转。BL32
加载完成后将通过 SMC
返回到 BL31
,然后由 BL31
跳转到 non secure EL1
或 non secure EL2
以执行 BL33
。
bl33: 一般是指uboot
, 有的会包括(bootloader)uboot->kernel->Anriod
流程, uboot 运行在non-secure mode
下的EL1
级别。
ATF 里面分为BL1,BL2,BL31,BL32,BL33,一般SoC厂商会从BL31添加自己的代码,其他的都是ARM默认的,没有人去改。bl1/bl2 一般都是平台自己实现。
本篇文章主要介绍 ATF。
如果触发异常,程序会跳转到异常向量表去执行。整个异常向量表的大小为 0x800
字节,每一个entry都是0x80
对齐。异常总共有 4种:
根据异常发生的 exception level又分为4类:
以 linux kernel为例:
ATF 中断向量表的定义位于文件:bl31/aarch64/runtime_exceptions.S
, 基地址为 runtime_exceptions
:
vector_base runtime_exceptions
/* ---------------------------------------------------------------------
* Current EL with SP_EL0 : 0x0 - 0x200
* ---------------------------------------------------------------------
*/
vector_entry sync_exception_sp_el0
#ifdef MONITOR_TRAPS
stp x29, x30, [sp, #-16]!
mrs x30, esr_el3
ubfx x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH
/* Check for BRK */
cmp x30, #EC_BRK
b.eq brk_handler
ldp x29, x30, [sp], #16
#endif /* MONITOR_TRAPS */
/* We don't expect any synchronous exceptions from EL3 */
b report_unhandled_exception
end_vector_entry sync_exception_sp_el0
vector_entry irq_sp_el0
/*
* EL3 code is non-reentrant. Any asynchronous exception is a serious
* error. Loop infinitely.
*/
b report_unhandled_interrupt
end_vector_entry irq_sp_el0
vector_entry fiq_sp_el0
b report_unhandled_interrupt
end_vector_entry fiq_sp_el0
vector_entry serror_sp_el0
no_ret plat_handle_el3_ea
end_vector_entry serror_sp_el0
/* ---------------------------------------------------------------------
* Current EL with SP_ELx: 0x200 - 0x400
* ---------------------------------------------------------------------
*/
vector_entry sync_exception_sp_elx
/*
* This exception will trigger if anything went wrong during a previous
* exception entry or exit or while handling an earlier unexpected
* synchronous exception. There is a high probability that SP_EL3 is
* corrupted.
*/
b report_unhandled_exception
end_vector_entry sync_exception_sp_elx
vector_entry irq_sp_elx
b report_unhandled_interrupt
end_vector_entry irq_sp_elx
vector_entry fiq_sp_elx
b report_unhandled_interrupt
end_vector_entry fiq_sp_elx
vector_entry serror_sp_elx
#if !RAS_EXTENSION
check_if_serror_from_EL3
#endif
no_ret plat_handle_el3_ea
end_vector_entry serror_sp_elx
/* ---------------------------------------------------------------------
* Lower EL using AArch64 : 0x400 - 0x600
* ---------------------------------------------------------------------
*/
vector_entry sync_exception_aarch64
/*
* This exception vector will be the entry point for SMCs and traps
* that are unhandled at lower ELs most commonly. SP_EL3 should point
* to a valid cpu context where the general purpose and system register
* state can be saved.
*/
apply_at_speculative_wa
check_and_unmask_ea
handle_sync_exception
end_vector_entry sync_exception_aarch64
vector_entry irq_aarch64
apply_at_speculative_wa
check_and_unmask_ea
handle_interrupt_exception irq_aarch64
end_vector_entry irq_aarch64
vector_entry fiq_aarch64
apply_at_speculative_wa
check_and_unmask_ea
handle_interrupt_exception fiq_aarch64
end_vector_entry fiq_aarch64
vector_entry serror_aarch64
apply_at_speculative_wa
#if RAS_EXTENSION
msr daifclr, #DAIF_ABT_BIT
b enter_lower_el_async_ea
#else
handle_async_ea
#endif
end_vector_entry serror_aarch64
/* ---------------------------------------------------------------------
* Lower EL using AArch32 : 0x600 - 0x800
* ---------------------------------------------------------------------
*/
vector_entry sync_exception_aarch32
/*
* This exception vector will be the entry point for SMCs and traps
* that are unhandled at lower ELs most commonly. SP_EL3 should point
* to a valid cpu context where the general purpose and system register
* state can be saved.
*/
apply_at_speculative_wa
check_and_unmask_ea
handle_sync_exception
end_vector_entry sync_exception_aarch32
vector_entry irq_aarch32
apply_at_speculative_wa
check_and_unmask_ea
handle_interrupt_exception irq_aarch32
end_vector_entry irq_aarch32
vector_entry fiq_aarch32
apply_at_speculative_wa
check_and_unmask_ea
handle_interrupt_exception fiq_aarch32
end_vector_entry fiq_aarch32
vector_entry serror_aarch32
apply_at_speculative_wa
#if RAS_EXTENSION
msr daifclr, #DAIF_ABT_BIT
b enter_lower_el_async_ea
#else
handle_async_ea
#endif
end_vector_entry serror_aarch32
与 32 位架构不同,64 位架构的异常向量表地址不固定,在启动的时候由软件将异常向量表的地址设置到专用寄存器VBAR(Vector Base Address Register)中。
从 include/arch/aarch64/asm_macros.S
可以看到宏 vector_base
将向量表放到了 .vectors
段中:
/*
* Declare the exception vector table, enforcing it is aligned on a
* 2KB boundary, as required by the ARMv8 architecture.
* Use zero bytes as the fill value to be stored in the padding bytes
* so that it inserts illegal AArch64 instructions. This increases
* security, robustness and potentially facilitates debugging.
*/
.macro vector_base label, section_name=.vectors
.section \section_name, "ax"
.align 11, 0
\label:
.endm
在 bl31/aarch64/bl31_entrypoint.S
可以看到 向量表的基地址赋值给了 _exception_vectors
:
/* ---------------------------------------------------------------------
* 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
在 include/arch/aarch64/el3_common_macros.S
中的 el3_entrypoint_common
函数中将向量表的基地址赋值给了 vbar_el3((Vector Base Address Register, Exception Level 3)) 寄存器, 用于指定异常向量表的基地址。通过修改VBAR_EL3
寄存器的值,可以改变异常处理程序的入口地址。
.macro el3_entrypoint_common \
_init_sctlr, _warm_boot_mailbox, _secondary_cold_boot, \
_init_memory, _init_c_runtime, _exception_vectors, \
_pie_fixup_size
......
/* ---------------------------------------------------------------------
* Set the exception vectors.
* ---------------------------------------------------------------------
*/
cix_postcode_debug_asm _code=0x150
adr x0, \_exception_vectors
msr vbar_el3, x0
isb
......
在ARM Trusted Firmware(ATF)中,el3_entrypoint_common
是一个通用的入口点函数,用于处理从非安全世界(例如:EL2, EL1)或安全世界(EL3)进入EL3时的一些初始化工作。
以下是el3_entrypoint_common函
数的一些常见作用:
保存当前的执行环境,包括当前异常级别下的系统寄存器。
设置新的执行环境,包括初始化栈,设置新的异常向量表地址,等等。
根据需要,可能会进行一些硬件初始化或配置,例如初始化内存管理单元(MMU)。
最后,el3_entrypoint_common函数通常会跳转到其他函数进行进一步的初始化,这可能包括启动操作系统,进入休眠状态,或者处理更具体的异常。
需要注意的是,el3_entrypoint_common函数的具体实现可能会根据具体的硬件平台和ATF版本有所不同,因此上述的作用可能会有所差异。
对于ARMv7 的定义(include/arch/aarch32/asm_macros.S
):
/*
* Declare the exception vector table, enforcing it is aligned on a
* 32 byte boundary.
*/
.macro vector_base label
.section .vectors, "ax"
.align 5
\label:
.endm
对于ARMv8 的定义(include/arch/aarch64/asm_macros.S
):
/*
* Declare the exception vector table, enforcing it is aligned on a
* 2KB boundary, as required by the ARMv8 architecture.
* Use zero bytes as the fill value to be stored in the padding bytes
* so that it inserts illegal AArch64 instructions. This increases
* security, robustness and potentially facilitates debugging.
*/
.macro vector_base label, section_name=.vectors
.section \section_name, "ax"
.align 11, 0
\label:
.endm
在上面 1.1 节的内容中我们可以看到处理同步异常的汇编宏: handle_sync_exception
(分为AArch32 和 AArch64 两种情况,这里值讨论AArch64),由于 SMC 触发的异常属于同步异常,所以执行 SMC 指令后首先会走到 sync_exception_aarch64
处。看下 sync_exception_aarch64
在ATF 中的实现:
vector_entry sync_exception_aarch64
/*
* This exception vector will be the entry point for SMCs and traps
* that are unhandled at lower ELs most commonly. SP_EL3 should point
* to a valid cpu context where the general purpose and system register
* state can be saved.
*/
apply_at_speculative_wa
check_and_unmask_ea
handle_sync_exception
end_vector_entry sync_exception_aarch64
可以看到 SMC 异常的处理包含三部分,接下来分别对这三部做介绍。
apply_at_speculative_wa
.macro apply_at_speculative_wa
#if ERRATA_SPECULATIVE_AT
/*
* Explicitly save x30 so as to free up a register and to enable
* branching and also, save x29 which will be used in the called
* function
*/
stp x29, x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X29]
bl save_and_update_ptw_el1_sys_regs
ldp x29, x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X29]
#endif
.endm
首先,编译器会检查是否启用了规避异步异常的修补方案(ERRATA_SPECULATIVE_AT
)。如果启用了,就会执行一系列的指令。
首先使用STP
指令将寄存器x29
和x30
的值存储到堆栈中,以便释放这两个寄存器供后续的指令使用。
然后,它调用 save_and_update_ptw_el1_sys_regs
函数。这个函数的作用根据函数名,应该是保存并更新EL1系统寄存器的页表遍历(Page Table Walk, PTW)相关的值。这可能是由于部分ARM处理器存在的一些硬件异常,需要通过软件来进行规避。
最后,它使用LDP
指令从堆栈中恢复寄存器x29
和x30
的值。
这段代码的主要作用是,在处理异常时,如果启用了异步异常的规避措施,就保存当前的状态,调用特定的函数进行处理,然后恢复之前的状态。
/*
* For SoCs which do not implement RAS, use DSB as a barrier to
* synchronize pending external aborts.
*/
dsb sy
/* Unmask the SError interrupt */
msr daifclr, #DAIF_ABT_BIT
/* Use ISB for the above unmask operation to take effect immediately */
isb
/*
* Refer Note 1. No need to restore X30 as both handle_sync_exception
* and handle_interrupt_exception macro which follow this macro modify
* X30 anyway.
*/
str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
mov x30, #1
str x30, [sp, #CTX_EL3STATE_OFFSET + CTX_IS_IN_EL3]
dmb sy
msr daifclr, #DAIF_ABT_BIT
打开Abort中断,Abort中断分为两种类型:Prefetch Abort和Data Abort。对于这两种Abort中断,处理器都会进入异常处理模式,并跳转到预设的异常处理程序进行处理。
isb
:Instruction Synchronization Barrier(指令同步屏障)这条指令确保了在它之前的所有指令都完成后,才开始执行它之后的指令。在这里,它确保了打开Abort中断的设置立即生效。。str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
将寄存器x30
的值存储到堆栈的指定位置。这里的位置是基于sp(Stack Pointer,栈指针)寄存器和偏移量CTX_GPREGS_OFFSET + CTX_GPREG_LR
计算得到的。mov x30, #1
:将1写入到寄存器x30。str x30, [sp, #CTX_EL3STATE_OFFSET +CTX_IS_IN_EL3]
:将寄存器x30
的值存储到堆栈的指定位置。这里的位置是基于sp寄存器和偏移量CTX_EL3STATE_OFFSET + CTX_IS_IN_EL3
计算得到的。这条指令标志着异常处理程序现在正在 EL3 执行级别中运行。dmb sy
:Data Memory Barrier(数据内存屏障)。这条指令确保了在它之前的内存访问指令都完成后,才会执行它之后的指令。这段代码的主要作用是打开Abort 中断,并将一些寄存器值存储到堆栈中以备后续的异常处理程序使用,同时也标志着异常处理程序正在 EL3执行级别中运行。
bl31/aarch64/runtime_exceptions.S
): /* ---------------------------------------------------------------------
* This macro handles Synchronous exceptions.
* Only SMC exceptions are supported.
* ---------------------------------------------------------------------
*/
.macro handle_sync_exception
#if ENABLE_RUNTIME_INSTRUMENTATION
/*
* Read the timestamp value and store it in per-cpu data. The value
* will be extracted from per-cpu data by the C level SMC handler and
* saved to the PMF timestamp region.
*/
mrs x30, cntpct_el0
str x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X29]
mrs x29, tpidr_el3
str x30, [x29, #CPU_DATA_PMF_TS0_OFFSET]
ldr x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X29]
#endif
mrs x30, esr_el3
ubfx x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH
/* Handle SMC exceptions separately from other synchronous exceptions */
cmp x30, #EC_AARCH32_SMC
b.eq smc_handler32
cmp x30, #EC_AARCH64_SMC
b.eq smc_handler64
/* Synchronous exceptions other than the above are assumed to be EA */
ldr x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
b enter_lower_el_sync_ea
.endm
ENABLE_RUNTIME_INSTRUMENTATION
),如果启用了,就会读取物理计数器(CNTPCT_EL0
)的值,并将其保存在每个CPU的数据中。这个值会被C级别的SMC处理程序提取并保存到PMF时间戳区域。UBFX
指令从中提取异常类(EC)字段。EC_AARCH32_SMC
(0x13),表示这是一个32位的安全监视器调用(SMC),就跳转到 smc_handler32
标签处处理;如果值等于EC_AARCH64_SMC
,表示这是一个64位的SMC,就跳转到 smc_handler64
标签处处理。如果异常类字段的值既不是EC_AARCH32_SMC
,也不是EC_AARCH64_SMC
,则假定这是一个异步异常(EA),并跳转到enter_lower_el_sync_ea
标签处处理。关于 ESR_EL3
EC 的字段:
ATF 代码中对于每个异常类型都做了对应的宏定义(include/arch/aarch64/arch.h
)
/* Exception Syndrome register bits and bobs */
#define ESR_EC_SHIFT U(26)
#define ESR_EC_MASK U(0x3f)
#define ESR_EC_LENGTH U(6)
#define ESR_ISS_SHIFT U(0)
#define ESR_ISS_LENGTH U(25)
#define EC_UNKNOWN U(0x0)
#define EC_WFE_WFI U(0x1)
#define EC_AARCH32_CP15_MRC_MCR U(0x3)
#define EC_AARCH32_CP15_MRRC_MCRR U(0x4)
#define EC_AARCH32_CP14_MRC_MCR U(0x5)
#define EC_AARCH32_CP14_LDC_STC U(0x6)
#define EC_FP_SIMD U(0x7)
#define EC_AARCH32_CP10_MRC U(0x8)
#define EC_AARCH32_CP14_MRRC_MCRR U(0xc)
#define EC_ILLEGAL U(0xe)
#define EC_AARCH32_SVC U(0x11)
#define EC_AARCH32_HVC U(0x12)
#define EC_AARCH32_SMC U(0x13)
#define EC_AARCH64_SVC U(0x15)
#define EC_AARCH64_HVC U(0x16)
#define EC_AARCH64_SMC U(0x17)
#define EC_AARCH64_SYS U(0x18)
#define EC_IABORT_LOWER_EL U(0x20)
#define EC_IABORT_CUR_EL U(0x21)
#define EC_PC_ALIGN U(0x22)
#define EC_DABORT_LOWER_EL U(0x24)
#define EC_DABORT_CUR_EL U(0x25)
#define EC_SP_ALIGN U(0x26)
#define EC_AARCH32_FP U(0x28)
#define EC_AARCH64_FP U(0x2c)
#define EC_SERROR U(0x2f)
#define EC_BRK U(0x3c)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。