本文主要是介绍uClinux代码随读随写(1)-start_kernel(),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
start_kernel()中代码main.c
...
lock_kernel();
printk(linux_banner);
setup_arch(&command_line);
printk("Kernel command line: %s/n", saved_command_line);
parse_options(command_line);
/*
* HACK ALERT! This is early. We're enabling the console before
* we've done PCI setups etc, and console_init() must be aware of
* this. But we do want output early, in case something goes wrong.
*/
console_init();
...
以上代码解析如下:
a. Call setup_arch() to set up cpu arch and get command line.
The command_line is from the default_command_line:
setup.c
...
char *from = default_command_line;
int bootmap_size;
...
default_command_line is initialize by CONFIG_CMDLINE:
setup.c
...
static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
...
CONFIG_CMDLINE is defined in .config which is created by "make menuconfig".
For example,CONFIG_CMDLINE="console=ttyS0,38400 root=/dev/rom0"
后面会根据CONFIG_CMDLINE来做初始化。
b. parse_options() 主要是解析command_line. 在这个函数里call checksetup(line),这个比较重要
main.c
...
if (checksetup(line))
continue;
...
在checksetup()中先比较line与kernel_param->str,如果equal,call p->setup_func,这里line如"root=/dev/rom0"
...
struct kernel_param *p;
p = &__setup_start;
do {
int n = strlen(p->str);
if (!strncmp(line,p->str,n)) {
if (p->setup_func(line+n))
return 1;
}
p++;
} while (p < &__setup_end);
这个__setup_start在vmlinux.lds.in中定义指向section {.setup.init):
__setup_start = .;
*(.setup.init)
__setup_end = .;
在Init.h有如下define:
#define __initsetup __attribute__ ((unused,__section__ (".setup.init")))
与
#define __setup(str, fn) /
static char __setup_str_##fn[] __initdata = str; /
static struct kernel_param __setup_##fn __attribute__((unused)) __initsetup = { __setup_str_##fn, fn }
这两个define就是把setup函数放在同一个section。 以一个struct kernel_param的结构存放。
__setup(str,fn)在很多files中都有call,checksetup()就是搜索与command_line有关的setup_func并调用。
在printk.c中
__setup("console=", console_setup);
在do_mounts.c中
__setup("root=", root_dev_setup);
console_setup(char *str)主要是save data struct到preferred_console与console_cmdline[i],这里str point to "ttyS0,38400",也就是等号之后部分。
代码如下:
...
preferred_console = i;
c = &console_cmdline[i];
memcpy(c->name, name, sizeof(c->name));
c->options = options;
c->index = idx;
...
root_dev_setup(char *str) call name_to_kdev_t(char *line)获取ROOT_DEV,这是个global variable,保存root_device_name
c. console_init()调用serial_console_init()
...
#elif defined(CONFIG_SERIAL)
serial_console_init();
#endif /* CONFIG_8xx */
...
serial_console_init() call register_console(&sercons); 代码如下:
...
static struct console sercons = {
name: "ttyS",
write: serial_console_write,
device: serial_console_device,
setup: serial_console_setup,
flags: CON_PRINTBUFFER,
index: -1,
};
/*
* Register console.
*/
void __init serial_console_init(void)
{
register_console(&sercons);
}
...
register_console主要是为了printk函数的实现,会调用struct sercons的setup函数并把sercons保存在console_drivers.
...
if (console->setup &&
console->setup(console, console_cmdline[i].options) != 0)
break;
...
if ((console->flags & CON_CONSDEV) || console_drivers == NULL) {
console->next = console_drivers;
console_drivers = console;
} else {
...
最后调用 release_console_sem() put out message. release_console_sem()调用call_console_drivers,最终会call到
sercons结构体里的serial_console_write。
上班时写的,比较匆忙,只是做为自己学习linux的笔记,uclinux内核为2.4,斜体为代码。
这篇关于uClinux代码随读随写(1)-start_kernel()的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!