kernel 命令行参数解析

@do_mounts.c
asmlinkage void __init 
start_kernel(void)
+-- parse_early_param();  
    +-- strlcpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE);  
    +-- parse_early_options(tmp_cmdline);  
        +-- parse_args("early options", cmdline, NULL, 0, 0, 0, do_early_param);
            +-- parse_one(param, val, doing, params, num, min_level, max_level, unknown); 
+-- parse_args("Booting kernel", static_command_line, __start___param, 
                __stop___param - __start___param, 0, 0, &unknown_bootoption); 
    +-- parse_one(param, val, doing, params, num, min_level, max_level, unknown);

int parse_args(const char *name,
	       char *args,                       //这里传入的实参是static_command_line
	       const struct kernel_param *params,//这里__start___param是内核注册的各种kernel_param
	       unsigned num,
	       s16 min_level,
	       s16 max_level,
	       int (*unknown)(char *param, char *val))
{
	char *param, *val;

	pr_debug("Parsing ARGS: %s\n", args);

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

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

		//从static_command_line中提取下一参数的name和val分别赋值给param和val;
		args = next_arg(args, &param, &val);
		irq_was_disabled = irqs_disabled();

		//根据提取的参数名param,从__start___param参数列表中找到对应的kernel_param结构
		//并以val为参数,调用对应kernel_param 结构中的set()函数: 
		//params[i].ops->set(val, &params[i]);
		ret = parse_one(param, val, params, num, min_level, max_level, unknown);
		if (irq_was_disabled && !irqs_disabled()) {
			printk(KERN_WARNING "parse_args(): option '%s' enabled "
					"irq's!\n", param);
		}
		……
	}

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

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

	+-- for (i = 0; i < num_params; i++)
		if (parameq(param, params[i].name)) {
			……
			mutex_lock(&param_lock);
			//所有"__param" section 的kernel_param 结构的set()函数就是在这里调用
			err = params[i].ops->set(val, &params[i]); 
			mutex_unlock(&param_lock);
			return err;
		}
	+-- if (handle_unknown)
	    //handle_unknown()就是unknown_bootoption()   
	    handle_unknown(param, val);
	    +-- obsolete_checksetup(param); //param --> line
		+-- p = __setup_start;  
		    do { 
		        //所有".init.setup" section 的obs_kernel_param结构的setup_func()
		        //都是在这里调用的;
		        p->setup_func(line + n);   
		        p++;  
		    }while (p < __setup_end);


static int __init obsolete_checksetup(char *line)
{
	const struct obs_kernel_param *p;
	int had_early_param = 0;

	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 = 1;
			} else if (!p->setup_func) {
				printk(KERN_WARNING "Parameter %s is obsolete,"
				       " ignored\n", p->str);
				return 1;
			} else if (p->setup_func(line + n))
				return 1;
		}
		p++;
	} while (p < __setup_end);

	return had_early_param;
}


//那么__param section 和 .init.setup section里面的结构体又是怎么来的呢?
//首先看__param section里面的struct kernel_param:

struct kernel_param {
	const char *name;
	const struct kernel_param_ops *ops;
	u16 perm;
	s16 level;
	union {
		void *arg;
		const struct kparam_string *str;
		const struct kparam_array *arr;
	};
};

struct kernel_param_ops {
	int  (*set) (const char *val, const struct kernel_param *kp);
	int  (*get) (char *buffer, const struct kernel_param *kp);
	void (*free)(void *arg);
};

//kernel用以下三个宏,定义出位于"__param" section的struct kernel_param 结构列表
#define module_param_cb(name, ops, arg, perm)				\
	__module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, 0)

#define core_param(name, var, type, perm)				\
	param_check_##type(name, &(var));				\
	__module_param_call("", name, &param_ops_##type, &var, perm, 0)

#define module_param_string(name, string, len, perm)			\
	static const struct kparam_string __param_string_##name		\
		= { len, string };					\
	__module_param_call(MODULE_PARAM_PREFIX, name,			\
			    &param_ops_string,				\
			    .str = &__param_string_##name, perm, 0);	\
	__MODULE_PARM_TYPE(name, "string")



#define __module_param_call(prefix, name, ops, arg, perm, level)	\
	/* Default value instead of permissions? */			\
	static int __param_perm_check_##name __attribute__((unused)) =	\
	BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2))	\
	+ BUILD_BUG_ON_ZERO(sizeof(""prefix) > MAX_PARAM_PREFIX_LEN);	\
	static const char __param_str_##name[] = prefix #name;		\
	static struct kernel_param __moduleparam_const __param_##name	\
	__used								\
	__attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
	= { __param_str_##name, ops, perm, level, { arg } }


	@vmlinux.lds.h
	//__section__("__param")就定义在此文件中
	/* Built-in module parameters. */				\
	__param : AT(ADDR(__param) - LOAD_OFFSET) {			\
		VMLINUX_SYMBOL(__start___param) = .;			\
		*(__param)						\
		VMLINUX_SYMBOL(__stop___param) = .;			\
	}	

	@vmlinux.lds.S 
	#include <asm-generic/vmlinux.lds.h> //vmlinux.lds.h就被包含在vmlinux.lds.S里面
	#include <asm/cache.h>
	#include <asm/thread_info.h>
	#include <asm/memory.h>
	#include <asm/page.h>

//再看.init.setup section里面的struct obs_kernel_param :
struct obs_kernel_param {
	const char *str;
	int (*setup_func)(char *);
	int early;
};


@vmlinux.lds.S
        ...
        .init.data : {
#ifndef CONFIG_XIP_KERNEL
                INIT_DATA
#endif
                INIT_SETUP(16)
                INIT_CALLS
                CON_INITCALL
                SECURITY_INITCALL
                INIT_RAM_FS
        }
        ...


@vmlinux.lds.h
#define INIT_SETUP(initsetup_align)                                     \
                . = ALIGN(initsetup_align);                             \
                VMLINUX_SYMBOL(__setup_start) = .;                      \
                *(.init.setup)                                          \
                VMLINUX_SYMBOL(__setup_end) = .;

//内核采用__setup()宏,定义出位于".init.setup" section的struct obs_kernel_param结构列表
 
#define __setup(str, fn)  __setup_param(str, fn, fn, 0)
        
#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 }
        

以load_ramdisk()函数为例

static int __init load_ramdisk(char *str)
{
        rd_doload = simple_strtol(str,NULL,0) & 3;
        return 1;
}
__setup("load_ramdisk=", load_ramdisk);
>>>
__setup_param("load_ramdisk=", load_ramdisk, load_ramdisk, 0)
>>>
static const char 
__setup_str_load_ramdisk[] 
    __initconst 
    __aligned(1) 
= "load_ramdisk="; 

static struct obs_kernel_param 
__setup_load_ramdisk  
    __used 
    __section(.init.setup) 
    __attribute__((aligned((sizeof(long))))) 
= { __setup_str_load_ramdisk, load_ramdisk, 0 }

</pre
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值