OpenSBI的启动分析
以fw_jump为例,从fw_jump.elf.ldS看到入口函数就是ENTRY(_start), _start定义在fw_base.S里面。
主要的启动流程都在fw_base.S里面,另外的三个文件主要是提供一些回调函数,不同的fw回调函数不同的实现方式。
3.1 初始化的大致流程
下面概述下boot的大概流程
1. 获取boot hart的id。对于fw_dynamic, fw_jump, fw_payload三种类型的fw, 获取boot hart的方法是不一样的。
fw_jump和fw_payload这里直接返回-1, fw_dynamic这种fw情况有点不一样,启动fw_dynamic的上一级程序会把
参数放到struct fw_dynamic_info里,用a2传给opensbi。
2. 负责启动的core进行初始化,其他hart跳转到_wait_reocate_copy_done,等候启动hart完成初始化
3. 重定位(动态库重定位,或加载地址和链接地址不相等的代码拷贝)
把fw从当前运行的位置拷贝到编译是指定的位置,和uboot kernel的代码重定向是一样的。
4. 设置boot阶段标志位BOOT_STATUES_RELOCATE_DONE,然后其他的core根据新的重定向后的代码,
跳到_wait_for_boot_hart,等待初始化core的下一步的初始化
5. 初始化core reset所有的寄存器,设置堆栈,清除BSS段
6. 为每一个core分配堆栈和scrash空间,初始化scratch(即struct sbi_scratch结构体,此结构如图scrathch布局.png)
7. 设备树重定位
8. boot阶段设置为BOOT_STATUS_BOOT_HART_DONE,主core进入_start_warm,从core判断BOOT_STATUS_BOOT_HART_DONE到了后,
延迟几个nop后也进入_start_warm。从core 执行3条nop指令是为了让boot core执行的最快。
9. 也就是说所有的core都要执行_start_warm,也就是说所有的core都要执行下面的几个步骤
10. 关闭和清理所有中断
11. 设置mscratch和sp寄存器
12. 设置mtvec trap处理寄存器为_trap_handler函数地址
13. 调用c函数sbi_init
14. 进一步的初始化,初始化一些板级资源,然后jump到下一级的boot
通过函数sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1, unsigned long next_addr, unsigned long next_mode, bool next_virt)
跳到下一级boot,其中a0=arg0;a1=arg1; arg0里面是hart id, arg1里面是fdt的地址,如果有,没有就是0.