u-boot启动过程之STEP2

在STEP1的最后,代码通过调用void start_armboot (void)进入了u-boot启动的第二阶段

1. void start_armboot (void)主要是对硬件的初始化,代码详解

void start_armboot (void)
{
    init_fnc_t **init_fnc_ptr;
    char *s;

    /* Pointer is writable since we allocated a register for it */
    // 初始化gd,使其指向global data区的基地址
    gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
    /* compiler optimization barrier needed for GCC >= 3.4 */
    //1. __asm__用于指示编译器在此插入汇编语句
    //2. __volatile__用于告诉编译器,严禁将此处的汇编语句与其它的语句重组合优化。即:原原本本按原来的样子处理这这里的汇编。
    //3. memory强制gcc编译器假设RAM所有内存单元均被汇编指令修改,这样cpu中的registers和cache中已缓存的内存单元中的数据将作废。
    // cpu将不得不在需要的时候重新读取内存中的数据。这就阻止了cpu又将registers,cache中的数据用于去优化指令,而避免去访问内存。
    //4. "":::表示这是个空指令。
    __asm__ __volatile__("": : :"memory");

    //清零global data区
    memset ((void*)gd, 0, sizeof (gd_t));
    //初始化gd->bd,使其指向bd_t的基地址
    gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
    //清零bd_t区
    memset (gd->bd, 0, sizeof (bd_t));

    // u-boot代码的大小。根据u-boot.lds可知,monitor_flash_len是.text + .rodata + .data + .got + .u_boot_cmd 的总长度。
    monitor_flash_len = _bss_start - _armboot_start;

    //init_sequence是初始化函数数组的起始地址,在这个循环中,会依次去执行初始化函数,若出现故障,则进入死循环。初始化函数包括
    //1. cpu_init,      /* basic cpu dependent setup, 分配IRQ, FIQ的栈地址 */
    //2. board_init,        /* basic board dependent setup, 初始化IO口 */
    //3. interrupt_init,        /* set up exceptions, 初始化时钟 */
    //4. env_init,      /* initialize environment, 初始化环境变量 */
    //5. init_baudrate,     /* initialze baudrate settings, 初始化波特率 */
    //6. serial_init,       /* serial communications setup , 初始化串口*/
    //7. console_init_f,        /* stage 1 init of console, 初始化终端 */
    //8. display_banner,        /* say that we are here, 打印一些信息到终端 */
    //9. dram_init,     /* configure available RAM banks, 初始化SDRAM的内存起始地址和大小。 */
    //10. display_dram_config, 打印SDRAM的大小。
    for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
        if ((*init_fnc_ptr)() != 0) {
            hang ();
        }
    }

    /* configure available FLASH banks */
    // 初始化NOR FLASH,配置每个sector的size等。
    size = flash_init ();
    // 打印出NOR FLASH 的整个SIZE信息
    display_flash_config (size);

    /* armboot_start is defined in the board-specific linker script */
    // 初始化malloc区,并全部清零
    mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);

#if (CONFIG_COMMANDS & CFG_CMD_NAND)
    //初始化NAND FLASH相关的寄存器。
    puts ("NAND:  ");
    nand_init();        /* go init the NAND */
#endif

    /* initialize environment */
    //初始化环境变量
    env_relocate ();

    /* IP Address */
    // 获取配置的IP地址
    gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");

    /* MAC Address */
    // 获取配置的MAC值,并将其存储到gd->bd->bi_enetaddr中。
    {
        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;
        }
    }

    // 初始化并注册外围设备,串口就是在这里初始化并注册的。
    devices_init ();    /* get the devices list going. */

    // 初始化gd中的jump table中的函数,如get_version,malloc,getenv
    jumptable_init ();

    // 查找是否有可用的输入输出设备,若有,将其作为标准的输入输出设备:
    // 输入: getc, tstc
    // 输出: putc,puts,printf
    console_init_r ();  /* fully init console as a device */

    // 初始化ARM的IO口。
    Port_Init();

    // PreLoadedONRAM这个变量在start.S中定义的。
    //.globl PreLoadedONRAM
    //PreLoadedONRAM:
    //.word 0
    if (!PreLoadedONRAM) {
        /* enable exceptions */
        enable_interrupts ();
        /* add by www.100ask.net */
        // 初始化usb口
        usb_init();
    }

    /* main_loop() can return to retry autoboot, if so just run it again. */
    // 经过一系列初始化后,进入主循环。
    for (;;) {
        main_loop ();
    }
}   

2. void main_loop (void)用于对FLASH进行分区、调用kernel,执行u-boot中输入的命令,其被void start_armboot (void)调用。

void main_loop (void)
{
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
    //初始化bootdelay相关的变量
    char *s;
    int bootdelay;
#endif

#ifdef CONFIG_JFFS2_CMDLINE
    // 初始化分区表,对FLASH进行分区
    //mtdparts=mtdparts=nandflash0:256k@0(bootloader),128k(params),2m(kernel),-(root)
    extern int mtdparts_init(void);
    if (!getenv("mtdparts"))
    {
        run_command("mtdparts default", 0);
    }
    else
    {
        mtdparts_init();
    }
#endif

#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
    // 获取 bootdelay的值: bootdelay=2
    s = getenv ("bootdelay");   
    // 转换成整数
    bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
    // 获取bootcmd的参数: bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0
    s = getenv ("bootcmd");

    // 倒计时开始,若倒计时结束,没有按下任何按键,则该条件成立
    if (bootdelay >= 0 && s && !abortboot (bootdelay)) 
    {
        // 打印Booting Linux ...
        printf("Booting Linux ...\n");            
        // 执行bootcmd的参数,nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0
        run_command (s, 0);
    }
#endif  /* CONFIG_BOOTDELAY */

    // 执行 menu 命令
    run_command("menu", 0);

    // 进入死循环,读取命令并执行之。
    for (;;) 
    {
        len = readline (CFG_PROMPT);

        flag = 0;   /* assume no special flags for now */
        if (len > 0)
            strcpy (lastcommand, console_buffer);
        else if (len == 0)
            flag |= CMD_FLAG_REPEAT;

        if (len == -1)
            puts ("<INTERRUPT>\n");
        else
            rc = run_command (lastcommand, flag);

        if (rc <= 0) {
            /* invalid command or not repeatable, forget it */
            lastcommand[0] = 0;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值