GRUB2启动和组成结构

仲霍英
2023-12-01

1.1 GRUB2特色

本文所用GRUB2版本为1.99GRUB2是为了取代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.

GRUB 2 has the following tasks:

* Create a compact core image. This will make Stage 1.5 unnecessary.
* Add support for dynamic loading to the core image, so that it can extend itself at the run time rather than at the build time.
* Add real memory management, to make GNU GRUB more extensible.
* Add a more object-oriented framework for file systems, files, devices, drives, terminals, commands, and OS loaders.
* Add support for internationalization. This includes support for non-ASCII character code, message catalogs like gettext, fonts, graphics console, and so on.
* Add an actual localization, based on the above internationalization support. We will target on Japanese as the first step.
* Segregate code specific to i386-pc from generic code, to make GNU GRUB portable.
* Add support for cross-platform installation.
* Develop additional software packages which will help our project and hopefully other projects.

 

GRUB2采用模块化动态加载的思想,相比GRUB来讲不用在构建时将所有功能都加入,这使得GRUB2的体积相比变得很小,整个GRUB2的内核映像可以控制在31KB以内(GRUB的映像在百KB级别),因此GRUB2完全可以移除GRUB中存在的stage 1.5阶段,而可以将整个映像放在GRUB中的stage1.5存放的位置。

 

1.2 X86 GRUB2启动流程

         GRUB2X86上的启动肯定也没什么独特的地方,此处再累述一下:

1)       上电 -> BIOS

上电后,硬件电路产生RESET信号并经复位引脚输入给CPUCPU进入实模式,CS寄存器默认值为0xF000IP寄存器默认值为0xFFF0,即跳转至0xFFFF0物理地址处执行第一条指令,0xFFFF0物理地址(ROM)存放的是BIOS执行代码,BIOS完成上电POSTBIOS中断调用等初始化,最终读取主引导扇区的512B的数据至0x7C00物理内存地址开始处,并跳转至0x7C00处执行代码;

 

主引导扇区512B数据格式:

a) 0x000 ~ 0x1BD:占446B,为MBR引导代码;

b) 0x1BE ~ 0x1FD:占64B4组磁盘分区表信息(DPT),每组分区信息占16B(这也

是为什么最多有4个主分区);以第一个分区为例,16B大小的分区字段如下:

 

 

c) 0x1FE ~ 0x1FF:结束标志,0x550xAA

      

                早期的硬盘采用盘片和磁头组成,每个盘片有2个盘面,每个盘面对应有1个磁头,当硬盘访问数据时,磁头在盘面上移动来读取数据;每个盘面由很多同心圆组成,每1个同心圆称作一个磁道,每个磁道逻辑上划分为63个扇区(实际的物理存储不是这样的结构),磁盘访问数据以扇区为单位;所有面的相同位置的同心圆构成柱面,早期CHSCylinder柱面、Head磁头、扇区Sector)寻址就是根据这样的结构产生的;

      

       硬盘在使用中,0面的0磁道的所有扇区即前63个扇区做为特殊用途,BIOS和操作系统不放置任何数据于此(例如,第一个引导扇区一般位于第64个扇区,一般做为bootloader使用,这也是为什么GRUB必须使用stage1.5的原因(因为其大小一般为100KB左右,超出了62个扇区的限制)。

2)       BIOS -> MBR(GRUB2 boot.img)

此场景中MBR引导代码即GRUB2boot/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.img0x8000处,并跳至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.Si386/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.imgkernel.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) 扇区数: 0x003c60*512=30KB

c) 目的段地址: 0x0820即内存0x8200处(放置kernel.img

 

3) 根据2)中的信息提取GRUB2kernel.img映像:

dd if=/dev/sda of=kernel.img bs=1k count=30 skip=1

转载于:https://www.cnblogs.com/cybertitan/archive/2012/10/10/2718993.html

 类似资料: