内核的启动代码,但一般情况下,是两部分,为了容易理解,可以这样分成三部分。
内核启动的第一部分,内核启动的位置在0x30008000,0x30001000存放标记列表,有可以标记列表不只一个,在0x30004000-0x30008000存放的系统的页表,这个页表只映射了很小一部分空间,在paging_init函数中为映射整个内存空间。整个过程主要是检查处理器,检查平台,创建页表,开启MMU,然后到start_kernel函数
start_kernel函数可以做为第二部分,主要用来初始化一些信息,建立与体系结构相关的信息,建立每cpu变量区,体系结构初始化,建立内存区域链,陷阱初始化,rcu初始化,中断初始化,软中断初始化,串口初始化,内存初始化,虚拟文件系统初始化,pid位图初始化,优先级树初始化,进程初始化,缓存区头部初始化,基树初始化,然后是rest_init函数。这里面有个重要的地方就是体系结构的初始化函数setup_arch,因为这个函数里面为建立页表,以及vfs_caches_init->mnt_init里面init_rootfs()和 init_mount_tree()函数 ,这两个函数建立了虚拟的根文件系统。
第三部分主要用来启动创建一个线程,然后执行调度程序,放弃CPU的执行权,在线程中执行do_basic_setup函数做一些基本的初始化,比如工作队列,驱动程序程序模型,也就是我们常说的,设备初始化,总线初始化,设备类初始化,固件初始化,平台总线和系统总线初始化,然后会调用do_initcalls这个函数,把在.init段中的函数运行起来。其中.init段的函数可以在vmlinux.lds中找到,最后是prepare_namespace这个函数,准备命名空间,挂载根文件系统,由于根文件系统可以有多个,所以都可以挂载到在第二部分提到的哪两个函数创建的虚拟的根文件系统中。如果挂载成功,就会运行根文件系统中的/sbin/init,"/etc/init","/bin/init","/bin/sh"目录下的初始化函数。运行成功就会看到,进入可操作命令状态,或者就是我们常见的No init found. Try passing init= option to kernel.。
第二部分的流程图如下,有些主重要的地方,会单独做出一些图来说明。没有详细列出的函数会在自己分析代码中给出分析。