[ATF]-ATF的RT_SVC的详解(runtime service)

文章目录


★★★ 链接 : 个人博客导读首页—点击此处 ★★★


1、RT_SVC的分类

在SCC文档中对rt_svc进行了定义和分类,具体形式如下:

  • ARM Architecture Calls
  • CPU Service Calls
  • SiP Service Calls
  • OEM Service Calls
  • Standard Secure Service Calls
  • Standard Hypervisor Service Calls
  • Vendor Specific Hypervisor Service Calls
  • Trusted Application Calls
  • Trusted OS Calls
    [ATF]-ATF的RT_SVC的详解(runtime service)

目前我们在ATF中常用的主要是Trusted OS Calls,如果是在MTK平台上SiP Service Calls也常使用的.

2、RT_SVC的注册

在ATF中有多种类型的rt_svc, 不同的rt_svc为不同的场景服务. 我们下面举三个例子详细说明:

(1)、Trusted OS Calls
我们以optee os为例,在ATF中注册一个rt_svc,为linux和optee_os交互服务.

例如在opteed_main.c中,定义了一个service,该servic call ranges是OEN_TOS_START–OEN_TOS_END,正好落在50-63之间, 对应的就是Trusted OS Calls

DECLARE_RT_SVC(
	opteed_fast,

	OEN_TOS_START,
	OEN_TOS_END,
	SMC_TYPE_FAST,
	opteed_setup,
	opteed_smc_handler
);

那么我们在linux kernel程序中,想和optee os通信,需要通过ATF中的这类rt_svc才行,所以呢我们在linux kernel中构造的smc cmdid的bit29:24需为50–63之间,才能调起ATF中的该服务。 同样,在optee发起返回linux kernel的smc call的smcid也需在50–63之间

(2)、ARM Architecture Calls
例如在arm_arch_svc_setup.c中,定义了一个service,它的call类型是OEN_ARM_START–OEN_ARM_END,落在0-0之间,对应的恰好是ARM Architecture Calls

/* Register Standard Service Calls as runtime service */
DECLARE_RT_SVC(
		arm_arch_svc,
		OEN_ARM_START,
		OEN_ARM_END,
		SMC_TYPE_FAST,
		NULL,
		arm_arch_svc_smc_handler
);

那么我们在linux kernel中,调用smc时的smc id的bit29:24需要等于0,此次的smc调用才会调用到这个runtime service的handler程序

(3)、SiP Service Calls
例如在mtk_sip_svc.c中,定义了一个service,它的call类型是OEN_SIP_START–OEN_SIP_END,落在2-2之间,对应的恰好是SiP Service Calls

/* Define a runtime service descriptor for fast SMC calls */
DECLARE_RT_SVC(
	mediatek_sip_svc,
	OEN_SIP_START,
	OEN_SIP_END,
	SMC_TYPE_FAST,
	NULL,
	sip_smc_handler
);

那么我们在linux kernel中,调用smc时的smc id的bit29:24需要等于2,那么此次的smc调用才会调用到这个runtime service的handler程序

3、rt_svc定义的原理和rt_svc的请求实现

**(1)、定义实现 **
在runtime_svc.h中,DECLARE_RT_SVC宏其实就是在section(“rt_svc_descs”)段中定义了一个全局变量.

/*
 * Convenience macros to declare a service descriptor
 */
#define DECLARE_RT_SVC(_name, _start, _end, _type, _setup, _smch)	\
	static const rt_svc_desc_t __svc_desc_ ## _name			\
		__section("rt_svc_descs") __used = {			\
			.start_oen = (_start),				\
			.end_oen = (_end),				\
			.call_type = (_type),				\
			.name = #_name,					\
			.init = (_setup),				\
			.handle = (_smch)				\
		}

section “rt_svc_descs”在RT_SVC_DESCS宏中

#define RT_SVC_DESCS					\
	. = ALIGN(STRUCT_ALIGN);			\
	__RT_SVC_DESCS_START__ = .;			\
	KEEP(*(rt_svc_descs))				\
	__RT_SVC_DESCS_END__ = .;

而在rodata_common的宏中,定义了RT_SVC_DESCS

#define RODATA_COMMON					\
	RT_SVC_DESCS					\
	FCONF_POPULATOR					\
	PMF_SVC_DESCS					\
	PARSER_LIB_DESCS				\
	CPU_OPS						\
	GOT						\
	BASE_XLAT_TABLE_RO

在bl31.ld.S中,将RODATA_COMMON放入了rodata段

    .rodata . : {
        __RODATA_START__ = .;
        *(SORT_BY_ALIGNMENT(.rodata*))

	RODATA_COMMON

        /* Place pubsub sections for events */
        . = ALIGN(8);
#include <lib/el3_runtime/pubsub_events.h>

        . = ALIGN(PAGE_SIZE);
        __RODATA_END__ = .;
    } >RAM

(2)、请求RT_SVC

在linux/optee中调用smc call后,触发同步异常,进入smc_handler64程序,然后跳转到对应的rt_svc

完整代码和注释如下

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

#if ENABLE_PAUTH
	/* Load and program APIAKey firmware key */
	bl	pauth_load_bl31_apiakey
#endif

	/*
	 * 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, xzr
	mov	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]

	/* Switch to SP_EL0 */
	msr	spsel, #MODE_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_el3
	mrs	x17, elr_el3
	mrs	x18, scr_el3
	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, #1

	mov	sp, x12

	/* Get the unique owning entity number */
	ubfx	x16, x0, #FUNCID_OEN_SHIFT, #FUNCID_OEN_WIDTH  ---------------- 获取FUNCID_OEN_SHIFT,对应第一节中的OEN_TOS_START
	ubfx	x15, x0, #FUNCID_TYPE_SHIFT, #FUNCID_TYPE_WIDTH  ---------------- 获取FUNCID_TYPE_SHIFT,对应第一节中的SMC_TYPE_FAST(fast还是yield,yield其实就是standard)
	orr	x16, x16, x15, lsl #FUNCID_OEN_WIDTH

	/* Load descriptor index from array of indices */
	adrp	x14, rt_svc_descs_indices  ----在runtime_svc_init()中会将所有的section rt_svc_descs段放入rt_svc_descs_indices数组,这里获取该数组地址
	add	x14, x14, :lo12:rt_svc_descs_indices
	ldrb	w15, [x14, x16]   ---找到rt_svc在rt_svc_descs_indices数组中的index

	/* 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_LOG2
	ldr	x15, [x11, w10, uxtw]    ------------------------------这句话对应的就是上述注释:handler = (base + off) + (index << log2(size))

	/*
	 * 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 DEBUG
	cbz	x15, rt_svc_fw_critical_error
#endif
	blr	x15     -------------------------------------跳转到handler

	b	el3_exit
上一篇:MIT6.S081学习总结-lab2: system calls


下一篇:Season01_01