文档章节

Linux引导过程内幕

munds
 munds
发布于 2016/03/13 09:28
字数 3681
阅读 170
收藏 9

3 月,跳不动了?>>>

Linux 引导过程内幕

从主引导记录到第一个用户空间应用程序的指导

引导 Linux® 系统的过程包括很多阶段。不管您是引导一个标准的 x86 桌面系统,还是引导一台嵌入式的 PowerPC® 机器,很多流程都惊人地相似。本文将探索 Linux 的引导过程,从最初的引导到启动第一个用户空间应用程序。在本文介绍的过程中,您将学习到各种与引导有关的主题,例如引导加载程序、内核解压、初始 RAM 磁盘以及 Linux 引导的其他一些元素。

让我们先从高级的视角来查看 Linux 引导过程,这样就可以看到整个过程的全貌了。然后将回顾一下在各个步骤到底发生了什么。在整个过程中,参考一下内核源代码可以帮助我们更好地了解内核源代码树,并在以后对其进行深入分析。

概述

图 1 是我们在 20,000 英尺的高度看到的视图。

图 1. Linux 引导过程在 20,000 英尺处的视图

Linux 引导过程在 20,000 英尺处的视图

当系统首次引导时,或系统被重置时,处理器会执行一个位于已知位置处的代码。在个人计算机(PC)中,这个位置在基本输入/输出系统(BIOS)中,它保存在主板上的闪存中。嵌入式系统中的中央处理单元(CPU)会调用这个重置向量来启动一个位于闪存/ROM 中的已知地址处的程序。在这两种情况下,结果都是相同的。因为 PC 提供了很多灵活性,BIOS 必须确定要使用哪个设备来引导系统。稍后我们将详细介绍这个过程。

当找到一个引导设备之后,第一阶段的引导加载程序就被装入 RAM 并执行。这个引导加载程序在大小上小于 512 字节(一个扇区),其作用是加载第二阶段的引导加载程序。

当第二阶段的引导加载程序被装入 RAM 并执行时,通常会显示一个动画屏幕,并将 Linux 和一个可选的初始 RAM 磁盘(临时根文件系统)加载到内存中。在加载映像时,第二阶段的引导加载程序就会将控制权交给内核映像,然后内核就可以进行解压和初始化了。在这个阶段中,第二阶段的引导加载程序会检测系统硬件、枚举系统链接的硬件设备、挂载根设备,然后加载必要的内核模块。完成这些操作之后启动第一个用户空间程序(init),并执行高级系统初始化工作。

这就是 Linux 引导的整个过程。现在让我们深入挖掘一下这个过程,并深入研究一下 Linux 引导过程的一些详细信息。


系统启动

系统启动阶段依赖于引导 Linux 系统上的硬件。在嵌入式平台中,当系统加电或重置时,会使用一个启动环境。这方面的例子包括 U-Boot、RedBoot 和 Lucent 的 MicroMonitor。嵌入式平台通常都是与引导监视器搭配销售的。这些程序位于目标硬件上的闪存中的某一段特殊区域,它们提供了将 Linux 内核映像下载到闪存并继续执行的方法。除了可以存储并引导 Linux 映像之外,这些引导监视器还执行一定级别的系统测试和硬件初始化过程。在嵌入式平台中,这些引导监视器通常会涉及第一阶段和第二阶段的引导加载程序。

提取 MBR 的信息

要查看 MBR 的内容,请使用下面的命令:

dd if=/dev/hda of=mbr.bin bs=512 count=1 # od -xa mbr.bin

这个 dd 命令需要以 root 用户的身份运行,它从 /dev/hda(第一个 IDE 盘) 上读取前 512 个字节的内容,并将其写入 mbr.bin 文件中。od 命令会以十六进制和 ASCII 码格式打印这个二进制文件的内容。

在 PC 中,引导 Linux 是从 BIOS 中的地址 0xFFFF0 处开始的。BIOS 的第一个步骤是加电自检(POST)。POST 的工作是对硬件进行检测。BIOS 的第二个步骤是进行本地设备的枚举和初始化。

给定 BIOS 功能的不同用法之后,BIOS 由两部分组成:POST 代码和运行时服务。当 POST 完成之后,它被从内存中清理了出来,但是 BIOS 运行时服务依然保留在内存中,目标操作系统可以使用这些服务。

