在读kernel代码时候又一次碰到early_param这个调用,网上查了下大体和__setup函数作用是一样的,都是在驱动起来后很早加载其回调函数,用来作一些早期的初始化。一直没注意其实现的逻辑过程,只知道应该这样用。现在来看看其到底是如何实现的。
先来看看一个序列图,比较简单:
上面的序列图调用过程会显得比较简单,逻辑并不复杂。由bootloader拉起start_kernel开始进行驱动加载,在加载moudle_init各种驱动之前会处理__setup和early_param这两种结构,如下图:
我们这里就从parse_early_param这个函数开始看起。
1.parse_early_param
void __init parse_early_param(void)
{
static int done __initdata;
static char tmp_cmdline[COMMAND_LINE_SIZE] __initdata;
if (done)
return;
/* All fall through to do_early_param. */
//拷贝cmdline字符串,cmdline前面说过是在DTS里面配置的,不是以前那种bootloader传递上来的方式了
strlcpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE);
//下面分析这个函数调用
parse_early_options(tmp_cmdline);
done = 1;
}
2.parse_early_options
void __init parse_early_options(char *cmdline)
{
parse_args("early options", cmdline, NULL, 0, 0, 0, NULL,
do_early_param);
}
这个函数一看就知道,会回调do_early_param来具体处理数据。这里注意其传进去的参数
3.parse_early_options
char *parse_args(const char *doing,
char *args,
const struct kernel_param *params,
unsigned num,
s16 min_level,
s16 max_level,
void *arg,
int (*unknown)(char *param, char *val,
const char *doing, void *arg))
{
char *param, *val, *err = NULL;
/* Chew leading spaces */
args = skip_spaces(args);
if (*args)
pr_debug("doing %s, parsing ARGS: '%s'\n", doing, args);
while (*args) {
int ret;
int irq_was_disabled;
//调用next_arg解析数据,args就是cmdline
param就是一个属性的起始地址
val就是属性值的起始地址也就是=号后面的内容。属性与属性之间用空格隔开
args = next_arg(args