在bl31_main 中会调用runtime_svc_init来初始化el3中定义的runtime service。由于runtime service都是通过DECLARE_RT_SVC 这个宏来定义的,从这个宏的实现可以发现所有的runtime service都是放在rt_svc_descs 这个段中
#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 }
void runtime_svc_init(void)
{
int rc = 0, index, start_idx, end_idx;
/* Assert the number of descriptors detected are less than maximum indices */
assert((RT_SVC_DESCS_END >= RT_SVC_DESCS_START) &&
(RT_SVC_DECS_NUM < MAX_RT_SVCS));
/* If no runtime services are implemented then simply bail out */
if (RT_SVC_DECS_NUM == 0)
return;
//将rt_svc_descs_indices 这个数组全部置成-1
/* Initialise internal variables to invalid state */
memset(rt_svc_descs_indices, -1, sizeof(rt_svc_descs_indices));
//rt_svc_descs 是个指针指向runtime service这个段的开始地址
rt_svc_descs = (rt_svc_desc_t *) RT_SVC_DESCS_START;
for (index = 0; index < RT_SVC_DECS_NUM; index++) {
rt_svc_desc_t *service = &rt_svc_descs[index];
/*
* An invalid descriptor is an error condition since it is
* difficult to predict the system behaviour in the absence
* of this service.
*/
//验证runtime service是否合法,实现比较简单,都是一些简单的判断.
rc = validate_rt_svc_desc(service);
if (rc) {
ERROR("Invalid runtime service descriptor %p\n",
(void *) service);
panic();
}
/*
* The runtime service may have separate rt_svc_desc_t
* for its fast smc and yielding smc. Since the service itself
* need to be initialized only once, only one of them will have
* an initialisation routine defined. Call the initialisation
* routine for this runtime service, if it is defined.
*/
//如果注册的runtime service的init函数不为null的话,就调用其init函数,例如opteed的init函数就是opteed_setup
if (service->init) {
rc = service->init();
if (rc) {
ERROR("Error initializing runtime service %s\n",
service->name);
continue;
}
}
/*
* Fill the indices corresponding to the start and end
* owning entity numbers with the index of the
* descriptor which will handle the SMCs for this owning
* entity range.
*/
//根据start_oen和service->call_type 生成唯一的start_idx,其实就是这两个变量移位只有在进行或操作
start_idx = get_unique_oen(rt_svc_descs[index].start_oen,
service->call_type);
assert(start_idx < MAX_RT_SVCS);
//生成唯一的end_idx
end_idx = get_unique_oen(rt_svc_descs[index].end_oen,
service->call_type);
assert(end_idx < MAX_RT_SVCS);
用index 填充start_idx和end_idx之间的memory.
for (; start_idx <= end_idx; start_idx++)
rt_svc_descs_indices[start_idx] = index;
}
}
在这个函数中会先判断这个rt_svc_descs 段是否ok。
#define RT_SVC_DESCS_START ((uintptr_t) (&__RT_SVC_DESCS_START__))
#define RT_SVC_DESCS_END ((uintptr_t) (&__RT_SVC_DESCS_END__))
而__RT_SVC_DESCS_START__和__RT_SVC_DESCS_END__ 分别表示rt_svc_descs的开始地址和结束地址,其是定义在一般在平台自己实现的code中,例如:
arm-trusted-firmware-master/plat/mediatek/mt6795/bl31.ld.S
__RT_SVC_DESCS_START__ = .;
KEEP(*(rt_svc_descs))
__RT_SVC_DESCS_END__ = .;
从(RT_SVC_DECS_NUM < MAX_RT_SVCS) 可以runtime service 最多不能超过128个.
runtime service 初始化就完成了。
在smc_handler64 中
/* Get the unique owning entity number */
ubfx x16, x0, #FUNCID_OEN_SHIFT, #FUNCID_OEN_WIDTH
ubfx x15, x0, #FUNCID_TYPE_SHIFT, #FUNCID_TYPE_WIDTH
orr x16, x16, x15, lsl #FUNCID_OEN_WIDTH
//这里x11 就指向runtime service的起始地址
adr x11, (__RT_SVC_DESCS_START__ + RT_SVC_DESC_HANDLE)
/* Load descriptor index from array of indices */
adr x14, rt_svc_descs_indices
ldrb w15, [x14, x16]
/*
* 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]
/*
* Any index greater than 127 is invalid. Check bit 7 for
* a valid index
*/
tbnz w15, 7, smc_unknown
/* Switch to SP_EL0 */
msr spsel, #0
/*
* Get the descriptor using the index
* x11 = (base + off), x15 = index
*
* handler = (base + off) + (index << log2(size))
*/
lsl w10, w15, #RT_SVC_SIZE_LOG2
//从x11开始找到runtime service的地址,然后存在x15 中,具体算法是x11 = (base + off), x15 = index
ldr x15, [x11, w10, uxtw]
最后跳到x15的runtime service开始执行,以opteed为例的话,这里的handler就是opteed_smc_handler
blr x15
执行完成后返回。
b el3_exit
#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 }
void runtime_svc_init(void)
{
int rc = 0, index, start_idx, end_idx;
/* Assert the number of descriptors detected are less than maximum indices */
assert((RT_SVC_DESCS_END >= RT_SVC_DESCS_START) &&
(RT_SVC_DECS_NUM < MAX_RT_SVCS));
/* If no runtime services are implemented then simply bail out */
if (RT_SVC_DECS_NUM == 0)
return;
//将rt_svc_descs_indices 这个数组全部置成-1
/* Initialise internal variables to invalid state */
memset(rt_svc_descs_indices, -1, sizeof(rt_svc_descs_indices));
//rt_svc_descs 是个指针指向runtime service这个段的开始地址
rt_svc_descs = (rt_svc_desc_t *) RT_SVC_DESCS_START;
for (index = 0; index < RT_SVC_DECS_NUM; index++) {
rt_svc_desc_t *service = &rt_svc_descs[index];
/*
* An invalid descriptor is an error condition since it is
* difficult to predict the system behaviour in the absence
* of this service.
*/
//验证runtime service是否合法,实现比较简单,都是一些简单的判断.
rc = validate_rt_svc_desc(service);
if (rc) {
ERROR("Invalid runtime service descriptor %p\n",
(void *) service);
panic();
}
/*
* The runtime service may have separate rt_svc_desc_t
* for its fast smc and yielding smc. Since the service itself
* need to be initialized only once, only one of them will have
* an initialisation routine defined. Call the initialisation
* routine for this runtime service, if it is defined.
*/
//如果注册的runtime service的init函数不为null的话,就调用其init函数,例如opteed的init函数就是opteed_setup
if (service->init) {
rc = service->init();
if (rc) {
ERROR("Error initializing runtime service %s\n",
service->name);
continue;
}
}
/*
* Fill the indices corresponding to the start and end
* owning entity numbers with the index of the
* descriptor which will handle the SMCs for this owning
* entity range.
*/
//根据start_oen和service->call_type 生成唯一的start_idx,其实就是这两个变量移位只有在进行或操作
start_idx = get_unique_oen(rt_svc_descs[index].start_oen,
service->call_type);
assert(start_idx < MAX_RT_SVCS);
//生成唯一的end_idx
end_idx = get_unique_oen(rt_svc_descs[index].end_oen,
service->call_type);
assert(end_idx < MAX_RT_SVCS);
用index 填充start_idx和end_idx之间的memory.
for (; start_idx <= end_idx; start_idx++)
rt_svc_descs_indices[start_idx] = index;
}
}
在这个函数中会先判断这个rt_svc_descs 段是否ok。
#define RT_SVC_DESCS_START ((uintptr_t) (&__RT_SVC_DESCS_START__))
#define RT_SVC_DESCS_END ((uintptr_t) (&__RT_SVC_DESCS_END__))
而__RT_SVC_DESCS_START__和__RT_SVC_DESCS_END__ 分别表示rt_svc_descs的开始地址和结束地址,其是定义在一般在平台自己实现的code中,例如:
arm-trusted-firmware-master/plat/mediatek/mt6795/bl31.ld.S
__RT_SVC_DESCS_START__ = .;
KEEP(*(rt_svc_descs))
__RT_SVC_DESCS_END__ = .;
从(RT_SVC_DECS_NUM < MAX_RT_SVCS) 可以runtime service 最多不能超过128个.
runtime service 初始化就完成了。
在smc_handler64 中
/* Get the unique owning entity number */
ubfx x16, x0, #FUNCID_OEN_SHIFT, #FUNCID_OEN_WIDTH
ubfx x15, x0, #FUNCID_TYPE_SHIFT, #FUNCID_TYPE_WIDTH
orr x16, x16, x15, lsl #FUNCID_OEN_WIDTH
//这里x11 就指向runtime service的起始地址
adr x11, (__RT_SVC_DESCS_START__ + RT_SVC_DESC_HANDLE)
/* Load descriptor index from array of indices */
adr x14, rt_svc_descs_indices
ldrb w15, [x14, x16]
/*
* 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]
/*
* Any index greater than 127 is invalid. Check bit 7 for
* a valid index
*/
tbnz w15, 7, smc_unknown
/* Switch to SP_EL0 */
msr spsel, #0
/*
* Get the descriptor using the index
* x11 = (base + off), x15 = index
*
* handler = (base + off) + (index << log2(size))
*/
lsl w10, w15, #RT_SVC_SIZE_LOG2
//从x11开始找到runtime service的地址,然后存在x15 中,具体算法是x11 = (base + off), x15 = index
ldr x15, [x11, w10, uxtw]
最后跳到x15的runtime service开始执行,以opteed为例的话,这里的handler就是opteed_smc_handler
blr x15
执行完成后返回。
b el3_exit