lk传递内核参数解析

参考链接:https://blog.csdn.net/skyflying2012/article/details/41142801

(1)早期参数解析:
parse_early_param(init/main.c)—>parse_early_options(tmp_cmdline)—>
parse_args(“early options”, cmdline, NULL, 0, 0, 0, do_early_param);

parse_args函数实现如下:
.路径:/kernel/params.c

char *parse_args(const char *doing,
         char *args,
         const struct kernel_param *params,
         unsigned num,
         s16 min_level,
         s16 max_level,
         int (*unknown)(char *param, char *val, const char *doing))
{
    char *param, *val;

    /* Chew leading spaces */
    args = skip_spaces(args);

    if (*args)
        pr_debug("doing %s, parsing ARGS: '%s'\n", doing, args);

    while (*args) {
        int ret;
        int irq_was_disabled;

		
/*args = next_arg(args, &param, &val);//这个函数就是获取解析一个值,
*param=args指向原始的args地址
*val是解析一个等号的值
*函数返回解析完一个等号的值后的下个参数首地址*/
        args = next_arg(args, &param, &val);
        /* Stop at -- */
        if (!val && strcmp(param, "--") == 0)
            return args; 
        irq_was_disabled = irqs_disabled();
        
//然后利用parse_one来一个个解析参数的意义
        ret = parse_one(param, val, doing, params, num,
                min_level, max_level, unknown);
        if (irq_was_disabled && !irqs_disabled())
            pr_warn("%s: option '%s' enabled irq's!\n",
                doing, param);

        switch (ret) {
        case -ENOENT:
            pr_err("%s: Unknown parameter `%s'\n", doing, param);
            return ERR_PTR(ret);
        case -ENOSPC:
            pr_err("%s: `%s' too large for parameter `%s'\n",
                   doing, val ?: "", param);
            return ERR_PTR(ret);
        case 0:
            break;
        default:
            pr_err("%s: `%s' invalid for parameter `%s'\n",
                   doing, val ?: "", param);
            return ERR_PTR(ret);
        }
    }

    /* All parsed OK. */
    return NULL;
}

然后利用parse_one来一个个解析参数的意义

ret = parse_one(param, val, doing, params, num,min_level, max_level, unknown);//unknown指向parse_args传进来的实参do_early_param

我们来看下parse_one的定义


static int parse_one(char *param,
		     char *val,
		     const char *doing,
		     const struct kernel_param *params,
		     unsigned num_params,
		     s16 min_level,
		     s16 max_level,
		     int (*handle_unknown)(char *param, char *val,
				     const char *doing))
{
	unsigned int i;
	int err;

	/* Find parameter 在早期的时候并不需要,但是在driver的时候可以*/
	for (i = 0; i < num_params; i++) {
		pr_debug("--flyaudio test --doing %s:\n", doing);
		if (parameq(param, params[i].name)) {
			if (params[i].level < min_level
			    || params[i].level > max_level)
				return 0;
			/* No one handled NULL, so do it here. */
			if (!val &&
			    !(params[i].ops->flags & KERNEL_PARAM_OPS_FL_NOARG))
				return -EINVAL;
			pr_debug("handling %s with %p\n", param,
				params[i].ops->set);//这里便是设置参数的值
			mutex_lock(&param_lock);
			param_check_unsafe(&params[i]);
			err = params[i].ops->set(val, &params[i]);
			mutex_unlock(&param_lock);
			return err;
		}
	}

	if (handle_unknown) {
		pr_debug("doing %s: %s='%s'\n", doing, param, val);
		return handle_unknown(param, val, doing);//直接调用调用 do_early_param解析参数
	}

	pr_debug("Unknown argument '%s'\n", param);
	return -ENOENT;
}//handle_unknown是在parse_args("early options", cmdline, NULL, 0, 0, 0, do_early_param)的参数do_early_param函数的地址

然后do_early_param函数的执行,看下do_early_param的定义

static int __init do_early_param(char *param, char *val, const char *unused)
{
	const struct obs_kernel_param *p;

	for (p = __setup_start; p < __setup_end; p++) {
		if ((p->early && parameq(param, p->str)) ||
		    (strcmp(param, "console") == 0 &&
		     strcmp(p->str, "earlycon") == 0)
		) {
			if (p->setup_func(val) != 0)
				pr_notice("Malformed early option '%s'\n", param);
		}
	}
	/* We accept everything at this stage. */
	return 0;
}

参考上面的链接的说法就是
kernel有一个Init.setup的区域,地址__setup_start到__setup_end
这个地址区域存了一份表(include/linux/init.h),这份表每个编号都是以一个

struct obs_kernel_param {
	const char *str;
	int (*setup_func)(char *);
	int early;
};结构体的形式存在.

const char *str;代表的是参数的关键字眼
int (*setup_func)(char *);是该设置参数的值函数,并具体的实现

例如;

static int __init console_setup(char *str)
{
	char buf[sizeof(console_cmdline[0].name) + 4]; /* 4 for "ttyS" */
	char *s, *options, *brl_options = NULL;
	int idx;

	if (_braille_console_setup(&str, &brl_options))
		return 1;

	/*
	 * Decode str into name, index, options.
	 */
	if (str[0] >= '0' && str[0] <= '9') {
		strcpy(buf, "ttyS");
		strncpy(buf + 4, str, sizeof(buf) - 5);
	} else {
		strncpy(buf, str, sizeof(buf) - 1);
	}
	buf[sizeof(buf) - 1] = 0;
	options = strchr(str, ',');
	if (options)
		*(options++) = 0;
#ifdef __sparc__
	if (!strcmp(str, "ttya"))
		strcpy(buf, "ttyS0");
	if (!strcmp(str, "ttyb"))
		strcpy(buf, "ttyS1");
#endif
	for (s = buf; *s; s++)
		if (isdigit(*s) || *s == ',')
			break;
	idx = simple_strtoul(s, NULL, 10);
	*s = 0;

	__add_preferred_console(buf, idx, options, brl_options);
	console_set_on_cmdline = 1;
	return 1;
}

__setup(“console=”, console_setup);
__setup这个宏展开后就是把console=参数对应console_setup函数

module_param展开后对应

Static struct kernel_param __moduleparam_const __param_use_acm 
 __used   __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) = {
.name = MODULE_PARAM_PREFIX#use_acm,
.ops = param_ops_bool,
.Perm=0,
.level = -1.
.arg = &use_acm
}

ops=param_ops_bool,是kernel_param_ops结构体,定义如下:

    struct kernel_param_ops param_ops_bool = {
        .set = param_set_bool,
        .get = param_get_bool,
    };

会像.init.setup一样放在某一个数据段,对应这一份表

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值