ATF SMC处理
创始人
2024-01-29 10:58:30
0

文章目录

  • ATF SMC上下文结构体
  • SMC handler实现

ATF SMC上下文结构体

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 */

SMC handler实现

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

这段代码很简单,

  1. 把当前的时间戳存到当前线程上下文中。
  2. 读出ESR_EL3的EC字段在这里插入图片描述
  3. 根据EC字段的值处理,如果是触发的aarch32的SMC, 就进入smc_handler32;如果触发的aarch64的SMC,就进入smc_handler64;否则就进入默认处理函数enter_lower_el_sync_ea 在这里插入图片描述
    在这里插入图片描述
	.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实现如下:

  1. 保存gp,pmcr,patuh寄存器到上下文中。
    bl31/aarch64/runtime_exception.S

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
  1. 切换SMC runtime的栈指针为SP_EL0, 并保存EL3相关寄存器。
	/** 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															
  1. 计算SMC handler索引,并判断其不得大于127。
	/* 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
  1. 根据SMC handler索引从__RT_SVC_DESCS_HANDLE中获取具体handler的函数指针。这个函数指针是在runtime_svc_init中初始化的。
	/** 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
  1. smc处理完之后调用el3_exit退出SMC。el3_exit上来先把SP设为SP_EL3,然后从栈中恢复SCR_EL3, SPSR_EL3,这个函数正好跟之前的保存上下文的操作反过来。
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所指向的地方跑。

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...