linux内核启动过程

linux内核启动过程完成启动内核并运行用户空间的init进程的功能。

当内核映像被加载到RAM之后,Bootloader的控制权被释放。内核映像并不是可直接
执行的目标代码,而是一个压缩过的zImage(小内核)或bzImage(大内核,bzImage中的
“b”是“big”意思)。
但是,并非zImage和bzImage映像中的一切都被压缩了,映像中包含未被压缩的
部分,这部分中包含解压缩程序,解压缩程序会解压缩映像中被压缩的部分。zImage
和bzImage都是用gzip压缩的,它们不仅是一个压缩文件,而且在这两个文件的开头
部分内嵌有gzip解压缩代码。

如下图所示,当bzImage(用于i386映像)被调用时,它从/arch/i386/boot/head.S
的start 汇编例程开始执行。这个例程子进行一些基本的硬件设置,并调用
/arch/i386/boot/compressed/head.S中的startup_32例程。startup_32 例程设置一个基本的
运行环境(如堆栈)后清除BSS 段,调用/arch/i386/boot/compressed/misc.c 中的
decompress_kernel()解压缩内核。

linux内核启动过程
                X86 PC上的Linux内核初始化


内核被解压缩到内存中之后会再调用/arch/i386/kernel/head.S 文件中的startup_32
例程,这个新的startup_32 例程(称为清除程序或进程0)会初始化页表,并启用内
存分页机制,接着为任何可选的浮点单元(FPU)检测CPU 的类型,并将其存储起
来供以后使用。
这些都做完之后,/init/main.c 中的start_kernel()函数被调用,进入与体系结构无关的
Linux内核部分。
start_kernel()会调用一系列初始化函数来设置中断,执行进一步的内存配置。之后,
/arch/i386/kernel/process.c 中kernel_thread()被调用以启动第一个核心线程,该线程执
行init() 函数,而原执行序列会调用cpu_idle(),等待调度。
作为核心线程的init()函数完成外设及其驱动程序的加载和初始化,挂接根文件系统。
init()打开/dev/console 设备,重定向stdin、stdout 和stderr 到控制台。之后,它搜索文件
系统中的init程序(也可以由“init=”命令行参数指定init程序),并使用execve()系统调
用执行init 程序。搜索init 程序的顺序为/sbin/init、/etc/init、/bin/init和/bin/sh。在嵌入式
系统中,多数情况下,可以给内核传入一个简单的shell 脚本来启动必需的嵌入式应用
程序。
至此,漫长的Linux 内核引导和启动过程就结束了,而init()对应的由start_kernel()
创建的第一个线程也进入用户模式。

 

参考:系统初始化