嵌入式开发论坛

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 58|回复: 0

5. ATF(ARM Trusted firmware)启动---bl31

[复制链接]

59

主题

62

帖子

249

积分

版主

Rank: 7Rank: 7Rank: 7

积分
249
发表于 2018-11-29 18:20:24 | 显示全部楼层 |阅读模式

在bl2中通过调用smc指令后会跳转到bl31中进行执行,bl31最终主要的作用是建立EL3 runtime software,在该阶段会建立各种类型的smc调用注册并完成对应的cortex状态切换。该阶段主要执行在monitor中。
1. bl31_entrypoint通过bl31.ld.S文件可知, bl31的入口函数是:bl31_entrypoint函数,该函数的内容如下:

  1. <code class="language-cpp">func bl31_entrypoint
  2. #if !RESET_TO_BL31
  3.         /* ---------------------------------------------------------------
  4.          * Preceding bootloader has populated x0 with a pointer to a
  5.          * 'bl31_params' structure & x1 with a pointer to platform
  6.          * specific structure
  7.          * ---------------------------------------------------------------
  8.          */
  9.         mov        x20, x0
  10.         mov        x21, x1

  11.         /* ---------------------------------------------------------------------
  12.          * For !RESET_TO_BL31 systems, only the primary CPU ever reaches
  13.          * bl31_entrypoint() during the cold boot flow, so the cold/warm boot
  14.          * and primary/secondary CPU logic should not be executed in this case.
  15.          *
  16.          * Also, assume that the previous bootloader has already set up the CPU
  17.          * endianness and has initialised the memory.
  18.          * ---------------------------------------------------------------------
  19.          */
  20. /* el3初始化操作,该el3_entrypoint_common函数在上面已经介绍过,其中runtime_exceptions为el3 runtime software的异常向量表,内容定义在bl31/aarch64/runtime_exceptions.S文件中 */
  21.         el3_entrypoint_common                                        \
  22.                 _set_endian=0                                        \
  23.                 _warm_boot_mailbox=0                                \
  24.                 _secondary_cold_boot=0                                \
  25.                 _init_memory=0                                        \
  26.                 _init_c_runtime=1                                \
  27.                 _exception_vectors=runtime_exceptions

  28.         /* ---------------------------------------------------------------------
  29.          * Relay the previous bootloader's arguments to the platform layer
  30.          * ---------------------------------------------------------------------
  31.          */
  32.         mov        x0, x20
  33.         mov        x1, x21
  34. #else
  35.         /* ---------------------------------------------------------------------
  36.          * For RESET_TO_BL31 systems which have a programmable reset address,
  37.          * bl31_entrypoint() is executed only on the cold boot path so we can
  38.          * skip the warm boot mailbox mechanism.
  39.          * ---------------------------------------------------------------------
  40.          */
  41.         el3_entrypoint_common                                        \
  42.                 _set_endian=1                                        \
  43.                 _warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS        \
  44.                 _secondary_cold_boot=!COLD_BOOT_SINGLE_CPU        \
  45.                 _init_memory=1                                        \
  46.                 _init_c_runtime=1                                \
  47.                 _exception_vectors=runtime_exceptions

  48.         /* ---------------------------------------------------------------------
  49.          * For RESET_TO_BL31 systems, BL31 is the first bootloader to run so
  50.          * there's no argument to relay from a previous bootloader. Zero the
  51.          * arguments passed to the platform layer to reflect that.
  52.          * ---------------------------------------------------------------------
  53.          */
  54.         mov        x0, 0
  55.         mov        x1, 0
  56. #endif /* RESET_TO_BL31 */

  57.         /* ---------------------------------------------
  58.          * Perform platform specific early arch. setup
  59.          * ---------------------------------------------
  60.          */
  61. /* 平台架构相关的初始化设置 */
  62.         bl        bl31_early_platform_setup
  63.         bl        bl31_plat_arch_setup

  64.         /* ---------------------------------------------
  65.          * Jump to main function.
  66.          * ---------------------------------------------
  67.          */
  68.         bl        bl31_main        //跳转到bl31_main函数,执行该阶段需要的主要操作

  69.         /* -------------------------------------------------------------
  70.          * Clean the .data & .bss sections to main memory. This ensures
  71.          * that any global data which was initialised by the primary CPU
  72.          * is visible to secondary CPUs before they enable their data
  73.          * caches and participate in coherency.
  74.          * -------------------------------------------------------------
  75.          */
  76.         adr        x0, __DATA_START__
  77.         adr        x1, __DATA_END__
  78.         sub        x1, x1, x0
  79.         bl        clean_dcache_range

  80.         adr        x0, __BSS_START__
  81.         adr        x1, __BSS_END__
  82.         sub        x1, x1, x0
  83.         bl        clean_dcache_range

  84.         b        el3_exit        //执行完成将跳转到bl33中执行,即执行bootloader
  85. endfunc bl31_entrypoint</code>        //执行完成将跳转到bl33中执行,即执行bootloader
  86. endfunc bl31_entrypoint
