赞
踩
在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的生命周期结束。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。