当前位置:   article > 正文

OPTEE学习笔记 - 启动流程(二)

optee

接上一篇OPTEE学习笔记 - 启动流程(一),本篇主要描述OPTEE被启动以后自己初始化的过程。

主核启动

由上篇文章可知,OPTEE第一个被执行的函数是__start

  1. FUNC _start , :
  2. mov x19, x0 /* Save pagable part address */
  3. #if defined(CFG_DT_ADDR)
  4. ldr x20, =CFG_DT_ADDR
  5. #else
  6. mov x20, x2 /* Save DT address */ /* 如果CFG_DT没配置,x2==0 */
  7. #endif
  8. adr x0, reset_vect_table
  9. msr vbar_el1, x0
  10. isb
  11. set_sctlr_el1
  12. isb
  13. #ifdef CFG_WITH_PAGER
  14. /* 忽略 */
  15. #else
  16. /*
  17. * The binary is built as:
  18. * [Core, rodata and data] : In correct location
  19. * [struct boot_embdata + data] : Should be moved to __end, first
  20. * uint32_t tells the length of the struct + data
  21. */
  22. adr_l x0, __end /* dst */
  23. adr_l x1, __data_end /* src */
  24. ldr w2, [x1] /* struct boot_embdata::total_len */ /* x2寄存器低32位保存struct长度 */
  25. /* Copy backwards (as memmove) in case we're overlapping */
  26. add x0, x0, x2 /* x0指向dst的末尾 */
  27. add x1, x1, x2 /* x1指向src的末尾 */
  28. adr x3, cached_mem_end
  29. str x0, [x3]
  30. adr_l x2, __end
  31. copy_init:
  32. ldp x3, x4, [x1, #-16]!
  33. stp x3, x4, [x0, #-16]!
  34. cmp x0, x2
  35. b.gt copy_init /* copy __data_end的数据到__end */
  36. #endif
  37. /*
  38. * Clear .bss, this code obviously depends on the linker keeping
  39. * start/end of .bss at least 8 byte aligned.
  40. */
  41. adr_l x0, __bss_start
  42. adr_l x1, __bss_end
  43. clear_bss:
  44. str xzr, [x0], #8
  45. cmp x0, x1
  46. b.lt clear_bss /* 清除bss段 */
  47. #ifdef CFG_VIRTUALIZATION
  48. /* 忽略 */
  49. #endif
  50. /* Setup SP_EL0 and SP_EL1, SP will be set to SP_EL0 */
  51. set_sp
  52. bl thread_init_thread_core_local
  53. /* Enable aborts now that we can receive exceptions */
  54. msr daifclr, #DAIFBIT_ABT
  55. /*
  56. * Invalidate dcache for all memory used during initialization to
  57. * avoid nasty surprices when the cache is turned on. We must not
  58. * invalidate memory not used by OP-TEE since we may invalidate
  59. * entries used by for instance ARM Trusted Firmware.
  60. */
  61. adr_l x0, __text_start
  62. ldr x1, cached_mem_end
  63. sub x1, x1, x0
  64. bl dcache_cleaninv_range
  65. /* Enable Console */
  66. bl console_init
  67. #ifdef CFG_CORE_ASLR
  68. /* 忽略 */
  69. #else
  70. mov x0, #0
  71. #endif
  72. adr x1, boot_mmu_config
  73. bl core_init_mmu_map
  74. #ifdef CFG_CORE_ASLR
  75. /* 忽略 */
  76. #endif
  77. bl __get_core_pos
  78. bl enable_mmu
  79. #ifdef CFG_CORE_ASLR
  80. /* 忽略 */
  81. #endif
  82. mov x0, x19 /* pagable part address */
  83. mov x1, #-1
  84. mov x2, x20 /* DT address */
  85. bl boot_init_primary
  86. /*
  87. * In case we've touched memory that secondary CPUs will use before
  88. * they have turned on their D-cache, clean and invalidate the
  89. * D-cache before exiting to normal world.
  90. */
  91. adr_l x0, __text_start
  92. ldr x1, cached_mem_end
  93. sub x1, x1, x0
  94. bl dcache_cleaninv_range
  95. /*
  96. * Clear current thread id now to allow the thread to be reused on
  97. * next entry. Matches the thread_init_boot_thread in
  98. * boot.c.
  99. */
  100. #ifndef CFG_VIRTUALIZATION
  101. bl thread_clr_boot_thread
  102. #endif
  103. #ifdef CFG_CORE_FFA
  104. /* 忽略 */
  105. #else
  106. /*
  107. * Pass the vector address returned from main_init
  108. * Compensate for the load offset since cpu_on_handler() is
  109. * called with MMU off.
  110. */
  111. ldr x0, boot_mmu_config + CORE_MMU_CONFIG_LOAD_OFFSET
  112. adr x1, thread_vector_table
  113. sub x1, x1, x0
  114. mov x0, #TEESMC_OPTEED_RETURN_ENTRY_DONE
  115. smc #0
  116. b . /* SMC should not return */
  117. #endif
  118. END_FUNC _start
  119. DECLARE_KEEP_INIT _start

_start主要做了以下几件事:

  1. 复制struct boot_embdata到__end以后,这里我没太明白struct boot_embdata的作用。从这段copy的逻辑看,这段数据在编译阶段是保存在bss段,copy到__end以后就清除掉了bss段。
  2. 跳转thread_init_thread_core_local初始化thread。OPTEE的thread设计会在其他文章中描述
  3. 初始化console
  4. 初始化mmu
  5. 跳转boot_init_primary。前篇提到,_start函数只会在primary core上被调用,secondary core的初始化是通过vector_cpu_on_entry函数实现的,因此我们目前说到的都是主核
  1. /*
  2. * Note: this function is weak just to make it possible to exclude it from
  3. * the unpaged area so that it lies in the init area.
  4. */
  5. void __weak boot_init_primary(unsigned long pageable_part,
  6. unsigned long nsec_entry __maybe_unused,
  7. unsigned long fdt)
  8. {
  9. unsigned long e = PADDR_INVALID;
  10. #if !defined(CFG_WITH_ARM_TRUSTED_FW)
  11. e = nsec_entry;
  12. #endif
  13. init_primary(pageable_part, e);
  14. paged_init_primary(fdt);
  15. }
  1. static void init_primary(unsigned long pageable_part, unsigned long nsec_entry)
  2. {
  3. /*
  4. * Mask asynchronous exceptions before switch to the thread vector
  5. * as the thread handler requires those to be masked while
  6. * executing with the temporary stack. The thread subsystem also
  7. * asserts that the foreign interrupts are blocked when using most of
  8. * its functions.
  9. */
  10. thread_set_exceptions(THREAD_EXCP_ALL);
  11. primary_save_cntfrq(); /* 空函数 */
  12. init_vfp_sec(); /* 空函数 */
  13. /*
  14. * Pager: init_runtime() calls thread_kernel_enable_vfp() so we must
  15. * set a current thread right now to avoid a chicken-and-egg problem
  16. * (thread_init_boot_thread() sets the current thread but needs
  17. * things set by init_runtime()).
  18. */
  19. thread_get_core_local()->curr_thread = 0;
  20. init_runtime(pageable_part); /* 初始化堆池 */
  21. if (IS_ENABLED(CFG_VIRTUALIZATION)) {
  22. /*
  23. * Virtualization: We can't initialize threads right now because
  24. * threads belong to "tee" part and will be initialized
  25. * separately per each new virtual guest. So, we'll clear
  26. * "curr_thread" and call it done.
  27. */
  28. thread_get_core_local()->curr_thread = -1;
  29. } else {
  30. thread_init_boot_thread();
  31. }
  32. thread_init_primary();
  33. thread_init_per_cpu();
  34. init_sec_mon(nsec_entry); /* 配置CFG_WITH_ARM_TRUSTED_FW,则是空函数 */
  35. }

init_primary()函数主要做了以下几件事:

  1. 初始化和设置本地线程
  2. 初始化堆池
  3. 设置本地线程栈空间

关于thread的设置将会在其他章节中描述,以上函数只简单说明一下thread_init_per_cpu

  1. void thread_init_per_cpu(void)
  2. {
  3. size_t pos = get_core_pos();
  4. struct thread_core_local *l = thread_get_core_local();
  5. init_sec_mon_stack(pos);
  6. set_tmp_stack(l, GET_STACK_BOTTOM(stack_tmp, pos) - STACK_TMP_OFFS);
  7. set_abt_stack(l, GET_STACK_BOTTOM(stack_abt, pos));
  8. thread_init_vbar(get_excp_vect());
  9. }

这个函数主要做的事情是对当前线程设置栈地址,然后设置了EL1的中断向量表。可以看到的是,在_start函数开始的地方也设置了中断向量表,设置的是reset_vect_table,在这里重新设置了中断向量表,是thread_excp_vect

从核启动

OPTEE学习笔记 - 启动流程(一)中的最后部分可知,从核启动是转入init_secondary_helper函数

  1. static void init_secondary_helper(unsigned long nsec_entry)
  2. {
  3. IMSG("Secondary CPU %zu initializing", get_core_pos());
  4. /*
  5. * Mask asynchronous exceptions before switch to the thread vector
  6. * as the thread handler requires those to be masked while
  7. * executing with the temporary stack. The thread subsystem also
  8. * asserts that the foreign interrupts are blocked when using most of
  9. * its functions.
  10. */
  11. thread_set_exceptions(THREAD_EXCP_ALL);
  12. secondary_init_cntfrq();
  13. thread_init_per_cpu();
  14. init_sec_mon(nsec_entry);
  15. main_secondary_init_gic();
  16. init_vfp_sec();
  17. init_vfp_nsec();
  18. IMSG("Secondary CPU %zu switching to normal world boot", get_core_pos());
  19. }

对比主核启动的初始化函数,可以看到做的内容差不多。

到目前为止,OPTEE的主从核就启动完成了。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/899348
推荐阅读
相关标签
  

闽ICP备14008679号