首页 > 代码库 > u-boot-2014.10移植第9天----深入分析代码(四)

u-boot-2014.10移植第9天----深入分析代码(四)

硬件平台:tq2440

开发环境:Ubuntu-3.11

u-boot版本:2014.10

本文允许转载,请注明出处:http://blog.csdn.net/fulinus


ENTRY(_main) 



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


#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK) //在smdk2410开发板的相关目录中没有定义;
    ldr sp, =(CONFIG_SPL_STACK)

#else

//CONFIG_SYS_INIT_SP_ADDR在include/configs/smdk2410.h中定义:

/* additions for new relocation code, must be added to all boards */
#define CONFIG_SYS_SDRAM_BASE   PHYS_SDRAM_1
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 0x1000 - \
                GENERATED_GBL_DATA_SIZE)

 PHYS_SDRAM_1:

#define PHYS_SDRAM_1        0x30000000 /* SDRAM Bank #1 */

    ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)  


#endif

8字节对齐

    bic sp, sp, #7  /* 8-byte alignment for ABI compliance */ 

栈顶保存到r2中

    mov r2, sp

将栈指针下移GD_SIZE,sp上面的GD_SIZE大小用于放全局变量

    sub sp, sp, #GD_SIZE    /* allocate one GD above SP */

8字节对齐

    bic sp, sp, #7  /* 8-byte alignment for ABI compliance */

保存栈底到r9中

    mov r9, sp      /* GD is above SP */

同上

    mov r1, sp

r0 = 0

    mov r0, #0

下面循环用于将栈空间和GD区域清零操作。

clr_gd:

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

    blo clr_gd

未定义,跳过

#if defined(CONFIG_SYS_MALLOC_F_LEN) && !defined(CONFIG_SPL_BUILD)
    sub sp, sp, #CONFIG_SYS_MALLOC_F_LEN
    str sp, [r9, #GD_MALLOC_BASE]

#endif

 * 2. Call board_init_f(). This function prepares the hardware for

调用board_init_f函数,为从系统的RAM中执行做硬件初始化。
 *    execution from system RAM (DRAM, DDR...) As system RAM may not

作为系统RAM可能还是不可用的,函数必须用现在的GD区域来保存
 *    be available yet, , board_init_f() must use the current GD to

需要传递给下一阶段的任意数据。
 *    store any data which must be passed on to later stages. These

包括重定位的目的地址,未来的栈和GD位置
 *    data include the relocation destination, the future stack, and
 *    the future GD location.

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;
#ifdef CONFIG_PRAM
    ulong reg;
#endif
    void *new_fdt = NULL;
    size_t fdt_size = 0;

先将GD区域清零gd的值就是前面的r9,GD的首地址。gd_t是一个很大的数据结构体。如下:

typedef struct global_data {
    bd_t *bd;
    unsigned long flags;
    unsigned int baudrate;
    unsigned long cpu_clk;  /* CPU clock in Hz!     */
    unsigned long bus_clk;
    /* We cannot bracket this with CONFIG_PCI due to mpc5xxx */
    unsigned long pci_clk;
    unsigned long mem_clk;
#if defined(CONFIG_LCD) || defined(CONFIG_VIDEO)
    unsigned long fb_base;  /* Base address of framebuffer mem */
#endif
#if defined(CONFIG_POST) || defined(CONFIG_LOGBUFFER)
    unsigned long post_log_word;  /* Record POST activities */
    unsigned long post_log_res; /* success of POST test */
    unsigned long post_init_f_time;  /* When post_init_f started */
#endif
#ifdef CONFIG_BOARD_TYPES
    unsigned long board_type;
#endif
    unsigned long have_console; /* serial_init() was called */
#ifdef CONFIG_PRE_CONSOLE_BUFFER
    unsigned long precon_buf_idx;   /* Pre-Console buffer index */
#endif
#ifdef CONFIG_MODEM_SUPPORT
    unsigned long do_mdm_init;
    unsigned long be_quiet;
#endif
    unsigned long env_addr; /* Address  of Environment struct */
    unsigned long env_valid;    /* Checksum of Environment valid? */
    
    unsigned long ram_top;  /* Top address of RAM used by U-Boot */


    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;
    struct global_data *new_gd; /* relocated global data */
    
#ifdef CONFIG_DM 
    struct udevice  *dm_root;   /* Root instance for Driver Model */
    struct udevice  *dm_root_f; /* Pre-relocation root instance */
    struct list_head uclass_root;   /* Head of core tree */
#endif                  


    const void *fdt_blob;   /* Our device tree, NULL if none */
    void *new_fdt;      /* Relocated FDT */
    unsigned long fdt_size; /* Space reserved for relocated FDT */
    void **jt;      /* jump table */
    char env_buf[32];   /* buffer for getenv() before reloc. */
#ifdef CONFIG_TRACE
    void        *trace_buff;    /* The trace buffer */
#endif
#if defined(CONFIG_SYS_I2C)
    int     cur_i2c_bus;    /* current used i2c bus */
#endif
#ifdef CONFIG_SYS_I2C_MXC

    void *srdata[10];
#endif
    unsigned long timebase_h;
    unsigned long timebase_l;
#ifdef CONFIG_SYS_MALLOC_F_LEN
    unsigned long malloc_base;  /* base address of early malloc() */
    unsigned long malloc_limit; /* limit address */
    unsigned long malloc_ptr;   /* current address */
#endif
    struct arch_global_data arch;   /* architecture-specific data */
} gd_t;


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

下面基本上就是在初始化GD区域。
    gd->mon_len = (ulong)&__bss_end - (ulong)_start;  初始化mon_len,代表uboot code的大小。
#ifdef CONFIG_OF_EMBED   //未定义
    /* Get a pointer to the FDT */
    gd->fdt_blob = __dtb_dt_begin;
#elif defined CONFIG_OF_SEPARATE //未定义
    /* FDT is at end of image */
    gd->fdt_blob = &_end;
#endif
    /* Allow the early environment to override the fdt address */
    gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16,
                        (uintptr_t)gd->fdt_blob);

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, //函数中主要完成减小PLL锁定时间,调整闭锁寄存器,配置MPLL、UPLL、I/O端口
#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 */
    print_cpuinfo,      /* display cpu info (and speed) */
