内核中对cmdline的解析

Posted 正在起飞的蜗牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了内核中对cmdline的解析相关的知识,希望对你有一定的参考价值。

1、__setup宏

参考博客:《__setup宏定义》

2、内核中解析cmdline的函数调用关系

	start_kernel()
		parse_early_param()
			parse_early_options()
				parse_args();
					next_arg()
					parse_one()
						do_early_param()

3、parse_early_param()函数

void __init parse_early_param(void)

	static __initdata int done = 0;
	static __initdata char tmp_cmdline[COMMAND_LINE_SIZE];

	if (done)
		return;

	/* All fall through to do_early_param. */
	strlcpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE);
	parse_early_options(tmp_cmdline);
	done = 1;

parse_early_param()函数调用parse_early_options()函数,并将cmdline传入。boot_command_line变量保存的是uboot传递给内核的cmdline,具体是在内核解析tag参数时赋值。

4、parse_early_options()函数

void __init parse_early_options(char *cmdline)

	parse_args("early options", cmdline, NULL, 0, do_early_param);

调用parse_args()函数并将cmdline和do_early_param函数指针传入。

5、parse_args()函数

int parse_args(const char *name,
	       char *args,
	       struct kernel_param *params,
	       unsigned num,
	       int (*unknown)(char *param, char *val))

	char *param, *val;
	
	/* Chew leading spaces */
	args = skip_spaces(args);

	while (*args) 
		int ret;
		int irq_was_disabled;

		args = next_arg(args, &param, &val);//解析cmdline的格式解析出cmdline的每个单元
		irq_was_disabled = irqs_disabled();
		ret = parse_one(param, val, params, num, unknown);
		if (irq_was_disabled && !irqs_disabled()) 
			······
		
		switch (ret) 
			······
		
	
	return 0;

(1)next_arg()函数:按照cmdline的格式逐个解析;
比如cmdline=“root=/dev/mmcblk0p2 rootfstype=ext3”
第一次解析结果:param=“root”,val="/dev/mmcblk0p2"
第二次解析结果:param=“rootfstype”,val=“ext3”
(2)parse_one()函数:
对每个从cmdline解析出的单元进行处理;

6、parse_one()函数

static int parse_one(char *param,
		     char *val,
		     struct kernel_param *params, 
		     unsigned num_params,
		     int (*handle_unknown)(char *param, char *val))

	······
	//handle_unknown函数指针就是do_early_param()函数
	if (handle_unknown) 
		DEBUGP("Unknown argument: calling %p\\n", handle_unknown);
		return handle_unknown(param, val);
	

	DEBUGP("Unknown argument `%s'\\n", param);
	return -ENOENT;

对next_arg()函数解析出的param和val进行处理,handle_unknown函数指针就是do_early_param()函数。具体的解析工作都是do_early_param()函数做的。

7、do_early_param()函数

static int __init do_early_param(char *param, char *val)

	struct obs_kernel_param *p;

	for (p = __setup_start; p < __setup_end; p++)  //遍历".init.setup"段,寻找匹配的obs_kernel_param结构体
		if ((p->early && strcmp(param, p->str) == 0) ||
		    (strcmp(param, "console") == 0 &&
		     strcmp(p->str, "earlycon") == 0)
		) 
			if (p->setup_func(val) != 0)	//匹配到obs_kernel_param结构体就执行绑定的处理函数
				printk(KERN_WARNING
				       "Malformed early option '%s'\\n", param);
		
	
	/* We accept everything at this stage. */
	return 0;

(1)__setup_start和__setup_end是".init.setup"段的起始/结束地址;
(2)".init.setup"段的遍历结合__setup宏和链接脚本进行理解;

以上是关于内核中对cmdline的解析的主要内容,如果未能解决你的问题,请参考以下文章

Linux内核__setup()宏介绍

linux内核启动参数解析及添加

linux kernel的cmdline參数解析原理分析

从 proc/pid/cmdline 解析命令行参数

内核中对uboot传参tags的校验

内核中对uboot传参tags的校验