2565|0

2781

帖子

419

TA的资源

五彩晶圆(中级)

楼主
 

【朱兆祺带你学嵌入式】第二章第八节 U-Boot-2013.04启动分析(4) [复制链接]

1)        调用board_init_f函数
    bl  board_init_f
实际上,board_init_f()函数是U-Boot执行的第一个C语言函数:void board_init_f(ulong bootflag),这个函数位于arch/arm/lib目录下的board.c文件中。
void board_init_f()函数的主要工作是:清空gd指向的结构体、逐步填充结构体,执行init_fnc_ptr函数指针数组中的各个初始化函数和划分内存区域等。结构体成员的初始化贯穿于board_init_f函数的整个过程,多数情况下成员的值是根据顶层配置文件的宏确定的。
    /* Pointer is writable since we allocated a register for it */
    gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);
gd_t是一个结构体类型,其定义在arch/arm/include/asm目录下的global_data.h文件中,前面已经详细分析过。
memset((void *)gd, 0, sizeof(gd_t));
将gd所指向的结构体内所有变量清零,长度为:sizeof(gd_t)。清空之后,在board_init_f()函中后面有很多代码是对gd所指向的结构体的成员进行重新复赋值。
    for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
        if ((*init_fnc_ptr)() != 0) {
            hang ();
        }
    }
在U-Boot中定义了一个init_sequence函数指针数组:
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,
};
函数的类型为init_fnc_t,init_fnc_t也是一个新定义的数据类型,这个数据类型是传入参数为空,返回值为有符号整形的函数,函数用于初始化工作。如下:
typedef int (init_fnc_t) (void);
board_init_f函数使用一个for循环语句来逐一执行数组中的初始化函数,如果初始化函数返回值不为0,程序调用hang函数挂起,不再继续往下运行。
addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;
这行代码告诉我们SDRAM的末位物理地址为0x5800 0000,即SDRAM的空间分布为0x5000 0000~0x57FF FFFF。说明SDRAM一共128MB的空间。
接下来的代码程序就是对这128M内存进行划分。
#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 */
    addr -= (4096 * 4);
    /* round down to next 64 kB limit */
    addr &= ~(0x10000 - 1);
    gd->tlb_addr = addr;
    debug("TLB table at: %08lx\n", addr);
#endif

    /* round down to next 4 kB limit */
    addr &= ~(4096 - 1);
    debug("Top of RAM usable for U-Boot at: %08lx\n", addr);
这里告诉我们是将SDRAM的最后64K(addr &= ~(0x10000 - 1))分配给TLB,所分配的地址为:0x57FF 0000~0x57FF FFFF。
#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\n", gd->mon_len >> 10, addr);
这段代码是在SDRAM中从后往前给u-boot分配BSS、数据段、代码段,分配地址为:0x57F7 5000~0x57FE FFFF。
/*
     * 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);
从后往前紧挨着代码段开辟一块了malloc空间,给予的地址为:0x57E6 D000~0x57E7 4FFF。
    /*
     * (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);
为bd结构体分配空间,地址为:0x57E6 CFD8~0x57E6 CFFF。
    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);
这是给gd结构体分配空间,地址为:0x57E6 CF60~0x57E6 CFD7。
    /* 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
    addr_sp += 128; /* leave 32 words for abort-stack   */
    gd->irq_sp = addr_sp;
#endif

    debug("New Stack Pointer is: %08lx\n", addr_sp);
分配异常中断空间,地址:0x57E6 CF50~0x57E6 CF5F。
图1. 16  SDRAM内存划分图

综合上面SDRAM的分配,那么内存分配即为如图1. 16所示。SDRAM的空间大小为128MB。
其中在smdk6410.h中,有这么一个宏定义:
#define CONFIG_SYS_SDRAM_BASE   0x50000000
这说明SDRAM的起始地址是:0x5000 0000。
完成gd结构体的初始化和内存的划分之后,执行board_init_f()函数的最后一行代码:
relocate_code(addr_sp, id, addr);
这行代码的意思很明显是要跳回到start.S中,跳回start.S中紧接着的是下面这一段代码。
    .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 */
将relocate_code()说带回来的三个参数分别装入r4、r5、r6寄存器中。
但是注意到,relocate_code这个函数的声明实在commom.h中,如下:
void    relocate_code (ulong, gd_t *, ulong) __attribute__ ((noreturn));
relocate_code函数的三个参数分别栈顶地址、数据ID(即全局结构gd)在SDRAM中的起始地址和在SDRAM中存储U-Boot的起始地址。
在start.S中所接着进行的是设置堆栈指针,如下:
/* 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, _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
r4是刚刚传回来的堆栈指针,那么将r4给sp,设定堆栈指针。
r6是在SDRAM中存储u-boot的起始地址,将r0和r6进行比较。如果此时的u-boot已经是在SDRAM中,则beq         clear_bss;如果不是,在NandFlash中,则要将u-boot复制到SDRAM中。
clear_bss:
#ifndef CONFIG_SPL_BUILD
    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:cmp r0, r1          /* clear loop... */
    bhs clbss_e         /* if reached end of bss, exit */
    str r2, [r0]
    add r0, r0, #4
    b   clbss_l
clbss_e:
#ifndef CONFIG_NAND_SPL
    bl coloured_LED_init
    bl red_led_on
#endif
#endif
上面这段代码是对BSS进行清零操作。
/*
* We are done. Do not return, instead branch to second part of board
* initialization, now running from RAM.
*/
#ifdef CONFIG_NAND_SPL
    ldr     pc, _nand_boot

_nand_boot: .word nand_boot
#else
    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
#endif
上面这段代码如果是NAND 启动的话,那么就设置SP后跳到nand_boot()函数里面进行复制代码到SDRAM,然后跳到U-Boot在SDRAM 的起始地址开始运行。但是由于CONFIG_NAND_SPL没有宏定义,则是执行else。在进入board_init_r之前,给了两个参数:r5、r6。
r5:数据ID(即全局结构gd)在SDRAM中的起始地址。
r6:在SDRAM中存储U-Boot的起始地址。
此帖出自ARM技术论坛
点赞 关注
个人签名
 

回复
举报
您需要登录后才可以回帖 登录 | 注册

查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表