linux内核中的early_param,17. 内核参数解析

17.3. 第二阶段第二个阶段"Booting kernel",用来解析__start___param与__stop___param之间的struct kernel_param成员,继续查看一下内核的链接脚本: include/asm-generic/vmlinux.lds.h

/* Built-in module parameters. */ __param : AT(ADDR(__param) - LOAD_OFFSET) { VMLINUX_SYMBOL(__start___param) = .; *(__param) VMLINUX_SYMBOL(__stop___param) = .; . = ALIGN((align)); VMLINUX_SYMBOL(__end_rodata) = .; }

arch/arm/kernel/vmlinux.lds

__start___param = .; *(__param) __stop___param = .;所以它们之间包含的段由__param声明: include/linux/moduleparam.h

#define __module_param_call(prefix, name, set, get, arg, perm) /* 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, perm, set, get, { arg } }这是一个非常复杂的宏,显然它针对模块参数。它定义了一个kernel_param类型的变量,这个变量被放到了段__param。 struct kernel_param {

const char *name;

unsigned int perm;

param_set_fn set;

param_get_fn get;

union {

void *arg;

const struct kparam_string *str;

const struct kparam_array *arr;

};

};内核中并不推荐直接使用__module_param_call宏来定义kernel_param的实例,而是又扩展了两个宏module_param_named和module_param。 #define module_param_call(name, set, get, arg, perm) __module_param_call(MODULE_PARAM_PREFIX, name, set, get, arg, perm)

/* Helper functions: type is byte, short, ushort, int, uint, long,

ulong, charp, bool or invbool, or XXX if you define param_get_XXX,

param_set_XXX and param_check_XXX. */

#define module_param_named(name, value, type, perm) param_check_##type(name, &(value)); module_param_call(name, param_set_##type, param_get_##type, &value, perm); __MODULE_PARM_TYPE(name, #type)

#define module_param(name, type, perm) module_param_named(name, name, type, perm)通常模块中使用module_param_named和module_param声明参数变量。为了理解上面的所做所为,这里对内核模块的编译做一个详尽的分析和说明。Linux编译内核模块的命令为make modules(如果不是在内核根文件夹下编译,那么需要-C参数指定内核文件夹)。在Linux的Makefile中对应的动作如下: modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux)

$(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.order) > $(objtree)/modules.order

@echo ' Building modules, stage 2.';

$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost

$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_modbuild注意到它是通过Makefile.modpost进行编译和链接的,总共分为六个步骤。其中编译时的命令为: quiet_cmd_cc_o_c = CC $@

cmd_cc_o_c = $(CC) $(c_flags) $(CFLAGS_MODULE) -c -o $@ $

#define ___module_cat(a,b) __mod_ ## a ## b

#define __module_cat(a,b) ___module_cat(a,b)

#define __MODULE_INFO(tag, name, info) static const char __module_cat(name,__LINE__)[] __used __attribute__((section(".modinfo"),unused)) = __stringify(tag) "=" info

#else /* !MODULE */

#define __MODULE_INFO(tag, name, info)

#endif自此,模块编译和编译入内核的两种方式从这里开始相揖别。对它们的处理完全不同。首先对模块编译相关的宏做一解释:__MODULE_INFO,它用来记录模块的相关信息,并且放在.ko文件的.modinfo代码节中。__MODULE_INFO通常并不由模块直接调用,而是通过宏再次对它进行了封装。 #define __MODULE_PARM_TYPE(name, _type) __MODULE_INFO(parmtype, name##type, #name ":" _type)而module_param_string,module_param_named和module_param又是对它的封装,用来定义参数。这三个宏被开放给模块使用。另外最通用的几个中在module.h中定义: /* Generic info of form tag = "info" */

#define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)

#define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias)

#define MODULE_LICENSE(_license) MODULE_INFO(license, _license)

#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description)

#define MODULE_PARM_DESC(_parm, desc) __MODULE_INFO(parm, _parm, #_parm ":" desc)

#define MODULE_VERSION(_version) MODULE_INFO(version, _version)

#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)为了深入对它的了解,一个__MODULE_PARM_TYPE(bisa, "string")的定义被扩展成如下信息,显然它被定义成一个静态数组,数组中定义了参数名,以及参数类型。 #define __stringify_1(x) #x

#define __stringify(x) __stringify_1(x)

static const char __mod_bisatype29[] __used __attribute__((section(".modinfo"),unused)) = "parmtype" "=" "bisa" ":" "string"通过modinfo命令可以查看内核模块的这些数组的内容: # modinfo xt_MARK.ko

filename: xt_MARK.ko

alias: ip6t_MARK

alias: ipt_MARK

description: Xtables: packet mark modification

author: Marc Boucher

license: GPL

depends:

vermagic: 2.6.28.6 preempt mod_unload ARMv6而第二种情况__MODULE_INFO宏被定义成空,所以被编译进内核的模块代码是没有对应的.modinfo节信息的。它使用struct kernel_param来表示参数的相关信息。并且这些信息被放在名为__param的节中。而内核在解析参数到"Booting kernel"阶段时,就会对这些节中的参数名一一匹配,如果通过Bootloader或者在CONFIG_CMDLINE中定义了该参数,那么此时将被解析,以备将来的内嵌的模块进行加载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值