optee的generic_boot_init_primary 分析

来源:互联网 发布:手机移动网络dns被劫持 编辑:程序博客网 时间:2024/06/14 15:53
generic_boot_init_primary是optee os初始化的主要函数
#if defined(CFG_WITH_ARM_TRUSTED_FW)
struct thread_vector_table *
generic_boot_init_primary(unsigned long pageable_part, unsigned long u __unused,
              unsigned long fdt)
{
    init_primary_helper(pageable_part, PADDR_INVALID, fdt);
    return &thread_vector_table;
}

unsigned long generic_boot_cpu_on_handler(unsigned long a0 __maybe_unused,
                     unsigned long a1 __unused)
{
    DMSG("cpu %zu: a0 0x%lx", get_core_pos(), a0);
    init_secondary_helper(PADDR_INVALID);
    return 0;
}
#else
void generic_boot_init_primary(unsigned long pageable_part,
                   unsigned long nsec_entry, unsigned long fdt)
{
    init_primary_helper(pageable_part, nsec_entry, fdt);
}

void generic_boot_init_secondary(unsigned long nsec_entry)
{
    init_secondary_helper(nsec_entry);
}
#endif
可见optee针对是否有ATF 提供不同的generic_boot_init_primary 函数,这里我们只讨论enable CFG_WITH_ARM_TRUSTED_FW的情况
generic_boot_init_primary 中仅仅是调用init_primary_helper

static void init_primary_helper(unsigned long pageable_part,
                unsigned long nsec_entry, unsigned long fdt)
{
    /*
     * Mask asynchronous exceptions before switch to the thread vector
     * as the thread handler requires those to be masked while
     * executing with the temporary stack. The thread subsystem also
     * asserts that the foreign interrupts are blocked when using most of
     * its functions.
     */
// 设定thread支持的所有异常,主要是写THREAD_EXCP_ALL到寄存器
    thread_set_exceptions(THREAD_EXCP_ALL);
//初始化cfp用于浮点运算,arm64 在init_vfp_sec 中disable vfp。要用vfp的话,需要通过thread_kernel_enable_vfp打开
    init_vfp_sec();
//只要是清零bss段,并设定heap的范围为__heap1_start~__heap1_end。初始化ta用的memory
    init_runtime(pageable_part);
//初始化thread用到的线程栈
    thread_init_primary(generic_boot_get_handlers());
//初始化pcpu结构
    thread_init_per_cpu();
    init_sec_mon(nsec_entry);
//初始化fdt,如果没有定义CFG_DT则为null函数
    init_fdt(fdt);
//从fdt中配置console
    configure_console_from_dt(fdt);

    IMSG("OP-TEE version: %s", core_v_str);
//初始化gic 各大厂商要自己实现
    main_init_gic();
//如果定义CFG_WITH_ARM_TRUSTED_FW 的话,init_vfp_nsec 为null 函数
    init_vfp_nsec();
//初始化共享内存并执行存放在__initcall_start段的其他初始化函数
    if (init_teecore() != TEE_SUCCESS)
        panic();
    DMSG("Primary CPU switching to normal world boot\n");
}
我们重点看一下init_teecore
TEE_Result init_teecore(void)
{
    static int is_first = 1;

    /* (DEBUG) for inits at 1st TEE service: when UART is setup */
    if (!is_first)
        return TEE_SUCCESS;
    is_first = 0;

#ifdef CFG_WITH_USER_TA
    tee_svc_uref_base = CFG_TEE_LOAD_ADDR;
#endif

    /* init support for future mapping of TAs */
    teecore_init_pub_ram();
//初始化timmer
    /* time initialization */
    time_source_init();
//调用initcall ,类似kernel
    /* call pre-define initcall routines */
    call_initcalls();

    IMSG("Initialized");
    return TEE_SUCCESS;
}

static void call_initcalls(void)
{
    initcall_t *call;

    for (call = &__initcall_start; call < &__initcall_end; call++) {
        TEE_Result ret;
        ret = (*call)();
        if (ret != TEE_SUCCESS) {
            EMSG("Initial call 0x%08" PRIxVA " failed",
                 (vaddr_t)call);
        }
    }
}
可以看到call_initcalls 会调用__initcall_start到__initcall_end 中定义的函数
inincalls的定义如下:
#ifndef INITCALL_H
#define INITCALL_H

#include <tee_api_types.h>

typedef TEE_Result (*initcall_t)(void);

#define __define_initcall(level, fn) \
    static initcall_t __initcall_##fn __attribute__((used)) \
    __attribute__((__section__(".initcall" level))) = fn

#define service_init(fn)    __define_initcall("1", fn)
#define service_init_late(fn)    __define_initcall("2", fn)
#define driver_init(fn)        __define_initcall("3", fn)
#define driver_init_late(fn)    __define_initcall("4", fn)

#endif
在程序中通过调用service_init/service_init_late/driver_init/driver_init_late 来注册initcall的函数,可见总共有四个优先级

static TEE_Result init_tzc400(void)
{
    void *va;

    DMSG("Initializing TZC400");

    va = phys_to_virt(TZC400_BASE, MEM_AREA_IO_SEC);
    if (!va) {
        EMSG("TZC400 not mapped");
        panic();
    }

    tzc_init((vaddr_t)va);
    tzc_dump_state();

    return TEE_SUCCESS;
}

service_init(init_tzc400);
例如这个例子中,就会在call_initcalls 中调用init_tzc400
原创粉丝点击