linux kernel 命令行参数解析-parse_early_params-parse_early_options-setup_boot_config-parse_args

 

上一篇:命令行参数获取 https://www.cnblogs.com/zhangzhiwei122/p/16060542.html

 

start_kernel 中解析参数的几个入口

870  行              early 阶段参数解析 -       setup_arch -> parse_early_params

871 行               setup_boot_config

884 ~ 895        最后解析所有参数。

 

early 阶段参数解析

1、kernel_start -> parse_early_params

2、kernel_start -> setup_arch -> parse_early_params

 

init/main.c

parse_early_params

 749/* Arch code calls this early on, or if not, just before other parsing. */
 750void __init parse_early_param(void)
 751{
 752        static int done __initdata;
 753        static char tmp_cmdline[COMMAND_LINE_SIZE] __initdata;
 754
 755        if (done)
 756                return;
 757
 758        /* All fall through to do_early_param. */
 759        strlcpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE);
 760        parse_early_options(tmp_cmdline);
 761        done = 1;
 762}

752 ~ 753 定义 static 的变量 done 和 数组 tmp_cmdline , 在Image的 bss段,被初始化为 0 。

755 ~ 756 根据 done 为0 或 1 ,保证 多次调用 parse_early_params 只调用 1 次 parse_early_options

759 ~ 760  拷贝 boot_command_line 数组内容到 tmp_cmdline 数组,然后用 tmp_cmdline 作参数,调用 parse_early_options .

 

parse_early_options

 742
 743void __init parse_early_options(char *cmdline)
 744{
 745        parse_args("early options", cmdline, NULL, 0, 0, 0, NULL,
 746                   do_early_param);
 747}

调用 parse_args, 但是,参数多数都传 0。 对照 下面的 parse_args 函数原型:

 doing , 传 “early options” 字符串,仅仅时 log 里面使用的字符串。

args 传 cmdline ,命令行参数 数组。

params  - 传递 NULL,表示不和任何 kernel_param 对象进行比较

num  - 0

min_level - 0

max_level 0

arg - NULL

unknown - do_early_param  找不到匹配的 kernel_param 对象时,调用这个 函数处理参数。

 

参数解析工具函数

linux/kernel/params.c

parse_args

 160/* Args looks like "foo=bar,bar2 baz=fuz wiz". */
 161char *parse_args(const char *doing,
 162                 char *args,
 163                 const struct kernel_param *params,
 164                 unsigned num,
 165                 s16 min_level,
 166                 s16 max_level,
 167                 void *arg,
 168                 int (*unknown)(char *param, char *val,
 169                                const char *doing, void *arg))
 170{
 171        char *param, *val, *err = NULL;
 172
 173        /* Chew leading spaces */
 174        args = skip_spaces(args);
 175
 176        if (*args)
 177                pr_debug("doing %s, parsing ARGS: '%s'\n", doing, args);
 178
 179        while (*args) {
 180                int ret;
 181                int irq_was_disabled;
 182
 183                args = next_arg(args, &param, &val);
 184                /* Stop at -- */
 185                if (!val && strcmp(param, "--") == 0)
 186                        return err ?: args;
 187                irq_was_disabled = irqs_disabled();
 188                ret = parse_one(param, val, doing, params, num,
 189                                min_level, max_level, arg, unknown);
 190                if (irq_was_disabled && !irqs_disabled())
 191                        pr_warn("%s: option '%s' enabled irq's!\n",
 192                                doing, param);
 193
 194                switch (ret) {
 195                case 0:
 196                        continue;
 197                case -ENOENT:
 198                        pr_err("%s: Unknown parameter `%s'\n", doing, param);
 199                        break;
 200                case -ENOSPC:
 201                        pr_err("%s: `%s' too large for parameter `%s'\n",
 202                               doing, val ?: "", param);
 203                        break;
 204                default:
 205                        pr_err("%s: `%s' invalid for parameter `%s'\n",
 206                               doing, val ?: "", param);
 207                        break;
 208                }
 209
 210                err = ERR_PTR(ret);
 211        }
 212
 213        return err;
 214}
 215

 

