文章目录
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中常用的主要是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