您的位置:首页 > 运维架构 > Linux

Linux引导过程概述

2009-09-21 14:08 239 查看
Linux 的启动流程目前比较流行的方式主要是以下步骤:

1、引导器(例如 GRUB)启动;

2、内核启动;

3、系统进程启动与配置。

本文以 GRUB 为研究对象,对 GRUB 启动与内核启动两个部分进行描述,关于系统进程的进一步启动与配置将用另一篇文章来说明。

常见的目录结构 (以 CentOS 5.3 为例):


/boot




|-- System.map-2.6.18-128.el5





|-- System.map-2.6.18-128.el5xen





|-- config-2.6.18-128.el5





|-- config-2.6.18-128.el5xen





|-- initrd-2.6.18-128.el5.img





|-- initrd-2.6.18-128.el5xen.img





|-- lost+found





|-- memtest86+-1.65





|-- message




|-- symvers-2.6.18-128.el5.gz





|-- symvers-2.6.18-128.el5xen.gz





|-- vmlinuz-2.6.18-128.el5





|-- vmlinuz-2.6.18-128.el5xen





|-- xen-syms-2.6.18-128.el5





|-- xen.gz-2.6.18-128.el5





`-- grub







|-- device.map







|-- e2fs_stage1_5







|-- fat_stage1_5







|-- ffs_stage1_5







|-- grub.conf







|-- iso9660_stage1_5







|-- jfs_stage1_5







|-- menu.lst -> ./grub.conf







|-

- minix_stage1_5







|-- reiserfs_stage1_5







|-- splash.xpm.gz







|-- stage1







|-- stage2







|-- ufs2_stage1_5







|-- vstafs_stage1_5







`-- xfs_stage1_5

图一: CentOS 5.3 的 /boot 目录

目录分作两大部分,一个是 /boot 目录下除 grub 目录以外的所有文件,这些是 Linux 的内核以及内核启动相关的一些文件;另一个就是 grub 下的所有文件, GRUB 引导器启动所需要的所有文件都在 grub 目录下。



核心文件组成:


/boot




|-- System.map-2.6.18-128.el5





|-- initrd-2.6.18-128.el5.img





|-- vmlinuz-2.6.18-128.el5





