Linux - 启动参数传递

本文详细介绍了启动参数在ARM架构中的作用,涉及引导加载程序如何通过代码嵌入、设备树和命令行设置来配置系统。重点讨论了U-Boot传递信息给内核的过程以及设备树和命令行的处理方法。
摘要由CSDN通过智能技术生成

概念

启动参数是用来配置和调整系统设置的重要工具

参数来源

  • 引导加载程序
  • 代码嵌入

参数形式

  • 设备树/Tag
  • 命令行

命令行设置

代码嵌入

    以arm 版本为例,其configs目录下的目标板的配置文件中存在如下类似内容:

    ....................

CONFIG_CMDLINE="noinitrd root=/dev/mtdblock2 rootfstype=jffs2 fbcon=rotate:1"

   ......................

GRUB设置

  1. 修改fgrub.cfg 的内容
  2. 使用grub2-mkconfig命令生效配置

设备树设置

  代码嵌入

     在头文件vmlinux.lds.h中可以发现如下定义:

      #define KERNEL_DTB()                            \
    STRUCT_ALIGN();                            \
    __dtb_start = .;                        \
    KEEP(*(.dtb.init.rodata))                    \
    __dtb_end = .;

 

启动参数的获取

   arc 架构

      .................................... 

    ; Uboot - kernel ABI
    ;    r0 = [0] No uboot interaction, [1] cmdline in r2, [2] DTB in r2
    ;    r1 = magic number (always zero as of now)
    ;    r2 = pointer to uboot provided cmdline or external DTB in mem
    ; These are handled later in handle_uboot_args()
    st    r0, [@uboot_tag]
    st      r1, [@uboot_magic]
    st    r2, [@uboot_arg]

     .................................   

由以上代码可知:

  • 引导程序知道是否需要传递信息给内核
  • 引导程序知道若需要传递信息给内核,信息的类型是怎样的
  • 相关内容存储在uboot_arg全局变量中

而后在内核的初始化中将有如下逻辑

void __init setup_arch(char **cmdline_p)

{

     handle_uboot_args();   //分析uboot传递的信息

      ..........................

}


void __init handle_uboot_args(void)
{

    //默认分析信息来源
    bool use_embedded_dtb = true;
    bool append_cmdline = false;    

    /* check that we know this tag */
    if (uboot_tag != UBOOT_TAG_NONE &&
        uboot_tag != UBOOT_TAG_CMDLINE &&
        uboot_tag != UBOOT_TAG_DTB) {
        pr_warn(IGNORE_ARGS "invalid uboot tag: '%08x'\n", uboot_tag);
        goto ignore_uboot_args;
    }

    if (uboot_magic != UBOOT_MAGIC_VALUE) {
        pr_warn(IGNORE_ARGS "non zero uboot magic\n");
        goto ignore_uboot_args;
    }

    if (uboot_tag != UBOOT_TAG_NONE &&
            uboot_arg_invalid((unsigned long)uboot_arg)) {
        pr_warn(IGNORE_ARGS "invalid uboot arg: '%px'\n", uboot_arg);
        goto ignore_uboot_args;
    }

    /* see if U-boot passed an external Device Tree blob */
    if (uboot_tag == UBOOT_TAG_DTB) {  //若传递的是设备树,则开始分析指向设备树的内存
        machine_desc = setup_machine_fdt((void *)uboot_arg);

        /* external Device Tree blob is invalid - use embedded one */
        use_embedded_dtb = !machine_desc; //判断是否是需要使用内嵌的设备树
    }

    if (uboot_tag == UBOOT_TAG_CMDLINE) //若传递的命令行,则执行字符串扩展
        append_cmdline = true;

ignore_uboot_args:

    if (use_embedded_dtb) {  //使用内嵌的设备树信息
        machine_desc = setup_machine_fdt(__dtb_start);
        if (!machine_desc)
            panic("Embedded DT invalid\n");
    }

    /*
     * NOTE: @boot_command_line is populated by setup_machine_fdt() so this
     * append processing can only happen after.
     */
    if (append_cmdline) {  //使用uboot传递的命令行参数
        /* Ensure a whitespace between the 2 cmdlines */
        strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
        strlcat(boot_command_line, uboot_arg, COMMAND_LINE_SIZE);
    }
}

在通过设备树指针寻找合适的machine_desc的过程中会执行scan指向设备树的内存

const struct machine_desc * __init setup_machine_fdt(void *dt)
{
    const struct machine_desc *mdesc;
    unsigned long dt_root;

    if (!early_init_dt_scan(dt))
        return NULL;

    ........................
}

bool __init early_init_dt_scan(void *params)
{
    ................

    early_init_dt_scan_nodes();
    return true;
}

void __init early_init_dt_scan_nodes(void)
{

    ...........................................

    /* Retrieve various information from the /chosen node */
    rc = early_init_dt_scan_chosen(boot_command_line);
    if (rc)
        pr_warn("No chosen node found, continuing without\n");

   .............................
}

 其核心函数如下

int __init early_init_dt_scan_chosen(char *cmdline)
{
    int l, node;
    const char *p;
    const void *rng_seed;
    const void *fdt = initial_boot_params;

//寻找合适的启动参数保持节点   

 node = fdt_path_offset(fdt, "/chosen");
    if (node < 0)
        node = fdt_path_offset(fdt, "/chosen@0");
    if (node < 0)
        /* Handle the cmdline config options even if no /chosen node */
        goto handle_cmdline;

   .....................

    /* Retrieve command line */

    //获取节点下的启动参数属性,若有效则拷贝
    p = of_get_flat_dt_prop(node, "bootargs", &l);
    if (p != NULL && l > 0)
        strscpy(cmdline, p, min(l, COMMAND_LINE_SIZE));

handle_cmdline:
    /*
     * CONFIG_CMDLINE is meant to be a default in case nothing else
     * managed to set the command line, unless CONFIG_CMDLINE_FORCE
     * is set in which case we override whatever was found earlier.
     */

//依据编译配置使用内置的命令行参数
#ifdef CONFIG_CMDLINE
#if defined(CONFIG_CMDLINE_EXTEND)
    strlcat(cmdline, " ", COMMAND_LINE_SIZE);
    strlcat(cmdline, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
#elif defined(CONFIG_CMDLINE_FORCE)
    strscpy(cmdline, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
#else
    /* No arguments from boot loader, use kernel's  cmdl*/
    if (!((char *)cmdline)[0])
        strscpy(cmdline, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
#endif
#endif /* CONFIG_CMDLINE */

    pr_debug("Command line is: %s\n", (char *)cmdline);

    return 0;
}

arm架构

 arm架构中有一种tag的结构也可以传递启动参数,其逻辑如下:

void __init setup_arch(char **cmdline_p)
{
    const struct machine_desc *mdesc = NULL;
    void *atags_vaddr = NULL;

    if (__atags_pointer)
        atags_vaddr = FDT_VIRT_BASE(__atags_pointer);

    setup_processor();
    if (atags_vaddr) {
        mdesc = setup_machine_fdt(atags_vaddr);
        if (mdesc)
            memblock_reserve(__atags_pointer,
                     fdt_totalsize(atags_vaddr));
    }
    if (!mdesc) //当通过设备树的方式获取machine_desc失败时使用tag的方式解析
        mdesc = setup_machine_tags(atags_vaddr, __machine_arch_type);

  ......................
}
 

  • 15
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值