Linux kernel parse command line

Linux kernel 解析 cmdline

参考其他博客(结尾处标明),结合自己近期的工作内容,记录此文档。

  • 问题: uboot启动成功后将cmdline传给kernel,进入kernel启动阶段,那么kernel如何解析cmdline呢?

uboot 传递cmdline

boot_prep_linux(arch/arm/lib/bootm.c) 中

static void boot_prep_linux(bootm_headers_t *images)
{
	char *commandline = env_get("bootargs");

	if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) {
#ifdef CONFIG_OF_LIBFDT
		debug("using: FDT\n");
		if (image_setup_linux(images)) {
			printf("FDT creation failed! hanging...");
			hang();
		}
#endif
	} else if (BOOTM_ENABLE_TAGS) {
		debug("using: ATAGS\n");
		setup_start_tag(gd->bd);
		if (BOOTM_ENABLE_SERIAL_TAG)
			setup_serial_tag(&params);
		if (BOOTM_ENABLE_CMDLINE_TAG)
			setup_commandline_tag(gd->bd, commandline);
		if (BOOTM_ENABLE_REVISION_TAG)
			setup_revision_tag(&params);
		if (BOOTM_ENABLE_MEMORY_TAGS)
			setup_memory_tags(gd->bd);
		if (BOOTM_ENABLE_INITRD_TAG) {
			/*
			 * In boot_ramdisk_high(), it may relocate ramdisk to
			 * a specified location. And set images->initrd_start &
			 * images->initrd_end to relocated ramdisk's start/end
			 * addresses. So use them instead of images->rd_start &
			 * images->rd_end when possible.
			 */
			if (images->initrd_start && images->initrd_end) {
				setup_initrd_tag(gd->bd, images->initrd_start,
						 images->initrd_end);
			} else if (images->rd_start && images->rd_end) {
				setup_initrd_tag(gd->bd, images->rd_start,
						 images->rd_end);
			}
		}
		setup_board_tags(&params);
		setup_end_tag(gd->bd);
	} else {
		printf("FDT and ATAGS support not compiled in - hanging\n");
		hang();
	}

	board_prep_linux(images);
}

static void setup_start_tag (bd_t *bd)
{
	params = (struct tag *)bd->bi_boot_params;

	params->hdr.tag = ATAG_CORE;
	params->hdr.size = tag_size (tag_core);

	params->u.core.flags = 0;
	params->u.core.pagesize = 0;
	params->u.core.rootdev = 0;

	params = tag_next (params);
}
static void setup_commandline_tag(bd_t *bd, char *commandline)
{
	char *p;

	if (!commandline)
		return;

	/* eat leading white space */
	for (p = commandline; *p == ' '; p++);

	/* skip non-existent command lines so the kernel will still
	 * use its default command line.
	 */
	if (*p == '\0')
		return;

	params->hdr.tag = ATAG_CMDLINE;
	params->hdr.size =
		(sizeof (struct tag_header) + strlen (p) + 1 + 4) >> 2;

	strcpy (params->u.cmdline.cmdline, p);

	params = tag_next (params);
}

params是一个全局静态变量用来存储要传给kernel的参数。
setup_start_tag初始化第一个tag,是tag_core类型的tag。最后调用tag_next跳到第一个tag末尾,为下一个tag做准备。
setup_commandline_tag设置第二个tag的hdr.tag为ATAG_CMDLINE,然后拷贝cmdline到tags的cmdline结构体中,跳到下一个tag。
setup_end_tag设置最后tag为ATAG_NONE,标志tag结束。

kernel 解析cmdline

参考链接3: link

Linux kernel 中可使用宏 __setup() 处理内核启动参数的解析。

调用流程
init/main.c
start_kernel

parse_args(“Booting kernel”,
static_command_line, __start___param,
__stop___param - __start___param,
-1, -1, NULL, &unknown_bootoption);
/* Args looks like “foo=bar,bar2 baz=fuz wiz”. */

  	parse_one
  		unknown_bootoption
  			obsolete_checksetup
  				setup_func   // 即obs_kernel_param定义的setup_func()

源代码

struct obs_kernel_param {
	const char *str;             //参数
	int (*setup_func)(char *);   //设置参数值的函数
	int early;
};
/*
 * Only for really core code.  See moduleparam.h for the normal way.
 *
 * Force the alignment so the compiler doesn't space elements of the
 * obs_kernel_param "array" too far apart in .init.setup.
 */
#define __setup_param(str, unique_id, fn, early)			\
	static const char __setup_str_##unique_id[] __initconst		\
		__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)
static bool __init obsolete_checksetup(char *line)
{
	const struct obs_kernel_param *p;
	bool had_early_param = false;

	p = __setup_start;
	do {
		int n = strlen(p->str);
		if (parameqn(line, p->str, n)) {
			if (p->early) {
				/* Already done in parse_early_param?
				 * (Needs exact match on param part).
				 * Keep iterating, as we can have early
				 * params and __setups of same names 8( */
				if (line[n] == '\0' || line[n] == '=')
					had_early_param = true;
			} else if (!p->setup_func) {
				pr_warn("Parameter %s is obsolete, ignored\n",
					p->str);
				return true;
			} else if (p->setup_func(line + n))
				return true;
		}
		p++;
	} while (p < __setup_end);

	return had_early_param;
}

实例

static int __init serial_is_dis_setup(char *str)
{
	if (strcmp(str, "0")){
		pr_err("%s[%d]: will disable serial  \n", __FUNCTION__, __LINE__);

		isUartRxDis_nsb = 1;
		isUartTxDis_nsb = 1;
	}
	return 1;
}

__setup("serial_is_dis=", serial_is_dis_setup);

//#define BOOT_CONSOLE_DISABLE_ARGS "earlycon=serial,0xf4329188 serial_is_dis=1 console=ttyS0,115200"

宏展开

static const char __setup_str_serial_is_dis_setup[] __initconst      \
  __aligned(1) = "serial_is_dis=";                     \

static struct obs_kernel_param __setup_str_serial_is_dis_setup       \
  __used __section(.init.setup)               \                
  __attribute__((aligned((sizeof(long)))))        \
  = { __setup_str_serial_is_dis_setup, serial_is_dis_setup, 0 }                    ## __setup_str_serial_is_dis_setup 在上面定义

[参考]
链接1: link
链接2: link
链接3: link

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值