uboot 2013.01 代码简析(3)第二阶段初始化

u-boot第二阶段初始化内容的入口函数是_main,_main位于arch/arm/lib/crt0.S文件中:

_main函数中先为调用board_init_f准备初始化环境(设置栈指针sp和并给gd_t结构分配空间):

.global _main

_main:

/*
 * Set up initial C runtime environment and call board_init_f(0).
 */

#if defined(CONFIG_NAND_SPL)
    /* deprecated, use instead CONFIG_SPL_BUILD */
    ldr    sp, =(CONFIG_SYS_INIT_SP_ADDR)
#elif defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
    ldr    sp, =(CONFIG_SPL_STACK)
#else
    ldr    sp, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
    bic    sp, sp, #7    /* 8-byte alignment for ABI compliance */
    sub    sp, #GD_SIZE    /* allocate one GD above SP */
    bic    sp, sp, #7    /* 8-byte alignment for ABI compliance */
    mov    r8, sp        /* GD is above SP */

然后调用board_init_f(0),这是因为r0可以作为输入参数:

mov r0, #0
bl  board_init_f

board_init_f(0)代码如下:

init_fnc_t *init_sequence[] = {
arch_cpu_init, /* basic arch cpu dependent setup */
mark_bootstage,
#ifdef CONFIG_OF_CONTROL
fdtdec_check_fdt,
#endif
#if defined(CONFIG_BOARD_EARLY_INIT_F)
board_early_init_f,
#endif
timer_init, /* initialize timer */
#ifdef CONFIG_BOARD_POSTCLK_INIT
board_postclk_init,
#endif
#ifdef CONFIG_FSL_ESDHC
get_clocks,
#endif
env_init, /* initialize environment */
init_baudrate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
display_banner, /* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo, /* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard, /* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
init_func_i2c,
#endif
dram_init, /* configure available RAM banks */
NULL,
};
void board_init_f(ulong bootflag)
{
    bd_t *bd;
    init_fnc_t **init_fnc_ptr;
    gd_t *id;
    ulong addr, addr_sp;
#ifdef CONFIG_PRAM
    ulong reg;
#endif
    void *new_fdt = NULL;
    size_t fdt_size = 0;

    memset((void *)gd, 0, sizeof(gd_t));

    gd->mon_len = _bss_end_ofs;
#ifdef CONFIG_OF_EMBED
    /* Get a pointer to the FDT */
    gd->fdt_blob = _binary_dt_dtb_start;
#elif defined CONFIG_OF_SEPARATE
    /* FDT is at end of image */
    gd->fdt_blob = (void *)(_end_ofs + _TEXT_BASE);
#endif
    /* Allow the early environment to override the fdt address */
    gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16,
                        (uintptr_t)gd->fdt_blob);

    for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
        if ((*init_fnc_ptr)() != 0) {
            hang ();
        }
    }

#ifdef CONFIG_OF_CONTROL
    /* For now, put this check after the console is ready */
    if (fdtdec_prepare_fdt()) {
        panic("** CONFIG_OF_CONTROL defined but no FDT - please see "
            "doc/README.fdt-control");
    }