要引导一个操作系统,BIOS 运行时会按照 CMOS 的设置定义的顺序来搜索处于活动状态并且可以引导的设备。引导设备可以是软盘、CD-ROM、硬盘上的某个分区、网络上的某个设备,甚至是 USB 闪存。

通常,Linux 都是从硬盘上引导的,其中主引导记录(MBR)中包含主引导加载程序。MBR 是一个 512 字节大小的扇区,位于磁盘上的第一个扇区中(0 道 0 柱面 1 扇区)。当 MBR 被加载到 RAM 中之后,BIOS 就会将控制权交给 MBR。


第一阶段引导加载程序

MBR 中的主引导加载程序是一个 512 字节大小的映像,其中包含程序代码和一个小分区表(参见图 2)。前 446 个字节是主引导加载程序,其中包含可执行代码和错误消息文本。接下来的 64 个字节是分区表,其中包含 4 个分区的记录(每个记录的大小是 16 个字节)。MBR 以两个特殊数字的字节(0xAA55)结束。这个数字会用来进行 MBR 的有效性检查。

图 2. MBR 剖析

MBR 剖析

主引导加载程序的工作是查找并加载次引导加载程序(第二阶段)。它是通过在分区表中查找一个活动分区来实现这种功能的。当找到一个活动分区时,它会扫描分区表中的其他分区,以确保它们都不是活动的。当这个过程验证完成之后,就将活动分区的引导记录从这个设备中读入 RAM 中并执行它。


第二阶段引导加载程序

次引导加载程序(第二阶段引导加载程序)可以更形象地称为内核加载程序。这个阶段的任务是加载 Linux 内核和可选的初始 RAM 磁盘。

GRUB 阶段引导加载程序

/boot/grub 目录中包含了 stage1stage1.5 和stage2 引导加载程序,以及很多其他加载程序(例如,CR-ROM 使用的是 iso9660_stage_1_5)。

在 x86 PC 环境中,第一阶段和第二阶段的引导加载程序一起称为 Linux Loader(LILO)或 GRand Unified Bootloader(GRUB)。由于 LILO 有一些缺点,而 GRUB 克服了这些缺点,因此下面让我们就来看一下 GRUB。(有关 GRUB、LILO 和相关主题的更多内容,请参阅本文后面的 参考资料 部分的内容。)

关于 GRUB,很好的一件事情是它包含了有关 Linux 文件系统的知识。GRUB 不像 LILO 一样使用裸扇区,而是可以从 ext2 或 ext3 文件系统中加载 Linux 内核。它是通过将两阶段的引导加载程序转换成三阶段的引导加载程序来实现这项功能的。阶段 1 (MBR)引导了一个阶段 1.5 的引导加载程序,它可以理解包含 Linux 内核映像的特殊文件系统。这方面的例子包括reiserfs_stage1_5(要从 Reiser 日志文件系统上进行加载)或 e2fs_stage1_5(要从 ext2 或 ext3 文件系统上进行加载)。当阶段 1.5 的引导加载程序被加载并运行时,阶段 2 的引导加载程序就可以进行加载了。

当阶段 2 加载之后,GRUB 就可以在请求时显示可用内核列表(在 /etc/grub.conf 中进行定义,同时还有几个软符号链接/etc/grub/menu.lst 和 /etc/grub.conf)。我们可以选择内核甚至修改附加内核参数。另外,我们也可以使用一个命令行的 shell 对引导过程进行高级手工控制。

将第二阶段的引导加载程序加载到内存中之后,就可以对文件系统进行查询了,并将默认的内核映像和 initrd 映像加载到内存中。当这些映像文件准备好之后,阶段 2 的引导加载程序就可以调用内核映像了。


内核

GRUB 中的手工引导

在 GRUB 命令行中,我们可以使用 initrd 映像引导一个特定的内核,方法如下:

grub> kernel /bzImage-2.6.14.2
[Linux-bzImage, setup=0x1400, size=0x29672e]
grub> initrd /initrd-2.6.14.2.img
[Linux-initrd @ 0x5f13000, 0xcc199 bytes]
grub> boot
Uncompressing Linux... Ok, booting the kernel.

如果您不知道要引导的内核的名称,只需使用斜线(/)然后按下 Tab 键即可。GRUB 会显示内核和 initrd 映像列表。

