• [转]uboot中SPL作用


    转:http://blog.csdn.net/voice_shen/article/details/17373671

    这篇文章写的非常详细

    [u-boot: 2014.01-rc1]

    本文将使用sama5d3xek SPL实现做为例子,具体代码可查看:https://github.com/voiceshen/u-boot/tree/sama5d3xek_spl_spi_nand

    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/cpu/armv7/start.S> (b lowlevel_init: arch/arm/cpu/armv7/lowlevel_init.S)  (b _main) --> <arch/arm/lib/crt0.S> (bl board_init_f) --> <arch/arm/lib/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/cpu/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/cpu/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/cpu/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/cpu/at91-common/spl.c> 此处暂时不分析。

    然后返回到start.S处,接下来调用:bl _main到<arch/arm/lib/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
     69         bic     sp, sp, #7      /* 8-byte alignment for ABI compliance */
     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/lib/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/cpu/armv7/at91/time.c>

    150~150: CONFIG_SPL_BOARD_INIT, 则调用spl_board_init(). 这是board相关的定义,<board/atmel/sama5d3xek/sama5d3xek.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。

  • 相关阅读:
    使用union all 遇到的问题(俩条sql语句行数的和 不等于union all 后的 行数的和 !);遗留问题 怎么找到 相差的呐俩条数据 ?
    78W的数据使用forall 进行批量转移;
    oracle 不能是用变量来作为列名和表名 ,但使用动态sql可以;
    oracle 查询优化及sql改写
    (十三)Jmeter之Bean Shell 的使用(二)
    (十二)Jmeter之Bean Shell的使用(一)
    (十一)Jmeter另一种调试工具 HTTP Mirror Server
    Image Processing and Computer Vision_Review:A survey of recent advances in visual feature detection(Author's Accepted Manuscript)——2014.08
    Image Processing and Computer Vision_Review:Local Invariant Feature Detectors: A Survey——2007.11
    Image Processing and Computer Vision_Review:A survey of recent advances in visual feature detection—2014.08
  • 原文地址:https://www.cnblogs.com/maxpak/p/5593019.html
Copyright © 2020-2023  润新知