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, ¶m, &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(¶ms[i])) 143 err = params[i].ops->set(val, ¶ms[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 函数处理。