嵌入式开发论坛

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

2. ATF(ARM Trusted firmware)启动---bl1

[复制链接]

59

主题

62

帖子

249

积分

版主

Rank: 7Rank: 7Rank: 7

积分
249
发表于 2018-11-29 18:10:17 | 显示全部楼层 |阅读模式
ATF(ARM Trusted Firmware)是一针对ARM芯片给出的底层的开源固件代码。固件将整个系统分成三种安全等级,分别为:EL0,EL1,EL2,并规定了每个安全等级中运行的Image名字。本文以ARCH64为示例,介绍冷启动时,ATF的运行过程。ATF的源代码可以从github上获取,具体地址如下:

  系统上电之后首先会运行SCP boot ROM。之后会跳转到ATF的bl1中继续执行。bl1主要初始化CPU,设定异常向量,将bl2的image加载到安全RAM中,然后跳转到bl2中进行执行。
  在bl2中将会去加载bl31和bl32以及bl33,其中的cpu状态切换以及跳转将在以下章节详细介绍。
  bl1的主要代码存放在bl1目录中, bl1的连接脚本是bl1/bl1.ld.s文件,其中可以看到bl1的入口函数是:bl1_entrypoint。
1.1 bl1_entrypoint  该函数主要需要执行EL3环境的基本初始化,设定向量表,加载bl2 image并跳转到bl2等操作

  1. func bl1_entrypoint
  2.         <span class="hljs-comment">/* ---------------------------------------------------------------------
  3.          * If the reset address is programmable then bl1_entrypoint() is
  4.          * executed only on the cold boot path. Therefore, we can skip the warm
  5.          * boot mailbox mechanism.
  6.          * ---------------------------------------------------------------------
  7.          */</span>
  8. <span class="hljs-comment">/* EL3级别运行环境的初始化,该函数定义在   include/common/aarch64/el3_common_macros.S文件中
  9. */</span>
  10.         el3_entrypoint_common                                        \
  11.                 _set_endian=<span class="hljs-number">1</span>                                        \
  12.                 _warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS        \
  13.                 _secondary_cold_boot=!COLD_BOOT_SINGLE_CPU        \
  14.                 _init_memory=<span class="hljs-number">1</span>                                        \
  15.                 _init_c_runtime=<span class="hljs-number">1</span>                                \
  16.                 _exception_vectors=bl1_exceptions

  17.         <span class="hljs-comment">/* ---------------------------------------------
  18.          * Architectural init. can be generic e.g.
  19.          * enabling stack alignment and platform spec-
  20.          * ific e.g. MMU & page table setup as per the
  21.          * platform memory map. Perform the latter here
  22.          * and the former in bl1_main.
  23.          * ---------------------------------------------
  24.          */</span>
  25.         bl        bl1_early_platform_setup        <span class="hljs-comment">//调用bl1_early_platform_setup函数完成底层初始化</span>
  26.         bl        bl1_plat_arch_setup        <span class="hljs-comment">//调用bl1_plat_arch_setup完成平台初始化</span>

  27.         <span class="hljs-comment">/* --------------------------------------------------
  28.          * Initialize platform and jump to our c-entry point
  29.          * for this type of reset.
  30.          * --------------------------------------------------
  31.          */</span>
  32.         bl        bl1_main        <span class="hljs-comment">//调用bl1_main函数,初始化验证模块,加载下一阶段的image到RAM中</span>

  33.         <span class="hljs-comment">/* --------------------------------------------------
  34.          * Do the transition to next boot image.
  35.          * --------------------------------------------------
  36.          */</span>
  37.         b        el3_exit        <span class="hljs-comment">//调用el3_exit函数,跳转到下一个image(bl2)</span>
  38. endfunc bl1_entrypoint
复制代码





