发新帖我要提问
12
返回列表
打印

SOC启动:SPL

[复制链接]
楼主: keer_zu
手机看帖
扫描二维码
随时随地手机跟帖
21
keer_zu|  楼主 | 2023-9-12 14:06 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
   该函数是一个空函数,但也带有__weak关键字。与我们上面分析的一样,它是一个弱函数,因此各平台可以根据自己的实际需求对其进行重定义。我们选取位于arch/arm/cpu/armv8/fsl-layerscape/spl.c中的定义为例,代码如下:
void board_init_f(ulong dummy)
{
    /* Clear global data */
    memset((void *)gd, 0, sizeof(gd_t));                                   (a)
    board_early_init_f();                                                  (b)
    timer_init();                                                          (c)
#ifdef CONFIG_ARCH_LS2080A                                                 (d)
    env_init();
#endif
    get_clocks();                                                          (e)

    preloader_console_init();                                              (f)

#ifdef CONFIG_SPL_I2C_SUPPORT                                              (g)
    i2c_init_all();
#endif
    dram_init();                                                           (h)
}

使用特权

评论回复
22
keer_zu|  楼主 | 2023-9-12 14:06 | 只看该作者
    该函数主要做一些board基本功能相关的初始化。如清空gd内存,定时器的初始化,获取系统时钟,总线时钟频率,console的初始化以及ddr的初始化等。下面对各步骤做一简要介绍:     
 (a)清空gd的内存。其中gd的定义位于arch/arm/include/asm/global_data.h中,它会从x18寄存器中获取gd指针,具体代码比较简单,这里不贴了。     
 (b)这个函数是每个board特定的一些初始化操作。     
 (c)定时器的初始化,对于fsl-layerscape平台其定义位于arch/arm/cpu/armv8/fsl-layerscape/cpu.c中,感兴趣的同学可以自行参阅。     
 (d)与特定的配置相关     
 (e)获取时钟频率,该函数的定义位于arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch2_speed.c(fsl_lsch3_speed.c)中,它的主要功能是获取处理器0的cpu时钟频率,总线时钟频率和ddr时钟频率等。
 (f)该函数用于初始化串口,其定义位于common/spl/spl.c中,代码如下。它首先根据配置信息设置串口的波特率,然后调用serial_init函数初始化串口,初始化完成后串口就可以输出信息了,此时设置gd的have_console标志,后续的代码可以通过判断该标志来确定当前串口是否可用,最后若设置了相关配置,则打印一些spl相关的信息。
void preloader_console_init(void)
{
    gd->baudrate = CONFIG_BAUDRATE;

    serial_init();      /* serial communications setup */

    gd->have_console = 1;

#if CONFIG_IS_ENABLED(BANNER_PRINT)
    puts("\nU-Boot " SPL_TPL_NAME " " PLAIN_VERSION " (" U_BOOT_DATE " - "
         U_BOOT_TIME " " U_BOOT_TZ ")\n");
#endif
#ifdef CONFIG_SPL_DISPLAY_PRINT
    spl_display_print();
#endif
}


使用特权

评论回复
23
keer_zu|  楼主 | 2023-9-12 14:06 | 只看该作者
(g)与特定配置相关,不做介绍。     
 (h)ddr相关的初始化,对于fsl-layerscape平台会获取dram的size,并将其存放到gd->ram_size中     
  回到_main中,步骤(10)是uboo重定位流程,其在SPL时不执行,故此处对其不做分析。因为start.s和crt0_64.s都是spl和uboot共用的,故相关函数只是通过相应的宏定义来控制代码的执行流程。     
(12)spl_relocate_stack_gd,该函数定义在common/spl/spl.c中。前面我们说过spl一般是运行在sram中,且此时的栈和gd数据都存放在sram中。但是现在ddr已经初始化完成,这时ddr已经可用,我们可以将其栈和gd重定位到ddr中。重定位的主要过程就是将栈指针,gd指针,malloc指针等设置到位于ddr中的新地址处,然后将老的gd数据等拷贝到新地址处。     
(13)-(16)注释写的很清楚,将x0和立即数0比较,若其不等于0(NULL),则将sp设置为等于x0,否则保持原来的值不变,即根据上面步骤(12)的结果来确定是否更新栈指针。     
(17)-(21)将bss段的内容清空。其中bss段的起始地址bss_start 和结束地址bss_end定义在spl的链接脚本arch/arm/cpu/armv8/u-boot-spl.lds中。其中循环的执行步骤为:     
  str xzr, [x0], #8 :xzr为0寄存器(x zero register),任何读该寄存器的操作都会返回0,。因此这条指令的含义是将0写入x0寄存器中内容为地址的内存中,然后x0 = x0 + 8.。由于xzr是64位寄存器,因此每次可以操作8个字节。     
  cmp x0, x1:比较x0和x1寄存器的内容,用来判断循环的退出条件    
  b.lo clear_loop:实际执行判断,当x0小于x1,即若未执行到bss段的结束地址(__bss_end)时,继续跳转到clear_loop标号处执行循环,否则结束循环。     
(22)该操作将gd指针放入x0寄存器中,以作为参数传给board_init_r函数。     
(23)将x18 + GD_RELOCADDR地址的内容加载到x1中     
(14)调用board_init_r函数,此处跳转命令为b,而不是bl,因此它不会再返回。board_init_r定义在common/spl/spl.c中,主要作用是进行一些必要的初始化工作,然后根据相关的配置情况,加载并启动下一阶段的镜像(一般为uboot)。由于该部分代码逻辑比较清晰,此处不再过多赘述。     

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则