当前位置:   article > 正文

uboot之SPL理解和主要流程梳理_spl: failed to boot from all boot devices

spl: failed to boot from all boot devices

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

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

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

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

  1. CONFIG_SPL=y
  2. CONFIG_SPL_RAW_IMAGE_SUPPORT=y
  3. CONFIG_SPL_LEGACY_IMAGE_SUPPORT=y
  4. CONFIG_SPL_SYS_MALLOC_SIMPLE=y
  5. CONFIG_SPL_CTC5236=y
  6. CONFIG_SPL_YMODEM_SUPPORT=y

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

  1. During the SPL build a variable named CONFIG_SPL_BUILD is exported
  2. in the make environment and also appended to CPPFLAGS with -DCONFIG_SPL_BUILD.
  3. Source files can therefore be compiled for SPL with different settings.
  4. 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

  1. # Linker Script
  2. ifdef CONFIG_SPL_LDSCRIPT
  3. # need to strip off double quotes
  4. LDSCRIPT := $(addprefix $(SRCTREE)/,$(subst ",,$(CONFIG_SPL_LDSCRIPT)))
  5. endif
  6. ifeq ($(wildcard $(LDSCRIPT)),)
  7. LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-spl.lds
  8. endif
  9. ifeq ($(wildcard $(LDSCRIPT)),)
  10. LDSCRIPT := $(TOPDIR)/$(CPUDIR)/u-boot-spl.lds
  11. endif
  12. ifeq ($(wildcard $(LDSCRIPT)),)
  13. $(error could not find linker script)
  14. endif

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

  1. MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,
  2. LENGTH = CONFIG_SPL_MAX_SIZE }
  3. MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR,
  4. LENGTH = CONFIG_SPL_BSS_MAX_SIZE }
  5. OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
  6. OUTPUT_ARCH(aarch64)
  7. ENTRY(_start)
  8. SECTIONS
  9. {
  10. .text : {
  11. . = ALIGN(8);
  12. *(.__image_copy_start)
  13. CPUDIR/start.o (.text*)
  14. *(.text*)
  15. } >.sram
  16. .rodata : {
  17. . = ALIGN(8);
  18. *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
  19. } >.sram
  20. .data : {
  21. . = ALIGN(8);
  22. *(.data*)
  23. } >.sram
  24. .u_boot_list : {
  25. . = ALIGN(8);
  26. KEEP(*(SORT(.u_boot_list*)));
  27. } >.sram
  28. .image_copy_end : {
  29. . = ALIGN(8);
  30. *(.__image_copy_end)
  31. } >.sram
  32. .end : {
  33. . = ALIGN(8);
  34. *(.__end)
  35. } >.sram
  36. _image_binary_end = .;
  37. .bss_start : {
  38. . = ALIGN(8);
  39. KEEP(*(.__bss_start));
  40. } >.sdram
  41. .bss : {
  42. *(.bss*)
  43. . = ALIGN(8);
  44. } >.sdram
  45. .bss_end : {
  46. KEEP(*(.__bss_end));
  47. } >.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) 。主要调用

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

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

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

  1. static int ymodem_normal_boot_flow(struct spl_image_info *spl_image)
  2. {
  3.     info.mode = xyzModem_ymodem;
  4. res = xyzModem_stream_open(&info, &err);
  5. NONZ_GOTO_END(res, end_stream);
  6. /* skip spl image */
  7. uboot_offset = CONFIG_SPL_PAD_TO;
  8. while(uboot_offset>0)
  9. {
  10. res = xyzModem_stream_read(buf, BUF_SIZE, &err);
  11. NOGT_GOTO_END(res, 0, end_stream);
  12. uboot_offset -= BUF_SIZE;
  13. }
  14. /* get 64 bytes uboot image header and (BUF_SIZE-64) bytes data */
  15. res = xyzModem_stream_read(buf, BUF_SIZE, &err);
  16. NOGT_GOTO_END(res, 0, end_stream);
  17. err = ctc5236_spl_parse_ih(spl_image, hdr);
  18. NEGA_GOTO_END(err, end_stream);
  19. ……
  20. }

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/130026?site
推荐阅读
相关标签
  

闽ICP备14008679号