复制代码




2. bl31_main
该函数主要完成必要初始化操作,配置EL3中的各种smc操作,以便在后续顺利响应在CA和TA中产生的smc操作

  1. <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">bl31_main</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span>
  2. </span>{
  3.         NOTICE(<span class="hljs-string">"BL31: %s\n"</span>, version_string);
  4.         NOTICE(<span class="hljs-string">"BL31: %s\n"</span>, build_message);

  5.         <span class="hljs-comment">/* Perform platform setup in BL31 */</span>
  6.         bl31_platform_setup();        <span class="hljs-comment">//初始化相关驱动,时钟等</span>

  7.         <span class="hljs-comment">/* Initialise helper libraries */</span>
  8.         bl31_lib_init();        <span class="hljs-comment">//用于执行bl31软件中相关全局变量的初始化</span>

  9.         <span class="hljs-comment">/* Initialize the runtime services e.g. psci. */</span>
  10.         INFO(<span class="hljs-string">"BL31: Initializing runtime services\n"</span>);
  11.         runtime_svc_init();        <span class="hljs-comment">//初始化el3中的service,通过在编译时指定特定的section来确定哪些service会被作为el3 service</span>

  12.         <span class="hljs-comment">/*
  13.          * All the cold boot actions on the primary cpu are done. We now need to
  14.          * decide which is the next image (BL32 or BL33) and how to execute it.
  15.          * If the SPD runtime service is present, it would want to pass control
  16.          * to BL32 first in S-EL1. In that case, SPD would have registered a
  17.          * function to intialize bl32 where it takes responsibility of entering
  18.          * S-EL1 and returning control back to bl31_main. Once this is done we
  19.          * can prepare entry into BL33 as normal.
  20.          */</span>

  21.         <span class="hljs-comment">/*
  22.          * If SPD had registerd an init hook, invoke it.
  23.          */</span>
  24. <span class="hljs-comment">/* 如果注册了TEE OS支持,在调用完成run_service_init之后会使用TEE OS的入口函数初始化bl32_init变量,然后执行对应的Init函数,以OP-TEE为例,bl32_init将会被初始化成opteed_init,到此将会执行 opteed_init函数来进入OP-TEE OS的Image,当OP-TEE image OS执行完了image后,将会产生一个TEESMC_OPTEED_RETURN_ENTRY_DONE的smc来通过bl31已经完成了OP-TEE的初始化*/</span>
  25.         <span class="hljs-keyword">if</span> (bl32_init) {
  26.                 INFO(<span class="hljs-string">"BL31: Initializing BL32\n"</span>);
  27.                 (*bl32_init)();
  28.         }
  29.         <span class="hljs-comment">/*
  30.          * We are ready to enter the next EL. Prepare entry into the image
  31.          * corresponding to the desired security state after the next ERET.
  32.          */</span>
  33.         bl31_prepare_next_image_entry();                <span class="hljs-comment">//准备跳转到bl33,在执行runtime_service的时候会存在一个spd service,该在service的init函数中将会去执行bl32的image完成TEE OS初始化</span>

  34.         console_flush();

  35.         <span class="hljs-comment">/*
  36.          * Perform any platform specific runtime setup prior to cold boot exit
  37.          * from BL31
  38.          */</span>
  39.         bl31_plat_runtime_setup();
  40. }
复制代码



