分类: LINUX
2013-05-18 14:55:27
原文地址:GRUB2启动和组成结构 作者:xlpang
本文所用GRUB2版本为1.99,GRUB2是为了取代GRUB而完全重写的第二版,引用:
GRUB 2, which is a rewrite of GRUB, is alive and under development. GRUB 2 aims at merging sources from PUPA in order to create the next generation of GNU GRUB. A mailing list and a wiki have been setup for discussing the development of GRUB 2. |
GRUB2采用模块化动态加载的思想,相比GRUB来讲不用在构建时将所有功能都加入,这使得GRUB2的体积相比变得很小,整个GRUB2的内核映像可以控制在31KB以内(GRUB的映像在百KB级别),因此GRUB2完全可以移除GRUB中存在的stage 1.5阶段,而可以将整个映像放在GRUB中的stage1.5存放的位置。
1.2 X86 GRUB2启动流程
GRUB2在X86上的启动肯定也没什么独特的地方,此处再累述一下:
1) 上电 -> BIOS
上电后,硬件电路产生RESET信号并经复位引脚输入给CPU,CPU进入实模式,CS寄存器默认值为0xF000,IP寄存器默认值为0xFFF0,即跳转至0xFFFF0物理地址处执行第一条指令,0xFFFF0物理地址(ROM)存放的是BIOS执行代码,BIOS完成上电POST、BIOS中断调用等初始化,最终读取主引导扇区的512B的数据至0x7C00物理内存地址开始处,并跳转至0x7C00处执行代码;
主引导扇区512B数据格式:
a) 0x000 ~ 0x1BD:占446B,为MBR引导代码;
b) 0x1BE ~ 0x1FD:占64B,4组磁盘分区表信息(DPT),每组分区信息占16B(这也
是为什么最多有4个主分区);以第一个分区为例,16B大小的分区字段如下:
c) 0x1FE ~ 0x1FF:结束标志,0x55和0xAA;
早期的硬盘采用盘片和磁头组成,每个盘片有2个盘面,每个盘面对应有1个磁头,当硬盘访问数据时,磁头在盘面上移动来读取数据;每个盘面由很多同心圆组成,每1个同心圆称作一个磁道,每个磁道逻辑上划分为63个扇区(实际的物理存储不是这样的结构),磁盘访问数据以扇区为单位;所有面的相同位置的同心圆构成柱面,早期CHS(Cylinder柱面、Head磁头、扇区Sector)寻址就是根据这样的结构产生的;
硬盘在使用中,0面的0磁道的所有扇区即前63个扇区做为特殊用途,BIOS和操作系统不放置任何数据于此(例如,第一个引导扇区一般位于第64个扇区,一般做为bootloader使用,这也是为什么GRUB必须使用stage1.5的原因(因为其大小一般为100KB左右,超出了62个扇区的限制)。
2) BIOS -> MBR(GRUB2 boot.img)
此场景中MBR引导代码即GRUB2的boot/i386/pc/boot.S编译出来的代码,称为boot.img;代码执行位置即0x7C00,主要行为:设置堆栈指针为0x2000处,探测硬盘CHS/LBA工作模式,并加载第二个扇区最终至0x8000处,并跳至0x8000执行;
另附PC机的头1MB内存空间分布(摘自documentation/i386/boot.txt):
| |
0A0000 +------------------------+
| Reserved for BIOS | Do not use. Reserved for BIOS EBDA.
09A000 +------------------------+
| Stack/heap/cmdline | For use by the kernel real-mode code.
098000 +------------------------+
| Kernel setup | The kernel real-mode code.
090200 +------------------------+
| Kernel boot sector | The kernel legacy boot sector.
090000 +------------------------+
| Protected-mode kernel | The bulk of the kernel image.
010000 +------------------------+
| Boot loader | <- Boot sector entry point 0000:7C00
001000 +------------------------+
| Reserved for MBR/BIOS |
000800 +------------------------+
| Typically used by MBR |
000600 +------------------------+
| BIOS use only |
000000 +------------------------+
由上述结构可知,bootloader约定使用0x1000~0x10000内存段;
3) GRUB2 boot.img-> GRUB2 diskboot.img (第2个扇区)
第二个扇区代码由boot/i386/pc/diskboot.S编译生成,称为diskboot.img;
boot.img最终加载diskboot.img至0x8000处,并跳至0x8000处执行代码;
4) GRUB2 diskboot.img -> GRUB2 kernel.img(第3~ n个扇区, n<63)
diskboot.img的作用是读取GRUB2的内核kernel.img(由kern\下的文件生成)至内存的某位置处;diskboot.img的组成:
a) 0x0~0x147:共328B,指令;
b) 0x148~0x1FF:共184B,用来保存数据集;每个数据集为12B,可以保存15个数据集;12B的数据集结构:其中0~7B表示起始扇区数,8~9B表示扇区数,10~11B表示目的段地址即kernel.img放在内存中的位置(通常都是0x8200),都在生成镜像(grub-mkimage)时确定;
这样diskboot.img会根据数据集的数据来确定kernel.img在硬盘上的存放位置和内存放置地址;kernel.img是经过压缩的,映像开头是i386/pc/startup.S和i386/pc/lzma_decode.S启动和lzma解压缩代码(7zip的压缩算法)代码以便用以解压缩(类似于bzImage的处理),进入保护模式,并解压至0x10000处,最终再将解压后的代码搬至0x8200处执行(0x8200~0x10000之间,不能超过0x10000内存地址),此时CPU已经是保护模式了,最终调用kern/main.c中的grub_main (),代码如下:
主要工作:初始化系统,加载模块,并进入normal或者rescue模式,GRUB2会根据配置文件或者用户输入,加载操作系统并运行;调用grub_load_modules()来加载所有的模块,这就是GRUB2扩展性能的体现之一。
1.3 GRUB2编译和安装编译:
进入grub-1.99/目录:
1) ./configure --prefix=/xlpang/grub_install --exec-prefix=/xlpang/grub_install/
CC=/opt/zte/x86_64_gcc4.1.2_glibc2.5.0/bin/x86_64-pc-linux-gnu-gcc CFLAGS=-static
2) make
3) make install
执行完毕后(注意用户权限),进入/xlpang/grub_install/就可以看到grub2的安装文件了。
安装:
登录目标PC机器,假设/dev/sda1已挂载到/目录,
1) 将grub_install/拷至/xlpang/中(安装时的放置路径需确保和编译时的路径一致;也可以
修改/xlpang/grub_install/sbin/ grub-install脚本文件开头的变量路径),执行:
/xlpang/grub_install/sbin/grub-install --no-floppy /dev/sda命令将grub2安装到sda硬盘第一个分区的/boot目录下,并将boot.img, diskboot.img和kernel.img写入其相应扇区中,其它文件安装在/boot/grub/目录下。
2) 生成/boot/grub/grub.cfg文件(在/boot/目录下放置bzImage内核映像):
编辑/xlpang/grub_install/etc/grub.d/40_custom文件,增加:
menuentry "linux_x86_64-2.6.21" {
set root=(hd0,1)
linux /boot/bzImage ro
initrd /boot/initramfs
}
3) 执行:/home/grub-mkconfig -o /boot/grub/grub.cfg
注:如果存在GRUB,将GRUB2安装至GRUB相同的目录,主机启动后仍然加载GRUB界面,即GRUB2兼容GRUB;
解决办法:将原来的GRUB安装目录移除或改名后再安装GRUB2至此目录。
1.4 GRUB2映像示例
安装好GRUB2后,可以验证下数据看看是否安装成功,有助于形成GRUB2更进一步的认识,以PC机为例:
1) 提取boot.img映像:dd if=/dev/sda of=boot.img bs=512 count=1
[root@ip49 sbin]# od -tx1 -Ax boot.img 000000 eb 63 90 8e c0 8e d8 8e d0 bc 00 7c 8b f4 fb fc 000010 bf 00 06 b9 00 01 f3 a5 b8 df 06 50 c3 00 0f 00 000020 00 0a 45 72 72 6f 72 20 6c 6f 61 64 69 6e 67 20 000030 6f 70 65 72 61 74 69 6e 67 20 73 79 73 74 03 02 000040 ff 00 00 20 01 00 00 00 00 02 fa 90 90 f6 c2 80 000050 75 02 b2 80 ea 59 7c 00 00 31 00 80 01 00 00 00 000060 00 00 00 00 ff fa 90 90 f6 c2 80 74 05 f6 c2 70 000070 74 02 b2 80 ea 79 7c 00 00 31 c0 8e d8 8e d0 bc 000080 00 20 fb a0 64 7c 3c ff 74 02 88 c2 52 be 80 7d 000090 e8 17 01 be 05 7c b4 41 bb aa 55 cd 13 5a 52 72 0000a0 3d 81 fb 55 aa 75 37 83 e1 01 74 32 31 c0 89 44 0000b0 04 40 88 44 ff 89 44 02 c7 04 10 00 66 8b 1e 5c 0000c0 7c 66 89 5c 08 66 8b 1e 60 7c 66 89 5c 0c c7 44 0000d0 06 00 70 b4 42 cd 13 72 05 bb 00 70 eb 76 b4 08 0000e0 cd 13 73 0d f6 c2 80 0f 84 d8 00 be 8b 7d e9 82 0000f0 00 66 0f b6 c6 88 64 ff 40 66 89 44 04 0f b6 d1 000100 c1 e2 02 88 e8 88 f4 40 89 44 08 0f b6 c2 c0 e8 000110 02 66 89 04 66 a1 60 7c 66 09 c0 75 4e 66 a1 5c 000120 7c 66 31 d2 66 f7 34 88 d1 31 d2 66 f7 74 04 3b 000130 44 08 7d 37 fe c1 88 c5 30 c0 c1 e8 02 08 c1 88 000140 d0 5a 88 c6 bb 00 70 8e c3 31 db b8 01 02 cd 13 000150 72 1e 8c c3 60 1e b9 00 01 8e db 31 f6 bf 00 80 000160 8e c6 fc f3 a5 1f 61 ff 26 5a 7c be 86 7d eb 03 000170 be 95 7d e8 34 00 be 9a 7d e8 2e 00 cd 18 eb fe 000180 47 52 55 42 20 00 47 65 6f 6d 00 48 61 72 64 20 000190 44 69 73 6b 00 52 65 61 64 00 20 45 72 72 6f 72 0001a0 0d 0a 00 bb 01 00 b4 0e cd 10 ac 3c 00 75 f4 c3 0001b0 00 00 00 00 00 00 00 00 c5 a5 c5 a5 00 00 80 01 0001c0 01 00 83 fe ff ff 3f 00 00 00 8d f2 34 0c 00 fe 0001d0 ff ff 83 fe ff ff cc f2 34 0c 76 d0 a8 10 00 fe 0001e0 ff ff 82 fe ff ff 42 c3 dd 1c 3f 82 3e 00 00 00 0001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa
|
执行“cat boot.img”后发现有“GRUB GeomHard DiskRead Error”输出,见boot.S
2) 提取diskboot.img映像:dd if=/dev/sda of=boot.img bs=512 count=1 skip=1
[root@ip49 sbin]# od -tx1 -Ax diskboot.img 000000 52 56 be 1b 81 e8 39 01 5e bf f4 81 66 8b 2d 83 000010 7d 08 00 0f 84 e2 00 80 7c ff 00 74 46 66 8b 1d 000020 66 8b 4d 04 66 31 c0 b0 7f 39 45 08 7f 03 8b 45 000030 08 29 45 08 66 01 05 66 83 55 04 00 c7 04 10 00 000040 89 44 02 66 89 5c 08 66 89 4c 0c c7 44 06 00 70 000050 50 c7 44 04 00 00 b4 42 cd 13 0f 82 af 00 bb 00 000060 70 eb 66 66 8b 45 04 66 09 c0 0f 85 97 00 66 8b 000070 05 66 31 d2 66 f7 34 88 54 0a 66 31 d2 66 f7 74 000080 04 88 54 0b 89 44 0c 3b 44 08 7d 79 8b 04 2a 44 000090 0a 39 45 08 7f 03 8b 45 08 29 45 08 66 01 05 66 0000a0 83 55 04 00 8a 54 0d c0 e2 06 8a 4c 0a fe c1 08 0000b0 d1 8a 6c 0c 5a 52 8a 74 0b 50 bb 00 70 8e c3 31 0000c0 db b4 02 cd 13 72 46 8c c3 8e 45 0a 58 c1 e0 05 0000d0 01 45 0a 60 1e c1 e0 03 89 c1 31 ff 31 f6 8e db 0000e0 fc f3 a5 1f be 23 81 e8 57 00 61 83 7d 08 00 0f 0000f0 85 24 ff 83 ef 0c e9 16 ff be 25 81 e8 42 00 5a 000100 ea 00 82 00 00 be 28 81 e8 36 00 eb 06 be 2d 81 000110 e8 2e 00 be 32 81 e8 28 00 eb fe 6c 6f 61 64 69 000120 6e 67 00 2e 00 0d 0a 00 47 65 6f 6d 00 52 65 61 000130 64 00 20 45 72 72 6f 72 00 bb 01 00 b4 0e cd 10 000140 46 8a 04 3c 00 75 f2 c3 00 00 00 00 00 00 00 00 000150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 * 0001f0 00 00 00 00 02 00 00 00 00 00 00 00 3c 00 20 08 |
执行“cat diskboot.img”后发现有“loading. ”和“GeomRead Error”输出,见diskboot.S;
另外,最后一行表示的含义:
a) 起始扇区LBA地址: 0x0000 0000 0000 0002即第三个扇区开始存放的是kernel.img
b) 扇区数: 0x003c即60*512=30KB
c) 目的段地址: 0x0820即内存0x8200处(放置kernel.img)
3) 根据2)中的信息提取GRUB2的kernel.img映像:
dd if=/dev/sda of=kernel.img bs=1k count=30 skip=1