美丽的开端是成功的一半,慢慢开始我的享受之路->kernel。

Linux启动流程:

wKioL1mvXhrS8WNyAACGShIq7jQ144.png


1.BIOS(基本输入输出系统)启动

    它的主要任务是提供CPU所需的启动指令,是预先编译好了供系统启动使用的启动程序,把他们存在ROM中,并安排他到一个固定的位置,FFFF:0000.

    首先是上电自检,然后对系统内的硬件设备进行监测和连接,并把测试所得的数据存放到BIOS数据区,以便操作系统启动时或启动后使用,最后,BIOS将从软盘或硬盘上

    读入Boot Loader。除了启动程序,BIOS还提供一组中断以便对硬件设备的访问。

2.读取MBR

    如果从硬盘启动,BIOS将读入该盘的零柱面零磁道上的1扇区(MBR),这个扇区存放着Boot Loader,该扇区的最后一个字节存放标志,如果为AA55,BIOS在完成硬件监测后会把控制权给Boot loader。

3.Boot Loader

    通常是一段汇编代码,存放在MBR中,它的主要作用就是将系统启动代码读入内存。BIOS将其读入至内存中物理地址0x07c00处。

    Boot Loader 就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核做好一切准备。

    Boot Loader有若干种,其中Grub、Lilo和spfdisk是常见的Loader。

4.加载内核

    Boot Loader一言总结就是把操作系统的代码调入内存。

    Boot Loader此时将控制权交给了Setup.s这段程序;首先,Setup.S对调入内存的操作系统检查,

它会通过BIOS中断获取内存容量信息,设置键盘的响应速度,设置显示器的基本模式,获取硬件信息,

检测是否有PS/2鼠标,这时操作系统就准备让CPU进入保护模式。当然,要先屏蔽中断,避免打扰。

    进入保护模式下的启动阶段,将控制权交给Head.S:做一些屏蔽中断的准备工作,知道start_kernel()被调用,中断向量表才被使用,检查CPU的类型,在start_kernel()根据这个结果设置,页初始化等。到这里中断管理,内存管理已经建立好,然后调用/INIT/MAIN.C中的start_kernel()函数(以后总结内核再详细讨论main.c)。进入main.c就是一系列的初始化了。

5.建立init进程

    init进程的建立是在main.c函数的最后一行调用,rest_init()->kernel_thread(init, NULL, CLONE_KERNEL);

init()函数:

1)建立 dbflush、kswapd 两个新的内核线程。

2)初始化 tty1 设备。该设备对应了多个终端(concole),用户登录时,就是登录在这

些终端上的。

3)启动 init 进程。 Linux 首先寻找 “/etc/init” 文件, 如果找不到, 就接着找 “/bin/init”

文件,若仍找不到,再去找“/sbin/init”。如果仍无法找到,启动将无法进行下去。否则便执行 init 文件,从而建立 init 进程。

    当 etc/init(假定它存在)执行时,建立好的 init 进程将根据启动脚本文件的内容创

建其它必要的进程去完成一些重要的操作。

(1)文件系统检查。

(2)启动系统的守护进程。

(3)对每个联机终端建立一个“getty”进程。

(4)执行“/etc/rc”下的命令文件。

    此后, “getty”会在每个终端上显示 “login” 提示符, 以等待用户的登录。 此时 “getty”会调用 “exec” 执行 “login” 程序, “login” 将核对用户帐户和密码, 如果密码正确, “login”调用“exec”执行 shell 的命令行解释程序(当然,也可以执行 X Windows 如果用户设置了的话)。shell 接着去执行用户默认的系统环境配置脚本文件(通常是用户的 home 目录下的

profile 文件)。

    init 还有另外一个任务,当某个终端或虚拟控制台上的用户注销之后,init 进程要为

该终端或虚拟控制台重新启动一个 “getty”,以便能够让其他用户登录。这是为什么呢?

你应该发现,当用户登录时,“getty”用的是“exec”而不是“fork”系统调用来执行

“login”,这样,“login”在执行的时候会覆盖“getty”的执行环境(同理,用户注册成

功后,“login”的执行环境也会被 shell 占用)。所以,如果想再次使用同一终端,必须再

启动一个“getty”。

    此外,init 进程还负责管理系统中的“孤儿”进程。如果某个进程创建子进程之后,

在子进程终止之前终止,则子进程成为孤儿进程。init 进程负责“收养”该进程,即孤儿进

程会立即成为 init 进程的子进程。这是为了保持进程树的完整性。

总结:Linux启动时一个相当复杂的过程,这些就是大概的总结。接下来分析main函数初始化,再下来就是按模块进行分析kernel。