U-Boot启动引导内核分析(二)

本文详细解析了U-Boot中bootm命令的工作原理及其如何引导内核启动的过程。通过分析do_bootm函数,展示了从获取内核镜像到加载及验证的整个流程。

标签:ARM   bootloader   U-Boot   代码分析 抵岸科技

 

 

也许细心的你会问:我在用UBoot的时候并没有直接进入用户命令界面呀,而是在倒计时结束后自动引导kernel。这是怎么回事呢?

在 main_loop()函数当中有如下一段代码:

#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
      •
      •
      •
s = getenv ("bootcmd");
        /*获取bootcmd 的内容*/
        /*bootcmd=nand read 0x22000000 0xB0000 0x200000; bootm */
      •
      •
# ifndef CFG_HUSH_PARSER
        run_command (s, 0);
        /*运行s包含的命令*/
        /*运行nand read 0x22000000 0xB0000 0x200000表示将NANDFLASH
      0xB0000处数据读取放于0x22000000处,读取长度为0x200000
        */
        /*运行bootm命令,引导内核启动*/
# else
        parse_string_outer(s, FLAG_PARSE_SEMICOLON |
                    FLAG_EXIT_FROM_LOOP);
# endif
      •
      •
      •
#endif    /* CONFIG_BOOTDELAY */

bootm命令是什么?它是怎样引导内核的?

要知道想解决这个问题,就要分析common/cmd_bootm.c中的函数do_bootm,因为引导kernel就是bootm这条命令的工作,do_bootm是命令bootm的执行函数。

现在我们来分析一下common/cmd_bootm.c中的函数do_bootm,这是bootm命令的处理函数。

int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
    ulong        iflag;
    const char    *type_name;
    uint        unc_len = CFG_BOOTM_LEN;
    uint8_t        comp, type, os;

    void        *os_hdr;
    ulong        os_data, os_len;
    ulong        image_start, image_end;
    ulong        load_start, load_end;
    ulong        mem_start;
    phys_size_t    mem_size;

    struct lmb lmb;

    memset ((void *)&images, 0, sizeof (images));
    images.verify = getenv_yesno ("verify");
    images.lmb = &lmb;

    lmb_init(&lmb);

    mem_start = getenv_bootm_low();
    mem_size = getenv_bootm_size();

    lmb_add(&lmb, (phys_addr_t)mem_start, mem_size);

    board_lmb_reserve(&lmb);

    /* get kernel image header, start address and length */
    /* 获取内核镜像头信息 */
    /* 打印 “## Booting kernel from Legacy Image at 22000000 ...
           Image Name:   Linux-2.6.30
           Image Type:   ARM Linux Kernel Image (uncompressed)
           Data Size:    1507760 Bytes = 1.4 MB
           Load Address: 20008000
           Entry Point: 20008000
           Verifying Checksum ... OK”*/
    os_hdr = boot_get_kernel (cmdtp, flag, argc, argv,
            &images, &os_data, &os_len);
    if (os_len == 0) {
        puts ("ERROR: can't get kernel image!/n");
        return 1;
    }

    /* get image parameters */
    /* 获取内核镜像格式 */
    switch (genimg_get_format (os_hdr)) {
    case IMAGE_FORMAT_LEGACY:
        /* 获取内核镜像参数 */
        type = image_get_type (os_hdr);
        comp = image_get_comp (os_hdr);
        os = image_get_os (os_hdr);

        image_end = image_get_image_end (os_hdr);
        load_start = image_get_load (os_hdr);
        break;
    }

    image_start = (ulong)os_hdr;
    load_end = 0;
    type_name = genimg_get_type_name (type);

    /* 禁止所有中断 */
    iflag = disable_interrupts();

#ifdef CONFIG_AMIGAONEG3SE
    /*
     * We've possible left the caches enabled during
     * bios emulation, so turn them off again
     */
    icache_disable();
    invalidate_l1_instruction_cache();
    flush_data_cache();
    dcache_disable();
#endif

    switch (comp) {
    case IH_COMP_NONE:
        /* 加载内核镜像 */
        /* 打印“Loading Kernel Image ... OK” */
        if (load_start == (ulong)os_hdr) {
            printf ("   XIP %s ... ", type_name);
        } else {
            printf ("   Loading %s ... ", type_name);

            memmove_wd ((void *)load_start,
                   (void *)os_data, os_len, CHUNKSZ);
        }
        load_end = load_start + os_len;
        puts("OK/n");
        break;
    }
    puts ("OK/n");
    debug ("   kernel loaded at 0x%08lx, end = 0x%08lx/n", load_start, load_end);
    show_boot_progress (7);
   
    /* 加载错误 */
    if ((load_start < image_end) && (load_end > image_start)) {
        debug ("image_start = 0x%lX, image_end = 0x%lx/n", image_start, image_end);
        debug ("load_start = 0x%lx, load_end = 0x%lx/n", load_start, load_end);

        if (images.legacy_hdr_valid) {
            if (image_get_type (&images.legacy_hdr_os_copy) == IH_TYPE_MULTI)
                puts ("WARNING: legacy format multi component "
                    "image overwritten/n");
        } else {
            puts ("ERROR: new format image overwritten - "
                "must RESET the board to recover/n");
            show_boot_progress (-113);
            do_reset (cmdtp, flag, argc, argv);
        }
    }

    show_boot_progress (8);

    lmb_reserve(&lmb, load_start, (load_end - load_start));

    switch (os) {
    default:            /* handled by (original) Linux case */
    case IH_OS_LINUX:
#ifdef CONFIG_SILENT_CONSOLE
        fixup_silent_linux();
#endif
        /* 引导内核启动函数 */
        do_bootm_linux (cmdtp, flag, argc, argv, &images);
        break;
    }

    show_boot_progress (-9);
#ifdef DEBUG
    puts ("/n## Control returned to monitor - resetting.../n");
    do_reset (cmdtp, flag, argc, argv);
#endif
    if (iflag)
        enable_interrupts();

    return 1;
}

至此do_bootm函数完成引导内核前的准备任务了。引导内核启动函数将由do_bootm_linux()函数执行。

 

 

 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值