@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, ¶m, &val);
irq_was_disabled = irqs_disabled();
//根据提取的参数名param,从__start___param参数列表中找到对应的kernel_param结构
//并以val为参数,调用对应kernel_param 结构中的set()函数:
//params[i].ops->set(val, ¶ms[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(¶m_lock);
//所有"__param" section 的kernel_param 结构的set()函数就是在这里调用
err = params[i].ops->set(val, ¶ms[i]);
mutex_unlock(¶m_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, ¶m_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, \
¶m_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 //vmlinux.lds.h就被包含在vmlinux.lds.S里面
#include
#include
#include
#include
//再看.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 }