深入理解 GNU GRUB - 01 介绍
说明:本文最初放在CSDN博客上,现重新整理到这里(http://blog.csdn.net/cppgp)。
1 概述
1.1 GRUB是什么
GNU GRUB是一款多重引导程序。简单来讲,引导程序是计算机开机运行的第一个软件,它的使命是装载操作系统并运行。实际上,由于平台、存储介质、操作系统、文件系统等的多样性,引导程序都很复杂,同时,引导程序要求有更高安全性、健壮性。
GNU GRUB支持多平台(例如X86、PowerPC等)、多存储介质(例如硬盘、软盘、光盘、 U盘)、多操作系统(例如Linux、Gnu Hurd等)、多重引导(例如Windows等)、多文件系统(例如Ext2、Ext3、Ext4、FAT32、NTFS)。支持模块化扩展,可按照配置文件及命令行方式加载操作系统。以下是一些设计引导程序基本概念及标准的文档:
- Multiboot
- http://www.gnu.org/software/grub/manual/multiboot/
- Multiboot-with-GRUB
- http://tldp.org/HOWTO/Multiboot-with-GRUB.html
本文对GRUB (grub-1.98) 实现进行跟踪和分析。为简化流程,我们做如下假定:
- Intel i386兼容系列CPU;
- 硬盘引导, GRUB安装在硬盘中,并且使用主引导记录MBSR(Master Boot Record)。
1.2 系统启动过程
当计算机开机时,所有电子元器件都处于随机状态。此时一个特殊的硬件电路产生复位脉冲信号RESET,经CPU复位引脚进入CPU,CPU检测到RESET信号后,设置某些寄存器为预定值,其中寄存器CS和IP被预置为CS:IP=0xF000:FFF0,并让CPU在实模式下运行,可知CPU将执行地址0xFFFF0处代码。硬件电路把地址0xFFFF0映射到ROM中, ROM上保存有BIOS(Basic Input/Output System)例程。BIOS例程完成通电自检(POST,Power-on-self-test)、硬件初始化、读取CMOS配置,并提供一组中断驱动的低级过程供操作系统启动时使用。 BIOS初始化完成后,将搜索一个操作系统来启动,按照用户配置,这个过程试图访问软盘、光盘、磁盘、USB、FLASH等存储芯片。在找到一个有效设备后,BIOS把该设备主引导记录(MBR,或者称作分区扇区,是0柱面0磁头1扇区,LBA下称为0扇区,512字节)的内容拷贝到RAM中物理地址为0x7C00的位置,然后跳转至CS:IP=0x0000:0x7C00执行来自MBR的代码。一个有效设备MBR中最后两个字节的值为0x AA 55。MBR分为三部分,分别是指令代码、分区表DPT (Disk Partition Table) 、幻数0x AA 55。 一般在MBR中存放引导程序的一部分,由这部分指令读取引导程序剩余部分,加载整个引导程序到内存并继续运行引导程序。引导程序查询可引导的操作系统列表,提供给用户选择,或者在超过一个预设的时间值后,加载默认的操作系统项。操作系统加载完毕后,计算机执行权限交给操作系统,而引导程序则功成身退。
1.3 GRUB 1.98加载流程
安装在硬盘中的GRUB,完整的加载到内存中需要三步:
- BIOS加载主引导记录MBR(512字节)到内存0x7C00~0x7DFF位置,并跳转执行0x7C00处
指令。这些指令设置堆栈(SP=0x2000),探测硬盘/软盘读取模式(LBA/CHS)并保存。无论LBA或者CHS,都将加载另一扇区(该扇区位置在安装过程中确定)代码到内存0x7000 位置,然后拷贝到内存0x8000处。跳转至0x8000执行。这部分指令由 grub-1.98/boot/i386/pc/boot.S生成。
- 0x8000~0x81FF处存放第一步中加载的扇区。这部分代码利用第一步中保存的读取
模式(mode)、以及堆栈(0x2000),以及安装时指定的扇区位置和扇区数,循环加载GRUB 剩余部分到内存0x8200开始的位置。在循环加载时,对于每次迭代,都是先加载到内存 0x7000处,然后拷贝到从0x8200开始的正确位置。这部分指令由 grub-1.98/boot/i386/pc/diskboot.S生成,在安装过程中,grub-mkimage更改扇区参数块值(0x1F4~0x1FF)为实际参数。
- 0x8200~x(x<0x10000) 处存放第二步中加载的指令。这部分指令是一个包含自解压
算法lzma的压缩包(启动和解压缩部分是未压缩的,对应为startup.S和lzma_decode.S 文件)。GRUB在这里进入CPU保护模式,自解压并释放到0x10000开始内存处,解压完成后再拷贝回原来位置,然后调用grub_main,grub_main位于未见grub-1.98/kern/main.c, grub_main初始化系统,加载模块,并进入normal或者rescue模式。GRUB将根据配置文件或者用户输入,加载操作系统并运行。如果主引导记录MBR被别的引导程序(或者操作系统)占用,则由这个引导程序(或者操作系统)负责加载GRUB所在分区的首扇区到内存0x7C00~0x7DFF,此后的处理完全一致。例如通过Windows引导Linux的双系统,假定 GRUB安装在sda6(扩展分区),Windows允许配置引导部分,加载sda6分区表所在扇区到内存0x7C00~0x7DFF并执行,此后的情况和前面所述就完全一致了。至于Windows下配置引导的方法比较简单, Win7下使用EasyBCD,XP下直接编辑C:/boot.ini文件并使用 GRUB4DOS(只需要grldr、menu.ls两个文件)就可实现,网上资料很多,这里就不再深入描述了。