Linux启动流程分析 ,这里仅简要分析Linux的大致启动流程,更多细节请阅读源码分析。
Linux内核启动过程分为解压和启动vmlinux。启动过程从内核映像入口开始执行,解压 vmlinux (内核自引导)并且转换到虚拟地址空间,再调用统一的内核启动函数start_kernel(),从而启动整个 Linux 系统。
1.解压vmlinux
什么是vmlinux?
zImage映像的入口代码是自引导程序。自引导程序包含一些初始化工作,这些工作包括什么呢?
参看:arch/arm/boot/compressed/head.S,包括设置加载运行zImage的起始和结束地址,保存体系结构ID,关闭中断,设置BSS等。
然后,进行解压内核映像并跳转到虚拟空间启动vmlinux。(应该说是解压内核镜像到内存)
2.启动vmlinux
这时执行到vmlinux 的入口地址,顺序执行内核启动程序。
首先,还是有一些初始化工作,包括检测并保持处理器类型和机器型号,打开MMU并跳转到start_kernel。
然后,执行Linux系统初始化。start_kernel 函数是 Linux 内核通用的初始化函数。参见init/main.c。
start_kernel()函数负责初始化内核各子系统,最后调用 rest_init(),启动一个叫作 init的内核线程,继续初始化。
在 init 内核线程中,将执行 init()函数的程序。init 函数负责完成挂接根文件系统、初始化设备驱动和启动用户空间的
init进程等重要工作。
对于 Linux 系统来说,挂接根文件系统、初始化设备驱动和启动用户空间的程序是必要的3项工作。
2.1挂接根文件系统
什么是根文件系统?
2.2初始化设备驱动
CPU子系统已经正常工作,内存管理和进程管理已经正常运转,但是还没有使用任何设备。
接下来继续初始化内核设备驱动程序,然后才能访问设备,做系统真正想要做的任务。
Linux内核映像把设备驱动程序的初始化函数指针链接成数组,即__initcall_start和__initcall_end之间的数据。然后通过
do_initcalls()函数调用数组中的函数指针,完成驱动程序的初始化。
2.3启动用户空间的程序
内核挂接跟文件系统成功以后,将通过run_init_process()函数执行应用程序。这是一个尝试的过程,如果execute_command
存在,则执行execute_command;如果不存在,则顺序执行/sbin/init、/etc/init、/bin/init、/bin/sh,直到有一个执行成功为止。