#if defined(CONFIG_DISPLAY_BOARDINFO)
    checkboard,     /* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C)
    init_func_i2c,
#endif
    dram_init,      /* configure available RAM banks */
    NULL,
};

    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打印信息了。
    debug("monitor len: %08lX\n", gd->mon_len);
    /*
     * Ram is setup, size stored in gd !!
     */
    debug("ramsize: %08lX\n", 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 + get_effective_memsize();  //获取SDRAM结束地址

#ifdef CONFIG_LOGBUFFER   //
#ifndef CONFIG_ALT_LB_ADDR
    /* reserve kernel log buffer */
    addr -= (LOGBUFF_RESERVE);
    debug("Reserving %dk for kernel logbuffer at %08lx\n", 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\n", reg, addr);
#endif /* CONFIG_PRAM */


#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
    /* reserve TLB table */
    gd->arch.tlb_size = PGTABLE_SIZE;   //预留TLB表
    addr -= gd->arch.tlb_size;


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


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


    /* round down to next 4 kB limit */
    addr &= ~(4096 - 1);
    debug("Top of RAM usable for U-Boot at: %08lx\n", 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
     */ 

为u-boot的代码和bss预留空间
    addr -= gd->mon_len;
    addr &= ~(4096 - 1);


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

    #ifndef CONFIG_SPL_BUILD   //http://blog.csdn.net/voice_shen/article/details/17373671
    /*
     * reserve memory for malloc() arena
     */
    addr_sp = addr - TOTAL_MALLOC_LEN;
    debug("Reserving %dk for malloc() at: %08lx\n",
            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\n",
            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\n",
            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\n",
              fdt_size, addr_sp);
    }
#endif


#ifndef CONFIG_ARM64    //未定义 ARM64!
    /* 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\n",
        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   /* CONFIG_ARM64 */
    /* 16-byte alignment for ABI compliance */
    addr_sp &= ~0x0f;
#endif  /* CONFIG_ARM64 */
#else
    addr_sp += 128; /* leave 32 words for abort-stack   */
    gd->irq_sp = addr_sp;


    /* mov r0, #0 not needed due to above code */ 将r0 = 0不光是由于上面代码的需要,下面也需要。

    bl  board_init_f


#if ! defined(CONFIG_SPL_BUILD)

/*
 * Set up intermediate environment (new sp and gd) and call
 * relocate_code(addr_moni). Trick here is that we‘ll return
 * ‘here‘ but relocated.
 */ 


    ldr sp, [r9, #GD_START_ADDR_SP] /* sp = gd->start_addr_sp */
    bic sp, sp, #7  /* 8-byte alignment for ABI compliance */
    ldr r9, [r9, #GD_BD]        /* r9 = gd->bd */
    sub r9, r9, #GD_SIZE        /* new GD is below bd */
    
    adr lr, here   //保存返回地址,here在下面。
    ldr r0, [r9, #GD_RELOC_OFF]     /* r0 = gd->reloc_off */
    add lr, lr, r0   // lr = lr + r0   代码重定位后执行的地址,起始下面b relocate_code返回后就跳到了u-boot代码被重新拷贝的地方。
    ldr r0, [r9, #GD_RELOCADDR]     /* r0 = gd->relocaddr */
    b   relocate_code  //函数定义在arch/arm/lib/relocate.S文件中。明天继续。

here:
    
/* Set up final (full) environment */


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

     //.globl  c_runtime_cpu_setup
c_runtime_cpu_setup:
    
    mov pc, lr 直接返回了

    
    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


    bl coloured_LED_init
    bl red_led_on


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


    /* we should not return here. */


#endif


ENDPROC(_main)

u-boot-2014.10移植第9天----深入分析代码(四)