MBR和GRUB概述
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.
|-- symvers-2.6.
|-- vmlinuz-2.6.18-128.el5
|-- vmlinuz-2.6.18-128.el5xen
|-- xen-syms-2.6.18-128.el5
|-- -2.6.18-128.el5
`-- grub
|-- device.map
|-- e2fs_stage1_5
|-- fat_stage1_5
|-- ffs_stage1_5
|-- f
|-- iso9660_stage1_5
|-- jfs_stage1_5
|-- menu.lst -> ./f
|-- minix_stage1_5
|-- reiserfs_stage1_5
|--
|-- 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
|-- f
|-- menu.lst -> ./f
|-- 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 .......;mx
00315f0: ebe4 177f 065d 6e19 434a 4a5a 1f8b
111e .....]
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 bs=1 skip=$((0x2082))
然后解压 即可得到二进制的内核。
值得一提的是,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
linux内核文件放在哪
顾名思义,其实 stage1_5d 确实是在 stage1 和 stage2 之间运行的,它包括了一些常见的文件系统的识别能力,这些文件的存在,意味着 grub 可以从多种文件系统中读取并加载 Linux 内核。
这个特性使得 grub 更加灵活的处理不同的文件系统格式。
虽然有 e2fs_stage1_5 这个文件的存在,但经过实验,我们发现在默认情况下编译的内核如果装载在 ext3 文件系统上,是不需要 stage1_5这个过程的。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。