当内核映像被加载到内存中,并且阶段 2 的引导加载程序释放控制权之后,内核阶段就开始了。内核映像并不是一个可执行的内核,而是一个压缩过的内核映像。通常它是一个 zImage(压缩映像,小于 512KB)或一个 bzImage(较大的压缩映像,大于 512KB),它是提前使用 zlib 进行压缩过的。在这个内核映像前面是一个例程,它实现少量硬件设置,并对内核映像中包含的内核进行解压,然后将其放入高端内存中,如果有初始 RAM 磁盘映像,就会将它移动到内存中,并标明以后使用。然后该例程会调用内核,并开始启动内核引导的过程。

当 bzImage(用于 i386 映像)被调用时,我们从 ./arch/i386/boot/head.S 的 start 汇编例程开始执行(主要流程图请参看图 3)。这个例程会执行一些基本的硬件设置,并调用./arch/i386/boot/compressed/head.S 中的 startup_32 例程。此例程会设置一个基本的环境(堆栈等),并清除 Block Started by Symbol(BSS)。然后调用一个叫做decompress_kernel 的 C 函数(在 ./arch/i386/boot/compressed/misc.c 中)来解压内核。当内核被解压到内存中之后,就可以调用它了。这是另外一个 startup_32 函数,但是这个函数在 ./arch/i386/kernel/head.S中。

在这个新的 startup_32 函数(也称为清除程序或进程 0)中,会对页表进行初始化,并启用内存分页功能。然后会为任何可选的浮点单元(FPU)检测 CPU 的类型,并将其存储起来供以后使用。然后调用 start_kernel 函数(在 init/main.c 中),它会将您带入与体系结构无关的 Linux 内核部分。实际上,这就是 Linux 内核的 main 函数。

图 3. Linux 内核 i386 引导的主要函数流程

Linux 内核 i386 引导的主要函数流程

通过调用 start_kernel,会调用一系列初始化函数来设置中断,执行进一步的内存配置,并加载初始 RAM 磁盘。最后,要调用kernel_thread(在 arch/i386/kernel/process.c 中)来启动 init 函数,这是第一个用户空间进程(user-space process)。最后,启动空任务,现在调度器就可以接管控制权了(在调用 cpu_idle 之后)。通过启用中断,抢占式的调度器就可以周期性地接管控制权,从而提供多任务处理能力。

在内核引导过程中,初始 RAM 磁盘(initrd)是由阶段 2 引导加载程序加载到内存中的,它会被复制到 RAM 中并挂载到系统上。这个initrd 会作为 RAM 中的临时根文件系统使用,并允许内核在没有挂载任何物理磁盘的情况下完整地实现引导。由于与外围设备进行交互所需要的模块可能是 initrd 的一部分,因此内核可以非常小,但是仍然需要支持大量可能的硬件配置。在内核引导之后,就可以正式装备根文件系统了(通过 pivot_root):此时会将 initrd 根文件系统卸载掉,并挂载真正的根文件系统。

decompress_kernel 输出

函数 decompress_kernel 就是显示我们通常看到的解压消息的地方:

Uncompressing Linux... Ok, booting the kernel.

initrd 函数让我们可以创建一个小型的 Linux 内核,其中包括作为可加载模块编译的驱动程序。这些可加载的模块为内核提供了访问磁盘和磁盘上的文件系统的方法,并为其他硬件提供了驱动程序。由于根文件系统是磁盘上的一个文件系统,因此 initrd 函数会提供一种启动方法来获得对磁盘的访问,并挂载真正的根文件系统。在一个没有硬盘的嵌入式环境中,initrd 可以是最终的根文件系统,或者也可以通过网络文件系统(NFS)来挂载最终的根文件系统。


Init

当内核被引导并进行初始化之后,内核就可以启动自己的第一个用户空间应用程序了。这是第一个调用的使用标准 C 库编译的程序。在此之前,还没有执行任何标准的 C 应用程序。

在桌面 Linux 系统上,第一个启动的程序通常是 /sbin/init。但是这不是一定的。很少有嵌入式系统会需要使用 init 所提供的丰富初始化功能(这是通过 /etc/inittab 进行配置的)。在很多情况下,我们可以调用一个简单的 shell 脚本来启动必需的嵌入式应用程序。


