start_kernel之挂载根文件系统
head.s最终会调用start_kernel函数
执行start_kernel的目的:挂载根文件系统,启动应用APP环境
asmlinkage void __init start_kernel(void)
printk(KERN_NOTICE "%s", linux_banner);
setup_arch(&command_line);//获取cmdline,初始化硬件
setup_command_line(command_line);
printk(KERN_NOTICE "Kernel command line: %s\n", boot_command_line);
console_init();//初始化console
rest_init();
static noinline void __init_refok rest_init(void)
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);//启动一个内核线程为kernel_init
schedule();
static int __init kernel_init(void * unused)
prepare_namespace();
mount_root();//挂载根文件系统
init_post();//运行应用程序
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");
举例内核怎么知道挂载那个根文件系统
假设在启动的时候传入参数:
bootargs=noinitrd root=/dev/mtdblock3 rootfstype=yaffs2 init=/init console=ttySAC0
bootcmd=nand read.jffs2 0xc0008000 kernel;bootm 0xc0008000
void __init prepare_namespace(void)
if (saved_root_name[0]) {
root_device_name = saved_root_name;
if (!strncmp(root_device_name, "mtd", 3) ||
!strncmp(root_device_name, "ubi", 3)) {
mount_block_root(root_device_name, root_mountflags);
goto out;
}
ROOT_DEV = name_to_dev_t(root_device_name);
if (strncmp(root_device_name, "/dev/", 5) == 0)
root_device_name += 5;
}
//搜索一下saved_root_name
static int __init root_dev_setup(char *line)
{
strlcpy(saved_root_name, line, sizeof(saved_root_name));
return 1;
}
__setup("root=", root_dev_setup);
//分析__setup()
#define __setup(str, fn) __setup_param(str, fn, fn, 0)
#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 }
//我们将其展开:
__setup("root=", root_dev_setup);
__setup_param("root=", root_dev_setup, root_dev_setup, 0)
static const char __setup_str_root_dev_setup[] __initconst \ //字符串
__aligned(1) = "root="; \
static struct obs_kernel_param __setup_root_dev_setup \
__used __section(.init.setup) __attribute__((aligned((sizeof(long))))) \\结构体
={
__setup_str_root_dev_setup,//名字
root_dev_setup,//函数
0
}
struct obs_kernel_param {
const char *str;
int (*setup_func)(char *);
int early;
};
//struct obs_kernel_param __setup_root_dev_setup 这个结构体什么时候被使用
//在内核中搜索.init.setup
grep -r ".init.setup"
__setup_start = .; *(.init.setup) __setup_end = .
//在源码中搜索__setup_start
parse_args("Booting kernel", static_command_line, __start___param,
__stop___param - __start___param,
&unknown_bootoption);
obsolete_checksetup(param)
static int __init obsolete_checksetup(char *line)
{
struct obs_kernel_param *p;
int had_early_param = 0;
p = __setup_start;
do {
int n = strlen(p->str);
if (!strncmp(line, p->str, n)) {
if (p->early) {
if (line[n] == '\0' || line[n] == '=')
had_early_param = 1;
} else if (!p->setup_func) {
printk(KERN_WARNING "Parameter %s is obsolete,"
" ignored\n", p->str);
return 1;
} else if (p->setup_func(line + n)) //最终调用这个setup_func
return 1;
}
p++;
} while (p < __setup_end);
//联系到前面:
static int __init root_dev_setup(char *line)
//将/dev/mtdblock3拷贝到root_device_name
void __init prepare_namespace(void)
if (saved_root_name[0]) {
root_device_name = saved_root_name;
if (!strncmp(root_device_name, "mtd", 3) ||
!strncmp(root_device_name, "ubi", 3)) {
mount_block_root(root_device_name, root_mountflags);
goto out;
}
ROOT_DEV = name_to_dev_t(root_device_name); //执行到这里
if (strncmp(root_device_name, "/dev/", 5) == 0)
root_device_name += 5;
}
initrd_load()
handle_initrd();
real_root_dev = new_encode_dev(ROOT_DEV);
create_dev("/dev/root.old", Root_RAM0);
pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
mount_root();//执行挂载
//先将/dev/ram0挂载,而后执行/linuxrc.等其执行完后。切换根目录,再挂载具体的根文件系统.