zoukankan      html  css  js  c++  java
  • Linux Command Line 解析

    Linux Command Line 解析

    0 处理模型

    Linux kernel的启动包括很多组件的初始化和相关配置,这些配置参数一般是通过command line进行配置的。在进行后续分析之前,先来理解一下command line的处理模型:
    要处理的对象是一个字符串,其中包含了各种配置信息,通常各个配置之间通过空格进行分离,每个配置的表达形式是如:param=value1,value2 或者很简单就是一个rw
    那么kernel就需要提供对这些参数进行处理的处理函数列表。根据参数的作用以及执行期的先后不同,这些处理函数被定义到不同的段中。针对每一个参数,Kernel都会到相应的段中查找相应的处理函数,最终进行各个组件的配置。

    1 配置格式

    常见的配置格式如:
     
    console=ttySAC0,115200 root=nfs nfsroot=192.168.1.9:/source/rootfs initrd=0x10800000,0x14af47
     

    2 配置方式

    2.1 Bootloader动态配置

    bootloader进行参数配置,command line将做为atag_list的一个节点传递到Kernel

    2.2 Kernel静态配置

    通过make menuconfig进行配置:运行后配置boot options->Default kernel command string。该配置将被静态编译到Kernel中,通过变量default_command_line访问。

    解析配置

    3.1 相关定义

    根据执行的先后顺序,可以将处理函数分为三个大类,他们分别存在于下面三个段中(参考top/arch/arm/kernel/vmlinux.lds:
     
    __setup_start = .; *(.init.setup) __setup_end = .;
     
    __early_begin = .; *(.early_param.init) __early_end = .;
     
    __start___param = .; *(__param) __stop___param = .;
     
    这三个段内存储的不是参数,而是command line参数所需要的处理函数。

    3.1.1 .early_param.init

    .early_param.init”所定义的处理相对靠前一些,它所处理的参数例如:initrd=cachepolicy=nocache nowb ecc= vmalloc= mem=,等等。
    这些处理函数是通过__early_param宏来定义的,例如:
    static void __init early_initrd(char **p)
    { …… }
    __early_param("initrd=", early_initrd);
    对于宏__early_param,可以在top/arch/arm/include/asm/Setup.h中找到如下定义:
     
    struct early_params {
        const char *arg;
        void (*fn)(char **p);
    };
    #define __early_param(name,fn)
    static struct early_params __early_##fn __used
    __attribute__((__section__(".early_param.init"))) = { name, fn }
     
     
    3.1.2 .init.setup
     
    .init.setup”定义的处理则要靠后一些,它所处理的参数例如:nfsroot= ip=,等等。
    这些处理函数是通过__setup宏来定义的,例如:
     
    static int __init nfs_root_setup(char *line)
    { …… }
    __setup("nfsroot=", nfs_root_setup);
     
    对于宏__setup,可以在top/include/linux/Init.h中看到:
     
    #define __setup_param(str, unique_id, fn, early)
        static char __setup_str_##unique_id[] __initdata __aligned(1) = str;
        static struct obs_kernel_param __setup_##unique_id
               __used __section(.init.setup)
               __attribute__((aligned((sizeof(long)))))
               = { __setup_str_##unique_id, fn, early }

    #define __setup(str, fn)
        __setup_param(str, fn, fn, 0)

    /* NOTE: fn is as per module_param, not __setup! Emits warning if fn
     * returns non-zero. */
    #define early_param(str, fn)
        __setup_param(str, fn, fn, 1)
     
    注意看的话,可以看到还有一个宏 early_param,它与宏__setup的定义相似,只不过最后一个宏参数是1而不是01表示需要提前处理的参数。

    3.1.3  __param

    这个段中保存的是build-in类型module的配置参数。该宏直接用来修饰需要的变量。

    3.2  解析

    3.2.1 相关变量

    相关的变量包括:
    default_command_line
    保存memuconfig配置的参数,如果bootloader传入了命令行参数,那么这个新的配置将被更新到该变量中。
    boot_command_line
    存在于.init.data段。最初是default_command_line的拷贝。
    command_line
    存在于.init.data段。在parse_cmdline()中被赋值,数据来源是default_command_line
    saved_command_line
    用于保存没有处理过的命令行参数,是boot_caommand_line的拷贝。
    static_command_line
    command_line的拷贝。

    3.2.2 主要函数

    函数名称:parse_cmdline()
    操作数据:default_command_line
    函数列表:.early_param.init段(在__early_begin__early_end之间)。
    函数功能:依据函数列表对default_command_line中的参数进行处理。
     
     
    函数名称:parse_early_param()
    操作数据:boot_command_line
    函数列表:.init.setup段中(__setup_start__setup_end之间),主要是通过宏early_param定义的部分。
    函数功能:依据函数列表对boot_command_line中的参数进行处理。
    注意parse_one()的第四个入参是0,而且第五个参数是NULL。这里没有给出参数队列,不会对boot_command_line的每个参数在参数队列中进行对比查找,而是直接在do_early_param()中进行条件判断,如果满足下面的条件,那么对该参数进行对应的操作:
     
    if ((p->early && strcmp(param, p->str) == 0) ||
                      (strcmp(param, "console") == 0 &&
                       strcmp(p->str, "earlycon") == 0)
                  )
     
     
    函数名称:parse_args()
    操作数据:static_command_line
    函数列表:__param段(__start___param__stop___param之间)。
    函数功能:该操作将依据函数列表,对static_command_line中的参数进行相应的操作。这个操作在parse_one()的第一部分代码完成:
     
    for (i = 0; i < num_params; i++) {
              if (parameq(param, params[i].name)) {
                     DEBUGP("They are equal! Calling %p ",
                            params[i].set);
                     return params[i].set(val, ¶ms[i]);
              }
       }
     
    接下来对于不被这个列表所支持的参数,将在unknown_bootoption()中进行处理。在unknown_bootoption()中主要是obsolete_checksetup()的操作。
     
     
    函数名称:obsolete_checksetup()
    操作数据:static_command_line
    函数列表:.init.setup段中(__setup_start__setup_end之间),主要是通过宏__setup定义的部分。
    函数功能:该操作将依据函数列表,对static_command_line中的参数进行相应的操作。如果是在parse_early_param()中已经处理的操作,那么这里不再处理;如果是查找到的条目中没有操作函数,那么这表示是过时的数据定义(有些早期的代码,没有定义这个函数);如果不是以上两种情形,那么利用找到的函数对参数进行处理。
  • 相关阅读:
    Oracle基础知识整理
    linux下yum安装redis以及使用
    mybatis 学习四 源码分析 mybatis如何执行的一条sql
    mybatis 学习三 mapper xml 配置信息
    mybatis 学习二 conf xml 配置信息
    mybatis 学习一 总体概述
    oracle sql 语句 示例
    jdbc 新认识
    eclipse tomcat 无法加载导入的web项目,There are no resources that can be added or removed from the server. .
    一些常用算法(持续更新)
  • 原文地址:https://www.cnblogs.com/jingzhishen/p/4777733.html
Copyright © 2011-2022 走看看