OP-TEE的内核初始化函数调用

描述

generic_boot_init_primary函数内容

generic_boot_init_primary函数是OP-TEE建立系统运行环境的入口函数,该函数会进行建立线程运行空间、初始化OP-TEE内核组件等操作。该函数的执行流程如图所示。

函数调用
generic_boot_init_primary函数执行流程

generic_boot_init_primary函数会调用init_primary_helper函数来完成系统运行环境的建立 ,如果系统支持ATF,则该函数会返回OP-TEE的处理句柄,该处理句柄主要包含

  • • 各种安全监控模式调用的处理函数、
  • • 安全世界状态(SWS)的中断
  • • 以及其他事件的处理函数,

ATF中的bl31解析完安全监控模式调用或中断请求后会在安全世界状态调用该处理句柄来处理对应的事件。

init_primary_helper函数的主要内容如下:

static void init_primary_helper(unsigned long pageable_part,
                        unsigned long nsec_entry, unsigned long fdt)
        {
            thread_set_exceptions(THREAD_EXCP_ALL); //设置支持哪些异常处理
            init_vfp_sec();                             //初始化浮点运算(根据实际需要考虑是否开启)
            //初始化各种memory,清空BSS段,分配TA运行时的memory
            init_runtime(pageable_part);
            /* 初始化TEE中支持的线程栈、异常处理、pagetable */
            thread_init_primary(generic_boot_get_handlers());
            //初始化每个CPU的monitor态的处理方式,如果支持ATF,则无需该操作
            thread_init_per_cpu();
            /* 如果系统不支持ATF,则需要配置在Linux内核中monitor的处理方式 */
            init_sec_mon(nsec_entry);
            /* 初始化device tree */
            init_fdt(fdt);
            /* 初始化中断控制器 */
            main_init_gic();
            /* 初始化非安全侧的浮点运算 */
            init_vfp_nsec();
            /* 初始化共享内存并执行存放在__initcall_start段的其他初始化函数 */
            if (init_teecore() ! = TEE_SUCCESS)
                panic();
            DMSG("Primary CPU switching to normal world bootn");
        }

init_primary_helper函数最后会调用init_teecore来完成OP-TEE内核的初始化 ,在init_teecore函数中会设定共享内存、系统时间,然后再返回去执行OP-TEE镜像文件中的_initcall段中的内容来启动系统的服务以及安全驱动的挂载。

call_initcalls函数

init_teecore函数通过调用call_initcalls来 启动系统的服务以及安全驱动的挂载 ,该函数的内容如下:

static void call_initcalls(void)
        {
            initcall_t *call;
            /* 遍历并执行_initcallx段中所有函数 */
            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函数之前,系统已完成了 memory、CPU相关设置、中断控制器、共享内存、线程堆栈设置、TA运行内存的分配等操作

call_initcalls是通过遍历OP-TEE镜像文件的_initcall段中从_initcall_start到_initcall_end之间的所有函数来完成启动服务和驱动的挂载操作。

OP-TEE镜像文件中** _initcalls段的内容是通过使用__define_initcall宏来告知编译器的**,在编译时会将使用该宏定义的函数保存到OP-TEE镜像文件的_initcall段中。该宏定义如下:

#define __define_initcall(level, fn) 
            static initcall_t __initcall_##fn __attribute__((used)) 
            __attribute__((__section__(".initcall" level))) = fn
  • • initcall_t:是一个函数指针类型(typedef int(*initcall_t)(void))。
  • attribute (( section ()):将fn对象放在一个由括号中的名称指定的section中。
  • • ##:连接作用。

例如,如果使用该宏如下:

__define_initcall("1", init_operation)

则该宏的作用是声明一个名称为__initcall_init_operation的函数指针,将该函数指针初始化为init_operation,并在编译时将该函数的内容存放在名称为“.initcall1”的段中。

core/arch/arm/kernel/kern.ld.S文件中存在如下内容:

__initcall_start = .;
        KEEP(*(.initcall1))
        KEEP(*(.initcall2))
        KEEP(*(.initcall3))
        KEEP(*(.initcall4))
        __initcall_end = .;

即在__initcall_start到__initcall_end之间保存的是initcall1到initcall4之间的内容,而在整个OP-TEE源代码的core/include/initcall.h文件中,__define_initcall宏被使用的情况如下:

#define __define_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)

所以遍历执行从__initcall_start到__initcall_end之间的内容就是启动OP-TEE的服务以及完成安全驱动的挂载。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分