1.2 el3_entrypoint_common函数
该函数是以宏的形式被定义的,主要完成el3基本设置和向量表注册

  1. .macro el3_entrypoint_common                                        \
  2.                 _set_endian, _warm_boot_mailbox, _secondary_cold_boot,        \
  3.                 _init_memory, _init_c_runtime, _exception_vectors
  4. <span class="hljs-comment">/* 设定大小端 */</span>
  5.         .<span class="hljs-keyword">if</span> \_set_endian
  6.                 <span class="hljs-comment">/* -------------------------------------------------------------
  7.                  * Set the CPU endianness before doing anything that might
  8.                  * involve memory reads or writes.
  9.                  * -------------------------------------------------------------
  10.                  */</span>
  11.                 mrs        x0, sctlr_el3
  12.                 bic        x0, x0, #SCTLR_EE_BIT
  13.                 msr        sctlr_el3, x0
  14.                 isb
  15.         .endif <span class="hljs-comment">/* _set_endian */</span>

  16. <span class="hljs-comment">/* 判定是否需要调用do_cold_boot流程 */</span>
  17.         .<span class="hljs-keyword">if</span> \_warm_boot_mailbox
  18.                 <span class="hljs-comment">/* -------------------------------------------------------------
  19.                  * This code will be executed for both warm and cold resets.
  20.                  * Now is the time to distinguish between the two.
  21.                  * Query the platform entrypoint address and if it is not zero
  22.                  * then it means it is a warm boot so jump to this address.
  23.                  * -------------------------------------------------------------
  24.                  */</span>
  25.                 bl        plat_get_my_entrypoint
  26.                 cbz        x0, do_cold_boot
  27.                 br        x0

  28.         do_cold_boot:
  29.         .endif <span class="hljs-comment">/* _warm_boot_mailbox */</span>

  30.         <span class="hljs-comment">/* ---------------------------------------------------------------------
  31.          * It is a cold boot.
  32.          * Perform any processor specific actions upon reset e.g. cache, TLB
  33.          * invalidations etc.
  34.          * ---------------------------------------------------------------------
  35.          */</span>
  36.         bl        reset_handler                <span class="hljs-comment">//执行reset handle操作</span>

  37. <span class="hljs-comment">/* 初始化异常向量 */</span>
  38.         el3_arch_init_common \_exception_vectors

  39. <span class="hljs-comment">/* 判定当前CPU是否是主CPU,如果是则做主CPU的初始化 */</span>
  40.         .<span class="hljs-keyword">if</span> \_secondary_cold_boot
  41.                 <span class="hljs-comment">/* -------------------------------------------------------------
  42.                  * Check if this is a primary or secondary CPU cold boot.
  43.                  * The primary CPU will set up the platform while the
  44.                  * secondaries are placed in a platform-specific state until the
  45.                  * primary CPU performs the necessary actions to bring them out
  46.                  * of that state and allows entry into the OS.
  47.                  * -------------------------------------------------------------
  48.                  */</span>
  49.                 bl        plat_is_my_cpu_primary
  50.                 cbnz        w0, do_primary_cold_boot

  51.                 <span class="hljs-comment">/* This is a cold boot on a secondary CPU */</span>
  52.                 bl        plat_secondary_cold_boot_setup
  53.                 <span class="hljs-comment">/* plat_secondary_cold_boot_setup() is not supposed to return */</span>
  54.                 bl        el3_panic

  55.         do_primary_cold_boot:
  56.         .endif <span class="hljs-comment">/* _secondary_cold_boot */</span>

  57.         <span class="hljs-comment">/* ---------------------------------------------------------------------
  58.          * Initialize memory now. Secondary CPU initialization won't get to this
  59.          * point.
  60.          * ---------------------------------------------------------------------
  61.          */</span>
  62. <span class="hljs-comment">/* 初始化memory */</span>
  63.         .<span class="hljs-keyword">if</span> \_init_memory
  64.                 bl        platform_mem_init
  65.         .endif <span class="hljs-comment">/* _init_memory */</span>

  66.         <span class="hljs-comment">/* ---------------------------------------------------------------------
  67.          * Init C runtime environment:
  68.          *   - Zero-initialise the NOBITS sections. There are 2 of them:
  69.          *       - the .bss section;
  70.          *       - the coherent memory section (if any).
  71.          *   - Relocate the data section from ROM to RAM, if required.
  72.          * ---------------------------------------------------------------------
  73.          */</span>
  74. <span class="hljs-comment">/* 初始化C语言的运行环境 */</span>
  75.         .<span class="hljs-keyword">if</span> \_init_c_runtime
  76. <span class="hljs-meta">#<span class="hljs-meta-keyword">ifdef</span> IMAGE_BL31</span>
  77.                 <span class="hljs-comment">/* -------------------------------------------------------------
  78.                  * Invalidate the RW memory used by the BL31 image. This
  79.                  * includes the data and NOBITS sections. This is done to
  80.                  * safeguard against possible corruption of this memory by
  81.                  * dirty cache lines in a system cache as a result of use by
  82.                  * an earlier boot loader stage.
  83.                  * -------------------------------------------------------------
  84.                  */</span>
  85.                 adr        x0, __RW_START__
  86.                 adr        x1, __RW_END__
  87.                 sub        x1, x1, x0
  88.                 bl        inv_dcache_range
  89. <span class="hljs-meta">#<span class="hljs-meta-keyword">endif</span> <span class="hljs-comment">/* IMAGE_BL31 */</span></span>

  90.                 ldr        x0, =__BSS_START__
  91.                 ldr        x1, =__BSS_SIZE__
  92.                 bl        zeromem

  93. #<span class="hljs-keyword">if</span> USE_COHERENT_MEM
  94.                 ldr        x0, =__COHERENT_RAM_START__
  95.                 ldr        x1, =__COHERENT_RAM_UNALIGNED_SIZE__
  96.                 bl        zeromem
  97. #endif

  98. #ifdef IMAGE_BL1
  99.                 ldr        x0, =__DATA_RAM_START__
  100.                 ldr        x1, =__DATA_ROM_START__
  101.                 ldr        x2, =__DATA_SIZE__
  102.                 bl        memcpy16
  103. #endif
  104.         .endif <span class="hljs-comment">/* _init_c_runtime */</span>

  105.         <span class="hljs-comment">/* ---------------------------------------------------------------------
  106.          * Use SP_EL0 for the C runtime stack.
  107.          * ---------------------------------------------------------------------
  108.          */</span>
  109.         msr        spsel, #<span class="hljs-number">0</span>

  110.         <span class="hljs-comment">/* ---------------------------------------------------------------------
  111.          * Allocate a stack whose memory will be marked as Normal-IS-WBWA when
  112.          * the MMU is enabled. There is no risk of reading stale stack memory
  113.          * after enabling the MMU as only the primary CPU is running at the
  114.          * moment.
  115.          * ---------------------------------------------------------------------
  116.          */</span>
  117.         bl        plat_set_my_stack        <span class="hljs-comment">//设定堆栈</span>

  118. #<span class="hljs-keyword">if</span> STACK_PROTECTOR_ENABLED
  119.         .<span class="hljs-keyword">if</span> \_init_c_runtime
  120.         bl        update_stack_protector_canary
  121.         .endif <span class="hljs-comment">/* _init_c_runtime */</span>
  122. #endif
  123.         .endm

  124. #endif <span class="hljs-comment">/* __EL3_COMMON_MACROS_S__ */</span>
