bl31 runtime service的注册和查找

来源:互联网 发布:不可逆矩阵qr分解 编辑:程序博客网 时间:2024/05/17 08:59
在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




原创粉丝点击