`-- grub







|-- grub.conf







|-- menu.lst -> ./grub.conf







|-- stage1







|-- stage2

图二: 核心文件说明

图二是一个简化了的目录结构,在大多数Linux实现中,这些是 Linux 启动最核心的几个文件,下面我们对这个结构中的文件加以说明。



内核文件说明:

Linux 内核启动相关文件:

vmlinuz --- Linux 内核

这个就是 Linux 可引导的、压缩的内核文件。

此文件通常后面带有内核版本号,但不是必需的,但有利于系统中存在多个不同的内核时加以区分。


vmlinuz 通常在 2.4 版内核时有两种方法建立,一个是通过编译时使用 make zimage 命令,这个方法是老的 2.4
版内核所支持的方式,用于生成较小的内核(512K 以下), 同时,在 2.4 版内核编译时使用 make bzimage
则可以生成一个大内核,其中 bz 的意思是 big zimage。 二者的主要区别在于小内核(zimage
形势)可以很小(4K),放在磁盘的前八个引导扇区,在装载时,先装载到
0x1000:0000 高端内存,然后再移动到 0x0200:0000 位置的低端内存,然后启动CPU,所以可以不需要单独的引导器; 而 bzimage 形式较大,在 512K 以上

,只能加载到
0x1000:0000 高端内存,然后启动CPU,需要有独立的引导器进行引导。

vmlinuz 在 2.6 版内核中并不直接支持 zimage 小内核方式,2.6版内核的编译过程不需要 make zimage 或 make bzimage 这一步 。




vmlinuz 虽然采用了 gzip 进行压缩 , 但由于其头部中添加了精简过的代码,所以不能直接用 gunzip
直接解压,我们通过观察一般的 gzip缩文件,发现有一个特征码 "1f8b" 。于是分析 vmlinuz 这个文件:

# xxd vmlinuz-2.6.18-128.el5 |egrep "/b1f8b" |head -n5


0002080: 1b00 1f8b
0800 e642 7749 0203 ec3b 6d78 .......BwI...;mx


00315f0: ebe4 177f 065d 6e19 434a 4a5a 1f8b 111e .....]n.CJJZ....


0058390: d1ad 1e11 0683 9f1f a857 1f8b a542 cb27 .........W...B.'


0073cb0: 9b51 e43c 482b 3685 1f8b 05f5 32fd b758 .Q.


0086a50: ed06 0bb5 1f8b 6d67 930c d7d0 2c6c 6c18 ......mg....,ll.

发现该特征码在 0x2082 处,由以下命令可以摘除这个部分:

# dd if=

vmlinuz-2.6.18-128.el5 of=vmlinuztest.gz bs=1 skip=$((0x2082))

然后解压 vmlinuz

test.gz 即可得到二进制的内核。

值得一提的是,2.4 以后版本的内核,不再提供无需引导器引导的机制





initrd --- initialized ram disk 初始化 RAM 磁盘


启动器(boot loader 即本文的 GRUB)会在内核启动前把 initrd 装入内存,该文件的作用是生成一个 RAM
磁盘,并在其上形成根文件系统,内核启动时会在访问真实的磁盘根文件系统前访问这个 RAM 磁盘中的根文件系统。2.6 版内核中,当内核执行完
initrd 中的内容后,对于 cpio 类型的 initrd ,会由 initrd 负责执行switchroot
来切换根文析系统到真实的文件系统中去,并开始真正的 init 进程;对于 image-initrd 这个类型来说,内核执行完 initrd
这个阶段以后,会返回到内核,继续内核初始化,然后由内核去调用真实文件系统中的 init 。本文的主要内容是介绍 Linux 2.6
版引导的过程,对于initrd 的更多细节不再赘述,有兴趣的读者,可以查阅相关的链接

。 关于 initrd 的动手实验,则可以在本站中找到



此文件通常后面带有内核版本号,但不是必需的,但有利于系统中存在多个不同的内核时加以区分。


关于 initrd 的另一个重点,是为什么要使用它,initrd
最重要的作用在于使引导过程更加灵活。为了在各种硬件平台上启动,将所有的硬件驱动都放到内核中显然不现实,initrd
的作用之一就是加载硬件驱动模块,从而可以在内核中只包含最基本的硬件驱动即可,将加载不同硬件驱动的任务交给 initrd ;关于 initrd
的另一个作用是支持 usb 启动,由于 usb 从驱动加载到真正可用的过程较慢,可能需要几秒钟的时间比较慢,在内核访问usb时,USB
设备可能还没初始化完成,将该过程放入到 initrd 中可以进行延时,完成正确加载和引导。

在某些情况下,我们可以使用 noinitrd 参数,使启动过程不使用 initrd 文件是可能的。




System.map --- 内核符号映射表


在弄清楚 System.map 的作用以前,首先要先了解两个名词,其中一个叫做 symbol(符号),另一个叫做 Oops 。

Symbol
: 符号,学过程序设计的话应该知道,一个符号是一个程序的创建块,它是一个变量名或一个函数名。 这里为什么要提到这个名词呢? 因为 Linux
内核并不使用符号来调用函数,而是直接使用函数的地址(指针),
这似乎造成了一个矛盾,因为编程的人并不喜欢使用地址的方式,于是符号表产生了,它允许在编程的过程中,使用符号,但是在编译时使用地址,”符号映射表
“由此产生了,它就是 System.map .

用 more 命令查看 System.map 文件可以看到类似下面的段:

64位的系统:

ffffffff81000000 A _text

ffffffff81000000 T startup_64

ffffffff810000b7 t ident_complete

ffffffff81000100 T secondary_startup_64

32位的系统:

c0100000 A _text

c0100000 T startup_32

c01000c6 t checkCPUtype

c0100147 t is486

Oops

当内核引用了一个无效指针时,通常被称为 Oops ,说明内核存在一个Bug。 内核在出现此错误时,会由 klogd
这个服务将此错误记载到日志中,如果该日志指出一个地址错误,显然还需要我们花些时间来找该地址对应的符号,klogd 通过检视
System.map 直接将符号取出,并记载该符号引发了一个 Oops 。


通过以上的描述,我们得到一个结论:System.map 是一个静态的内核符号映射表!

既然说到静态,那么就说明如果是在运行期间动态加载的某些模块,可能不在其中,如何得到它们呢? 系统中的 proc 文件系统中存在一个动态的映射表, 在 2.6 Kernel 中通常是 /proc/kallsyms 。

另外,类似 lsof 和 ps 等命令,是需要这个映射表的存在的,但既使没有这个文件,系统的启动依然可以进行。





GRUB 文件说明:

stage1 --- 磁盘引导第一阶段


当 BIOS 加电自检完成以后,假设系统是从硬盘启动,则 BIOS 的最后一件事情就是读取该硬盘的 0 道 0 面 1 扇区,即我们常用说的
MBR ,它只有 512 个字节大小,它与 stage1 具有什么样的关系呢? 我们先来看一下关于 MBR 的构成:



图三:MBR 的组成(摘自 IBM 官方网站)


MBR 共由三个部分组成:1、Bootloader 就是引导代码,其作用主要是加载第二阶段启动(即stage2),2、Partition
table 分区表, 3、Magic Number 魔数,就是那个 55AA 标志,用以检验该 MBR 的有效性。

我们可以用如下命令导出该扇区到文件(假设该硬盘为 hda):

dd if=/dev/hda of=mbr.bin bs=512 count=1

然后我们用

xxd mbr.bin

xxd /boot/grub/stage1


仔细对比发现,该扇区的 Bootloader 部分与 MagicNumber部分与 stage1 文件完全一样,原来,在使用 grub
的安装命令进行引导器安装时,grub 会用 stage1 文件的前 446 字节覆盖 MBR的前446
字节。在这里我们得到另一个启示,那就是不能简单的认为 MBR 等价于 stage1 ,为了保护 MBR ,我们还是应该对 MBR 做备份。



stage1_5 --- 关于文件系统格式的“魔术师”

应该注意到,所有带有 stage1_5 字样的文件,全部都和文件系统名字有关:







|-- e2fs_stage1_5







|-- fat_stage1_5







|-- ffs_stage1_5







|-- iso9660_stage1_5







|-- jfs_stage1_5









|-

- minix_stage1_5







|-- reiserfs_stage1_5









|-- ufs2_stage1_5







|-- vstafs_stage1_5







`-- xfs_stage1_5

