内核启动时怎么处理启动参数
<br />关键点:parse_args __setup宏<br />Linux允许用户通过bootloader传递内核配置选项给内核,例如<br />console=ttyS1,115200n8 androidboot.hardware=eee_701 vga=788<br />内核在初始化过程中调用parse_args函数对这些选项进行解析,并调用相应的处理函数。<br /> <br />内
关键点:parse_args __setup宏
Linux允许用户通过bootloader传递内核配置选项给内核,例如
console=ttyS1,115200n8 androidboot.hardware=eee_701 vga=788
内核在初始化过程中调用parse_args函数对这些选项进行解析,并调用相应的处理函数。
内核启动时怎么处理启动参数的了:通过__setup宏定义obs_kernel_param结构变量都被放入.init.setup段中,这样一来实际是使.init.setup段变成一张表,Kernel在处理每一个启动参数时,都会来查找这张表,与每一个数据项中的成员str进行比较,如果完全相同,就会调用该数据项的函数指针成员setup_func所指向的函数(该函数是在使用__setup宏定义该变量时传入的函数参数),并将启动参数如root=后面的内容传给该处理函数。
精髓是利用__setup宏建立了字符和对应处理函数集合的表,parse_args函数依次将命令行参数与这个表比较,找到匹配了就执行对应的处理函数。
__setup宏的来源及使用
内核组件用__setup宏来注册关键字及相关联 的任何文本都会作为输入传给
function_handler。
不同的内核选项可以关联相同的处理函数,比如内核选项netdev和ether都关联了netdev_boot_setup函数。
理。
两次解析
相应于__setup宏和early_param宏两种注册形式,内核在初始化时,调用了两次parse_args函数进行解析。
parse_early_param();
parse_args("Booting kernel", static_command_line, __start___param,
__stop___param - __start___param,
&unknown_bootoption);
parse_args的第一次调用就在parse_early_param函数里面,为什么会出现两次调用parse_args的情况?这是因为内核选项又分成了两种,就像现实世界中的我们,一种是普普通通的,一种是有特权的,有特权的需要在普通选项之前进行处理。
使用early_param声明的那些选项就会首先由parse_early_param去解析。
下面的例子来自于init/do_mounts.c,其中root_dev_setup作为处理程序被注册给“root=”关键字:
__setup("root=", root_dev_setup);
比如我们在启动向参数终有
noinitrd root=/dev/mtdblock2 console=/linuxrc
setup_arch解释时会发现root=/dev/mtdblock2,然后它就会调用root_dev_setup
static int __init root_dev_setup(char *line)
{
strlcpy(saved_root_name, line, sizeof(saved_root_name));
return 1;
}
我们容易看出,这个函数就是给saved_root_name赋值,saved_root_name这个全局变量非常重要,
比如printk。cstatic int __init console_setup(char *str)
{
char buf[sizeof(console_cmdline[0].name) + 4]; /* 4 for index */
char *s, *options, *brl_options = NULL;
int idx;
#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
if (!memcmp(str, "brl,", 4)) {
brl_options = "";
str += 4;
} else if (!memcmp(str, "brl=", 4)) {
brl_options = str + 4;
str = strchr(brl_options, ',');
if (!str) {
printk(KERN_ERR "need port name after brl=/n");
return 1;
}
*(str++) = 0;
}
#endif
/*
* Decode str into name, index, options.
*/
if (str[0] >= '0' && str[0] <= '9') {
strcpy(buf, "ttyS");
strncpy(buf + 4, str, sizeof(buf) - 5);
} else {
strncpy(buf, str, sizeof(buf) - 1);
}
buf[sizeof(buf) - 1] = 0;
if ((options = strchr(str, ',')) != NULL)
*(options++) = 0;
#ifdef __sparc__
if (!strcmp(str, "ttya"))
strcpy(buf, "ttyS0");
if (!strcmp(str, "ttyb"))
strcpy(buf, "ttyS1");
#endif
for (s = buf; *s; s++)
if ((*s >= '0' && *s <= '9') || *s == ',')
break;
idx = simple_strtoul(s, NULL, 10);
*s = 0;
__add_preferred_console(buf, idx, options, brl_options);
console_set_on_cmdline = 1;
return 1;
}
__setup("console=", console_setup);
更多推荐
所有评论(0)