结束语

与 Linux 本身非常类似,Linux 的引导过程也非常灵活,可以支持众多的处理器和硬件平台。最初,加载引导加载程序提供了一种简单的方法,不用任何花架子就可以引导 Linux。LILO 引导加载程序对引导能力进行了扩充,但是它却缺少文件系统的感知能力。最新一代的引导加载程序,例如 GRUB,允许 Linux 从一些文件系统(从 Minix 到 Reise)上进行引导。

        

                                                                                                                                                转载 from http://www.ibm.com/developerworks/cn/linux/l-linuxboot/ 

本文转载自:http://www.ibm.com/developerworks/cn/linux/l-linuxboot/

下一篇: MBR反汇编
munds
粉丝 2
博文 14
码字总数 1918
作品 0
私信 提问
加载中

评论(0)

Linux的相关资源帖

http://www.kerneltravel.net/?page_id=8 2.6内核模块编程实例指导 内核模块编程之入门(一)-话说模块 内核模块编程之入门(二)—必备知识 内核模块编程之入门(三)-模块实用程序简介 内核...

AlphaJay
2010/05/21
243
0
Linux 引导过程内幕

早期时,启动一台计算机意味着要给计算机喂一条包含引导程序的纸带,或者手工使用前端面板地址/数据/控制开关来加载引导程序。尽管目前的计算机已经装备了很多工具来简化引导过程,但是这一切...

nothingfinal
2013/03/31
0
0
Grub引导程序的安装、配置及使用汇总

(一)安装linux时安装grub. 安装redhat linux时会提示安装引导程序,如果选择grub为引导程序,建议把grub安装到硬盘的引导扇区MBR.grub 还可以引导其它操作系统,如 FreeBSD、NetBSD、OpenBSD、...

红薯
2009/05/07
2K
0
Oracle Linux 7.3 发布,新增 UEFI 安全引导

Oracle Linux 7.3 (Oracle Linux 7 Update 3)发布了,Oracle Linux 全称为 Oracle Enterprise Linux ,是由 Oracle 公司提供支持的企业级 Linux 发行。 这是第一个包含 UEK 版本 4(UEK R...

王练
2016/11/12
3.9K
3
Linux的启动流程(CentOS 6)

前言 Linux启动的过程在实际生产中有着至关重要的作用。试想一下,如果我们在实际生产中服务器因为某一个服务出了问题,而不能启动,这时我们应该怎么办。如果我们了解Linux的详细启动过程,...

Eumenides_s
2017/09/14
0
0

没有更多内容

加载失败,请刷新页面

加载更多

每年营收翻倍的 AfterShip 是如何体系化做新员工培训(下)

AfterShip 自 2012 年成立以来,每年业务都可实现 100% 的复合增长。对于这家公司来说,组建团队是一件更重要的事情,并且尤为重视工程师团队文化的建设,他们推崇团队文化多元化及相互包容性...

爱客科技
9分钟前
10
0
如何在企业内部实现云信私有化

在信息安全愈发重要的今天,企业越来越重视和业务有关的数据,视其为企业的生命线,云信针对这一特点专门构建了一整套私有化方案,并且在多家行业龙头企业内部稳定运行,成为企业内部发展的助...

真正稳定的网易云信
10分钟前
10
0
动态代理的实际应用

原文链接 前言 最近在用 Python 的 SQLAlchemy 库时(一个类似于 Hibernate 的 ORM 框架),发现它的 Events 事件还挺好用。 简单说就是当某张表的数据发生变化(曾、删、改)时会有一个事件...

crossoverJie
14分钟前
5
0
视频直播技术之如何搭建流媒体服务器?

实时视频直播是这两年非常火的技术形态,已经渗透到教育、在线互娱等各种业务场景中。但要搭建一套实时视频直播系统,并非易事,下面针对直播系统的的搭建做一下说明: 1.1 通常的直播系统的...

图玩智能科技
15分钟前
16
0
SpringTask任务调度详解+SpringBoot整合

1 定时任务的框架 Quartz:整合了Spring SpringTask:轻量 SpringBoot整合SpringTask:两行代码即可搞定 1.1.说说定时任务的应用场景 1. 月底扣话费2. 会员到期3. 生日祝福4. qq好友生日祝...

漫路h
15分钟前
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部