zoukankan      html  css  js  c++  java
  • [TI-Sitara]启动流程

    前段时间在准备AM437x启动相关的一些事情,对MLO、SPL等事情也是有些糊涂,于是分享下面这篇文章

    转自http://blog.csdn.net/psvoldemort/article/details/41861959

    参考文件

    1,AM335x ARM Cortex-A8 Microprocessors (MPUs) Technical Reference Manual.pdf;

    2,am3359.pdf;

    目录

    • 1.am335x的cpu上电后,会跳到哪个地址去执行?
    • 1.1.第一级 bootloader:
    • 1.2.第二级 bootloader:
    • 1.3.第三级 bootloader:
    • 2.第二级 bootloader:MLO(SPL)做了哪些事情?
    • 2.1.SPL内存重映射
    • 2.2.保存启动参数 bl    save_boot_params
    • 2.3.设置 CPU 为 SVC32 模式
    • 2.4.CPU的初始化
    • 2.5.执行 s_init() 函数,实现 CPU 的初始化
    • 2.6.使能第二级缓冲区
    • 2.7.关闭看门狗(WDT)
    • 2.8.给外设设置好 PLL 和 时钟频率等
    • 2.9.使能 32-KHz 频率的实时时钟
    • 2.10.使能UART0
    • 2.11.初始化 定时器
    • 2.12.初始化控制台,通过UART可以查看相关信息
    • 2.13.配置 DDR
    • 2.14.设置 internal RAM 内存空间的栈指针,调用 board_init_f()函数
    • 2.15.代码重定向
    • 2.16.清空 bss 段
    • 2.17.调用函数 board_init_r,用以完成 MLO(SPI)阶段的所有初始化,并跳转到 uboot.img 阶段
    • 3.第三级 bootloader:uboot.img 做了哪些事情?

    1.am335x的cpu上电后,会跳到哪个地址去执行?

    答:芯片到uboot启动流程 :Internal-ROM → MLO(SPL)→ uboot.img

    AM335x 中bootloader被分成了 3 个部分

    1.1.第一级 bootloader:

    引导加载程序,板子上电后会自动执行这些代码,如选择哪种方式启动(NAND,SDcard,UART。。。),然后跳转转到第二级 bootloader。这些代码应该是存放在 176KB 的 ROM 中。

    1.2.第二级 bootloader:

    MLO(SPL),用以硬件初始化:关闭看门狗,关闭中断,设置 CPU 时钟频率、速度等操作。然后会跳转到第三级bootloader。MLO文件应该会被映射到 64 KB的 Internal SRAM 中。

    1.3.第三级 bootloader:

    uboot.img,C代码的入口。

    其中第一级 bootloader 是板子固化的,第二级和第三级是通过编译 uboot 所得的


    2.第二级 bootloader:MLO(SPL)做了哪些事情?

    MLO(SPL)内存分布如下:

    2.1.SPL内存重映射

    < PATH : /arch/arm/cpu/armv7/omap-common/u-boot-spl.lds >
    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("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
    OUTPUT_ARCH(arm)
    ENTRY(_start)
    SECTIONS
    {
        .text      :
        {
        __start = .;
          arch/arm/cpu/armv7/start.o    (.text)
          *(.text*)
        } >.sram
     
        . = ALIGN(4);
        .rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram
     
        . = ALIGN(4);
        .data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
        . = ALIGN(4);
        __image_copy_end = .;
        _end = .;
     
        .bss :
        {
            . = ALIGN(4);
            __bss_start = .;
            *(.bss*)
            . = ALIGN(4);
            __bss_end__ = .;
        } >.sdram
    }
    <PATH : /include/configs/am335x_evm.h>
    #define CONFIG_SPL_TEXT_BASE        0x402F0400
    #define CONFIG_SPL_MAX_SIZE     (46 * 1024)
    #define CONFIG_SPL_STACK        LOW_LEVEL_SRAM_STACK
     
    #define CONFIG_SPL_BSS_START_ADDR   0x80000000
    #define CONFIG_SPL_BSS_MAX_SIZE     0x80000     /* 512 KB */ <span style="font-size:16px;color:#003399;"><strong></strong></span>

    2.2.保存启动参数 bl    save_boot_params

    <PATH : /arch/arm/cpu/armv7/start.S>
    /*
     * the actual reset code
     */
     
    reset:
        bl  save_boot_params
    <PATH : /arch/arm/cpu/armv7/omap-common/lowlevel_init.S>
    .global save_boot_params
    save_boot_params:
        /*
         * See if the rom code passed pointer is valid:
         * It is not valid if it is not in non-secure SRAM
         * This may happen if you are booting with the help of
         * debugger
         */
        ldr     r2, =NON_SECURE_SRAM_START
        cmp r2, r0
        bgt 1f
        ldr r2, =NON_SECURE_SRAM_END
        cmp r2, r0
        blt 1f
     
        /*
         * store the boot params passed from rom code or saved
         * and passed by SPL
         */
        cmp r0, #0
        beq 1f
        ldr r1, =boot_params
        str r0, [r1]
    /*《PATH: /arch/arm/include/asm/arch-ti81xx/omap.h》
     * Non-secure SRAM Addresses
     * Non-secure RAM starts at 0x40300000 for GP devices. But we keep SRAM_BASE
     * at 0x40304000(EMU base) so that our code works for both EMU and GP
     */
    #define NON_SECURE_SRAM_START   0x40304000
    #define NON_SECURE_SRAM_END 0x4030E000
    #define LOW_LEVEL_SRAM_STACK    0x4030B7FC
    问题:这些参数是保存在哪里的?大概有哪些参数?

    答:这些参数保存的内存地址为 64 KB 的 OCM RAM 中:

    注:Dowloaded Image 区域:是用来保存 MLO(SPL) 文件的,其最大可达到 109 KB

    2.3.设置 CPU 为 SVC32 模式

        <PATH :/arch/arm/cpu/armv7/start.S>       
            /*
         * set the cpu to SVC32 mode
         */
        mrs r0, cpsr
        bic r0, r0, #0x1f
        orr r0, r0, #0xd3
        msr cpsr,r0
    • CPSR:程序状态寄存器(current program status register)(当前程序状态寄存器),在任何处理器模式下被访问。它包含了条件标志位、中断禁止位、当前处理器模式标志以及其他的一些控制和状态位。

    CPSR在用户级编程时用于存储条件码。

    • SPSR:程序状态保存寄存器(saved program statusregister),每一种处理器模式下都有一个状态寄存器SPSR,SPSR用于保存CPSR的状态,以便异常返回后恢复异常发生时的工作状态。当特定的异常中断发生时,这个寄存器用于存放当前程序状态寄存器的内容。在异常中断退出时,可以用SPSR来恢复CPSR。由于用户模式和系统模式不是异常中断模式,所以他没有SPSR。当用户在用户模式或系统模式访问SPSR,将产生不可预知的后果。

    详解:http://blog.chinaunix.net/uid-28458801-id-3487199.html

    2.4.CPU的初始化

    《PATH : /arch/arm/cpu/armv7/start.S》
        /* the mask ROM code should have PLL and others stable */
    #ifndef CONFIG_SKIP_LOWLEVEL_INIT
        bl  cpu_init_crit
    #endif
    
    
    <PATH : /arch/arm/cpu/armv7/omap-common/lowlevel_init.S>
    .globl lowlevel_init
    lowlevel_init:
        /*
         * Setup a temporary stack
         */
        ldr sp, =LOW_LEVEL_SRAM_STACK
     
        /*
         * Save the old lr(passed in ip) and the current lr to stack
         */
        push    {ip, lr}
     
        /*
         * go setup pll, mux, memory
         */
        bl  s_init
        pop {ip, pc}

    问题:CPU的初始化有哪些内容?

    答:@b1@ 首先要设置堆栈区,因为将会调用 C函数来实现CPU的初始化

    问题:这个堆栈在什么位置,其内存大小是多少?

    答: 

    《PATH :/arch/arm/include/asm/arch-ti81xx/omap.h》
    #define LOW_LEVEL_SRAM_STACK    0x4030B7FC<strong></strong>


    2.5.执行 s_init() 函数,实现 CPU 的初始化

    <PATH : /board/ti/am335x/evm.c>
    /*
     * early system init of muxing and clocks.
     */
    void s_init(void)
    {
        /* Can be removed as A8 comes up with L2 enabled */
        l2_cache_enable();
     
        /* WDT1 is already running when the bootloader gets control
         * Disable it to avoid "random" resets
         */
        __raw_writel(0xAAAA, WDT_WSPR);
        while(__raw_readl(WDT_WWPS) != 0x0);
        __raw_writel(0x5555, WDT_WSPR);
        while(__raw_readl(WDT_WWPS) != 0x0);
     
    #ifdef CONFIG_SPL_BUILD
        /* Setup the PLLs and the clocks for the peripherals */
        pll_init();
     
        /* Enable RTC32K clock */
        rtc32k_enable();
     
        /* UART softreset */
        u32 regVal;
        u32 uart_base = DEFAULT_UART_BASE;
     
        enable_uart0_pin_mux();
        /* IA Motor Control Board has default console on UART3*/
        /* XXX: This is before we've probed / set board_id */
        if (board_id == IA_BOARD) {
            uart_base = UART3_BASE;
        }
     
        regVal = __raw_readl(uart_base + UART_SYSCFG_OFFSET);
        regVal |= UART_RESET;
        __raw_writel(regVal, (uart_base + UART_SYSCFG_OFFSET) );
        while ((__raw_readl(uart_base + UART_SYSSTS_OFFSET) &
                UART_CLK_RUNNING_MASK) != UART_CLK_RUNNING_MASK);
     
        /* Disable smart idle */
        regVal = __raw_readl((uart_base + UART_SYSCFG_OFFSET));
        regVal |= UART_SMART_IDLE_EN;
        __raw_writel(regVal, (uart_base + UART_SYSCFG_OFFSET));
     
        /* Initialize the Timer */
        init_timer();
     
        preloader_console_init();
     
        printf("
    location /board/ti/am335x
    ");        //@@
    /*@@*/
    //  led();
    /*@@*/
         
        config_am335x_ddr();
     
    #endif
    }

    2.6.使能第二级缓冲区

    /* Can be removed as A8 comes up with L2 enabled */
    l2_cache_enable();
     
    <PATH : /arch/arm/cpu/armv7/ti81xx/cache.S>
    l2_cache_enable:
        push    {r0, r1, r2, lr}
        mrc 15, 0, r3, cr1, cr0, 1
        orr r3, r3, #2
        mcr 15, 0, r3, cr1, cr0, 1
        pop {r1, r2, r3, pc}

     

    2.7.关闭看门狗(WDT)

    /* WDT1 is already running when the bootloader gets control
     * Disable it to avoid "random" resets
     */
    __raw_writel(0xAAAA, WDT_WSPR);
    while(__raw_readl(WDT_WWPS) != 0x0);
    __raw_writel(0x5555, WDT_WSPR);
    while(__raw_readl(WDT_WWPS) != 0x0);
    <PATH : /arch/arm/include/asm/arch-ti81xx/cpu.h>
    #define WDT_WSPR    (WDT_BASE + 0x048)
     
     
    <PATH : /arch/arm/include/asm/arch-ti81xx/hardware.h>
    /* Watchdog Timer */
    #ifdef CONFIG_AM335X
    #define WDT_BASE            0x44E35000
    #else
    #define WDT_BASE            0x480C2000
    #endif


    2.8.给外设设置好 PLL 和 时钟频率等

    /* Setup the PLLs and the clocks for the peripherals */
    pll_init();
     
     
    <PATH : /board/ti/am335x/pll.c>
    /*
     * Configure the PLL/PRCM for necessary peripherals
     */
    void pll_init()
    {
        mpu_pll_config(MPUPLL_M_500);
        core_pll_config();
        per_pll_config();
        ddr_pll_config();
        /* Enable the required interconnect clocks */
        interface_clocks_enable();
        /* Enable power domain transition */
        power_domain_transition_enable();
        /* Enable the required peripherals */
        per_clocks_enable();
    }

      


    2.9.使能 32-KHz 频率的实时时钟

    /* Enable RTC32K clock */
    rtc32k_enable();
     
     《PATH : /board/ti/am335x/evm.c》
    static void rtc32k_enable(void)
    {
        /* Unlock the rtc's registers */
        __raw_writel(0x83e70b13, (AM335X_RTC_BASE + RTC_KICK0_REG));
        __raw_writel(0x95a4f1e0, (AM335X_RTC_BASE + RTC_KICK1_REG));
     
        /* Enable the RTC 32K OSC */
        __raw_writel(0x48, (AM335X_RTC_BASE + RTC_OSC_REG));
    }
     
    <PATH : /arch/arm/include/asm/arch-ti81xx/hardware.h>
    /* RTC base address */
    #define AM335X_RTC_BASE            0x44E3E000
     
    <PATH : /board/ti/am335x/evm.c>
    #define RTC_KICK0_REG        0x6c
    #define RTC_KICK1_REG        0x70
    #define RTC_OSC_REG        0x54

    2.10.使能UART0

      /* UART softreset */
        u32 regVal;
        u32 uart_base = DEFAULT_UART_BASE;
     
        enable_uart0_pin_mux();
        /* IA Motor Control Board has default console on UART3*/
        /* XXX: This is before we've probed / set board_id */
        if (board_id == IA_BOARD) {
            uart_base = UART3_BASE;
        }
     
        regVal = __raw_readl(uart_base + UART_SYSCFG_OFFSET);
        regVal |= UART_RESET;
        __raw_writel(regVal, (uart_base + UART_SYSCFG_OFFSET) );
        while ((__raw_readl(uart_base + UART_SYSSTS_OFFSET) &
                UART_CLK_RUNNING_MASK) != UART_CLK_RUNNING_MASK);
     
        /* Disable smart idle */
        regVal = __raw_readl((uart_base + UART_SYSCFG_OFFSET));
        regVal |= UART_SMART_IDLE_EN;
        __raw_writel(regVal, (uart_base + UART_SYSCFG_OFFSET));
     
     
    <PATH : /arch/arm/include/asm/arch-ti81xx/cpu.h>
    #ifdef CONFIG_AM335X
    #define DEFAULT_UART_BASE       UART0_BASE
    #endif
     
    <PATH : /arch/arm/include/asm/arch-ti81xx/hardware.h>
    #ifdef CONFIG_AM335X
    #define UART0_BASE          0x44E09000
    #else
    #define UART0_BASE          0x48020000
    #endif

    2.11.初始化 定时器

    /* Initialize the Timer */
    init_timer();
      
    <PATH : /board/ti/am335x/evm.c>
    static void init_timer(void)
    {
        /* Reset the Timer */
        __raw_writel(0x2, (DM_TIMER2_BASE + TSICR_REG));
     
        /* Wait until the reset is done */
        while (__raw_readl(DM_TIMER2_BASE + TIOCP_CFG_REG) & 1);
     
        /* Start the Timer */
        __raw_writel(0x1, (DM_TIMER2_BASE + TCLR_REG));
    }
     
    <PATH : /arch/arm/include/asm/arch-ti81xx/hardware.h>
    /* DM Timer base addresses */
    #define DM_TIMER0_BASE          0x4802C000
    #define DM_TIMER1_BASE          0x4802E000
    #define DM_TIMER2_BASE          0x48040000
    #define DM_TIMER3_BASE          0x48042000
    #define DM_TIMER4_BASE          0x48044000
    #define DM_TIMER5_BASE          0x48046000
    #define DM_TIMER6_BASE          0x48048000
    #define DM_TIMER7_BASE          0x4804A000

    2.12.初始化控制台,通过UART可以查看相关信息

    preloader_console_init();
     
    《PATH : /arch/arm/cpu/armv7/omap-common/spl.c》
    /* This requires UART clocks to be enabled */
    void preloader_console_init(void)
    {
        const char *u_boot_rev = U_BOOT_VERSION;
        char rev_string_buffer[50];
     
        gd = &gdata;
        gd->bd = &bdata;
        gd->flags |= GD_FLG_RELOC;
        gd->baudrate = CONFIG_BAUDRATE;
     
        serial_init();      /* serial communications setup */
     
        /* Avoid a second "U-Boot" coming from this string */
        u_boot_rev = &u_boot_rev[7];
     
        printf("
    U-Boot SPL %s (%s - %s)
    ", u_boot_rev, U_BOOT_DATE,
            U_BOOT_TIME);
        omap_rev_string(rev_string_buffer);
        printf("Texas Instruments %s
    ", rev_string_buffer);
    } 

    2.13.配置 DDR

       config_am335x_ddr();
     
    《PATH :》
    /*  void DDR2_EMIF_Config(void); */
    static void config_am335x_ddr(void)
    {
        int data_macro_0 = 0;
        int data_macro_1 = 1;
     
        enable_ddr_clocks();
     
        config_vtp();
     
        Cmd_Macro_Config();
     
        Data_Macro_Config(data_macro_0);
        Data_Macro_Config(data_macro_1);
     
        __raw_writel(PHY_RANK0_DELAY, DATA0_RANK0_DELAYS_0);
        __raw_writel(PHY_RANK0_DELAY, DATA1_RANK0_DELAYS_0);
     
        __raw_writel(DDR_IOCTRL_VALUE, DDR_CMD0_IOCTRL);
        __raw_writel(DDR_IOCTRL_VALUE, DDR_CMD1_IOCTRL);
        __raw_writel(DDR_IOCTRL_VALUE, DDR_CMD2_IOCTRL);
        __raw_writel(DDR_IOCTRL_VALUE, DDR_DATA0_IOCTRL);
        __raw_writel(DDR_IOCTRL_VALUE, DDR_DATA1_IOCTRL);
     
        __raw_writel(__raw_readl(DDR_IO_CTRL) & 0xefffffff, DDR_IO_CTRL);
        __raw_writel(__raw_readl(DDR_CKE_CTRL) | 0x00000001, DDR_CKE_CTRL);
     
        config_emif_ddr2();
    }
     
     
    《PATH : /arm/include/asm/arch-ti81xx/cpu.h》
    #define DATA0_RANK0_DELAYS_0        (DDR_PHY_BASE_ADDR + 0x134)
    #define DATA1_RANK0_DELAYS_0        (DDR_PHY_BASE_ADDR + 0x1D8)
     
    /* DDR offsets */
    #define DDR_PHY_BASE_ADDR       0x44E12000
    #define DDR_IO_CTRL         0x44E10E04
    #define DDR_CKE_CTRL            0x44E1131C
    #define CONTROL_BASE_ADDR       0x44E10000

    2.14.设置 internal RAM 内存空间的栈指针,调用 board_init_f()函数

    /* Set stackpointer in internal RAM to call board_init_f */
    call_board_init_f:
        ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
        bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
        ldr r0,=0x00000000
        bl  board_init_f
    #define CONFIG_SYS_INIT_SP_ADDR     (CONFIG_SYS_INIT_RAM_ADDR + 
                         CONFIG_SYS_INIT_RAM_SIZE - 
                         GENERATED_GBL_DATA_SIZE)
     
    #define CONFIG_SYS_INIT_RAM_ADDR    SRAM0_START
    #define CONFIG_SYS_INIT_RAM_SIZE    SRAM0_SIZE
     
    #ifdef CONFIG_AM335X
    #define SRAM0_START         0x402F0400
    #else
    #define SRAM0_START         0x40300000
    #endif
     
    #if defined(CONFIG_AM335X) || defined(CONFIG_TI814X)
    #define SRAM0_SIZE          (0x1B400) /* 109 KB */
    #define SRAM_GPMC_STACK_SIZE        (0x40)
    #endif
     
    #define GENERATED_GBL_DATA_SIZE (128) /* (sizeof(struct global_data) + 15) & ~15 */ 
    
    void board_init_f(ulong dummy)
    {
        /*
         * We call relocate_code() with relocation target same as the
         * CONFIG_SYS_SPL_TEXT_BASE. This will result in relocation getting
         * skipped. Instead, only .bss initialization will happen. That's
         * all we need
         */
        debug(">>board_init_f()
    ");
        relocate_code(CONFIG_SPL_STACK, &gdata, CONFIG_SPL_TEXT_BASE);
    }
     
    #define CONFIG_SPL_TEXT_BASE        0x402F0400
    #define CONFIG_SPL_MAX_SIZE     (46 * 1024)
    #define CONFIG_SPL_STACK        LOW_LEVEL_SRAM_STACK
    
    #define LOW_LEVEL_SRAM_STACK    0x4030B7FC 
    
    /*
     * void relocate_code (addr_sp, gd, addr_moni)
     *
     * This "function" does not return, instead it continues in RAM
     * after relocating the monitor code.
     *
     */
        .globl  relocate_code
    relocate_code:
        mov r4, r0  /* save addr_sp */
        mov r5, r1  /* save addr of gd */
        mov r6, r2  /* save addr of destination 0x402F0400*/</path>

    2.15.代码重定位

    代码重定向,它首先检测自己(MLO)是否已经在内存中:

    如果是直接跳到下面的堆栈初始化代码 clear_bss。

    如果不是就将自己从Nor Flash中拷贝到内存中。

    Nor Flash 和Nand Flash 本质区别就在于是否进行代码拷贝,也就是下面代码所表述:无论
    是Nor Flash 还是Nand Flash,核心思想就是将 uboot 代码搬运到内存中去运行,但是没有拷
    贝bss 后面这段代码,只拷贝bss 前面的代码,bss 代码是放置全局变量的。Bss 段代码是为
    了清零,拷贝过去再清零重复操作。

        /* Set up the stack                         */
    stack_setup:
        mov sp, r4
     
        adr r0, _start
        cmp r0, r6
        moveq   r9, #0      /* no relocation. relocation offset(r9) = 0 */
        beq clear_bss       /* skip relocation */
        mov r1, r6          /* r1 <- scratch for copy_loop */
        ldr r3, _image_copy_end_ofs
        add r2, r0, r3      /* r2 <- source end address      */
     
    copy_loop:                              /* 自拷贝 */
        ldmia   r0!, {r9-r10}       /* copy from source address [r0]    */
        stmia   r1!, {r9-r10}       /* copy to   target address [r1]    */
        cmp r0, r2          /* until source end address [r2]    */
        blo copy_loop
        @a6@ 清空 bss 段

    2.16.清空 bss 段

    clear_bss:
     
        ldr r0, _bss_start_ofs
        ldr r1, _bss_end_ofs
        mov r4, r6          /* reloc addr */
        add r0, r0, r4
        add r1, r1, r4
     
        mov r2, #0x00000000     /* clear                */
     
    clbss_l:str r2, [r0]        /* clear loop...            */
        add r0, r0, #4
        cmp r0, r1
        bne clbss_l
     
    /*
     * These are defined in the board-specific linker script.
     */
    .globl _bss_start_ofs
    _bss_start_ofs:
        .word __bss_start - _start          /* __bss_start = 0x80000000 */

    2.17.调用函数 board_init_r,用以完成 MLO(SPI)阶段的所有初始化,并跳转到 uboot.img 阶段

    /*
     * We are done. Do not return, instead branch to second part of board
     * initialization, now running from RAM.
     */
    jump_2_ram:
    /*
     * If I-cache is enabled invalidate it
     */
    #ifndef CONFIG_SYS_ICACHE_OFF
        mcr p15, 0, r0, c7, c5, 0   @ invalidate icache
        mcr     p15, 0, r0, c7, c10, 4  @ DSB
        mcr     p15, 0, r0, c7, c5, 4   @ ISB
    #endif
        ldr r0, _board_init_r_ofs
        adr r1, _start
        add lr, r0, r1
        add lr, lr, r9
        /* setup parameters for board_init_r */
        mov r0, r5      /* gd_t */
        mov r1, r6      /* dest_addr */
        /* jump to it ... */
        mov pc, lr
     
    _board_init_r_ofs:
        .word board_init_r - _start
    《PATH : /arch/arm/cpu/armv7/omap-common/spl.c 》
    void board_init_r(gd_t *id, ulong dummy)
    {
        u32 boot_device;
        debug(">>spl:board_init_r()
    ");
     
        timer_init();
        i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
     
    #ifdef CONFIG_SPL_BOARD_INIT
        spl_board_init();
    #endif
     
        boot_device = omap_boot_device();
        debug("boot device - %d
    ", boot_device);
        switch (boot_device) {
    #ifdef CONFIG_SPL_MMC_SUPPORT
        case BOOT_DEVICE_MMC1:
        case BOOT_DEVICE_MMC2:
            spl_mmc_load_image();
            break;
    #endif
    #ifdef CONFIG_SPL_NAND_SUPPORT
        case BOOT_DEVICE_NAND:
            spl_nand_load_image();
            break;
    #endif
    #ifdef CONFIG_SPL_YMODEM_SUPPORT
        case BOOT_DEVICE_UART:
            spl_ymodem_load_image();
            break;
    #endif
        default:
            printf("SPL: Un-supported Boot Device - %d!!!
    ", boot_device);
            hang();
            break;
        }
     
        switch (spl_image.os) {
        case IH_OS_U_BOOT:
            debug("Jumping to U-Boot
    ");
            jump_to_image_no_args();
            break;
        default:
            puts("Unsupported OS image.. Jumping nevertheless..
    ");
            jump_to_image_no_args();
        }
    }

    3,第三级 bootloader:uboot.img 做了哪些事情?

    uboot.img 内存分布如下:

    访问 /arch/arm/lib/board.c 中 的 board_init_f() 函数

    在 uboot.img 运行过程中,有两个非常重要的结构体:gd_t 和 bd_t 。

    其中 gd_t :global_data 数据结构的定义,位于:/arch/arm/include/asm/global_data.h 中。

                     其成员主要是一些全局的系统初始化参数。

    其中 bd_t :bd_info 数据结构的定义,位于:/arch/arm/include/asm/u-boot.h 中。

                     其成员是开发板的相关参数。

    /*
     * The following data structure is placed in some memory which is
     * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or
     * some locked parts of the data cache) to allow for a minimum set of
     * global variables during system initialization (until we have set
     * up the memory controller so that we can use RAM).
     *
     * Keep it *SMALL* and remember to set GENERATED_GBL_DATA_SIZE > sizeof(gd_t)
     */
     
    typedef struct  global_data {
        bd_t        *bd;
        unsigned long   flags;
        unsigned long   baudrate;
        unsigned long   have_console;   /* serial_init() was called */
        unsigned long   env_addr;   /* Address  of Environment struct */
        unsigned long   env_valid;  /* Checksum of Environment valid? */
        unsigned long   fb_base;    /* base address of frame buffer */
    #ifdef CONFIG_FSL_ESDHC
        unsigned long   sdhc_clk;
    #endif
    #ifdef CONFIG_AT91FAMILY
        /* "static data" needed by at91's clock.c */
        unsigned long   cpu_clk_rate_hz;
        unsigned long   main_clk_rate_hz;
        unsigned long   mck_rate_hz;
        unsigned long   plla_rate_hz;
        unsigned long   pllb_rate_hz;
        unsigned long   at91_pllb_usb_init;
    #endif
    #ifdef CONFIG_ARM
        /* "static data" needed by most of timer.c on ARM platforms */
        unsigned long   timer_rate_hz;
        unsigned long   tbl;
        unsigned long   tbu;
        unsigned long long  timer_reset_value;
        unsigned long   lastinc;
    #endif
    #ifdef CONFIG_IXP425
        unsigned long   timestamp;
    #endif
        unsigned long   relocaddr;  /* Start address of U-Boot in RAM */
        phys_size_t ram_size;   /* RAM size */
        unsigned long   mon_len;    /* monitor len */
        unsigned long   irq_sp;     /* irq stack pointer */
        unsigned long   start_addr_sp;  /* start_addr_stackpointer */
        unsigned long   reloc_off;
    #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
        unsigned long   tlb_addr;
    #endif
        void        **jt;       /* jump table */
        char        env_buf[32];    /* buffer for getenv() before reloc. */
    } gd_t;
     
    #define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r8")
     
     
    typedef struct bd_info {
        int         bi_baudrate;    /* serial console baudrate */
        unsigned long   bi_ip_addr; /* IP Address */
        ulong           bi_arch_number; /* unique id for this board */
        ulong           bi_boot_params; /* where this board expects params */
        struct              /* RAM configuration */
        {
        ulong start;
        ulong size;
        }           bi_dram[CONFIG_NR_DRAM_BANKS];
    } bd_t;

    其中 DECLARE_GLOBAL_DATA_PTR 宏定义在系统初始化过程中会被频繁调用,

    的作用是,声明gd这么一个全局的指针,这个指针指向gd_t结构体类型,并且这个gd指针是保存在ARM的r8这个寄存器里面的。

    uboot.img 第一个运行的文件还是 start.o,其在运行访问的 board_init_f() 函数定义在 /arch/arm/lib/board.c 中:

    void board_init_f(ulong bootflag)
    {
        bd_t *bd;
        init_fnc_t **init_fnc_ptr;
        gd_t *id;
        ulong addr, addr_sp;
     
        /* Pointer is writable since we allocated a register for it */
        gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);
        /* compiler optimization barrier needed for GCC >= 3.4 */
        __asm__ __volatile__("": : :"memory");
     
        memset((void *)gd, 0, sizeof(gd_t));
     
            ...
    }
    #define CONFIG_SYS_INIT_RAM_ADDR    SRAM0_START
    #define CONFIG_SYS_INIT_RAM_SIZE    SRAM0_SIZE
    #define CONFIG_SYS_INIT_SP_ADDR     (CONFIG_SYS_INIT_RAM_ADDR + 
                         CONFIG_SYS_INIT_RAM_SIZE - 
                         GENERATED_GBL_DATA_SIZE)
     
    #define SRAM0_START         0x402F0400
     
    #define SRAM0_SIZE          (0x1B400) /* 109 KB */
     
    #define GENERATED_GBL_DATA_SIZE (128) /* (sizeof(struct global_data) + 15) & ~15 */

    因此,系统初始化参数将会被保存在 (保存 MLO(SPL)文件的内存空间的)末尾 2 KB 处。

    通过计算的 gb 指针指向的内存空间地址为 gb = 0x4030B000

    gb_t 结构体中某些元素的值是来自于 uboot.img's header,这个header的数据保存在内存的0x807FFFCO,大小为 64字节

    /*
     * Legacy format image header,
     * all data in network byte order (aka natural aka bigendian).
     */
    typedef struct image_header {
        uint32_t    ih_magic;   /* Image Header Magic Number    */
        uint32_t    ih_hcrc;    /* Image Header CRC Checksum    */
        uint32_t    ih_time;    /* Image Creation Timestamp */
        uint32_t    ih_size;    /* Image Data Size      */
        uint32_t    ih_load;    /* Data  Load  Address      */
        uint32_t    ih_ep;      /* Entry Point Address      */
        uint32_t    ih_dcrc;    /* Image Data CRC Checksum  */
        uint8_t     ih_os;      /* Operating System     */
        uint8_t     ih_arch;    /* CPU architecture     */
        uint8_t     ih_type;    /* Image Type           */
        uint8_t     ih_comp;    /* Compression Type     */
        uint8_t     ih_name[IH_NMLEN];  /* Image Name       */
    } image_header_t;
    /*
     * 8MB into the SDRAM to allow for SPL's bss at the beginning of SDRAM.
     * 64 bytes before this address should be set aside for u-boot.img's
     * header. That is 0x807FFFC0--0x80800000 should not be used for any
     * other needs.
     */
    #define CONFIG_SYS_TEXT_BASE        0x80800000</path>
    void board_init_f(ulong bootflag)
    {
        bd_t *bd;
        init_fnc_t **init_fnc_ptr;
        gd_t *id;
        ulong addr, addr_sp;
     
        /* Pointer is writable since we allocated a register for it */
        gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);
        /* compiler optimization barrier needed for GCC >= 3.4 */
        __asm__ __volatile__("": : :"memory");
     
        memset((void *)gd, 0, sizeof(gd_t));
     
            ...
    }
  • 相关阅读:
    JavaWeb网上商城项目中用户注册,使用MailServer和FoxMail搭建本地邮件服务器
    myeclipse编码问题
    Date日期类型的绑定
    springmvc学习之jdk版本,tomcat版本,spring版本
    mybatis-ehcache整合中出现的异常 ibatis处理器异常(executor.ExecutorException)解决方法
    .net里面<app.config>中value值不能填写特殊符号问题
    sqldeveloper中Excel数据的导入与导出
    IntelliJ IDEA 2019.2最新版本免费激活码(转)
    sqlserver 的一些小总结
    SQL 跨数据库同步数据 、跨数据库跨更新数据
  • 原文地址:https://www.cnblogs.com/aaronLinux/p/6769060.html
Copyright © 2011-2022 走看看