u-boot中SPL源代码分析

更新日期:2021-10-15

来源:纯净之家


系统大全为您提供

 本文将使用sama5d3xek SPL实现做为例子
  u-boot SPL (second program loader), 对许多人来说也说很陌生。下面对此进行一个简单介绍。
  1. arm SoC的启动过程:
  RomBoot --> SPL --> u-boot --> Linux kernel --> file system --> start application
  (RomBoot是固化在SoC内部的。)
  u-boot实现了一个新功能,能在编译u-boot的同时生成SPL二进制文件。
  2. SPL运行代码go through
  从u-boot-spl.lds链接文件可知,启动代码也是start.S.
  (reset) <arch/arm

u-boot中SPL源代码分析

u/armv7/start.S> (b lowlevel_init: arch/arm

u-boot中SPL源代码分析

u/armv7/lowlevel_init.S) (b _main) --> <arch/arm

u-boot中SPL源代码分析

b/crt0.S> (bl board_init_f) --> <arch/arm

u-boot中SPL源代码分析

b/spl.c> (board_init_r) --> <common/spl/spl.c> (jump_to_image_no_args去启动u-boot) 到此SPL的生命周期结束。
  简单来讲:SPL所做工作,一些硬件的初始化,然后读取u-boot,最后调转至u-boot.
  3. 下面具体分析SPL的相关代码。
  <arch/arm

u-boot中SPL源代码分析

u/armv7/start.S>
  110 reset:
  111         bl      save_boot_params
  112         /*
  113          * disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,
  114          * except if in HYP mode already
  115          */
  116         mrs     r0, cpsr
  117         and     r1, r0, #0x1f           @ mask mode bits
  118         teq     r1, #0x1a               @ test for HYP mode
  119         bicne   r0, r0, #0x1f           @ clear all mode bits
  120         orrne   r0, r0, #0x13           @ set SVC mode
  121         orr     r0, r0, #0xc0           @ disable FIQ and IRQ
  122         msr     cpsr,r0
  123
  124 /*
  125  * Setup vector:
  126  * (OMAP4 spl TEXT_BASE is not 32 byte aligned.
  127  * Continue to use ROM code vector only in OMAP4 spl)
  128  */
  129 #if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
  130         /* Set V=0 in CP15 SCTRL register - for VBAR to point to vector */
  131         mrc     p15, 0, r0, c1, c0, 0   @ Read CP15 SCTRL Register
  132         bic     r0, #CR_V               @ V = 0
  133         mcr     p15, 0, r0, c1, c0, 0   @ Write CP15 SCTRL Register
  134
  135         /* Set vector address in CP15 VBAR register */
  136         ldr     r0, =_start
  137         mcr     p15, 0, r0, c12, c0, 0  @Set VBAR
  138 #endif
  139
  140         /* the mask ROM code should have PLL and others stable */
  141 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
  142         bl      cpu_init_cp15
  143         bl      cpu_init_crit
  144 #endif
  145
  146         bl      _main
  111:如果没有重新定义save_boot_params,则使用<arch/arm

u-boot中SPL源代码分析

u/armv7/start.S>中的save_boot_params.其不做任何事情,直接返回。
  116~138: 看注释即可明白。
  141: 因为SPL主要是对SoC进行初始化,所以不会定义CONFIG_SKIP_LOWLEVE_INIT, 即142,143行得以执行。
  142: cpu_init_cpu15, 主要作用invalidate L1 I/D cache, disable MMU. 检查是否需要workaround.
  143: cpu_init_crit直接跳转到lowlevel_init
  下面看看lowlevel_init的实现:
  <arch/arm

u-boot中SPL源代码分析

u/armv7/lowlevel_init.S>
  18 ENTRY(lowlevel_init)
  19         /*
  20          * Setup a temporary stack
  21          */
  22         ldr     sp, =CONFIG_SYS_INIT_SP_ADDR
  23         bic     sp, sp, #7 /* 8-byte alignment for ABI compliance */
  24 #ifdef CONFIG_SPL_BUILD
  25         ldr     r9, =gdata
  26 #else
  27         sub     sp, #GD_SIZE
  28         bic     sp, sp, #7
  29         mov     r9, sp
  30 #endif
  31         /*
  32          * Save the old lr(passed in ip) and the current lr to stack
  33          */
  34         push    {ip, lr}
  35
  36         /*
  37          * go setup pll, mux, memory
  38          */
  39         bl      s_init
  40         pop     {ip, pc}
  41 ENDPROC(lowlevel_init)

 22: 对stack pointer赋值成CONFIG_SYS_INIT_SP_ADDR
  23: 确保sp是8字节对齐。
  25:将gdata的地址存入到r9寄存器中。
  39:跳转到s_init.对Atmel sama5d3xek board, s_init定义在:<arch/arm

u-boot中SPL源代码分析

u/at91-common/spl.c> 此处暂时不分析。
  然后返回到start.S处,接下来调用:bl _main到<arch/arm

u-boot中SPL源代码分析

b/crt0.S>
  58 ENTRY(_main)
  59
  60 /*
  61  * Set up initial C runtime environment and call board_init_f(0)。
  62  */
  63
  64 #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
  65         ldr     sp, =(CONFIG_SPL_STACK)
  66 #else
  67         ldr     sp, =(CONFIG_SYS_INIT_SP_ADDR)

  68 #endif

 70         sub     sp, #GD_SIZE    /* allocate one GD above SP */
  71         bic     sp, sp, #7      /* 8-byte alignment for ABI compliance */
  72         mov     r9, sp          /* GD is above SP */
  73         mov     r0, #0
  74         bl      board_init_f
  65: 重新对SP赋值
  69: 确认sp是8字对齐
  70:相当于保留一个global_data的大小。
  71: 确认更新后的sp是8字对齐
  72:r9指向global_data
  73:r0赋值0
  74:跳转到board_init_f中运行。
  board_init_f在<arch/arm

u-boot中SPL源代码分析

b/spl.c>定义:
  20 /*
  21  * In the context of SPL, board_init_f must ensure that any clocks/etc for
  22  * DDR are enabled, ensure that the stack pointer is valid, clear the BSS
  23  * and call board_init_f.  We provide this version by default but mark it
  24  * as __weak to allow for platforms to do this in their own way if needed.
  25  */
  26 void __weak board_init_f(ulong dummy)
  27 {
  28         /* Clear the BSS. */
  29         memset(__bss_start, 0, __bss_end - __bss_start);
  30
  31         /* Set global data pointer. */
  32         gd = &gdata;
  33
  34         board_init_r(NULL, 0);
  35 }
  26: board_init_f是一个弱函数,是可以被重新定义的。
  29:对BSS段进行清零操作。
  34: 跳转到board_init_r
  board_init_r在<common/spl/spl.c>中定义:
  132 void board_init_r(gd_t *dummy1, ulong dummy2)
  133 {
  134         u32 boot_device;
  135         debug("》spl:board_init_r() ");
  136
  137 #ifdef CONFIG_SYS_SPL_MALLOC_START
  138         mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,
  139                         CONFIG_SYS_SPL_MALLOC_SIZE);
  140 #endif
  141
  142 #ifndef CONFIG_PPC
  143         /*
  144          * timer_init() does not exist on PPC systems. The timer is initialized
  145          * and enabled (decrementer) in interrupt_init() here.
  146          */
  147         timer_init();
  148 #endif
  149
  150 #ifdef CONFIG_SPL_BOARD_INIT
  151         spl_board_init();
  152 #endif
  135: 输出debug信息:》spl:board_init_r();
  137~140: 如果定义了:CONFIG_SYS_SPL_MALLOC_START, 则进行memory的malloc池初始化。以后调用malloc就在这个池子里面分配内存。

142~148: 如果没有定义:CONFIG_PPC, 则进行timer的初始化:timer_init() <arm/arm

u-boot中SPL源代码分析

u/armv7/at91/time.c>
  150~150: CONFIG_SPL_BOARD_INIT, 则调用spl_board_init()。 这是board相关的定义,<board/atmel

u-boot中SPL源代码分析

ma5d3xek

u-boot中SPL源代码分析

ma5d3xek.c>
  一切就绪后,就要检查从什么设备来启动了。这里就贴出RAM,MMC, NAND相关代码
  154         boot_device = spl_boot_device();
  155         debug("boot device - %d ", boot_device);
  156         switch (boot_device) {
  157 #ifdef CONFIG_SPL_RAM_DEVICE
  158         case BOOT_DEVICE_RAM:
  159                 spl_ram_load_image();
  160                 break;
  161 #endif
  162 #ifdef CONFIG_SPL_MMC_SUPPORT
  163         case BOOT_DEVICE_MMC1:
  164         case BOOT_DEVICE_MMC2:
  165         case BOOT_DEVICE_MMC2_2:
  166                 spl_mmc_load_image();
  167                 break;
  168 #endif
  169 #ifdef CONFIG_SPL_NAND_SUPPORT
  170         case BOOT_DEVICE_NAND:
  171                 spl_nand_load_image();
  172                 break;
  173 #endif
  154: 获取spl_boot_device,即从什么设备启动。
  157~161:如果定义了CONFIG_SPL_RAM_DEVICE, 则执行spl_ram_load_image(),其就是将image下载到ram中。
  162~168:如果定义了CONFIG_SPL_MMC_SUPPORT, 则执行spl_mmc_load_image(),其就是将image从mmc/sd里面读取到ram中。
  169~173:如果定义了CONFIG_SPL_NAND_SUPPORT, 则执行spl_nand_load_image(), 其就是将image从nand flash中读取到ram中。
  当要启动的image位于RAM中后,我们就可以启动之。
  213         switch (spl_image.os) {
  214         case IH_OS_U_BOOT:
  215                 debug("Jumping to U-Boot ");
  216                 break;
  217 #ifdef CONFIG_SPL_OS_BOOT
  218         case IH_OS_LINUX:
  219                 debug("Jumping to Linux ");
  220                 spl_board_prepare_for_linux();
  221                 jump_to_image_linux((void *)CONFIG_SYS_SPL_ARGS_ADDR);
  222 #endif
  223         default:
  224                 debug("Unsupported OS image Jumping nevertheless ");
  225         }
  226         jump_to_image_no_args(&spl_image);
  227 }

  213: 判断image的类型。

 
  214:如果是u-boot,则直接到227去运行u-boot.
  218:如果是Linux,则到221去启动Linux.

  至此,SPL结束它的生命,控制权交于u-boot或Linux. 

 

  

以上就是系统大全给大家介绍的如何使的方法都有一定的了解了吧,好了,如果大家还想了解更多的资讯,那就赶紧点击系统大全官网吧。

 

本文来自系统大全http://www.win7cn.com/如需转载请注明!推荐:win7纯净版