uboot之SPL理解和主要流程梳理

在uboot代码的/doc/README.spl文件有简单的介绍:

To unify all existing implementations for a secondary program loader (SPL)
and to allow simply adding of new implementations this generic SPL framework
has been created. With this framework almost all source files for a board
can be reused. No code duplication or symlinking is necessary anymore.

可见,SPL被称作:二次程序加载器。UBOOT的SPL提供了一种框架,在这个框架内能够方便的实现一种SPL。该框架能复用一个单板几乎所有的UBOO和SPL的源码

SPL模块的主要公共代码在common\spl目录。要使能SPL,要在configs/***_defconfig文件中配置相关SPL的编译宏。如下配置:

CONFIG_SPL=y
CONFIG_SPL_RAW_IMAGE_SUPPORT=y
CONFIG_SPL_LEGACY_IMAGE_SUPPORT=y
CONFIG_SPL_SYS_MALLOC_SIMPLE=y
CONFIG_SPL_CTC5236=y
CONFIG_SPL_YMODEM_SUPPORT=y

编译SPL过程中可使用CONFIG_SPL_BUILD编译宏。而对于arm的单板可用CONFIG_PRELOADER。

During the SPL build a variable named CONFIG_SPL_BUILD is exported
in the make environment and also appended to CPPFLAGS with -DCONFIG_SPL_BUILD.
Source files can therefore be compiled for SPL with different settings.
ARM-based boards have previously used the option CONFIG_PRELOADER for it.

SPL最后生成u-boot-spl, u-boot-spl.bin 和u-boot-spl.map.

SPL的链接脚本是u-boot-spl.lds

 # Linker Script
    ifdef CONFIG_SPL_LDSCRIPT
    # need to strip off double quotes
    LDSCRIPT := $(addprefix $(SRCTREE)/,$(subst ",,$(CONFIG_SPL_LDSCRIPT)))
    endif
    
    ifeq ($(wildcard $(LDSCRIPT)),)
        LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-spl.lds
    endif
    ifeq ($(wildcard $(LDSCRIPT)),)
        LDSCRIPT := $(TOPDIR)/$(CPUDIR)/u-boot-spl.lds
    endif
    ifeq ($(wildcard $(LDSCRIPT)),)
    $(error could not find linker script)
    endif

对应以ARM V8为例,其具体的链接脚本在arch\arm\cpu\armv8如下:

MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,
        LENGTH = CONFIG_SPL_MAX_SIZE }
MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR,
        LENGTH = CONFIG_SPL_BSS_MAX_SIZE }

OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
OUTPUT_ARCH(aarch64)
ENTRY(_start)
SECTIONS
{
    .text : {
        . = ALIGN(8);
        *(.__image_copy_start)
        CPUDIR/start.o (.text*)
        *(.text*)
    } >.sram

    .rodata : {
        . = ALIGN(8);
        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
    } >.sram

    .data : {
        . = ALIGN(8);
        *(.data*)
    } >.sram

    .u_boot_list : {
        . = ALIGN(8);
        KEEP(*(SORT(.u_boot_list*)));
    } >.sram

    .image_copy_end : {
        . = ALIGN(8);
        *(.__image_copy_end)
    } >.sram

    .end : {
        . = ALIGN(8);
        *(.__end)
    } >.sram

    _image_binary_end = .;

    .bss_start : {
        . = ALIGN(8);
        KEEP(*(.__bss_start));
    } >.sdram

    .bss : {
        *(.bss*)
         . = ALIGN(8);
    } >.sdram

    .bss_end : {
        KEEP(*(.__bss_end));
    } >.sdram

arch\arm\cpu\armv8\start.S,作为SPL的入口。

SPL的执行流程如下:

(reset) <arm\cpu\armv8\start.S中执行bllowlevel_init,

(b lowlevel_init: arch\arm\cpu\armv8\lowlevel_init.S) 中执行bllowlevel_init

(b _main) –> <arch/arm/lib/crt0.S>

(bl board_init_f <common\board_f.c>

后调用 <arch/arm/lib/spl.c> (board_init_r) 。主要调用

#ifdef CONFIG_SPL_BOARD_INIT
    spl_board_init();
    /*1 spl_board_init多数CPU会在对应的arch其自己cpu目录下进行针对其CPU的实现。
       如centec芯片 spl.c (arch\arm\cpu\armv8\ctc5236)*/
#endif
    /*board_boot_order common/spl/spl.c有弱引用定义。数CPU会在对应的arch其自己cpu目录下进行针对其CPU的实现。如arch\arm\cpu\armv8\ctc5236下有自己的实现*/
    board_boot_order(spl_boot_list);
    if (boot_from_devices(&spl_image, spl_boot_list,
                  ARRAY_SIZE(spl_boot_list))) {
        puts("SPL: failed to boot from all boot devices\n");
        hang();
    }

boot_from_devices会去查找注册的boot接口。以ctc5236为例,会根据注册的flash和UART去引导uboot。

UART的引导入口在 spl_ymodem_ctc5236.c (common\spl)。主要代码如下:

static int ymodem_normal_boot_flow(struct spl_image_info *spl_image)
{
    info.mode = xyzModem_ymodem;
    res = xyzModem_stream_open(&info, &err);
    NONZ_GOTO_END(res, end_stream);
    
    /* skip spl image */
    uboot_offset = CONFIG_SPL_PAD_TO;
    while(uboot_offset>0)
    {
        res = xyzModem_stream_read(buf, BUF_SIZE, &err);
        NOGT_GOTO_END(res, 0, end_stream);
        uboot_offset -= BUF_SIZE;
    }
    
    /* get 64 bytes uboot image header and (BUF_SIZE-64) bytes data */
    res = xyzModem_stream_read(buf, BUF_SIZE, &err);
    NOGT_GOTO_END(res, 0, end_stream);

    err = ctc5236_spl_parse_ih(spl_image, hdr);
    NEGA_GOTO_END(err, end_stream);
    ……
}

(jump_to_image_no_args去启动u-boot) 到此SPL的生命周期结束。

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值