本人刚开始学linux内核,有理解错误地方欢迎指正!
内核版本2.6.32.2
/*
*在include/linux/autoconf.h中定义,也即是在通过make menuconfig中进行手动配置产生的
*/
#define CONFIG_CMDLINE "console=ttySAC0,115200"
static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
void __init setup_arch(char **cmdline_p)
{
...
...
...
char *from = default_command_line;
...
...
...
/*
*将命令行参数(CONFIG_CMDLINE中的值["console=ttySAC0,115200"])复制到全局变量boot_command_line中
*/
memcpy(boot_command_line, from, COMMAND_LINE_SIZE);
boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
parse_cmdline(cmdline_p, from);
...
...
...
}
struct early_params {
const char *arg;
void (*fn)(char **p);
};
/*
*该宏定义一个struct early_params结构的变量,并将该变量的数据放在".early_param.init"段中
*/
#define __early_param(name,fn) \
static struct early_params __early_##fn __used __attribute__((__section__(".early_param.init"))) = { name, fn }
/*
*在arch/arm/kernel/vmlinux.lds.S文件中有如下定义
*/
__early_begin = .;
*(.early_param.init)
__early_end = .;
/*
*上面两段内容实际上表示的意思是:
*将所有通过宏(__early_param)定义的变量都放在".early_param.init"段中,
*可以将".early_param.init"段理解成一个数组,所有的变量按照数组的排
*列方式组合在一起,__early_begin就是这个数组的起始地址,__early_end
*就是这个数组的结束地址.
*/
static char __initdata command_line[COMMAND_LINE_SIZE];
static void __init parse_cmdline(char **cmdline_p, char *from)
{
char c = ' ', *to = command_line;//command_line为空数组
int len = 0;
for (;;) {
if (c == ' ') {
extern struct early_params __early_begin, __early_end;
struct early_params *p;
/*
*通过上面的解释,这里可以理解为遍历数组中的所有元素
*/
for (p = &__early_begin; p < &__early_end; p++) {
int arglen = strlen(p->arg);
/*通过比较名字来判断是否找到能解析该命令行参数的数据结构*/
if (memcmp(from, p->arg, arglen) == 0) {
if (to != command_line)
to -= 1;
from += arglen;
/*调用定义的函数来解析该命令行参数*/
p->fn(&from);
/*查找下一个命令行参数*/
while (*from != ' ' && *from != '\0')
from++;
break;
}
}
}
/*下面6行代码表示将没有找到的其它命令行参数复制到全局变量command_line中*/
c = *from++;
if (!c)
break;
if (COMMAND_LINE_SIZE <= ++len)
break;
*to++ = c;
}
*to = '\0';
*cmdline_p = command_line;
}
/*
*通过上面的理解可以得出parse_cmdline函数的作用:
*如果某个命令行参数已经通过宏__early_param定义了,那么就调用它的解析函数
*来解析它;如果没有定义,那么就把它复制到全局变量command_line中.
*假如命令行参数为"console=ttySAC0,115200 mem=16M",那么:
* mem=16M将被解析出来,而"console=ttySAC0,115200"则被复制到全局变量command_line中
*/
char *saved_command_line;
static char *static_command_line;
static void __init setup_command_line(char *command_line)
{
saved_command_line = alloc_bootmem(strlen (boot_command_line)+1);
static_command_line = alloc_bootmem(strlen (command_line)+1);
strcpy (saved_command_line, boot_command_line);
strcpy (static_command_line, command_line);
}
/*
*setup_command_line函数很简单,作用:
*1,为全局变量saved_command_line和static_command_line分配内存;
*2,将全局变量boot_command_line的内容复制到saved_command_line中
*3,将 变量command_line的内容复制到static_command_line中
*说明:boot_command_line中的内容为没有被解析过的命令行参数
* command_line中的内容为已经被解析过的命令行参数
*/
void __init parse_early_param(void)
{
static __initdata int done = 0;
static __initdata char tmp_cmdline[COMMAND_LINE_SIZE];
if (done)
return;
/* All fall through to do_early_param. */
strlcpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE);
parse_early_options(tmp_cmdline);
done = 1;
}
void __init parse_early_options(char *cmdline)
{
parse_args("early options", cmdline, NULL, 0, do_early_param);
}
int parse_args(const char *name,
char *args,
struct kernel_param *params,
unsigned num,
int (*unknown)(char *param, char *val))
{
char *param, *val;
...
/* 跳过起始空格部分 */
while (isspace(*args))
args++;
while (*args) {
int ret;
...
/*解析命令行参数部分,函数完成后,param=参数名,val=该参数的值,并返回指向下一个
*参数地址的指针
*/
args = next_arg(args, ¶m, &val);
...
ret = parse_one(param, val, params, num, unknown);
...
...
...
}
/* All parsed OK. */
return 0;
}
/*quote 引号("")*/
static char *next_arg(char *args, char **param, char **val)
{
unsigned int i, equals = 0;
int in_quote = 0, quoted = 0;
char *next;
/*
*如果以引号(")开头
*/
if (*args == '"') {
/*跳过引号*/
args++;
/*标记在引号中*/
in_quote = 1;
/*标记被引用*/
quoted = 1;
}
for (i = 0; args[i]; i++) {
/*
*如果遇到空格并且已经跳出引号之外[或者从来没有出现过引号]
*那么跳出for循环,表示已经找到一个完整的arg
*比如[console=ttySAC0,115200]
*/
if (isspace(args[i]) && !in_quote)
break;
/*
*如果从来没有出现过等号(=)
*那么等号出现时,记下该等号的下标(i)
*比如[console=ttySAC0,115200]中,equals = i = 7
*/
if (equals == 0) {
if (args[i] == '=')
equals = i;
}
/*如果再次出引号,将in_quote的值取反*/
if (args[i] == '"')
in_quote = !in_quote;
}
*param = args;
/*如果没有检测到等号(=),那么表示该参数的值为空;否则不为空*/
if (!equals)
*val = NULL;
else {
/*将等号(=)位置的字符重新赋值为NULL,例如此时 *param = console */
args[equals] = '\0';
/* *val指向等号(=)下一个字符的地址 */
*val = args + equals + 1;
/* Don't include quotes in value. */
/*不要将引号包含在值里面*/
if (**val == '"') {
(*val)++;
if (args[i-1] == '"')
args[i-1] = '\0';
}
if (quoted && args[i-1] == '"')
args[i-1] = '\0';
}
if (args[i]) {
args[i] = '\0';
next = args + i + 1;
} else
next = args + i;
/* Chew up trailing spaces. */
while (isspace(*next))
next++;
return next;
}
static int parse_one(char *param,
char *val,
struct kernel_param *params,
unsigned num_params,
int (*handle_unknown)(char *param, char *val))
{
unsigned int i;
/* Find parameter */
/*通过上面传过来的参数值来看,num_params = 0,所以这里什么都不做*/
for (i = 0; i < num_params; i++) {
if (parameq(param, params[i].name)) {
DEBUGP("They are equal! Calling %p\n",
params[i].set);
return params[i].set(val, ¶ms[i]);
}
}
/*这里的handle_unknown = do_early_param,所以实际上是在调用do_early_param函数*/
if (handle_unknown) {
DEBUGP("Unknown argument: calling %p\n", handle_unknown);
return handle_unknown(param, val);
}
DEBUGP("Unknown argument `%s'\n", param);
return -ENOENT;
}
struct obs_kernel_param {
const char *str;
int (*setup_func)(char *);
int early;
};
#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 }
/*
*该宏定义了两个变量:
*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 }
*/
#define __setup(str, fn) \
__setup_param(str, fn, fn, 0)
#define early_param(str, fn) \
__setup_param(str, fn, fn, 1)
/*
*比如 __setup("console=", console_setup) 这个宏定义了如下两个变量
*static const char __setup_str_console_setup[] __initconst __aligned(1) = "console=";
*static struct obs_kernel_param __setup_console_setup __used __section(.init.setup) __attribute__((aligned((sizeof(long)))))
* = { __setup_str_console_setup, console_setup, 0 }
*/
static int __init do_early_param(char *param, char *val)
{
struct obs_kernel_param *p;
for (p = __setup_start; p < __setup_end; p++) {
/*如果p->early = 1 并且参数名相等*/
if ((p->early && strcmp(param, p->str) == 0) ||
(strcmp(param, "console") == 0 &&
strcmp(p->str, "earlycon") == 0)
) {
/*调用解析函数*/
if (p->setup_func(val) != 0)
printk(KERN_WARNING
"Malformed early option '%s'\n", param);
}
}
/* We accept everything at this stage. */
return 0;
}