3. runtime_svc_init
该函数主要用来建立smc索引表并执行EL3中提供的service的初始化操作


  1. <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">runtime_svc_init</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span>
  2. </span>{
  3.         <span class="hljs-keyword">int</span> rc = <span class="hljs-number">0</span>, index, start_idx, end_idx;

  4.         <span class="hljs-comment">/* Assert the number of descriptors detected are less than maximum indices */</span>
  5. <span class="hljs-comment">/*判定rt_svc_descs段中的是否超出MAX_RT_SVCS条*/</span>
  6.         assert((RT_SVC_DESCS_END >= RT_SVC_DESCS_START) &&
  7.                         (RT_SVC_DECS_NUM < MAX_RT_SVCS));

  8.         <span class="hljs-comment">/* If no runtime services are implemented then simply bail out */</span>
  9.         <span class="hljs-keyword">if</span> (RT_SVC_DECS_NUM == <span class="hljs-number">0</span>)
  10.                 <span class="hljs-keyword">return</span>;

  11.         <span class="hljs-comment">/* Initialise internal variables to invalid state */</span>
  12. <span class="hljs-comment">/* 初始化 t_svc_descs_indices数组中的数据成-1,表示当前所有的service无效*/</span>
  13.         <span class="hljs-built_in">memset</span>(rt_svc_descs_indices, <span class="hljs-number">-1</span>, <span class="hljs-keyword">sizeof</span>(rt_svc_descs_indices));

  14. <span class="hljs-comment">/* 获取第一条EL3 service在RAM中的起始地址,通过获取RT_SVC_DESCS_START的值来确定,该值在链接文件中有定义 */</span>
  15.         rt_svc_descs = (<span class="hljs-keyword">rt_svc_desc_t</span> *) RT_SVC_DESCS_START;

  16. <span class="hljs-comment">/* 遍历整个rt_svc_des段,将其call type与rt_svc_descs_indices中的index建立对应关系 */</span>
  17.         <span class="hljs-keyword">for</span> (index = <span class="hljs-number">0</span>; index < RT_SVC_DECS_NUM; index++) {
  18.                 <span class="hljs-keyword">rt_svc_desc_t</span> *service = &rt_svc_descs[index];

  19.                 <span class="hljs-comment">/*
  20.                  * An invalid descriptor is an error condition since it is
  21.                  * difficult to predict the system behaviour in the absence
  22.                  * of this service.
  23.                  */</span>
  24. <span class="hljs-comment">/* 判定在编译的时候注册的service是否有效 */</span>
  25.                 rc = validate_rt_svc_desc(service);
  26.                 <span class="hljs-keyword">if</span> (rc) {
  27.                         ERROR(<span class="hljs-string">"Invalid runtime service descriptor %p\n"</span>,
  28.                                 (<span class="hljs-keyword">void</span> *) service);
  29.                         panic();
  30.                 }

  31.                 <span class="hljs-comment">/*
  32.                  * The runtime service may have separate rt_svc_desc_t
  33.                  * for its fast smc and standard smc. Since the service itself
  34.                  * need to be initialized only once, only one of them will have
  35.                  * an initialisation routine defined. Call the initialisation
  36.                  * routine for this runtime service, if it is defined.
  37.                  */</span>
  38. <span class="hljs-comment">/* 执行当前service的init的操作 */</span>
  39.                 <span class="hljs-keyword">if</span> (service->init) {
  40.                         rc = service->init();
  41.                         <span class="hljs-keyword">if</span> (rc) {
  42.                                 ERROR(<span class="hljs-string">"Error initializing runtime service %s\n"</span>,
  43.                                                 service->name);
  44.                                 <span class="hljs-keyword">continue</span>;
  45.                         }
  46.                 }

  47.                 <span class="hljs-comment">/*
  48.                  * Fill the indices corresponding to the start and end
  49.                  * owning entity numbers with the index of the
  50.                  * descriptor which will handle the SMCs for this owning
  51.                  * entity range.
  52.                  */</span>
  53. <span class="hljs-comment">/* 根据该service的call type以及start oen来确定一个唯一的index,并且将该service中支持的所有的call type生成的唯一表示映射到同一个index中 */</span>
  54.                 start_idx = get_unique_oen(rt_svc_descs[index].start_oen,
  55.                                 service->call_type);
  56.                 assert(start_idx < MAX_RT_SVCS);
  57.                 end_idx = get_unique_oen(rt_svc_descs[index].end_oen,
  58.                                 service->call_type);
  59.                 assert(end_idx < MAX_RT_SVCS);
  60.                 <span class="hljs-keyword">for</span> (; start_idx <= end_idx; start_idx++)
  61.                         rt_svc_descs_indices[start_idx] = index;
  62.         }
  63. }
复制代码





4. DECLARE_RT_SVC
该宏用来在编译的时候将EL3中的service编译进rt_svc_descs段中,该宏定义如下:

  1. #<span class="hljs-meta-keyword">define</span> DECLARE_RT_SVC(_name, _start, _end, _type, _setup, _smch) \
  2.         static const rt_svc_desc_t __svc_desc_ ## _name \
  3.                 __section(<span class="hljs-meta-string">"rt_svc_descs"</span>) __used = { \
  4.                         .start_oen = _start, \
  5.                         .end_oen = _end, \
  6.                         .call_type = _type, \
  7.                         .name = #_name, \
  8.                         .init = _setup, \
  9.                         .handle = _smch }
复制代码



start_oen:该service的起始内部number

end.oen: 该service的末尾number
call_type: 调用的smc的类型
name: 该service的名字
init: 该service在执行之前需要被执行的初始化操作
handle: 当触发了call type的调用时调用的handle该请求的函数
5.以OP-TEE为例从bl31跳转到OP-TEE实现从bl31到OP-TEE的跳转是通过执行opteed_setup函数来实现的,该函数在执行runtime_svc_int中对各service做service->init()函数来实现,而OPTEE这个service就是通过DECALARE_RT_SVC被注册到tr_svc_descs段中,代码存在service/spd/opteed/opteed_main.c文件中,内容如下:


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|TEE and Virtualization

GMT+8, 2019-3-18 23:26 , Processed in 0.085693 second(s), 19 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表