网上有好多的文章写过这个题目,本文是结合一些资料并加入一些自己的理解,也是自己对Linux系统编程系列文章的一个开始,并在此留个见证,督促自己一定要把这个系列的文章写完。个人理解难免会有偏颇甚至错误的地方,还请各位看官指正,谢谢!
笔者个人习惯个Linux的启动过程分成三个部分分别是 BootLoader、Linux内核启动、用户程序启动,下图中画出了两个部分,下面一次说明:
所谓BootLoader其实可以分别是 Boot 和Load,boot表示启动包括硬件启动,选择器启动等;load是加载,这里当然是加载Linux内核了。在计算机上电以后首先要做的是硬件自检接着是启动BIOS这两个过程主要做的工作时读取一些关键的硬件信息(设备启动顺序信息、硬盘信息、内存信息、时钟信息、PnP特性等)对应上图就是A、B两个部分。接下来是启动选择器,这个选择器实际上是一段程序,当你的机器上装有多个操作系统的时候会启动;这个过程其实就是读取MBR以及选择指定的操作系统的过程。当系统执行到这个阶段的时候系统就开始加载内核了,此时BootLoader的工作也就全部完成了。
内核加载成功以后就是内核的启动过程。一些系统会直接进入到G所标示的步骤但大多数系统的做法是先经过E、F再到G,因为这样系统会启动的更快,原因是initrd的启动速度和大小要远远小于根文件系统,加载速度自然就会很快。
E:这一步叫做加载最小文件系统,在嵌入式开发中往往这段程序会做成一个叫做initrd.img的镜像,这里包括能够维持内核运行的基本文件系统框架。这一步首先会解压缩镜像之后装载initrd.img;然后通过initrd.img再挂载整个根文件系统或者之后执行linuxrc脚本或者直接执行/sbin/init程序到,此时linux系统内核就已经启动成功了;
H:接下来内核会启动该/sbin/init程序,这个程序是整个操作系统的第一个用户进程,进程ID是1 。随着这个进程的启动操作系统的启动也进入了第三个阶段,就是用户程序启动阶段,这个阶段主要是一些初始化脚本的执行以及一些服务程序的执行,这里主要介绍init进程所做的工作:
1. 执行函数do_basic_setup(),它会对外部设备进行全面地初始化。
2. 构建系统的虚拟文件系统目录树,挂接系统中作为根目录的设备(其具体的文 件系统已经在之前步骤中注册)。
3. 打开设备/dev/console,并通过函数sys_dup()打开的连接复制两次,使得文件号0,1 ,2 全部指向控制台。这三个文件连接就是通常所说的“标准输入”stdin,“标准输出”stdout和“标准出错信息”stderr这三个标准I/O通道。这里要说明一下后期所有的用户程序中默认都会打开0、1、2这三个文件描述符,原因就是init进程之后所有的进程都是init进程的子孙进程,这三个文件描述符全部直接或间接的继承自init进程。
4. 准备好以上一切之后,系统开始进入用户层的初始化阶段。内核通过系统调用execve()加载执T子相应的用户层初始化程序,依次尝试加载程 序"/sbin/initl"," /etc/init"," /bin/init',和“/bin/sh。只要其中有一个程序加载获得成功,那么系统就将开始用户层的初始化,而不会再回到init()函数段中。至 此,init()函数结束,Linux内核的引导 部分也到此结束。
5. 之后执行/etc/init.d下的所有程序(分级别执行),最后启动/bin/login程序进入登陆界面;init进程还有一个功能就是领养孤儿进程。
参考:
http://www.cnblogs.com/QLinux/articles/2540304.html
http://www.cnblogs.com/king-77024128/articles/2275545.html