ATF在处理SMC的时候会把CPU的寄存器保存起来,退出SMC的时候恢复现场。使用qemu_v8.mk编译出来的ATF没有定义CTX_INCLUDE_EL2_REGS,CTX_INCLUDE_FPREGS和CTX_INCLUDE_PAUTH_REGS。
lib/context.h
typedef struct cpu_context {gp_regs_t gpregs_ctx;el3_state_t el3state_ctx;el1_sysregs_t el1_sysregs_ctx;
#if CTX_INCLUDE_EL2_REGSel2_sysregs_t el2_sysregs_ctx;
#endif
#if CTX_INCLUDE_FPREGSfp_regs_t fpregs_ctx;
#endifcve_2018_3639_t cve_2018_3639_ctx;
#if CTX_INCLUDE_PAUTH_REGSpauth_t pauth_ctx;
#endif
} cpu_context_t;
以gp_regs_t 为例,它就是定义了一个uint64_t数组,总共包含64个元素。
DEFINE_REG_STRUCT(gp_regs, CTX_GPREG_ALL);
#define DEFINE_REG_STRUCT(name, num_regs) \typedef struct name { \uint64_t ctx_regs[num_regs]; \} __aligned(16) name##_t
#define CTX_GPREG_ALL (CTX_GPREGS_END >> DWORD_SHIFT)#define CTX_GPREGS_OFFSET U(0x0)
#define CTX_GPREG_X0 U(0x0)
...
#define CTX_GPREG_X29 U(0xe8)
#define CTX_GPREG_LR U(0xf0)
#define CTX_GPREG_SP_EL0 U(0xf8)
#define CTX_GPREGS_END U(0x100)
#define DWORD_SHIFT U(3)
0x00 - 0xFF 保存了通用寄存器。
0x100 - 0x13F 保存了EL3的状态寄存器
#define CTX_SCR_EL3 U(0x0)
#define CTX_ESR_EL3 U(0x8)
#define CTX_RUNTIME_SP U(0x10)
#define CTX_SPSR_EL3 U(0x18)
#define CTX_ELR_EL3 U(0x20)
#define CTX_PMCR_EL0 U(0x28)
#define CTX_IS_IN_EL3 U(0x30)
#define CTX_EL3STATE_END U(0x40) /* Align to the next 16 byte boundary */
0x140 - 0x1AF保存了EL1的系统寄存器
#define CTX_SPSR_EL1 U(0x0)
#define CTX_ELR_EL1 U(0x8)
#define CTX_SCTLR_EL1 U(0x10)
#define CTX_TCR_EL1 U(0x18)
#define CTX_CPACR_EL1 U(0x20)
#define CTX_CSSELR_EL1 U(0x28)
#define CTX_SP_EL1 U(0x30)
#define CTX_ESR_EL1 U(0x38)
#define CTX_TTBR0_EL1 U(0x40)
#define CTX_TTBR1_EL1 U(0x48)
#define CTX_MAIR_EL1 U(0x50)
#define CTX_AMAIR_EL1 U(0x58)
#define CTX_ACTLR_EL1 U(0x60)
#define CTX_TPIDR_EL1 U(0x68)
#define CTX_TPIDR_EL0 U(0x70)
#define CTX_TPIDRRO_EL0 U(0x78)
#define CTX_PAR_EL1 U(0x80)
#define CTX_FAR_EL1 U(0x88)
#define CTX_AFSR0_EL1 U(0x90)
#define CTX_AFSR1_EL1 U(0x98)
#define CTX_CONTEXTIDR_EL1 U(0xa0)
#define CTX_VBAR_EL1 U(0xa8)
#define CTX_AARCH32_END U(0xb0) /* Align to the next 16 byte boundary */
REE从EL1调用SMC后就会进入到ATF的sync_exception_aarch64中。从反汇编来看,apply_at_speculative_wa和check_and_unmask_ea是空实现,所以直接进到了handle_sync_exception中。
bl31/aarch64/runtime_exception.S
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_wacheck_and_unmask_eahandle_sync_exception
end_vector_entry sync_exception_aarch64
这段代码很简单,
.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 //读出CNTPCT的值str x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X29] //把X29存到上下文中mrs x29, tpidr_el3 //读出当前线程上下文str x30, [x29, #CPU_DATA_PMF_TS0_OFFSET] //把TIMESTAMP存到线程上下文中ldr x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X29] //恢复X29
#endifmrs x30, esr_el3 //读出ESR_EL3ubfx x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH //根据ESR_EL3中的EC值来选择SMC/* Handle SMC exceptions separately from other synchronous exceptions */cmp x30, #EC_AARCH32_SMCb.eq smc_handler32cmp x30, #EC_AARCH64_SMC //AARCH64走的这条路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
smc_handler64实现如下:
smc_handler64:/* NOTE: The code below must preserve x0-x4 *//** Save general purpose and ARMv8.3-PAuth registers (if enabled).* If Secure Cycle Counter is not disabled in MDCR_EL3 when* ARMv8.5-PMU is implemented, save PMCR_EL0 and disable Cycle Counter.*/bl save_gp_pmcr_pauth_regs
lib/el3_runtime/context.S
func save_gp_pmcr_pauth_regsstp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0]stp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2]stp x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4]stp x6, x7, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X6]stp x8, x9, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X8]stp x10, x11, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X10]stp x12, x13, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X12]stp x14, x15, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X14]stp x16, x17, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X16]stp x18, x19, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X18]stp x20, x21, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X20]stp x22, x23, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X22]stp x24, x25, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X24]stp x26, x27, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X26]stp x28, x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X28]mrs x18, sp_el0str x18, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_SP_EL0]/* ----------------------------------------------------------* Check if earlier initialization MDCR_EL3.SCCD to 1 failed,* meaning that ARMv8-PMU is not implemented and PMCR_EL0* should be saved in non-secure context.* ----------------------------------------------------------*/mrs x9, mdcr_el3tst x9, #MDCR_SCCD_BITbne 1f/* Secure Cycle Counter is not disabled */mrs x9, pmcr_el0/* Check caller's security state */mrs x10, scr_el3tst x10, #SCR_NS_BITbeq 2f/* Save PMCR_EL0 if called from Non-secure state */str x9, [sp, #CTX_EL3STATE_OFFSET + CTX_PMCR_EL0]/* Disable cycle counter when event counting is prohibited */
2: orr x9, x9, #PMCR_EL0_DP_BITmsr pmcr_el0, x9isb
1:
#if CTX_INCLUDE_PAUTH_REGS/* ----------------------------------------------------------* Save the ARMv8.3-PAuth keys as they are not banked* by exception level* ----------------------------------------------------------*/add x19, sp, #CTX_PAUTH_REGS_OFFSETmrs x20, APIAKeyLo_EL1 /* x21:x20 = APIAKey */mrs x21, APIAKeyHi_EL1mrs x22, APIBKeyLo_EL1 /* x23:x22 = APIBKey */mrs x23, APIBKeyHi_EL1mrs x24, APDAKeyLo_EL1 /* x25:x24 = APDAKey */mrs x25, APDAKeyHi_EL1mrs x26, APDBKeyLo_EL1 /* x27:x26 = APDBKey */mrs x27, APDBKeyHi_EL1mrs x28, APGAKeyLo_EL1 /* x29:x28 = APGAKey */mrs x29, APGAKeyHi_EL1stp x20, x21, [x19, #CTX_PACIAKEY_LO]stp x22, x23, [x19, #CTX_PACIBKEY_LO]stp x24, x25, [x19, #CTX_PACDAKEY_LO]stp x26, x27, [x19, #CTX_PACDBKEY_LO]stp x28, x29, [x19, #CTX_PACGAKEY_LO]
#endif /* CTX_INCLUDE_PAUTH_REGS */ret
endfunc save_gp_pmcr_pauth_regs
/** Populate the parameters for the SMC handler.* We already have x0-x4 in place. x5 will point to a cookie (not used* now). x6 will point to the context structure (SP_EL3) and x7 will* contain flags we need to pass to the handler.*/mov x5, xzrmov x6, sp/** Restore the saved C runtime stack value which will become the new* SP_EL0 i.e. EL3 runtime stack. It was saved in the 'cpu_context'* structure prior to the last ERET from EL3.*/ldr x12, [x6, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP] //从当前栈SP_EL3中拿出smc runtime栈SP_EL0指针/* Switch to SP_EL0 */msr spsel, #MODE_SP_EL0 //切换栈指针到SP_EL0/** Save the SPSR_EL3, ELR_EL3, & SCR_EL3 in case there is a world* switch during SMC handling.* TODO: Revisit if all system registers can be saved later.*/mrs x16, spsr_el3mrs x17, elr_el3mrs x18, scr_el3 //保存SPSR_EL3, ELR_EL3 & SCR_EL3到ATF SMC上下文中stp x16, x17, [x6, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]str x18, [x6, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3]/* Copy SCR_EL3.NS bit to the flag to indicate caller's security */bfi x7, x18, #0, #1mov sp, x12
/* Get the unique owning entity number */ //获取SMC Handler的索引ubfx x16, x0, #FUNCID_OEN_SHIFT, #FUNCID_OEN_WIDTHubfx x15, x0, #FUNCID_TYPE_SHIFT, #FUNCID_TYPE_WIDTHorr x16, x16, x15, lsl #FUNCID_OEN_WIDTH/* Load descriptor index from array of indices */adrp x14, rt_svc_descs_indicesadd x14, x14, :lo12:rt_svc_descs_indicesldrb w15, [x14, x16]/* Any index greater than 127 is invalid. Check bit 7. */tbnz w15, 7, smc_unknown
/** Get the descriptor using the index* x11 = (base + off), w15 = index** handler = (base + off) + (index << log2(size))*/adr x11, (__RT_SVC_DESCS_START__ + RT_SVC_DESC_HANDLE)lsl w10, w15, #RT_SVC_SIZE_LOG2ldr x15, [x11, w10, uxtw]/** Call the Secure Monitor Call handler and then drop directly into* el3_exit() which will program any remaining architectural state* prior to issuing the ERET to the desired lower EL.*/
#if DEBUGcbz x15, rt_svc_fw_critical_error
#endifblr x15 //跳转到具体的smc handler
func el3_exit
#if ENABLE_ASSERTIONS/* el3_exit assumes SP_EL0 on entry */mrs x17, spselcmp x17, #MODE_SP_EL0ASM_ASSERT(eq)
#endif/* ----------------------------------------------------------* Save the current SP_EL0 i.e. the EL3 runtime stack which* will be used for handling the next SMC.* Then switch to SP_EL3.* ----------------------------------------------------------*/mov x17, spmsr spsel, #MODE_SP_ELXstr x17, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP]/* ----------------------------------------------------------* Restore SPSR_EL3, ELR_EL3 and SCR_EL3 prior to ERET* ----------------------------------------------------------*/ldr x18, [sp, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3]ldp x16, x17, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]msr scr_el3, x18msr spsr_el3, x16msr elr_el3, x17
接下来恢复el1的系统寄存器,通用寄存器,PMCR和PATUH寄存器。
restore_ptw_el1_sys_regs/* ----------------------------------------------------------* Restore general purpose (including x30), PMCR_EL0 and* ARMv8.3-PAuth registers.* Exit EL3 via ERET to a lower exception level.* ----------------------------------------------------------*/bl restore_gp_pmcr_pauth_regsldr x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
最后调用exception_return退出EL3的模式。exception_return就是一句eret,然后程序会回到el1,从elr_el1所指向的地方跑。
上一篇:字符串的算法题目-字符串