一、__tagtable分析,对于arm平台,解析uboot向内核传递的参数
//对应文件 arch\arm\include\asm\setup.h
struct tagtable {
__u32 tag;
int (*parse)(const struct tag *);
};
#define __tag __used __attribute__((__section__(".taglist.init")))
#define __tagtable(tag, fn) static struct tagtable __tagtable_##fn __tag = { tag, fn }
如tagtable(ATAG_MEM, parse_tag_mem32)
展开后,该结构体变量会放在.taglist.init段中
static struct tagtable __tagtable_parse_tag_mem32 __used __attribute__((__section__(".taglist.init"))) =
{
ATAG_MEM,
parse_tag_mem32
}
//调用过程
start_kernel->setup_arch->parse_tags->parse_tag
static int __init parse_tag(const struct tag *tag)
{
extern struct tagtable __tagtable_begin, __tagtable_end;
struct tagtable *t;
//.taglist.init段中的结构体中对应的函数都会被执行
for (t = &__tagtable_begin; t < &__tagtable_end; t++)
if (tag->hdr.tag == t->tag) {
t->parse(tag);
break;
}
return t < &__tagtable_end;
}
arch/arm/kernel/vmlinux.lds.S
__tagtable_begin = .;
*(.taglist.init)
__tagtable_end = .;
二、early_param、__setup,对于x86平台,解析grub.cfg等向内核传递的参数
//include/linux/init.h
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 }
#define __setup(str, fn) __setup_param(str, fn, fn, 0)
//对于setup(str,fn)其展开为
static struct obs_kernel_param __setup_fn__used __section( .init.setup) __attribute__((aligned((sizeof(long)))))={
str
fn,
0
}
#define early_param(str, fn) __setup_param(str, fn, fn, 1)
//其展开为
static struct obs_kernel_param __setup_fn__used __section(.init.setup) __attribute__((aligned((sizeof(long)))))=
{
str,
fn,
1
}
early_param、__setup都是放在.init.setup段中的结构体变量.
early_param/__setup调用过程,二次解析
第一次解析,解析early_param结构体函数
start_kernel->parse_early_param->parse_early_options->parse_args("early options", cmdline, NULL, 0, do_early_param);
static int __init do_early_param(char *param, char *val)
{
struct obs_kernel_param *p;
for (p = __setup_start; p < __setup_end; p++) { /*在.init.setup段中结构体中依次执行相应的函数*/
if ((p->early && strcmp(param, p->str) == 0) || /*p->early=1即解析的是early_param结构体函数*/
(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;
}
第二次解析,解析__setup结构体函数
start_kernel->parse_args("Booting kernel", static_command_line, __start___param,__stop___param - __start___param,&unknown_bootoption);
arch/arm/kernel/vmlinux.lds.S
__setup_start = .;
*(.init.setup)
__setup_end = .;