当前位置:   article > 正文

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

atf bl31 无法启动

     

在bl2中通过调用smc指令后会跳转到bl31中进行执行,bl31最终主要的作用是建立EL3 runtime software,在该阶段会建立各种类型的smc调用注册并完成对应的cortex状态切换。该阶段主要执行在monitor中。

1. bl31_entrypoint

通过bl31.ld.S文件可知, bl31的入口函数是:bl31_entrypoint函数,该函数的内容如下:

  1. 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
//执行完成将跳转到bl33中执行,即执行bootloader endfunc bl31_entrypoint

2. bl31_main

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

  1. void bl31_main(void)
  2. {
  3. NOTICE("BL31: %s\n", version_string);
  4. NOTICE("BL31: %s\n", build_message);
  5. /* Perform platform setup in BL31 */
  6. bl31_platform_setup(); //初始化相关驱动,时钟等
  7. /* Initialise helper libraries */
  8. bl31_lib_init(); //用于执行bl31软件中相关全局变量的初始化
  9. /* Initialize the runtime services e.g. psci. */
  10. INFO("BL31: Initializing runtime services\n");
  11. runtime_svc_init(); //初始化el3中的service,通过在编译时指定特定的section来确定哪些service会被作为el3 service
  12. /*
  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. */
  21. /*
  22. * If SPD had registerd an init hook, invoke it.
  23. */
  24. /* 如果注册了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的初始化*/
  25. if (bl32_init) {
  26. INFO("BL31: Initializing BL32\n");
  27. (*bl32_init)();
  28. }
  29. /*
  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. */
  33. bl31_prepare_next_image_entry(); //准备跳转到bl33,在执行runtime_service的时候会存在一个spd service,该在service的init函数中将会去执行bl32的image完成TEE OS初始化
  34. console_flush();
  35. /*
  36. * Perform any platform specific runtime setup prior to cold boot exit
  37. * from BL31
  38. */
  39. bl31_plat_runtime_setup();
  40. }

3. runtime_svc_init

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

  1. void runtime_svc_init(void)
  2. {
  3. int rc = 0, index, start_idx, end_idx;
  4. /* Assert the number of descriptors detected are less than maximum indices */
  5. /*判定rt_svc_descs段中的是否超出MAX_RT_SVCS条*/
  6. assert((RT_SVC_DESCS_END >= RT_SVC_DESCS_START) &&
  7. (RT_SVC_DECS_NUM < MAX_RT_SVCS));
  8. /* If no runtime services are implemented then simply bail out */
  9. if (RT_SVC_DECS_NUM == 0)
  10. return;
  11. /* Initialise internal variables to invalid state */
  12. /* 初始化 t_svc_descs_indices数组中的数据成-1,表示当前所有的service无效*/
  13. memset(rt_svc_descs_indices, -1, sizeof(rt_svc_descs_indices));
  14. /* 获取第一条EL3 service在RAM中的起始地址,通过获取RT_SVC_DESCS_START的值来确定,该值在链接文件中有定义 */
  15. rt_svc_descs = (rt_svc_desc_t *) RT_SVC_DESCS_START;
  16. /* 遍历整个rt_svc_des段,将其call type与rt_svc_descs_indices中的index建立对应关系 */
  17. for (index = 0; index < RT_SVC_DECS_NUM; index++) {
  18. rt_svc_desc_t *service = &rt_svc_descs[index];
  19. /*
  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. */
  24. /* 判定在编译的时候注册的service是否有效 */
  25. rc = validate_rt_svc_desc(service);
  26. if (rc) {
  27. ERROR("Invalid runtime service descriptor %p\n",
  28. (void *) service);
  29. panic();
  30. }
  31. /*
  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. */
  38. /* 执行当前service的init的操作 */
  39. if (service->init) {
  40. rc = service->init();
  41. if (rc) {
  42. ERROR("Error initializing runtime service %s\n",
  43. service->name);
  44. continue;
  45. }
  46. }
  47. /*
  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. */
  53. /* 根据该service的call type以及start oen来确定一个唯一的index,并且将该service中支持的所有的call type生成的唯一表示映射到同一个index中 */
  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. for (; 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. #define DECLARE_RT_SVC(_name, _start, _end, _type, _setup, _smch) \
  2. static const rt_svc_desc_t __svc_desc_ ## _name \
  3. __section("rt_svc_descs") __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文件中,内容如下:

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号