1.处理u-boot传入的参数
2.判断是否支持该CPU
3.判断是否支持单板
4.建立页表(启动MMU)
5.调到start_kernal
6.挂载根文件系统
7.最终目的是运行应用程序
u-boot的目的是为了启动内核,内核的目的是为了启动应用程序
构建根文件系统:
应用程序是挂在在根文件系统中的;
在内核启动之后,会使用文件/linux/init/main.c文件中的init_post函数启动应用程序;
/* This is a non __init function. Force it to be noinline otherwise gcc
* makes it inline to init() and it becomes part of init.text section
*/
noinline 的作用是让该函数在出现错误的时候按照警告进行处理
#define noinline __attribute__(noinline)
static int noinline init_post(void)
{
free_initmem();
unlock_kernel();
mark_rodata_ro();
system_state = SYSTEM_RUNNING;
numa_default_policy();
//第一打开设备 /dev/console
//在linux中一切皆文件,设备只是一种特殊的文件
if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
printk(KERN_WARNING "Warning: unable to open an initial console.\n");
(void) sys_dup(0);
//复制出一个文件指向 --> /dev/console 第一个文件指向第零个文件
(void) sys_dup(0);
//复制出一个文件指向 --> /dev/console 第二个文件指向第零个文件
//这样处理之后所有的打印信息和所有的输入输出信息,都会到文件 /dev/console 中去
if (ramdisk_execute_command) {
run_init_process(ramdisk_execute_command);
printk(KERN_WARNING "Failed to execute %s\n",
ramdisk_execute_command);
}
/*
* We try each of these until one succeeds.
*
* The Bourne shell can be used instead of init if we are
* trying to recover a really broken machine.
*/
if (execute_command) {
run_init_process(execute_command);
printk(KERN_WARNING "Failed to execute %s. Attempting "
"defaults...\n", execute_command);
}
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");
panic("No init found. Try passing init= option to kernel.");
}
printk函数;
printk相当于printf的孪生姐妹,她们一个运行在用户态,另一个则在内核态被人们所熟知。但是根据不同的操作系统也会有不一样的效果,例如编写一个hello word 内核模块,使用这个函数不一定会将内容显示到终端上,但是一定在内核缓冲区里,可以使用dmesg查看效果
sys_open函数如下:
asmlinkage long sys_open(const char __user *filename, int flags, int mode)
{
long ret;
if (force_o_largefile())
flags |= O_LARGEFILE;
ret = do_sys_open(AT_FDCWD, filename, flags, mode);
/* avoid REGPARM breakage on x86: */
prevent_tail_call(ret);
return ret;
}
下图转载自网络: