LXR | KVM | PM | Time | Interrupt | Systems Performance | Bootup Optimization

RISC-V spl/OpenSBI/u-boot/Linux启动流程交互节点

 OpenSBI给出的fw_dynamic镜像启动建议流程:

 实际详细流程如下:

1 SPL到OpenSBI

spl启动流程如下:

  • 从外设加载镜像到DDR中。
  • 解析镜像格式,比如FIT。
  • 解析FIT中OpenSBI镜像地址和入口地址;uboot镜像地址,并附着到fdt中;解析获取fdt地址。
  • 准备好HART ID、fdt地址、struct fw_dynamic_info结构体三个参数后,跳转到OpenSBI镜像开始执行。
_start
  wait_for_gd_init
    board_init_f
      spl_early_init
  spl_stack_gd_setup
    spl_call_board_init_r
      board_init_r
        spl_invoke_opensbi--如果镜像类型是IH_OS_OPENSBI则启动OpenSBI。
          spl_opensbi_find_uboot_node--在设备树中查找U-Boot节点,包含了U-Boot镜像的配置信息。这些信息从FIT镜像中解析,append到fdt_addr中。
          fit_image_get_entry--获取U-Boot的entry地址,如果没有找到则使用load地址。
          fit_image_get_load--获取U-Boot的load地址。
          --填充opensbi_info结构体,这个结构体包含了传递给OpenSBI的信息,如魔术数字、版本、下一阶段地址、模式、选项和首选启动HART ID。
          invalidate_icache_all--使缓存无效,确保调用的是最新的代码。
          --通过转换spl_image->entry_point为函数指针并调用它,将控制权交给 OpenSBI。
          opensbi_entry(gd->arch.boot_hart, (ulong)spl_image->fdt_addr,(ulong)&opensbi_info);--第一个参数HART ID,第二个参数FDT地址,第三个参数struct fw_dynamic_info。

 struct spl_image_info 结构体用于存储有关引导过程中使用的图像(通常是内核或引导程序的一部分)的信息。这个结构体在 U-Boot 的 SPL(Second Program Loader,第二阶段引导加载程序)中定义,用于传递图像的加载和入口信息。

struct spl_image_info {
    const char *name;--表示镜像的名称。
    u8 os;
    uintptr_t load_addr;--OpenSBI加载到内存中的地址。
    uintptr_t entry_point;--OpenSBI的入口点地址,通常是代码的第一条指令的地址。
#if CONFIG_IS_ENABLED(LOAD_FIT) || CONFIG_IS_ENABLED(LOAD_FIT_FULL)
    void *fdt_addr;--用于FDT的地址。
#endif
    u32 boot_device;
    u32 offset;
    u32 size;
    u32 flags;
    void *arg;
#ifdef CONFIG_SPL_LEGACY_IMAGE_CRC_CHECK
    ulong dcrc_data;
    ulong dcrc_length;
    ulong dcrc;
#endif
};

struct fw_dynamic_info 结构体是 OpenSBI 规范中定义的一个结构体,用于在引导加载程序(如 U-Boot)和 OpenSBI 之间传递动态信息。这个结构体通常在系统启动的早期阶段被填充,并由引导加载程序传递给 OpenSBI。

struct fw_dynamic_info {
    unsigned long magic;--用于标识数据结构的版本和兼容性。这有助于确保 OpenSBI 能够识别和处理传入的信息。
    unsigned long version;--结构体的版本号,用于确保 OpenSBI 能够理解结构体中包含的信息。
    unsigned long next_addr;--下一阶段引导程序或操作系统的入口地址。这个地址指示 OpenSBI 在初始化完成后跳转到的位置。
    unsigned long next_mode;--指示下一阶段引导程序或操作系统的运行模式。比如OpenSBI之后是u-boot,运行于S Mode。
    unsigned long options;--提供给OpenSBI库的选项。
    unsigned long boot_hart;--首选的引导HART(硬件线程)ID。在多HART系统中,这个字段指定了哪一个HART应该跳转到OpenSBI。
} __packed;

OpenSBI启动时a0存放启动HART ID、a1存放fdt地址、a2存放struct fw_dynamic_info结构体地址:

__start
  fw_boot_hart--从a2寄存器指向的struct fw_dynamic_info中获取boot_hart。
  fw_save_info--将next_addr、next_mode、options、boot_hart分别保存到_dynamic_next_addr、_dynamic_next_mode、_dynamic_options、_dynamic_boot_hard中。
  fw_platform_init--共5个参数:a0-boot HART, a1-FDT地址。
  
_scratch_init--获取fw_save_info保存的变量,填入struct sbi_scratch的next_addr、next_mode、options。并将FDT地址填入next_arg1中。

2 OpenSBI到u-boot

 结合《OpenSBI主要启动流程解析》,在sbi_hart_switch_mode时跳转到u-boot:

sbi_hsm_hart_start_finish--hardid作为第一参数,从struct sbi_scratch中获取next_arg1、next_addr、next_mode作为第2-4参数启动下一级镜像。
  sbi_hart_switch_mode
    --判断下一级镜像Mode,仅支持S和U。
    --配置next_mode到CSR_MSTATUS、next_addr配置到CSR_STVEC中。
    --调用mret指令,hardid和next_arg1作为第1-2参数启动u-boot。

 在u-boot起始阶段,将hartid和next_arg1保存到gd_t中:

_start
        mv    tp, a0
    mv    s1, a1
    SREG    s1, GD_FIRMWARE_FDT_ADDR(gp)
    /* save the boot hart id to global_data */
    SREG    tp, GD_BOOT_HART(gp)

3 u-boot到Linux

uboot启动Linux:

bo_bootm_linux
  boot_jump_linux
    kernel--使用images->ep地址,以gd->arch.boot_hart和images->ft_addr作为第1-2参数。

RISC-V kernel启动时保存a0/a1寄存器到s0/s1:

_start
  _start_kernel
    mv s0, a0
    mv s1, a1
    setup_vm--以DTB物理地址为参数,配置页表映射。

 

posted on 2024-09-07 23:59  ArnoldLu  阅读(88)  评论(0编辑  收藏  举报

导航