复制代码



该函数是需要带参数调用,参数说明如下:

_set_endian:设定大小端
_warm_boot_mailbox:检查当前是属于冷启动还是热启动(power on or reset)
_secondary_cold_boot: 确定当前的CPU是主CPU还是从属CPU
_init_memory:是否需要初始化memory
_init_c_runtime: 是否需要初始化C语言的执行环境
_exception_vectors: 异常向量表地址
1.3 bl1_early_patform_setup该函数用来完成早期的初始化操作,主要包括memory, page table, 所需外围设备的初始化以及相关状态设定等;

  1. <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">bl1_early_platform_setup</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span>
  2. </span>{
  3. <span class="hljs-comment">/* 使能看门狗,初始化console,初始化memory */</span>
  4.         arm_bl1_early_platform_setup();

  5.         <span class="hljs-comment">/*
  6.          * Initialize Interconnect for this cluster during cold boot.
  7.          * No need for locks as no other CPU is active.
  8.          */</span>
  9.         plat_arm_interconnect_init();<span class="hljs-comment">//初始化外围设备</span>
  10.         <span class="hljs-comment">/*
  11.          * Enable Interconnect coherency for the primary CPU's cluster.
  12.          */</span>
  13.         plat_arm_interconnect_enter_coherency();<span class="hljs-comment">//使能外围设备</span>
  14. }
复制代码



1.4 bl_main
该函数完成bl2 image的加载和运行环境的设置,如果开启了trusted boot,则需要对image进行verify操作

  1. <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">bl1_main</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span>
  2. </span>{
  3.         <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> image_id;

  4.         <span class="hljs-comment">/* Announce our arrival */</span>
  5.         NOTICE(FIRMWARE_WELCOME_STR);
  6.         NOTICE(<span class="hljs-string">"BL1: %s\n"</span>, version_string);
  7.         NOTICE(<span class="hljs-string">"BL1: %s\n"</span>, build_message);

  8.         INFO(<span class="hljs-string">"BL1: RAM %p - %p\n"</span>, (<span class="hljs-keyword">void</span> *)BL1_RAM_BASE,
  9.                                         (<span class="hljs-keyword">void</span> *)BL1_RAM_LIMIT);

  10.         print_errata_status();

  11. <span class="hljs-meta">#<span class="hljs-meta-keyword">if</span> DEBUG</span>
  12.         <span class="hljs-keyword">u_register_t</span> val;
  13.         <span class="hljs-comment">/*
  14.          * Ensure that MMU/Caches and coherency are turned on
  15.          */</span>
  16. <span class="hljs-meta">#<span class="hljs-meta-keyword">ifdef</span> AARCH32</span>
  17.         val = read_sctlr();
  18. <span class="hljs-meta">#<span class="hljs-meta-keyword">else</span></span>
  19.         val = read_sctlr_el3();
  20. <span class="hljs-meta">#<span class="hljs-meta-keyword">endif</span></span>
  21.         assert(val & SCTLR_M_BIT);
  22.         assert(val & SCTLR_C_BIT);
  23.         assert(val & SCTLR_I_BIT);
  24.         <span class="hljs-comment">/*
  25.          * Check that Cache Writeback Granule (CWG) in CTR_EL0 matches the
  26.          * provided platform value
  27.          */</span>
  28.         val = (read_ctr_el0() >> CTR_CWG_SHIFT) & CTR_CWG_MASK;
  29.         <span class="hljs-comment">/*
  30.          * If CWG is zero, then no CWG information is available but we can
  31.          * at least check the platform value is less than the architectural
  32.          * maximum.
  33.          */</span>
  34.         <span class="hljs-keyword">if</span> (val != <span class="hljs-number">0</span>)
  35.                 assert(CACHE_WRITEBACK_GRANULE == SIZE_FROM_LOG2_WORDS(val));
  36.         <span class="hljs-keyword">else</span>
  37.                 assert(CACHE_WRITEBACK_GRANULE <= MAX_CACHE_LINE_SIZE);
  38. <span class="hljs-meta">#<span class="hljs-meta-keyword">endif</span></span>

  39.         <span class="hljs-comment">/* Perform remaining generic architectural setup from EL3 */</span>
  40.         bl1_arch_setup();        <span class="hljs-comment">//设置下一个image的EL级别</span>

  41. <span class="hljs-meta">#<span class="hljs-meta-keyword">if</span> TRUSTED_BOARD_BOOT</span>
  42.         <span class="hljs-comment">/* Initialize authentication module */</span>
  43.         auth_mod_init();        <span class="hljs-comment">//初始化image的验证模块</span>
  44. <span class="hljs-meta">#<span class="hljs-meta-keyword">endif</span> <span class="hljs-comment">/* TRUSTED_BOARD_BOOT */</span></span>

  45.         <span class="hljs-comment">/* Perform platform setup in BL1. */</span>
  46.         bl1_platform_setup();        <span class="hljs-comment">//平台相关设置,主要是IO的设置</span>

  47.         <span class="hljs-comment">/* Get the image id of next image to load and run. */</span>
  48.         image_id = bl1_plat_get_next_image_id();        <span class="hljs-comment">//获取下一个阶段image的ID值。默认返回值为BL2_IMAGE_ID</span>

  49.         <span class="hljs-comment">/*
  50.          * We currently interpret any image id other than
  51.          * BL2_IMAGE_ID as the start of firmware update.
  52.          */</span>
  53.         <span class="hljs-keyword">if</span> (image_id == BL2_IMAGE_ID)
  54.                 bl1_load_bl2();                <span class="hljs-comment">//将bl2 image加载到安全RAM中</span>
  55.         <span class="hljs-keyword">else</span>
  56.                 NOTICE(<span class="hljs-string">"BL1-FWU: *******FWU Process Started*******\n"</span>);

  57.         bl1_prepare_next_image(image_id);        <span class="hljs-comment">//获取bl2 image的描述信息,包括名字,ID,entry potin info等,并将这些信息保存到bl1_cpu_context的上下文中</span>
  58.         console_flush();
  59. }
复制代码



1.5 bl1_prepare_next_image
该函数用来获取bl2 image的描述信息,获取bl2的入口地址,这只下个阶段的CPU上下文,以备执行从bl1跳转到bl2的操作使用

  1. <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">bl1_prepare_next_image</span><span class="hljs-params">(<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> image_id)</span>
  2. </span>{
  3.         <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> security_state;
  4.         <span class="hljs-keyword">image_desc_t</span> *image_desc;
  5.         <span class="hljs-keyword">entry_point_info_t</span> *next_bl_ep;

  6. <span class="hljs-meta">#<span class="hljs-meta-keyword">if</span> CTX_INCLUDE_AARCH32_REGS</span>
  7.         <span class="hljs-comment">/*
  8.          * Ensure that the build flag to save AArch32 system registers in CPU
  9.          * context is not set for AArch64-only platforms.
  10.          */</span>
  11.         <span class="hljs-keyword">if</span> (((read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL1_SHIFT)
  12.                         & ID_AA64PFR0_ELX_MASK) == <span class="hljs-number">0x1</span>) {
  13.                 ERROR(<span class="hljs-string">"EL1 supports AArch64-only. Please set build flag "</span>
  14.                                 <span class="hljs-string">"CTX_INCLUDE_AARCH32_REGS = 0"</span>);
  15.                 panic();
  16.         }
  17. <span class="hljs-meta">#<span class="hljs-meta-keyword">endif</span></span>

  18.         <span class="hljs-comment">/* Get the image descriptor. */</span>
  19. <span class="hljs-comment">/* 获取bl2 image的描述信息,主要包括入口地址,名字等信息 */</span>
  20.         image_desc = bl1_plat_get_image_desc(image_id);
  21.         assert(image_desc);

  22.         <span class="hljs-comment">/* Get the entry point info. */</span>
  23. <span class="hljs-comment">/* 获取image的入口地址信息 */</span>
  24.         next_bl_ep = &image_desc->ep_info;

  25.         <span class="hljs-comment">/* Get the image security state. */</span>
  26. <span class="hljs-comment">/* 获取bl2 image的安全状态(判定该image是属于安全态的image的还是非安全态的image) */</span>
  27.         security_state = GET_SECURITY_STATE(next_bl_ep->h.attr);

  28.         <span class="hljs-comment">/* Setup the Secure/Non-Secure context if not done already. */</span>
  29. <span class="hljs-comment">/* 设定用于存放CPU context的变量 */</span>
  30.         <span class="hljs-keyword">if</span> (!cm_get_context(security_state))
  31.                 cm_set_context(&bl1_cpu_context[security_state], security_state);

  32.         <span class="hljs-comment">/* Prepare the SPSR for the next BL image. */</span>
  33. <span class="hljs-comment">/* 为下个阶段的image准备好SPSR数据 */</span>
  34.         <span class="hljs-keyword">if</span> (security_state == SECURE) {
  35.                 next_bl_ep->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
  36.                                    DISABLE_ALL_EXCEPTIONS);
  37.         } <span class="hljs-keyword">else</span> {
  38.                 <span class="hljs-comment">/* Use EL2 if supported else use EL1. */</span>
  39.                 <span class="hljs-keyword">if</span> (read_id_aa64pfr0_el1() &
  40.                         (ID_AA64PFR0_ELX_MASK << ID_AA64PFR0_EL2_SHIFT)) {
  41.                         next_bl_ep->spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
  42.                                 DISABLE_ALL_EXCEPTIONS);
  43.                 } <span class="hljs-keyword">else</span> {
  44.                         next_bl_ep->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
  45.                            DISABLE_ALL_EXCEPTIONS);
  46.                 }
  47.         }

  48.         <span class="hljs-comment">/* Allow platform to make change */</span>
  49.         bl1_plat_set_ep_info(image_id, next_bl_ep);

  50.         <span class="hljs-comment">/* Prepare the context for the next BL image. */</span>
  51. <span class="hljs-comment">/* 使用获取到的bl2 image的entrypoint info数据来初始化cpu context */</span>
  52.         cm_init_my_context(next_bl_ep);
  53. <span class="hljs-comment">/* 为进入到下个EL级别做准备 */</span>
  54.         cm_prepare_el3_exit(security_state);

  55.         <span class="hljs-comment">/* Indicate that image is in execution state. */</span>
  56. <span class="hljs-comment">/* 设定image的执行状态 */</span>
  57.         image_desc->state = IMAGE_STATE_EXECUTED;

  58. <span class="hljs-comment">/* 打印出bl2 image的入口信息 */</span>
  59.         print_entry_point_info(next_bl_ep);
  60. }
复制代码












回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2019-3-19 00:08 , Processed in 0.090361 second(s), 19 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

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