NXP Linux startup process analysis

uboot step

under the folder /git/arch/arm/cpu/armv8/start.S  .global _start  -> bl _main -> /git/arch/arm/cpu/lib/crt0_64.S ENTRY(_main) ->

->bl board_init_f (common/board_f.c, static const init_fnc_t init_sequence_f[]) ->b relocate_code (arch/arm/lib/relocate_64.S)->c_runtime_cpu_setup (arch/arm/cpu/armv8/start.S) ->board_init_r (common/board_r.c, static init_fnc_t init_sequence_r[]) 

[经验] 基于armv8架构对u-boot进行启动流程分析(一)以下为链接
https://bbs.elecfans.com/jishu_2282359_1_1.html
[经验] 基于armv8架构对u-boot进行启动流程分析(二)以下为链接
https://www.ws-dc.com/jishu_2282360_1_1.html
uboot启动流程(3)
https://adtxl.com/index.php/archives/757.html

内核启动先导知识
https://zhuanlan.zhihu.com/p/522195519

ArmV8启动知识梳理

https://bbs.elecfans.com/jishu_2282359_1_1.html
Alt text
上图详细概括了arm官方推荐的armv8的启动层次结构:
官方将启动分为了BL1,BL2,BL31,BL32,BL33阶段,根据顺序,芯片启动后首先执行BL1阶段代码,接着验签启动BL2,BL2根据具体设计启动BL31或者BL33,BL32只有在有BL31时才可能会存在并被验签加载启动。
armv8分为Secure World和Non-Secure World(Normal World),四种异常级别从高到低分别为EL3,EL2,EL1,EL0。
Secure World就是可以执行可信的firmware和app,比如密码支付,指纹识别等一系列依赖安全保证的服务。
Non-Secure World就是我们常见的u-boot,linux,qnx等裸机程序或者操作系统。

  • EL3具有最高管理权限,负责安全监测和安全模式切换。
  • EL2主要提供了对虚拟化的支持。
  • EL1是一个特权模式,能够执行一些特权指令,用于运行各类操作系统,在安全模式则是可信任OS。
  • EL0是无特权模式,所有APP应用都在EL0。

上图中的BL1,BL2,BL31,BL32,BL33分别对应如下功能:

  • BL1:是一切信任的根,一般就是固化在ROM中的一段启动加载代码,用于引导bl2,并对bl2进行验签保证可信任执行;
  • BL2:一般是在flash中的一段可信安全启动代码,它的可信建立在bl1对它的验证,主要完成一些平台相关的初始化,比如对ddr的初始化等,并在完成初始化后寻找BL31或者BL33进行执行;如果找到了BL31则不会继续调用BL33,如果没有BL31则BL33必须有;
  • BL31:BL31不像BL1和BL2是一次性运行的,它作为最后一道可信任固件存在,在系统运行时通过smc指令陷入EL3调用系统安全服务或者在Secure World和Non-Secure World之间进行切换;在完成BL31初始化后会去寻找BL32或者BL33进行验签后加载执行;
  • BL32:OPTee OS + 安全app,它是一个可信安全的OS运行在EL1并在EL0启动可信任APP(上述的指纹验证等app),并在Trust OS运行完成后通过smc指令返回- - BL31,BL31切换到Non-Seucre World继续执行BL33;
  • BL33:非安全固件,也就是我们常见的UEFI firmware或者u-boot也可能是直接启动Linux kernel;
    启动BL1,BL2,BL31,BL32则是一个完整的ATF信任链建立流程(ARM Trusted Firmware),像常见的PSCI(Power State Coordination Interface)功能则是在ATF的BL31上实现;

最后一张图完整展示整个调用流程:
Alt text
BL2根据是否存在BL31和BL32可选择性的加载不同firmware;
综上所述可知u-boot是一个运行在非安全世界的bootloader,负责加载各类操作系统,并提供丰富的驱动接口;并根据是否存在安全固件还可以进行不同的boot流程,如下。
u-boot,u-boot-spl,u-boot-tpl的关系:
对于一般嵌入式而言只需要一个u-boot作为bootloader即可,但是在小内存,或者有atf的情况下还可以有spl,tpl;
spl:Secondary Program Loader,二级加载器
tpl:Tertiary Program Loader,三级加载器
出现spl和tpl的原因最开始是因为系统sram太小,rom无法在ddr未初始化的情况下一次性把所有代码从flash,emmc,uxx等搬运到sram中执行,也或者是flash太小,无法完整放下整个u-boot来进行片上执行。所以u-boot又定义了spl和tpl,spl和tpl走u-boot完全相同的boot流程,不过在spl和tpl中大多数驱动和功能被去除了,根据需要只保留一部分spl和tpl需要的功能,通过CONFIG_SPL_BUILD和CONFIG_TPL_BUILD控制;一般只用spl就足够了,spl完成ddr初始化,并完成一些外设驱动初始化,比如u,emmc,以此从其他外围设备加载u-boot,但是如果对于小系统spl还是太大了,则可以继续加入tpl,tpl只做ddr等的特定初始化保证代码体积极小,以此再次从指定位置加载spl,spl再去加载u-boot。
从目前来看,spl可以取代上图中bl2的位置,或者bl1,根据具体厂商实现来决定,有一些芯片厂商会将spl固化在rom中,使其具有从emmc,u
等设备加载u-boot或者其他固件的能力。
当然在有atf的情况下可以由atf加载u-boot,或者由spl加载atf,atf再去加载u-boot。甚至在快速启动的系统中可以直接由spl启动加载linux等操作系统而跳过启动u-boot;在上图中arm官方只是给出了一个建议的启动信任链,具体实现都需要芯片厂商来决定