看linux驱动,发现module_param_string的用法
module_param_string(path, fw_path_para, sizeof(fw_path_para), 0644);网上查了下,说是为可以在用户空间设置参数。特地的看了下代码实现
文件路径:
include/linux/moduleparam.h
#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, \
¶m_ops_string, \
.str = &__param_string_##name, perm, -1, 0);\
__MODULE_PARM_TYPE(name, "string")
#define __module_param_call(prefix, name, ops, arg, perm, level, flags) \
/* Default value instead of permissions? */ \
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, THIS_MODULE, ops, \
VERIFY_OCTAL_PERMISSIONS(perm), level, flags, { arg } }
__param : AT(ADDR(__param) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___param) = .; \
*(__param) \
VMLINUX_SYMBOL(__stop___param) = .; \
} \
又是用到了
attribute 属性
section 告诉编译器将函数编译存放到指定的name地址段。这样所有调用__module_param_call这个宏的代码都将按顺序放到这个地址段,获取其头和尾地址,就可以对所有的函数进行操作。
看看kernel_param结构体的定义
struct kernel_param {
const char *name;
struct module *mod;
const struct kernel_param_ops *ops;
const u16 perm;
s8 level;
u8 flags;
union {
void *arg;
const struct kparam_string *str;
const struct kparam_array *arr;
};
};
查找代码发现,有三处与这个函数相关
after_dashes = parse_args("Booting kernel",
static_command_line, __start___param,
__stop___param - __start___param,
-1, -1, NULL, &unknown_bootoption);
static void __init do_initcall_level(int level)
{
initcall_t *fn;
strcpy(initcall_command_line, saved_command_line);
parse_args(initcall_level_names[level],
initcall_command_line, __start___param,
__stop___param - __start___param,
level, level,
NULL, &repair_env_string);
for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
do_one_initcall(*fn);
}
这两个都是解析cmdline的,从中找到name匹配进行操作。剩下的一个是模块调用
static void __init param_sysfs_builtin(void)
{
const struct kernel_param *kp;
unsigned int name_len;
char modname[MODULE_NAME_LEN];
for (kp = __start___param; kp < __stop___param; kp++) {
char *dot;
if (kp->perm == 0)
continue;
dot = strchr(kp->name, '.');
if (!dot) {
/* This happens for core_param() */
strcpy(modname, "kernel");
name_len = 0;
} else {
name_len = dot - kp->name + 1;
strlcpy(modname, kp->name, name_len);
}
kernel_add_sysfs_param(modname, kp, name_len);
}
}
static int __init param_sysfs_init(void)
{
module_kset = kset_create_and_add("module", &module_uevent_ops, NULL);
if (!module_kset) {
printk(KERN_WARNING "%s (%d): error creating kset\n",
__FILE__, __LINE__);
return -ENOMEM;
}
module_sysfs_initialized = 1;
version_sysfs_builtin();
param_sysfs_builtin();
return 0;
}
subsys_initcall(param_sysfs_init);
这里很明显定义了一个模块,主要目地为每个定义,生成属性节点
相似的宏定义还有
#define module_param_call(name, set, get, arg, perm) \
static const struct kernel_param_ops __param_ops_##name = \
{ .flags = 0, (void *)set, (void *)get }; \
__module_param_call(MODULE_PARAM_PREFIX, \
name, &__param_ops_##name, arg, \
(perm) + sizeof(__check_old_set_param(set))*0, -1, 0)
#define core_param(name, var, type, perm) \
param_check_##type(name, &(var)); \
__module_param_call("", name, ¶m_ops_##type, &var, perm, -1, 0)
#define core_param_unsafe(name, var, type, perm) \
param_check_##type(name, &(var)); \
__module_param_call("", name, ¶m_ops_##type, &var, perm, \
-1, KERNEL_PARAM_FL_UNSAFE)
#define __level_param_cb(name, ops, arg, perm, level) \
__module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, level, 0)
#define module_param_cb(name, ops, arg, perm) \
__module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, -1, 0)
#define module_param_cb_unsafe(name, ops, arg, perm) \
__module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, -1, \
KERNEL_PARAM_FL_UNSAFE)