#endif

    debug("monitor len: %08lX
", gd->mon_len);
    /*
     * Ram is setup, size stored in gd !!
     */
    debug("ramsize: %08lX
", gd->ram_size);
#if defined(CONFIG_SYS_MEM_TOP_HIDE)
    /*
     * Subtract specified amount of memory to hide so that it won't
     * get "touched" at all by U-Boot. By fixing up gd->ram_size
     * the Linux kernel should now get passed the now "corrected"
     * memory size and won't touch it either. This should work
     * for arch/ppc and arch/powerpc. Only Linux board ports in
     * arch/powerpc with bootwrapper support, that recalculate the
     * memory size from the SDRAM controller setup will have to
     * get fixed.
     */
    gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE;
#endif

    addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;

#ifdef CONFIG_LOGBUFFER
#ifndef CONFIG_ALT_LB_ADDR
    /* reserve kernel log buffer */
    addr -= (LOGBUFF_RESERVE);
    debug("Reserving %dk for kernel logbuffer at %08lx
", LOGBUFF_LEN,
        addr);
#endif
#endif

#ifdef CONFIG_PRAM
    /*
     * reserve protected RAM
     */
    reg = getenv_ulong("pram", 10, CONFIG_PRAM);
    addr -= (reg << 10);        /* size is in kB */
    debug("Reserving %ldk for protected RAM at %08lx
", reg, addr);
#endif /* CONFIG_PRAM */

#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
    /* reserve TLB table */
    gd->tlb_size = 4096 * 4;
    addr -= gd->tlb_size;

    /* round down to next 64 kB limit */
    addr &= ~(0x10000 - 1);

    gd->tlb_addr = addr;
    debug("TLB table from %08lx to %08lx
", addr, addr + gd->tlb_size);
#endif

    /* round down to next 4 kB limit */
    addr &= ~(4096 - 1);
    debug("Top of RAM usable for U-Boot at: %08lx
", addr);

#ifdef CONFIG_LCD
#ifdef CONFIG_FB_ADDR
    gd->fb_base = CONFIG_FB_ADDR;
#else
    /* reserve memory for LCD display (always full pages) */
    addr = lcd_setmem(addr);
    gd->fb_base = addr;
#endif /* CONFIG_FB_ADDR */
#endif /* CONFIG_LCD */

    /*
     * reserve memory for U-Boot code, data & bss
     * round down to next 4 kB limit
     */
    addr -= gd->mon_len;
    addr &= ~(4096 - 1);

    debug("Reserving %ldk for U-Boot at: %08lx
", gd->mon_len >> 10, addr);

#ifndef CONFIG_SPL_BUILD
    /*
     * reserve memory for malloc() arena
     */
    addr_sp = addr - TOTAL_MALLOC_LEN;
    debug("Reserving %dk for malloc() at: %08lx
",
            TOTAL_MALLOC_LEN >> 10, addr_sp);
    /*
     * (permanently) allocate a Board Info struct
     * and a permanent copy of the "global" data
     */
    addr_sp -= sizeof (bd_t);
    bd = (bd_t *) addr_sp;
    gd->bd = bd;
    debug("Reserving %zu Bytes for Board Info at: %08lx
",
            sizeof (bd_t), addr_sp);

#ifdef CONFIG_MACH_TYPE
    gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */
#endif

    addr_sp -= sizeof (gd_t);
    id = (gd_t *) addr_sp;
    debug("Reserving %zu Bytes for Global Data at: %08lx
",
            sizeof (gd_t), addr_sp);

#if defined(CONFIG_OF_SEPARATE) && defined(CONFIG_OF_CONTROL)
    /*
     * If the device tree is sitting immediate above our image then we
     * must relocate it. If it is embedded in the data section, then it
     * will be relocated with other data.
     */
    if (gd->fdt_blob) {
        fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32);

        addr_sp -= fdt_size;
        new_fdt = (void *)addr_sp;
        debug("Reserving %zu Bytes for FDT at: %08lx
",
              fdt_size, addr_sp);
    }
#endif

    /* setup stackpointer for exeptions */
    gd->irq_sp = addr_sp;
#ifdef CONFIG_USE_IRQ
    addr_sp -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);
    debug("Reserving %zu Bytes for IRQ stack at: %08lx
",
        CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ, addr_sp);
#endif
    /* leave 3 words for abort-stack    */
    addr_sp -= 12;

    /* 8-byte alignment for ABI compliance */
    addr_sp &= ~0x07;
#else
    addr_sp += 128;    /* leave 32 words for abort-stack   */
    gd->irq_sp = addr_sp;
#endif

    debug("New Stack Pointer is: %08lx
", addr_sp);

#ifdef CONFIG_POST
    post_bootmode_init();
    post_run(NULL, POST_ROM | post_bootmode_get(0));
#endif

    gd->bd->bi_baudrate = gd->baudrate;
    /* Ram ist board specific, so move it to board code ... */
    dram_init_banksize();
    display_dram_config();    /* and display it */

    gd->relocaddr = addr;
    gd->start_addr_sp = addr_sp;
    gd->reloc_off = addr - _TEXT_BASE;
    debug("relocation Offset is: %08lx
", gd->reloc_off);
    if (new_fdt) {
        memcpy(new_fdt, gd->fdt_blob, fdt_size);
        gd->fdt_blob = new_fdt;
    }
    memcpy(id, (void *)gd, sizeof(gd_t));
}

从代码中可以看出,board_init_f对gd内容进行初始化并将其拷贝到id变量中。

此外,代码中还对init_sequence中的所有函数按顺序依次执行,

从而完成了对MPLL、UPLL、GPIO、Timer、波特率、串口配置以及显示u-boot版本号、显示CPU型号、显示DRAM信息等功能

接着设置新sp和gd,然后跳转到relocate_code进行重定位,relocate_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 */

    adr    r0, _start
    cmp    r0, r6
    moveq    r9, #0        /* no relocation. relocation offset(r9) = 0 */
    beq    relocate_done        /* skip relocation */
    mov    r1, r6            /* r1 <- scratch for copy_loop */
    ldr    r3, _bss_start_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

#ifndef CONFIG_SPL_BUILD
    /*
     * fix .rel.dyn relocations
     */
    ldr    r0, _TEXT_BASE        /* r0 <- Text base */
    sub    r9, r6, r0        /* r9 <- relocation offset */
    ldr    r10, _dynsym_start_ofs    /* r10 <- sym table ofs */
    add    r10, r10, r0        /* r10 <- sym table in FLASH */
    ldr    r2, _rel_dyn_start_ofs    /* r2 <- rel dyn start ofs */
    add    r2, r2, r0        /* r2 <- rel dyn start in FLASH */
    ldr    r3, _rel_dyn_end_ofs    /* r3 <- rel dyn end ofs */
    add    r3, r3, r0        /* r3 <- rel dyn end in FLASH */
fixloop:
    ldr    r0, [r2]        /* r0 <- location to fix up, IN FLASH! */
    add    r0, r0, r9        /* r0 <- location to fix up in RAM */
    ldr    r1, [r2, #4]
    and    r7, r1, #0xff
    cmp    r7, #23            /* relative fixup? */
    beq    fixrel
    cmp    r7, #2            /* absolute fixup? */
    beq    fixabs
    /* ignore unknown type of fixup */
    b    fixnext
fixabs:
    /* absolute fix: set location to (offset) symbol value */
    mov    r1, r1, LSR #4        /* r1 <- symbol index in .dynsym */
    add    r1, r10, r1        /* r1 <- address of symbol in table */
    ldr    r1, [r1, #4]        /* r1 <- symbol value */
    add    r1, r1, r9        /* r1 <- relocated sym addr */
    b    fixnext
fixrel:
    /* relative fix: increase location by offset */
    ldr    r1, [r0]
    add    r1, r1, r9
fixnext:
    str    r1, [r0]
    add    r2, r2, #8        /* each rel.dyn entry is 8 bytes */
    cmp    r2, r3
    blo    fixloop
#endif

relocate_done:

    mov    pc, lr

relocate_code刚开始执行前先将here的值保存到lr寄存器中,然后执行重定位,执行完毕后跳转到lr寄存器(即here)执行。

然后对BSS段进行初始化:

here:

/* Set up final (full) environment */

    bl    c_runtime_cpu_setup    /* we still call old routine here */

    ldr    r0, =__bss_start    /* this is auto-relocated! */
    ldr    r1, =__bss_end__    /* this is auto-relocated! */

    mov    r2, #0x00000000        /* prepare zero to clear BSS */

clbss_l:cmp    r0, r1            /* while not at end of BSS */
    strlo    r2, [r0]        /* clear 32-bit BSS word */
    addlo    r0, r0, #4        /* move to next */
    blo    clbss_l

接着调用board_init_r()函数:

    bl coloured_LED_init
    bl red_led_on

#if defined(CONFIG_NAND_SPL)

    /* call _nand_boot() */
    ldr     pc, =nand_boot

#else

    /* call board_init_r(gd_t *id, ulong dest_addr) */
    mov    r0, r8            /* gd_t */
    ldr    r1, [r8, #GD_RELOCADDR]    /* dest_addr */
    /* call board_init_r */
    ldr    pc, =board_init_r    /* this is auto-relocated! */

#endif

board_init_r函数代码如下:

void board_init_r(gd_t *id, ulong dest_addr)
{
    ulong malloc_start;
#if !defined(CONFIG_SYS_NO_FLASH)
    ulong flash_size;
#endif

    gd->flags |= GD_FLG_RELOC;    /* tell others: relocation done */
    bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R, "board_init_r");

    monitor_flash_len = _end_ofs;

    /* Enable caches */
    enable_caches();

    debug("monitor flash len: %08lX
", monitor_flash_len);
    board_init();    /* Setup chipselects */
    /*
     * TODO: printing of the clock inforamtion of the board is now
     * implemented as part of bdinfo command. Currently only support for
     * davinci SOC's is added. Remove this check once all the board
     * implement this.
     */
#ifdef CONFIG_CLOCKS
    set_cpu_clk_info(); /* Setup clock information */
#endif
    serial_initialize();

    debug("Now running in RAM - U-Boot at: %08lx
", dest_addr);

#ifdef CONFIG_LOGBUFFER
    logbuff_init_ptrs();
#endif
#ifdef CONFIG_POST
    post_output_backlog();
#endif

    /* The Malloc area is immediately below the monitor copy in DRAM */
    malloc_start = dest_addr - TOTAL_MALLOC_LEN;
    mem_malloc_init (malloc_start, TOTAL_MALLOC_LEN);

#ifdef CONFIG_ARCH_EARLY_INIT_R
    arch_early_init_r();
#endif
    power_init_board();

#if !defined(CONFIG_SYS_NO_FLASH)
    puts("Flash: ");

    flash_size = flash_init();
    if (flash_size > 0) {
# ifdef CONFIG_SYS_FLASH_CHECKSUM
        print_size(flash_size, "");
        /*
         * Compute and print flash CRC if flashchecksum is set to 'y'
         *
         * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
         */
        if (getenv_yesno("flashchecksum") == 1) {
            printf("  CRC: %08X", crc32(0,
                (const unsigned char *) CONFIG_SYS_FLASH_BASE,
                flash_size));
        }
        putc('
');
# else    /* !CONFIG_SYS_FLASH_CHECKSUM */
        print_size(flash_size, "
");
# endif /* CONFIG_SYS_FLASH_CHECKSUM */
    } else {
        puts(failed);
        hang();
    }
#endif

#if defined(CONFIG_CMD_NAND)
    puts("NAND:  ");
    nand_init();        /* go init the NAND */
#endif

#if defined(CONFIG_CMD_ONENAND)
    onenand_init();
#endif

#ifdef CONFIG_GENERIC_MMC
    puts("MMC:   ");
    mmc_initialize(gd->bd);
#endif

#ifdef CONFIG_HAS_DATAFLASH
    AT91F_DataflashInit();
    dataflash_print_info();
#endif

    /* initialize environment */
    if (should_load_env())
        env_relocate();
    else
        set_default_env(NULL);

#if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI)
    arm_pci_init();
#endif

    stdio_init();    /* get the devices list going. */

    jumptable_init();

#if defined(CONFIG_API)
    /* Initialize API */
    api_init();
#endif

    console_init_r();    /* fully init console as a device */

#ifdef CONFIG_DISPLAY_BOARDINFO_LATE
# ifdef CONFIG_OF_CONTROL
    /* Put this here so it appears on the LCD, now it is ready */
    display_fdt_model(gd->fdt_blob);
# else
    checkboard();
# endif
#endif

#if defined(CONFIG_ARCH_MISC_INIT)
    /* miscellaneous arch dependent initialisations */
    arch_misc_init();
#endif
#if defined(CONFIG_MISC_INIT_R)
    /* miscellaneous platform dependent initialisations */
    misc_init_r();
#endif

     /* set up exceptions */
    interrupt_init();
    /* enable exceptions */
    enable_interrupts();

    /* Initialize from environment */
    load_addr = getenv_ulong("loadaddr", 16, load_addr);

#ifdef CONFIG_BOARD_LATE_INIT
    board_late_init();
#endif

#ifdef CONFIG_BITBANGMII
    bb_miiphy_init();
#endif
#if defined(CONFIG_CMD_NET)
    puts("Net:   ");
    eth_initialize(gd->bd);
#if defined(CONFIG_RESET_PHY_R)
    debug("Reset Ethernet PHY
");
    reset_phy();
#endif
#endif

#ifdef CONFIG_POST
    post_run(NULL, POST_RAM | post_bootmode_get(0));
#endif

#if defined(CONFIG_PRAM) || defined(CONFIG_LOGBUFFER)
    /*
     * Export available size of memory for Linux,
     * taking into account the protected RAM at top of memory
     */
    {
        ulong pram = 0;
        uchar memsz[32];

#ifdef CONFIG_PRAM
        pram = getenv_ulong("pram", 10, CONFIG_PRAM);
#endif
#ifdef CONFIG_LOGBUFFER
#ifndef CONFIG_ALT_LB_ADDR
        /* Also take the logbuffer into account (pram is in kB) */
        pram += (LOGBUFF_LEN + LOGBUFF_OVERHEAD) / 1024;
#endif
#endif
        sprintf((char *)memsz, "%ldk", (gd->ram_size / 1024) - pram);
        setenv("mem", (char *)memsz);
    }
#endif

    /* main_loop() can return to retry autoboot, if so just run it again. */
    for (;;) {
        main_loop();
    }

    /* NOTREACHED - no way out of command loop except booting */
}

在board_init_r函数中依次执行使能数据Cache和指令Cache,三个串口初始化,内存分配初始化,flash初始化,nand初始化,mmc设备初始化,stdio初始化,stdout和stderr初始化,开中断,网卡初始化等操作,

然后反复执行main_loop函数。

u-boot第二个阶段的执行内容如下:

(1)为board_init_f准备sp和gd

(2)执行board_init_f,对MPLL、UPLL、GPIO、Timer、波特率、串口配置,显示u-boot版本号、CPU型号和DRAM信息,并初始化gd内容。

(3)调用relocate_code进行代码重定位

(4)初始化BSS

(5)调用board_init_r,使能数据Cache和指令Cache,三个串口初始化,内存分配初始化,flash初始化,nand初始化,

   mmc设备初始化,stdio初始化,stdout和stderr初始化,开中断,网卡初始化,然后执行main_loop等待用户输入命令或者超时后进入linux内核。

原文地址:https://www.cnblogs.com/qiaoqiao2003/p/3727841.html