00000100 f4 40 89 44 08 0f b6 c2 c0 e8 02 66 89 04 66 a1 |.@.D.......f..f.| 00000110 60 7c 66 09 c0 75 4e 66 a1 5c 7c 66 31 d2 66 f7 |`|f..uNf.\\|f1.f.| 00000120 34 88 d1 31 d2 66 f7 74 04 3b 44 08 7d 37 fe c1 |4..1.f.t.;D.}7..| 00000130 88 c5 30 c0 c1 e8 02 08 c1 88 d0 5a 88 c6 bb 00 |..0........Z....| 00000140 70 8e c3 31 db b8 01 02 cd 13 72 1e 8c c3 60 1e |p..1......r...`.| 00000150 b9 00 01 8e db 31 f6 bf 00 80 8e c6 fc f3 a5 1f |.....1..........| 00000160 61 ff 26 5a 7c be 80 7d eb 03 be 8f 7d e8 34 00 |a.&Z|..}....}.4.| 00000170 be 94 7d e8 2e 00 cd 18 eb fe 47 52 55 42 20 00 |..}.......GRUB .| 00000180 47 65 6f 6d 00 48 61 72 64 20 44 69 73 6b 00 52 |Geom.Hard Disk.R| 00000190 65 61 64 00 20 45 72 72 6f 72 0d 0a 00 bb 01 00 |ead. Error......| 000001a0 b4 0e cd 10 ac 3c 00 75 f4 c3 00 00 00 00 00 00 |.....<.u........| 000001b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 24 12 |..............$.| 000001c0 0f 09 00 52 be bd 7d 31 c0 cd 13 46 8a 0c 84 c9 |...R..}1...F....| 000001d0 75 0f be da 7d e8 cc ff eb 96 46 6c 6f 70 70 79 |u...}.....Floppy| 000001e0 00 bb 00 70 8e c3 31 db b8 01 02 b5 00 b6 00 cd |...p..1.........| 000001f0 13 72 d4 b6 01 b5 4f e9 f1 fe 00 00 00 00 55 aa |.r....O.......U.| 00000200
然后可以文本比较工具进行比较,贴图如下,左边是/boot/grub2/i386-pc/boot.img
大致有四处不同
1) 0x0003~0x0040, /boot/grub2/i386-pc/boot.img全为0, 在真正的磁盘MBR中,被grub2-install填入了必要的数据。
注意:0x0000~0x0002为eb 63 60汇编为jmp short 0x0067 ,中间这部分被grub2-insall装填部分数据,暂时不知道是为什么使用
2) 0x0066~0x0067, /boot/grub2/i386-pc/boot.img 为eb 05, 被grub2-install修改为90 90 90 为nop指令,这里修改了两个nop指令
3) 0x01b8~0x01bb, /boot/grub2/i386-pc/boot.img 00 00 00 00, 被grub2-install修改为 a7 36 08
00,这部分代码请参考https://en.wikipedia.org/wiki/Master_boot_record 其中的Structure of a modern standard MBR, 我拷贝到这里作参考
被修改的这4个Byte[a7 36 08 00] 为32 bit Disk Signature,它是可选的, 我想可能是为了UEFI使用。
4) 0x01be~0x01fd, DPT硬盘分区表部分,保持不变grub2-install不会去修改
如果大家有兴趣可以去研究代码,知道grub2-install还有很多工作,这里就不在描述。
6.6. 硬盘总结
一块SCSI硬盘逻辑结构简单来说如下图所示:
LBA0: 固定存储MBR,一般GRUB2的boot.img就存放在这里
LBA1~LBA2047: 被称为“Embedding Area”“MBR Gap”,一般GRUB2的core.img就存放这里 LBA2048后面为我的两个硬盘分区,他们放在连续的区域
7. 启动过程
在前面介绍相关的知识,咱们回归到主题,现在开始启动过程
7.1. BIOS
系统上电之后,由固化在ROM里面的BIOS代码运行,进行硬件检查及初始化工作。有关BIOS具体运行原理在这里不作描述,有兴趣的请参考相关书籍。
最近的EFI作为BIOS的替代或升级,支持更多的功能,在这里也不做描述。
BIOS运行的最后两步操作我们必须知道
1) 加载LBA-0(或者CHS的0柱面、0磁头、1扇区)的MBR,共512字节到内存中0x7C00位置
2) 从内存0x7C00位置运行
我们知道拷贝到MBR中的正式GRUB2 boot.img,从这个时候开始,GRUB2正式登上历史舞台。但是请注意,并不是说BIOS就全部退出舞台,BIOS依然为GRUB2提供底层服务,比如硬盘读取等等(通过BIOS INT13 功能), GRUB2在一穷二白基础上还离不开BIOS
============================================ 地址0x7C00
============================================
这里有个问题,为什么BIOS会加载MBR到0x7C00的位置,而不是其他的位置? 答案请参考:
http://stackoverflow.com/questions/2058690/what-is-significance-of-memory-at-00007c00-to-booting-sequence
这个问题是应该由最初的IBM PC BIOS的设计者们(软件及硬件)来回答,但是简单的答案可能是0x7C00是距离地下最初32K安装内存有1K大小(512Bytes给MBR以及另外的512Bytes作运行时堆栈使用)
7.2. GRUB2中boot.img
BIOS加载MBR到0x7C00并从该处运行的时候,实际上就是boot.img开始运行了,我们的工作来了,我们将介绍boot.img将要干什么,可以从官方网站http://www.gnu.org/software/grub/.去使用git下载源码, 源码是采用AT&T风格的汇编。
这里我们采用反汇编的方式取得Intel风格代码 1) 我们已经在6.2MBR中使用DD命令导出的MBR 2) 安装nasm
[root@controller i386-pc]# yum install nasm Loaded plugins: fastestmirror, langpacks Loading mirror speeds from cached hostfile * base: mirrors.btte.net * extras: mirrors.163.com * updates: mirrors.btte.net
Package nasm-2.10.07-7.el7.x86_64 already installed and latest version Nothing to do
3) 进行反汇编
[root@controller image]# ndisasm -o 0x7c00 mbr.bin > mbr.asm
这里加入-o 0x7c00是告诉反汇编器这段代码在0x7c00处运行,使生成的mbr.asm更加容易理解
在这里我把反汇编的代码mbr.asm作为附件供参考,后面的boot.S是官方源码:
mbr.asmboot.S
注意:boot.S是AT&T汇编语法,反编译的mbr.asm是Intel汇编语法,两者有区别,如果感兴趣,请参阅相关文档进行学习。下面详细讲解主要流程。
7.2.1. Step1无条件跳转
/*位于0x7C00的语句就是一条跳转语句, 跳转到0x7c65处*/
00007C00 EB63 jmp short 0x7c65
7.2.2. Step2 初始化
/* 禁止中断 目前是不安全的*/
00007C65 FA cli 00007C66 90 nop 00007C67 90 nop
/*