174 跳过空白字符

183 从args 里面取参数到 param 和 value 里面,然后args 指向  去掉 参数后的位置。

188 ~ 189 调用 parse_one ,传递刚解析出来的  params 和 value ,以及 parse_args 函数的输入参数,params - NULL,num  - 0   min_level - 0   max_level 0    arg - NULL  unknown - do_early_param 

 

parse_one

 115static int parse_one(char *param,
 116                     char *val,
 117                     const char *doing,
 118                     const struct kernel_param *params,
 119                     unsigned num_params,
 120                     s16 min_level,
 121                     s16 max_level,
 122                     void *arg,
 123                     int (*handle_unknown)(char *param, char *val,
 124                                     const char *doing, void *arg))
 125{
 126        unsigned int i;
 127        int err;
 128
 129        /* Find parameter */
 130        for (i = 0; i < num_params; i++) {
 131                if (parameq(param, params[i].name)) {
 132                        if (params[i].level < min_level
 133                            || params[i].level > max_level)
 134                                return 0;
 135                        /* No one handled NULL, so do it here. */
 136                        if (!val &&
 137                            !(params[i].ops->flags & KERNEL_PARAM_OPS_FL_NOARG))
 138                                return -EINVAL;
 139                        pr_debug("handling %s with %p\n", param,
 140                                params[i].ops->set);
 141                        kernel_param_lock(params[i].mod);
 142                        if (param_check_unsafe(&params[i]))
 143                                err = params[i].ops->set(val, &params[i]);
 144                        else
 145                                err = -EPERM;
 146                        kernel_param_unlock(params[i].mod);
 147                        return err;
 148                }
 149        }
 150
 151        if (handle_unknown) {
 152                pr_debug("doing %s: %s='%s'\n", doing, param, val);
 153                return handle_unknown(param, val, doing, arg);
 154        }
 155
 156        pr_debug("Unknown argument '%s'\n", param);
 157        return -ENOENT;
 158}

 

130 行遍历 params 数组,(数组中元素个数由 num_params 确定)

131 如果数组中 的param[i].name   和 当前要处理的 param 相同,经过一些检查后,在143 行,调用 params[i].ops->set 函数。

 

151 ~ 153  如果指定了 handle_unknown 函数,对 当前要处理的param  value 调用 handle_unknown 函数。

 

setup_boot_config 中参数解析

to be done

 

最后参数解析

 884        parse_early_param();
 885        after_dashes = parse_args("Booting kernel",
 886                                  static_command_line, __start___param,
 887                                  __stop___param - __start___param,
 888                                  -1, -1, NULL, &unknown_bootoption);
 889        if (!IS_ERR_OR_NULL(after_dashes))
 890                parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
 891                           NULL, set_init_arg);
 892        if (extra_init_args)
 893                parse_args("Setting extra init args", extra_init_args,
 894                           NULL, 0, -1, -1, NULL, set_init_arg);

 

885 ~ 888  Booting kernel, 每个命令行参数 与  __start___param  这个数组中的 strct kernel_param 对象进行匹配,匹配成功就调用 strct kernel_param 对象 的 ops->setup 函数,匹配失败,就调用 unknown_bootoption 函数。

              碰到    --    结束返回。

889 ~ 891 如果 上面 返回的  after_dashes 指针不为空,则说明  还有参数需要解析。 Setting  init args  参数。 不和任何 strct kernel_param 对象进行匹配,所有参数,都被 set_init_args 函数处理。

 

892 ~ 894 如果 extra_init_args  这个字符串指针 不为 NULL, (在setup_boot_options 中设置),则 对这个字符串进行解析。 不和任何 strct kernel_param 对象进行匹配,所有参数,都被 set_init_args 函数处理。

 

posted @ 2022-03-27 10:03  张志伟122  阅读(524)  评论(0编辑  收藏  举报