uboot向kernel的传参机制——bootm与tags

最近阅读代码学习了uboot boot kernel的过程以及uboot如何传参给kernel,记录下来,与大家共享:

U-boot版本:2014.4

Kernel版本:3.4.55


一 uboot 如何启动 kernel

1 do_bootm

uboot下使用bootm命令启动内核镜像文件uImage,uImage是在zImage头添加了64字节的镜像信息供uboot解析使用,具体这64字节头的内容,我们在分析bootm命令的时候就会一一说到,那直接来看bootm命令。

在common/cmd_bootm.c中

int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
#ifdef CONFIG_NEEDS_MANUAL_RELOC
    static int relocated = 0;

    if (!relocated) {
        int i;

        /* relocate boot function table */
        for (i = 0; i < ARRAY_SIZE(boot_os); i++)
            if (boot_os[i] != NULL)
                boot_os[i] += gd->reloc_off;

        /* relocate names of sub-command table */
        for (i = 0; i < ARRAY_SIZE(cmd_bootm_sub); i++)
            cmd_bootm_sub[i].name += gd->reloc_off;

        relocated = 1;
    }
#endif
    /* determine if we have a sub command */
    argc--; argv++;
    if (argc > 0) {
        char *endp;

        simple_strtoul(argv[0], &endp, 16);
        /* endp pointing to NULL means that argv[0] was just a
         * valid number, pass it along to the normal bootm processing
         *
         * If endp is ':' or '#' assume a FIT identifier so pass
         * along for normal processing.
         *
         * Right now we assume the first arg should never be '-'
         */
        if ((*endp != 0) && (*endp != ':') && (*endp != '#'))
            return do_bootm_subcommand(cmdtp, flag, argc, argv);
    }

    return do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START |
        BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER |
        BOOTM_STATE_LOADOS |
#if defined(CONFIG_PPC) || defined(CONFIG_MIPS)
        BOOTM_STATE_OS_CMDLINE |
#endif
        BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
        BOOTM_STATE_OS_GO, &images, 1);
}
数组boot_os是bootm最后阶段启动kernel时调用的函数数组,CONFIG_NEEDS_MANUAL_RELOC中的代码含义是将boot_os函数都进行偏移(uboot启动中会将整个code拷贝到靠近sdram顶端的位置执行),

但是boot_os函数在uboot relocate时已经都拷贝了,所以感觉没必要在进行relocate。这个宏因此没有定义,直接走下面。

新版uboot对于boot kernel实现了一个类似状态机的机制,将整个过程分成很多个阶段,uboot将每个阶段称为subcommand,

核心函数是do_bootm_states,需要执行哪个阶段,就在do_bootm_states最后一个参数添加那个宏定义,如: BOOTM_STATE_START

do_bootm_subcommand是按照bootm参数来指定运行某一个阶段,也就是某一个subcommand

对于正常的uImage,bootm加tftp的load地址就可以。

2 do_bootm_states

这样会走到最后函数do_bootm_states,那就来看看核心函数do_bootm_states

static int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc,
        char * const argv[], int states, bootm_headers_t *images,
        int boot_progress)
{
    boot_os_fn *boot_fn;
    ulong iflag = 0;
    int ret = 0, need_boot_fn;

    images->state |= states;

    /*
     * Work through the states and see how far we get. We stop on
     * any error.
     */
    if (states & BOOTM_STATE_START)
        ret = bootm_start(cmdtp, flag, argc, argv);
参数中需要注意bootm_headers_t *images,这个参数用来存储由image头64字节获取到的的基本信息。由do_bootm传来的该参数是images,是一个全局的静态变量。

首先将states存储在images的state中,因为states中有BOOTM_STATE_START,调用bootm_start.

3 第一阶段:bootm_start

static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
    memset((void *)&images, 0, sizeof(images));
    images.verify = getenv_yesno("verify");

    boot_start_lmb(&images);

    bootstage_mark_name(BOOTSTAGE_ID_BOOTM_START, "bootm_start");
    images.state = BOOTM_STATE_START;

    return 0;
}
获取verify,bootstage_mark_name标志当前状态为bootm start(bootstage_mark_name可以用于无串口调试,在其中实现LED控制)。

boot_start_lmb暂时还没弄明白,以后再搞清楚。

最后修改images.state为bootm start。

bootm_start主要工作是清空images,标志当前状态为bootm start。


4 第二阶段:bootm_find_os

由bootm_start返回后,do_bootm传了BOOTM_STATE_FINDOS,所以进入函数bootm_find_os

static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
             char * const argv[])
{
    const void *os_hdr;

    /* get kernel image header, start address and length */
    os_hdr = boot_get_kernel(cmdtp, flag, argc, argv,
            &images, &images.os.image_start, &images.os.image_len);
    if (images.os.image_len == 0) {
        puts("ERROR: can't get kernel image!\n");
        return 1;
    }

调用boot_get_kernel,函数较长,首先是获取image的load地址,如果bootm有参数,就是img_addr,之后如下:

    bootstage_mark(BOOTSTAGE_ID_CHECK_MAGIC);

    /* copy from dataflash if needed */
    img_addr = genimg_get_image(img_addr);

    /* check image type, for FIT images get FIT kernel node */
    *os_data = *os_len = 0;
    buf = map_sysmem(img_addr, 0);
首先标志当前状态,然后调用genimg_get_image
  • 22
    点赞
  • 124
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值