Linux基础知识 ·

Linux开机流程浅析

[隐藏]

BIOS、开机自检与MBR/GPT

在个人电脑架构下,你想要启动整部系统首先就得要让系统去载入 BIOS ( Basic Input Output System ),并通过 BIOS 程序去载入 CMOS 的信息,并且藉由 CMOS 内的设定值取得主机的各项硬件设定,例如 CPU 与周边设备的沟通时脉、开机装置的搜寻顺序、磁盘的大小与类型、系统时间、各周边设备的是否启动 Plug and Play (PnP,随插即用装置)、各周边设备的 I/O 位址、以及与 CPU 沟通的 IRQ 岔断等等的信息。

在取得这些信息后,BIOS还会进行开机自我测试( Power-on Self Test, POST ) 。然后开始执行硬件侦测的初始化,并设定 PnP 装置,之后再定义出可开机的装置顺序,接下来就会开始进行开机装置的资料读取了。

由于我们的系统需要放置于存储设备!所以 BIOS 会指定开机的装置好让我们可以读取设备中的操作系统内核数据。但由于不同的操作系统他的文件系统格式不相同,因此我们必须要以一个开机管理程序来处理内核载入 ( load  )的问题,因此这个开机管理程序就被称为 Boot Loader 了。这个 Boot Loader 程序就在开机装置的第一个扇区( sector )内,也就是 MBR ( Master Boot Record 主要开机记录区)

BIOS是通过硬件的 INT 13 中断功能来读取 MBR 的,也就是说,只要BIOS能够侦测的到你的磁盘(不论该磁盘是 SATA 还是 SAS ),那他就有办法通过 INT 13 这条通道来读取该磁盘的第一个扇区内的 MBR 程序!这样 boot loader 也就能够被执行了!

Boot Loader 的功能

Boot Loade r的最主要功能是要认识操作系统的数据格式并据以载入内到内存中去执行。由于不同操作系统的数据格式不一致,因此每种操作系统都有自己的 boot loader!用自己的loader才有办法载入内核!

每个文件系统( filesystem 或者是 partition )都会保留一块开机磁区( boot sector )提供操作系统安装 boot loader ,而通常操作系统预设都会安装一份 loader 到他根目录所在的文件系统的boot sector上。

每个操作系统预设是会安装一套 boot loader 到他自己的文件系统中,而在 Linux 系统安装时,你可以选择将 boot loader 安装到 MBR 去,也可以选择不安装。如果选择安装到 MBR 的话,那理论上你在 MBR 与 boot sector 都会保有一份 boot loader 程序。至于 Windows 安装时,他预设会主动的将 MBR 与 boot sector 都装上一份 boot loader!所以, 你会发现安装多重作业系统时,你的 MBR 常常会被不同的作业系统的 boot loader 所覆盖啦!

虽然各个操作系统都可以安装一份 boot loader 到他们的 boot sector 中,这样操作系统可以通过自己的 boot loader 来载入内核。

boot loader 主要的功能如下:

  • 提供选单:使用者可以选择不同的开机项目,这也是多重开机的重要功能!
  • 载入内核文件:直接指向可开机的程序区段来开始操作系统;
  • 转交其他loader:将开机管理功能转交给其他loader负责。

由于具有选单功能,因此我们可以选择不同的内核来开机。而由于具有控制权转交的功能,因此我们可以载入其他 boot sector 内的 loader !不过 Windows 的 loader 预设不具有控制权转交的功能,因此你不能使用 Windows 的 loader 来载入Linux 的 loader !这也是为啥先装 Windows 再装 Linux 的缘故。

载入内核侦测硬件与initramfs 的功能

当我们藉由 boot loader 的管理而开始读取内核文件后,接下来, Linux 就会将内核解压缩到内存当中,并且利用内核的功能,开始测试与驱动各个周边装置,包括储存装置、 CPU、网路卡、声卡等等。此时 Linux 内核会以自己的功能重新侦测一次硬件,而不一定会使用 BIOS 侦测到的硬件信息!也就是说,内核此时才开始接管 BIOS 后的工作了。一般来说,内核会被放置到 /boot 里面,并且取名为 /boot/vmlinuz!

为了硬体开发商与其他内核功能开发者的便利,因此 Linux 内核是可以通过动态载入内核模块,这些内核模块就放置在 /lib/modules/ 目录内。 由于模块放置到磁盘根目录内(要记得 /lib 不可以与 / 分别放在不同的 partition !),因此在开机的过程中内核必须要挂载根目录,这样才能够读取内核模块提供载入驱动程序的功能。 而且为了担心影响到磁盘内的文件系统,因此开机过程中根目录是以只读的方式来挂载的,当完成内核的载入后会重新以预设属性挂载文件系统。

一般来说,非必要的功能且可以编译成为模块的内核功能,目前的 Linux distributions 都会将其编译成为模块。因此USB, SATA, SCSI...等磁盘装置的驱动程序通常都是以模块的方式来存在的。现在来思考一种情况,假设你的 linux 是安装在 SATA 磁盘上面的,你可以通过 BIOS 的 INT 13 取得 boot loader 与 kernel 来开机,然后 kernel会开始接管系统并且侦测硬体及尝试挂载根目录来取得额外的驱动程序。

问题是,内核根本不认识 SATA 磁盘,所以需要载入 SATA 磁盘的驱动程序,否则根本就无法挂载根目录。但是SATA 的驱动程序在 /lib/modules 内,你根本无法挂载根目录又怎么读取到 /lib/modules/ 内的驱动程序?是吧!非常的两难吧!在这个情况之下,你的 Linux 是无法顺利开机的!那怎办?没关系,我们可以通过虚拟文件系统来处理这个问题。

虚拟文件系统(Initial RAM Disk或Initial RAM Filesystem)一般使用的文件名为 /boot/initrd 或 /boot/initramfs ,这个文件的特色是,他也能够通过 boot loader 来载入到内存中,然后这个文件会被解压缩并且在内存当中模拟成一个根目录,且此模拟在内存当中的文件系统能够提供一支可执行的程序,通过该程序来载入开机过程中所最需要的内核模块,通常这些模块就是USB, RAID, LVM, SCSI等文件系统与磁盘介面的驱动程序!等载入完成后,会帮助内核重新呼叫 systemd 来开始后续的正常开机流程

其实 initramfs 就是一个小型的根目录,这个小型根目录里面也是通过 systemd 来进行管理,并且这个小型系统就是通过 initrd. target 来开机,而 initrd.target 也是需要读入一堆例如 basic.target, sysinit.target 等等的硬件侦测、内核功能启用的流程, 然后开始让系统顺利运作。最终才又卸载 initramfs 的小型文件系统,实际挂载系统的根目录!

此外,initramfs 并没有包山包海,它仅带开机过程会用到的内核模块而已。所以如果你在initramfs 里面去找modules 这个关键字的话, 就可以发现主要的内核模块大概就是SCSI、virtio、RAID 等等跟磁碟相关性比较高的模块!现在由于磁盘大部分都是使用SATA , 所以并没有IDE 的格式的!所以,没有initramfs 的话,你的Linux 几乎就是不能顺利开机的啦!除非你将SATA 的模块直接编译到内核去了!

在内核完整的载入后,主机应该就开始正确的运作了,接下来,就是要开始执行系统的第一支程序:init

 

参与评论