顾名思义,其实 stage1_5d 确实是在 stage1 和 stage2 之间运行的,它包括了一些常见的文件系统的识别能力,这些文件的存在,意味着 grub 可以从多种文件系统中读取并加载 Linux 内核。

这个特性使得 grub 更加灵活的处理不同的文件系统格式。

虽然有
e2fs_stage1_5 这个文件的存在,但经过实验,我们发现在默认情况下编译的内核如果装载在 ext3 文件系统上,是不需要 stage1_5这个过程的。



stage2 --- 真正的 grub 就在这里


注意到 stage2 的文件尺寸,超过了 512 字节的大小,所以 grub 本身并不能放到 mbr 中去,mbr
那446字节的作用,主要就是找到这个 stage2,它读取 menu.list 文件显示系统引导菜单,识别不同的引导指令,并完成
vmlinuz 和 initrd 的加载,其实,这个就是真正的 grub 了!

menu.list 文件就是 grub 的引导菜单, grub 会执行菜单里的命令,完成引导,因为红帽这个系列的系统进行了一些特别的设置,所以存在一个叫做 grub.conf 的软链接,指向 menu.list 。





结论:


启动中最重要的东西:mbr/stage1 、grub/stage2 、kernel/vmlinuz ,三者是最最核心的。stage1_5
的作用是使 grub 有处理更多文件系统的灵活能力,而 initrd
使内核启动更加灵活,在不同的平台上,对不同的硬件,使用不同的驱动,从而减小静态内核的尺寸。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: