学习uboot之三start_armboot分析

在上一篇中我们介绍了uboot启动过程中最先执行的代码start.S。
经过start.S的,uboot的代码已经从NAND FLASH中拷贝到RAM0x33f80000处
然后

        ldr pc, _start_armboot
        _start_armboot: .word start_armboot

接着,分析start_armboot。
如果你曾经接触过uboot的话,你就应该知道uboot的所有源文件基本都会参与
编译,但是基本上都是通过宏控制实际参与编译的内容。在本篇中,我会把没有定义相关宏的内容
自动忽略。

    /* Pointer is writable since we allocated a register for it */
    gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
    /* compiler optimization barrier needed for GCC >= 3.4 */
    __asm__ __volatile__("": : :"memory");

    memset ((void*)gd, 0, sizeof (gd_t));
    gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
    memset (gd->bd, 0, sizeof (bd_t));

其中gd的定义为#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm (“r8”)

可以看出gd是一个放在寄存器r8中的一个指针,指向gd_t结构。

__asm__ __volatile__("": : :"memory");

这里是一个特殊的用法:
1) asm用于指示编译器在此插入汇编语句。
2) volatile用于告诉编译器,严禁将此处的汇编语句与其它的语句重组合优化。即:原原本本按原来的样子处理这这里的汇编。
3) memory强制gcc编译器假设RAM所有内存单元均被汇编指令修改,这样cpu中的registers和cache中已缓存的内存单元中的数据将作废。cpu将不得不在需要的时候重新读取内存中的数据。这就阻止了cpu又将registers,cache中的数据用于去优化指令,而避免去访问内存。
4) “”:::表示这是个空指令。

关于更详细的阐述可参考https://www.cnblogs.com/pengdonglin137/p/3573972.html


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

    init_fnc_t *init_sequence[] = {

        cpu_init,
        /*对S3C2440的端口A-H进行初始化,设置bd参数bi_arch_number,bi_boot_params*/ 
        board_init,
        /*对定时器4进行初始化,用于计时之用,10ms超时*/        
        interrupt_init,     /* set up exceptions */
        /*对gd->env_addr进行设置,指向default_environment*/
        env_init,       /* initialize environment */
        /*设置gd->bd->bi_baudrate*/
        init_baudrate,      /* initialze baudrate settings */
        /*串口初始化函数,具体操作可参看前面前奏之uart章节*/
        serial_init,        /* serial communications setup */
        console_init_f,     /* stage 1 init of console */
        display_banner,     /* say that we are here */
        /*初始化gd中关于RAM的参数配置*/
        dram_init,      /* configure available RAM banks */
        display_dram_config,
        NULL,
};
对NAND进行初始化,打印NAND大小
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
    puts ("NAND:  ");
    nand_init();        /* go init the NAND */
#endif

    /* initialize environment */
    env_relocate ();
    /*读取环境变量,获取ip地址*/
    /* IP Address */
    gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");

    /*获取配置网卡的MAC地址*/
    /* MAC Address */
    {
        int i;
        ulong reg;
        char *s, *e;
        char tmp[64];

        i = getenv_r ("ethaddr", tmp, sizeof (tmp));
        s = (i > 0) ? tmp : NULL;

        for (reg = 0; reg < 6; ++reg) {
            gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
            if (s)
                s = (*e) ? e + 1 : e;
        }

    }

    /*创建dev_list 并添加了serial设备*/
    devices_init ();    /* get the devices list going. */

    /*初始化console,将serial作为标准输入,标准输出以及错误输出*/
    console_init_r ();  /* fully init console as a device */

    /*设置CPSR寄存器,开启中断*/
    enable_interrupts ();

        /* Initialize from environment */
    if ((s = getenv ("loadaddr")) != NULL) {
        load_addr = simple_strtoul (s, NULL, 16);
        printf("load_addr:%p\n\r",load_addr);
    }

#if (CONFIG_COMMANDS & CFG_CMD_NET)
    /*从环境变量中初始化Bootfile变量*/
    if ((s = getenv ("bootfile")) != NULL) {
        copy_filename (BootFile, s, sizeof (BootFile));
        printf("BootFile:%s\n\r",BootFile);
    }
#endif  /* CFG_CMD_NET */


#if (CONFIG_COMMANDS & CFG_CMD_NET)
    eth_initialize(gd->bd);
#endif

以上基本就是start_armboot的全部初始化内容了。我们知道uboot的主要功能为加载系统到RAM中,并跳转过去执行。其实具体来说就是我们下一篇要讲的main_loop ()主体部分。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值