GRUB2及启动过程详解_第1页
GRUB2及启动过程详解_第2页
GRUB2及启动过程详解_第3页
GRUB2及启动过程详解_第4页
GRUB2及启动过程详解_第5页
已阅读5页,还剩43页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

GRUB2及启动过程详解作者:南瓜剪子2016年7月28日TOC\o"1-3"\h\u142571.概述 2163962.CentOS7中GRUB2 291873.GRUB2的bootstrapimage文件 35993.1.boot.img 317983.2.diskboot.img 479403.3.kernel.img 446923.4.core.img 4159263.5.*.mod 4169084.对比GRUBLegacy 554464.1.stage1 5245284.2.*_stage1_5 5210514.3.stage2 5268365.grub2-mkimage定制core.img 6285956.GRUB2安装 7323916.1.Linux是怎么命名设备(/dev/sda) 775246.2.MBR(MasterBootRecord) 8321736.3.MBR分区表DPT(DiskPartitionTable) 1024056.4.LBAandCHS 14304526.4.1.CHS(cylinders-heads-sectors) 14309286.4.2.LBA(LogicalBlockAddress) 14239516.5.boot.img和core.img安装 15211306.6.硬盘总结 1890587.启动过程 1954237.1.BIOS 19306507.2.GRUB2中boot.img 20147077.2.1.Step1无条件跳转 20175827.2.2.Step2初始化 20195767.2.3.Step3判断硬盘是否支持LBA还是只支持CHS 22103947.2.4.Step4采用LBA加载core.img第一个扇区 23107287.2.5.Step5拷贝core.img第一个扇区到内存指定位置 25215827.2.6.Step6执行core.img第一条语句 27153227.2.7.Step7boot.img总结 27153427.3.GRUB2中core.img 2858237.3.1.diskboot.img 28142267.3.2.GRUB2coreStartup 34148367.3.3.GRUB主函数即GRUB主要功能 37230817.3.4.加载LinuxKernel 38168137.4.Linuxkernel 47143788.结束语 48320729.参考文献 48概述计算机系统上电之后由固化到ROM中的BIOS(UEFI)进行操作,然后导入硬盘MBR中BootLoader并调到其运行,由BootLoader对操作系统内核进行加载,并将控制权交给操作系统.下图简单描述了CentOS7的启动过程(CentOS7使用GRUB2作为BootLoader):现在的BootLoader有很多类型,大致如下:对Linux来说GRUB2占据了统治地位对Windows来说Bootmgr/BCD占据了统治地位对Apple系统缺省的是BootX作为一名计算机工程师,了解BootLoader的原理是很重要。本文着重介绍GRUB2及其启动流程.读完本文,相信读者能够对BootLoader原理有一定深刻理解,并能大致知道其他BootLoader的作用.本文在介绍一些基本知识后,在第7章会引入基本的反汇编过程来讲解GRUB2的启动流程,因为只有直接读代码才能深入学习原理.需要读者:-有一定的汇编语言知识,如果读者对汇编不敢兴趣,可以跳过相关章节-同时也需要读者有一定C语言知识本文稍微有点长,但都是作者本人的经验总结,如果静下心读完,相信对你会有帮助,相比其它GRUB一厚本书,能节约你很多时间。但由于作者水平有限,有不足之处忘谅解。CentOS7中GRUB2GRUB2是GNU下面的一个项目,有关其详细信息,请参考官方网站:/software/grub/.相对于GRUB2,原先的GRUB(i.e.version0.9x)被称为:GRUBLegacy.官网上说明:GRUBLegacyisnolongerbeingdeveloped.从1.x开始的新版本就称为GRUB2(注意,虽然称为GRUB2,但其版本号却是从1.x开始1.99也是GRUB2).现在各种最新发行版本的Linux(包括CentOS7)都采用GRUB2.在CentOS7上可以查看安装的GRUB2版本[root@controller~]#rpm-qa|grep"grub"grub2-2.02-0.34.el7.centos.x86_64在CentOS7下面/boot/grub2目录可以看到有关GRUB2相关文件.在/boot/grub2/i386-pc目录下是GRUB2bootstrapimages文件,该目录大部分文件是以.mod结尾,这些文件为GRUB2模块文件,最后在该目录下面有以下两个image文件:[root@controlleri386-pc]#ls-lrt*.img-rw-r--r--.1rootroot266187\u67081123:33core.img-rw-r--r--.1rootroot5127\u67081123:33boot.img以上两个img文件都会被grub2-install命令安装到硬盘上相应位置(在硬盘什么位置后面会说),很有意思的是请注意两点boot.img固定为512Bytecore.img小于32KByte如果你觉得好奇,可以用file命令查看这些image文件类型[root@controlleri386-pc]#fileboot.imgboot.img:x86bootsector;partition4:ID=0xd4,starthead205,startsector4277266767,0sectors,codeoffset0x63[root@controlleri386-pc]#filecore.imgcore.img:data[root@controlleri386-pc]#filexfs.modxfs.mod:ELF32-bitLSBrelocatable,Intel80386,version1(SYSV),notstripped对于boot.imgfile命令明确指出其为x86bootsector,而mod文件却是ELF文件,接下来让我们进一步了解这些bootstrapimage文件GRUB2的bootstrapimage文件GRUB2有以下各种bootstrapimages文件,大伙应悉知,这些image会被grub2-install安装到硬盘相应的位置,当BIOS完成后,他们会被加载并引导系统继续完成启动.boot.img在PCBIOS系统中,这个image是GRUB2第一个被运行的.它被写在MBR(MasterBootRecord)或者在分区(partition)的bootsector中.因为MBR或PCbootsector是固定512字节,这个文件的大小也固定为512byte.boot.img功能很简单,主要是读磁盘中core.img中的第一个扇区(sector)到内存中并跳到该部分运行(如果是硬盘启动,那么该扇区就是下面要介绍的diskboot.img).因为只有512字节,boot.img不能够加载文件系统(比如CentOS7中XFS或其它Linux的EXT4等等),并且只能是从硬盘固定的位置加载.diskboot.img当从硬盘启动的时候这是core.img第一个扇区(sector)的内容,主要功能是读剩下的core.img到内存中并开始运行kernel.img.同样diskboot.img没有文件系统的功能(XFS,EXT4等),当他读取剩余的core.img时候,依然从硬盘固定位置读取.根据启动的介质不同,类似diskboot.img文件有很多,在安装GRUB时候选用其中一个,目前大部分都是从硬盘启动diskboot.imgcdboot.img:从CD-ROM启动pxeboot.img:从PXE网络启动Lnxboot.img:如果从其他bootloader比如LILO(用image=’section)启动,这个image使GRUB看上去像一个Linux内核.kernel.img这个文件包含了GRUB2基本的运行时支撑:对设备及文件的框架,环境变量,恢复模式下的命令行等等.一般我们不会直接使用它,但是它是core.img中必不可少的一部分.core.img这个是GRUB的核心.他是被grub2-mkimage命令生存,包含了kernel.img以及一些必须必要的modules.通常core.img包含了足够的模块(modules)为了访问XFS/EXT4文件系统/boot/grub2目录,并且在运行时加载从文件系统(XFS)所有剩余的模块,这些剩余模块包含启动目录处理,加载操作系统等等功能.模块化的设计思路最主要的目的是使core.img保持足够小,目前disk限制core.img安装必须小于32KB.core.img一般被安装在硬盘特殊区域:embeddingarea(夹层区),这个区一般有32K限制,我们在后面会介绍什么是夹层区.*.mod所有GRUB其他部分被称为模块,他们大部分被core.img在运行时自动动态加载,其中一小部分被整合到core.img中,这小部分是必须,比如文件系统支持(xfs.mod)模块可以手工加载,请参考insmodcommand(在本文不作介绍,请查阅相关文档)注意:如果对以上各种image文件还是不清楚,请继续往下读,后面会有详细说明。

对比GRUBLegacyGRUB2与GRUBLegacy不同,很多人都熟悉GRUBLegacy里面的stage1,stage1_5,stage2等等概念,而在GRUB2里面,这些被各种bootstrapimage文件替代:boot.imgdiskboot.imgcore.img大伙应悉知以上三个imagesstage1GRUBLegacy中stage1相当于GRUB2中boot.img,他们完成相同的功能.*_stage1_5GRUBLegacy中Stage1.5包含了足够的文件系统(XFS或EXT4)代码而允许Stage2从文件系统中直接载入系统,就这个意义上来说很像GRUB2中的core.img.不过core.img功能更加强大,它提供了恢复shell,使能够在不能加载其他模块(modules)情况下(比如partitionnumber已经改变)能够人工恢复。Core.img能够被灵活的创建,允许从LVM或者RAID加载模块.GRUBLegacy能够运行stage1和stage2而不运行stage1.5,但是对GRUB2来说,core.img是必须的。stage2GRUB2没有对应stage2的image.它从/boot/grub加载相应的模块。

grub2-mkimage定制core.img上一章介绍的core.img至少包含了一下几个部分diskboot.imgkernel.imgrequired*.mod他们被grub2-mkimage命令整合成core.img文件,实际上当运行完该命令最终生成的是上一章中/boot/grub2/i386-pc目录下的两个image文件boot.imgcore.img有兴趣的读者请参照mangrub2-mkimage查阅相关信息,定制自己的core.img:[lanzhou@controllerimage]$grub2-mkimage-Oi386-pc-p/boot/grub2-v-ocore.imgxfsgrub2-mkimage:info:thetotalmodulesizeis0x26e4.grub2-mkimage:info:reading/usr/lib/grub/i386-pc/kernel.img.grub2-mkimage:info:locatingthesection.textat0x0.grub2-mkimage:info:locatingthesection.rodataat0x5494.grub2-mkimage:info:locatingthesection.dataat0x6448.grub2-mkimage:info:locatingthesection.bssat0x6bd0.grub2-mkimage:info:reading/usr/lib/grub/i386-pc/fshelp.mod.grub2-mkimage:info:reading/usr/lib/grub/i386-pc/xfs.mod.grub2-mkimage:info:kernel_img=0x2649700,kernel_size=0x6bd0.grub2-mkimage:info:thecoresizeis0x5085.grub2-mkimage:info:reading/usr/lib/grub/i386-pc/lzma_decompress.img.grub2-mkimage:info:reading/usr/lib/grub/i386-pc/diskboot.img.grub2-mkimage:info:writing0x200bytes.grub2-mkimage:info:writing0x5bc5bytes.core.img是内核的名字,生成在当前目录下,i386-pc是镜像的格式,xfs是加入内核的模块。常用模块有:xfs:支持xfs文件系统(CentOS7缺省的文件系统)ext2:支持ext2文件系统但是我们一般不直接运行该命令,一般运行grub2-install.该命令会自动调用grub2-mkimage.

GRUB2安装当一切准备好后,我们可运行以下命令grub2-install/dev/sda去安装grub2(缺省的--boot-directory=/boot/)不过一般的CentOS7已经安装好了GRUB2,除非你感兴趣,不用运行上面命令.在继续后面的内容之前,下面有几个概念大伙必须知道:Linux是怎么命名设备(/dev/sda)比如/dev/sda5,如下图所示1)SCSI硬盘第一个SCSI接口硬盘:/dev/sda第二个SCSI接口硬盘:/dev/sdb2)USB如果只有一块硬盘,那么第一个USB盘也可能是/dev/sdb(usb存储设备也目前在内核中在两种驱动方法,一种是模拟SCSI硬盘,另一种是非模拟SCSI硬盘,前一种目前比较多)3)SATA如果只有一个SATA硬盘,第一个SATA硬盘也是:/dev/sda4)IDE硬盘第一个IDE接口主盘:/dev/hda第一个IDE接口从盘:/dev/hdb第二个IDE接口主盘:/dev/hdc第二个IDE接口从盘:/dev/hdd注意:1)所以只靠/dev/sda无法知道设备类型,也许是SCSI,SATA或者U盘,但是一般来说/dev/sda都会是SCSI硬盘,本文不在详述SCSI,IDE,SATA区别,请参考相关资料2)有关分区,见下文6.3DPTMBR(MasterBootRecord)MBR,即主引导记录,是对IBM兼容机的硬盘或者可移动磁盘分区时,在驱动器最前端的一段引导扇区,其地址为采用CHS寻址:MBR固定为硬盘的0柱面、0磁头、1扇区采用LBA寻址:MBR固定LBA0(注意,我们将在后面介绍CHS与LBA,目前普片采用LBA寻址)MBR长度为512字节,它一般由三个部分组成:主引导程序硬盘分区表DPT(DiskPartitiontable)固定4个分区,每分区16byte分区有效标志,以55AA结尾的MBRStructureofaclassicalgenericMBRAddressDescriptionSize

(\o"Byte"bytes)\o"Hexadecimal"Hex\o"Decimal"Dec+000hex+0Bootstrapcodearea446+1BEhex+446Partitionentry1Partitiontable

(forprimarypartitions)16+1CEhex+462Partitionentry216+1DEhex+478Partitionentry316+1EEhex+494Partitionentry416+1FEhex+51055hexBootsignature[a]2+1FFhex+511AAhexTotalsize:446+4*16+2512本表摘自:/wiki/Master_boot_record注意1)由于后面支持EFI及GPT,上述结构有些变化,但在本文不作描述,有兴趣的读者可以参看相关EFI及GPT文档2)上文中的boot.img将会被grub2-install命令拷贝到MBR主引导程序部分(也就是Bootstrapcodearea),在后面将会详细分析boot.img====================================================工具:导出并查看MBR====================================================我们可以用DD命令把MBR从硬盘中导出来[root@controllerimage]#ddif=/dev/sdaof=mbr.binbs=1count=512512+0recordsin512+0recordsout512bytes(512B)copied,0.00173968s,294kB/s然后我们可以使用hexdump查看其内容[root@controllerimage]#hexdump-Cmbr.bin00000000eb6390108ed0bc00b0b800008ed88ec0|.c|00000010fbbe007cbf0006b90002f3a4ea210600|...|!..|0000002000bebe073804750b83c61081fefe0775|8.uu|00000030f3eb16b402b001bb007cb2808a74018b||...t..|000000404c02cd13ea007c0000ebfe0000000000|L||0000005000000000000000000000008001000000||0000006000000000fffa9090f6c2807405f6c270|t...p|000000707402b280ea797c000031c08ed88ed0bc|ty|..1|000000800020fba0647c3cff740288c252be057c|...d|<.t...R..||00000090b441bbaa55cd135a52723d81fb55aa75|.A..U..ZRr=..U.u|000000a03783e101743231c0894404408844ff89|7...t21..D.@.D..|000000b04402c7041000668b1e5c7c66895c0866|Df..\|f.\.f|000000c08b1e607c66895c0cc744060070b442cd|..`|f.\..D..p.B.|000000d0137205bb0070eb76b408cd13730d5a84|.r...p.vs.Z.|000000e0d20f83de00be857de98200660fb6c688|}...f|000000f064ff40668944040fb6d1c1e20288e888|d.@f.D|00000100f4408944080fb6c2c0e80266890466a1|.@.Df..f.|00000110607c6609c0754e66a15c7c6631d266f7|`|f..uNf.\|f1.f.|000001203488d131d266f774043b44087d37fec1|4..1.f.t.;D.}7..|0000013088c530c0c1e80208c188d05a88c6bb00|..0Z|00000140708ec331dbb80102cd13721e8cc3601e|p..1r...`.|00000150b900018edb31f6bf00808ec6fcf3a51f|1|0000016061ff265a7cbe807deb03be8f7de83400|a.&Z|..}}.4.|00000170be947de82e00cd18ebfe475255422000|..}GRUB.|0000018047656f6d0048617264204469736b0052|Geom.HardDisk.R|0000019065616400204572726f720d0a00bb0100|ead.Error|000001a0b40ecd10ac3c0075f4c3000000000000|<.u|000001b00000000000000000a736080000008020|6|000001c0210083dd1e3f0008000000a00f0000dd|!?|000001d01f3f8efeffff00a80f000058f0000000|.?X|000001e000000000000000000000000000000000||000001f0000000000000000000000000000055aa|U.|00000200黑色部分为启动代码蓝色部分为分区表DPT(下面会介绍)红色部分为分区有效标志55AAMBR分区表DPT(DiskPartitionTable)DPT作为MBR中的一部分,已经使用了好长一段时间,直到最近GPT及EFI的出现。但是DPT作为一个经典,还是有很多东西学习,在这一章我简要介绍一下DPT.====================================================工具:fdisk====================================================linux上经典的工具fdisk就是对有关的DPT进行操作。[root@controllersbin]#fdisk-l/dev/sdaDisk/dev/sda:8589MB,8589934592bytes,6777216sectorsUnits=sectorsof1*512=512bytesSectorsize(logical/physical):512bytes/512bytesI/Osize(minimum/optimal):512bytes/512bytesDisklabeltype:dosDiskidentifier:0x000836a7DeviceBootStartEndBlocksIdSystem/dev/sda1*2048102604751200083Linux/dev/sda210260481677721578755848eLinuxLVM可以看到我的CentOS7上面/dev/sda这个SCSI硬盘包含了两个分区:sda1,sda2注意其中sda1从2048sector(LBA2048)开始我们说了MBR在第一个sector,所有第一个分区sda1不能从0sector开始从很早前dos,第一个分区只能从LBA64开始,而从LBA2048开始是为了2011年后采用高级格式化的硬盘4k分区对齐fdisk输出单位:1block=1024bytes=2sectors1sector=512bytes====================================================DPT解析====================================================如果把上一章6.2MBR中导出的mbr.binHEX中的DPT对比查看partition1:8020210083dd1e3f0008000000a00f00partition2:00dd1f3f8efeffff00a80f000058f000partition3:00000000000000000000000000000000partition4:00000000000000000000000000000000对照下面两张表翻译过来引导标志分区类型起始扇区总扇区partition10x80(活动)0x83(Linux)0x0800(2048sectors)0xfa000(1024000sectors)partition10x000x8e(LinuxLVM)0x0fa800(1026048sectors)0xf05800(15751168sectors)与fdisk输出完全一致====================================================DPT编码====================================================DPT中各自段意义MBR偏移偏移长度含义0x01BE0x001Byte引导标志(BootIndicator):指明该分区是否是活动分区0x01BF0x011Byte起始磁头(StartHead)0x01C00x026位起始扇区(StartSector):只用0~5位,后面两位被起始柱面使用0x01C10x0310位起始柱面(StartCylinder):共10位,最大值10230x01C20x041Byte分区类型描述(PartitionTypeIndicator),分区类型0x01C30x051Byte结束磁头(EndHead)0x01C40x066位结束扇区(EndSector):只用0~5位,后面两位被结束柱面使用0x01C50x0710位结束柱面(EndCylinder):共10位,最大值10230x01C60x084Byte本分区之前使用的扇区数(SectorsPrecedingPartition)0x01CA0x0C4Byte本分区的总扇区数(Sectorsinpartition)分区类型描述(PartitionTypeIndicator)代码类型0x00Dos或Windows不允许使用,视为非法0x01FAT120x02XENIXroot0x03XENIXusr0x04FAT16小于32MB0x05Extended0x06FAT16大于32MB0x08AIX0x09AIXbootable0x0AOS/2BootManage0x0BWindows95FAT320x0CWindows95FAT320x0EWindows95FAT160x0FWindows95Extended(>8GB)0x10OPUS0x11HiddenFAT120x12Compaqdiagnost0x14HiddenFAT16<32M0x16HiddenFAT160x17HiddenHPFS/NTFS0x18ASTWindowsswap0x1BHiddenFAT320x1CHiddenFAT32partition(UsingLBA-modeINT13extensions)0x1EHiddenLBAVFATpartition0x24NECDOS0x3CPartitionMagic0x40Venix802860x41PPCPrePBoot0x42SFS0x4DQNX4.x0x4EQNX4.x2ndpart0x4FQNX4.x3rdpart0x50OnTrackDM0x51OnTrackDM6Aux0x52CP/M0x53OnTrackDM6Aux0x54OnTrackDM60x55EZ-Drive0x56GoldenBow0x5CPriamEdisk0x61SpeedStor0x63GNUHURDorSys0x64NovellNetware0x65NovellNetware0x70DiskSecureMult0x75PC/IX0x80OldMinix0x81Minix/OldLinux0x82Linuxswap0x83Linux0x84OS/2hiddenC:0x85LinuxExtended0x86NTFSvolumeSet0x87NTFSvolumeSet0x8eLinuxLVM0x93Amoebba0x94AmoebbaBBT0xA0IBMThinkpadhidden0xA5BSD/3860xA6OpenBSD0xA7NextSTEP0xB7BSDIfs0xB8BSDIswap0xC0DR-DOS/NovellDossecuredpartition0xC1DR-DOS/sec0xC4DR-DOS/sec0xC6DR-DOS/sec0xC7Syrinx0xDBCP/M/CTOS0xE1DOSaccess0xE3DOSR/00xE4SpeedStor0xEBBeOSfs0xF1SpeedStor0xF2DOS3.3+secondarypartition0xF4SpeedStor0xFELANStep0xFFBBT采用DPT同一块硬盘可以安装多种文件系统而互不影响====================================================扩展分区====================================================按照DPT中要求,linux最多限制有4个主分区1)也就是你可以把硬盘分为4个主分区/dev/sda1(主分区)/dev/sda2(主分区)/dev/sda3(主分区)/dev/sda4(主分区)如果需要把硬盘分为多4个分区,那么必须使用扩展分区,扩展分区做多1个,在扩展分区下面在设立若干个逻辑分区:/dev/sda1(主分区)/dev/sda2(主分区)/dev/sda3(扩展分区)/dev/sda5(逻辑分区)/dev/sda6(逻辑分区)/dev/sda7(逻辑分区)注意:扩展分区的分区类型描述(PartitionTypeIndicator)为0x85逻辑分区并不是从sda4开始,sda4固定分配给主分区

LBAandCHS关于硬盘的寻址与定位有两种方式:CHS是24位寻址,LBS是可以支持64位寻址CHS(cylinders-heads-sectors)CHS寻址模式将硬盘划分为磁头(Heads)、柱面(Cylinder)、扇区(Sector)。柱面(Cylinder):所有磁片中半径相同的同心磁道构成“柱面",意思是这一系列的磁道垂直叠在一起,就形成一个柱面的形状。简单地理解,柱面数=磁道数。磁头(Heads):每张磁片的正反两面各有一个磁头,一个磁头对应一张磁片的一个面。因此,用第几磁头就可以表示数据在哪个磁面。扇区(Sector):将磁道划分为若干个小的区段,就是扇区。虽然很小,但实际是一个扇子的形状,故称为扇区。每个扇区的容量为512字节。知道了磁头数、柱面数、扇区数,就可以很容易地确定数据保存在硬盘的哪个位置。也很容易确定硬盘的容量,其计算公式是:硬盘容量=磁头数×柱面数×扇区数×512字节CHS限制1:BIOSINT13h接口柱面地址10位 1024磁头地址8位 256扇区地址6位 63(扇区从1开始,并不是从0开始)共24位的寻址方式,最大硬盘空间8GBCHS限制2:IDE(ATA)柱面地址16位 65536磁头地址4位 16扇区地址6位 63共24位的寻址方式,最大硬盘空间127.5GBCHS目前基本上不再使用,由于24位寻址空间的局限太大,目前普片采用LBA方式采用CHS寻址,MBR地址为0柱面、0磁头、1扇区LBA(LogicalBlockAddress)LBA是非常单纯的一种寻址模式﹔从0开始编号来定位区块,第一区块LBA=0,第二区块LBA=1,依此类推。这种寻址模式取代了原先操作系统必须面对存储设备硬件构造的方式。最具代表性的首推CHS(cylinders-heads-sectors,磁柱-磁头-扇区)寻址模式LBA最大的好处能偷突破CHS24bit限制,老式设备支持28bitLBA,新设备一般支持48bitLBA采用LBA寻址,MBR地址为LBA-0boot.img和core.img安装在了解上面的基础知识后,在回到我们的GRUB2,我们知道boot.img将会拷贝到MBR,也就是LBA-0的位置,那么core.img将会被放置在什么地方?MBR与GPT有不同解决方案:请参考/software/grub/manual/grub.html#BIOS-installationMBR在MBR和第一个partition之间有一段空白磁盘空间。大伙还记得5.3DPT中fdisk命令查看第一个分区的位置从2048sector(LBA2048)开始,那么前面之一段都是空白。这个空白磁盘空间有各种名称"boottrack","MBRgap","embeddingarea",但是有至少必须32Kbyte,一般来说core.img将会被拷贝到这个区域中2)GPTGPT作为UEF的一部分,也能够被使用在BIOS平台上,但是必须得有一个专门的GPT分区,这个分区至少32KB大小,建议1M,名字为BIOSBootPartition,然后core.img拷贝到这个分区。采用GPT方案有好处,不会使用"MBRgap"区域。本文中将描述第一种MBR方案,也就是当运行grub2-install命令,至少会做两件事情拷贝boot.img到LBA-0的MBR引导代码中拷贝core.img到LBA-1开始到LBA-31中的空闲代码中====================================================深入研究mbr.bin====================================================除了上面的,其实grub2-install还完成了其它的工作,有兴趣可以研究下,在这里进行一个额外的对比给大家看看:mbr.bin(我们已经在6.2MBR中使用DD命令导出的MBR)/boot/grub2/i386-pc/boot.img然后使用命令hexdump导出文件[root@controlleri386-pc]#hexdump-Cvboot.img00000000eb639000000000000000000000000000|.c|0000001000000000000000000000000000000000||0000002000000000000000000000000000000000||0000003000000000000000000000000000000000||0000004000000000000000000000000000000000||0000005000000000000000000000008001000000||0000006000000000fffaeb05f6c2807405f6c270|t...p|000000707402b280ea797c000031c08ed88ed0bc|ty|..1|000000800020fba0647c3cff740288c252be057c|...d|<.t...R..||00000090b441bbaa55cd135a52723d81fb55aa75|.A..U..ZRr=..U.u|000000a03783e101743231c0894404408844ff89|7...t21..D.@.D..|000000b04402c7041000668b1e5c7c66895c0866|Df..\|f.\.f|000000c08b1e607c66895c0cc744060070b442cd|..`|f.\..D..p.B.|000000d0137205bb0070eb76b408cd13730d5a84|.r...p.vs.Z.|000000e0d20f83de00be857de98200660fb6c688|}...f|000000f064ff40668944040fb6d1c1e20288e888|d.@f.D|00000100f4408944080fb6c2c0e80266890466a1|.@.Df..f.|00000110607c6609c0754e66a15c7c6631d266f7|`|f..uNf.\|f1.f.|000001203488d131d266f774043b44087d37fec1|4..1.f.t.;D.}7..|0000013088c530c0c1e80208c188d05a88c6bb00|..0Z|00000140708ec331dbb80102cd13721e8cc3601e|p..1r...`.|00000150b900018edb31f6bf00808ec6fcf3a51f|1|0000016061ff265a7cbe807deb03be8f7de83400|a.&Z|..}}.4.|00000170be947de82e00cd18ebfe475255422000|..}GRUB.|0000018047656f6d0048617264204469736b0052|Geom.HardDisk.R|0000019065616400204572726f720d0a00bb0100|ead.Error|000001a0b40ecd10ac3c0075f4c3000000000000|<.u|000001b000000000000000000000000000002412|$.|000001c00f090052bebd7d31c0cd13468a0c84c9|...R..}1...F|000001d0750fbeda7de8ccffeb96466c6f707079|u...}Floppy|000001e000bb00708ec331dbb80102b500b600cd|...p..1|000001f01372d4b601b54fe9f1fe0000000055aa|.rOU.|00000200然后可以文本比较工具进行比较,贴图如下,左边是/boot/grub2/i386-pc/boot.img大致有四处不同1)0x0003~0x0040,/boot/grub2/i386-pc/boot.img全为0,在真正的磁盘MBR中,被grub2-install填入了必要的数据。注意:0x0000~0x0002为eb6360汇编为jmpshort0x0067,中间这部分被grub2-insall装填部分数据,暂时不知道是为什么使用2)0x0066~0x0067,/boot/grub2/i386-pc/boot.img为eb05,被grub2-install修改为909090为nop指令,这里修改了两个nop指令3)0x01b8~0x01bb,/boot/grub2/i386-pc/boot.img00000000,被grub2-install修改为a7360800,这部分代码请参考/wiki/Master_boot_record其中的StructureofamodernstandardMBR,我拷贝到这里作参考被修改的这4个Byte[a7360800]为32bitDiskSignature,它是可选的,我想可能是为了UEFI使用。4)0x01be~0x01fd,DPT硬盘分区表部分,保持不变grub2-install不会去修改如果大家有兴趣可以去研究代码,知道grub2-install还有很多工作,这里就不在描述。硬盘总结一块SCSI硬盘逻辑结构简单来说如下图所示:LBA0:固定存储MBR,一般GRUB2的boot.img就存放在这里LBA1~LBA2047:被称为“EmbeddingArea”“MBRGap”,一般GRUB2的core.img就存放这里LBA2048后面为我的两个硬盘分区,他们放在连续的区域

启动过程在前面介绍相关的知识,咱们回归到主题,现在开始启动过程BIOS系统上电之后,由固化在ROM里面的BIOS代码运行,进行硬件检查及初始化工作。有关BIOS具体运行原理在这里不作描述,有兴趣的请参考相关书籍。最近的EFI作为BIOS的替代或升级,支持更多的功能,在这里也不做描述。BIOS运行的最后两步操作我们必须知道加载LBA-0(或者CHS的0柱面、0磁头、1扇区)的MBR,共512字节到内存中0x7C00位置从内存0x7C00位置运行我们知道拷贝到MBR中的正式GRUB2boot.img,从这个时候开始,GRUB2正式登上历史舞台。但是请注意,并不是说BIOS就全部退出舞台,BIOS依然为GRUB2提供底层服务,比如硬盘读取等等(通过BIOSINT13功能),GRUB2在一穷二白基础上还离不开BIOS============================================地址0x7C00============================================这里有个问题,为什么BIOS会加载MBR到0x7C00的位置,而不是其他的位置?答案请参考:/questions/2058690/what-is-significance-of-memory-at-00007c00-to-booting-sequence这个问题是应该由最初的IBMPCBIOS的设计者们(软件及硬件)来回答,但是简单的答案可能是0x7C00是距离地下最初32K安装内存有1K大小(512Bytes给MBR以及另外的512Bytes作运行时堆栈使用)

GRUB2中boot.imgBIOS加载MBR到0x7C00并从该处运行的时候,实际上就是boot.img开始运行了,我们的工作来了,我们将介绍boot.img将要干什么,可以从官方网站/software/grub/.去使用git下载源码,源码是采用AT&T风格的汇编。这里我们采用反汇编的方式取得Intel风格代码我们已经在6.2MBR中使用DD命令导出的MBR安装nasm[root@controlleri386-pc]#yuminstallnasmLoadedplugins:fastestmirror,langpacksLoadingmirrorspeedsfromcachedhostfile*base:*extras:*updates:Packagenasm-2.10.07-7.el7.x86_64alreadyinstalledandlatestversionNothingtodo进行反汇编[root@controllerimage]#ndisasm-o0x7c00mbr.bin>mbr.asm这里加入-o0x7c00是告诉反汇编器这段代码在0x7c00处运行,使生成的mbr.asm更加容易理解在这里我把反汇编的代码mbr.asm作为附件供参考,后面的boot.S是官方源码:注意:boot.S是AT&T汇编语法,反编译的mbr.asm是Intel汇编语法,两者有区别,如果感兴趣,请参阅相关文档进行学习。下面详细讲解主要流程。Step1无条件跳转/*位于0x7C00的语句就是一条跳转语句,跳转到0x7c65处*/00007C00EB63jmpshort0x7c65Step2初始化/*禁止中断目前是不安全的*/00007C65FAcli00007C6690nop00007C6790nop/**注意,BIOS在把控制权交给MBR前,会在DL中设置正确的Bit位,表明MBR来源*DL=00h1stfloppydisk(“driveA:”)*DL=01h2ndfloppydisk(“driveB:”)*DL=80h1stharddisk*DL=81h2ndharddisk*因为我们是磁盘加载的MBR,所以我们dl里面存的是0x80。*下面这段应为来自官方源代码注释*ThisisaworkaroundforbuggyBIOSeswhichdon'tpassboot*drivecorrectly.IfGRUBisinstalledintoaHDD,checkif*DLismaskedcorrectly.Ifnot,assumethattheBIOSpassed*abogusvalueandsetDLto0x80,sincethisistheonly*possiblebootdrive.IfGRUBisinstalledintoafloppy,*thisdoesnothing(onlyjump).*意思是有些BIOS类型并没有正确的设置DL寄存器,我们检测是否DL置了0x80bit位*如过不是,我们手工设置为DL为0x80*注意test相当于用and(位与)判断,实际上是测试Bit位是否被置上*/00007C68F6C280testdl,0x8000007C6B7405jz0x7c72/*如果DL不在区间0-0x0fand0x80-0x8f.那么需要设置DL为0x80*如果DL在区间0x10-0x7f,那么不需要设置DL为0x80*/00007C6DF6C270testdl,0x7000007C707402jz0x7c7400007C72B280movdl,0x8000007C74EA797C0000jmpword0x0:0x7c79/*ax清零,ds赋值0,ss赋值0*/00007C7931C0xorax,ax00007C7B8ED8movds,ax00007C7D8ED0movss,ax/*设置堆栈:设置了实模式下的堆栈段地址(栈顶位置)0x2000*/00007C7FBC0020movsp,0x2000/*恢复中断再次安全*/00007C82FBsti/*从内存0x7c64读入AL,在0x7c64,我们值为0xFF,比较两个数为相等*那么不执行0x7c8a*这里只是检查我们是否有forceddiskreference*/00007C83A0647Cmoval,[0x7c64]00007C863CFFcmpal,0xff00007C887402jz0x7c8c00007C8A88C2movdl,alStep3判断硬盘是否支持LBA还是只支持CHS/*在前面我们介绍了CHS及LBA,这两种对硬盘读寻址有很大不同*在加载后续GRUB2core.img的前,我们必须判断硬盘是否支持LBA还是只支持CHS*//*savedrivereferencefirstthing!*/00007C8C52pushdx/*set%sitothediskaddresspacket*/00007C8DBE057Cmovsi,0x7c05/*调用BIOSINT13功能,检查硬盘是否支持LBA*通过BIOS调用INT0x13来确定是否支持扩展,LBA扩展功能分两个子集,如下:第一个子集提供了访问大硬盘所必须的功能,包括:****************************************************************1.检查扩展是否存在:ah=41h,bx=0x55aa,dl=drive(0×80~0xff)2.扩展读:ah=42h3.扩展写:ah=43h4.校验扇区:ah=44h5.扩展定位:ah=47h6.取得驱动器参数:ah=48h****************************************************************第二个子集提供了对软件控制驱动器锁定和弹出的支持,包括:****************************************************************1.检查扩展:ah=41h2.锁定/解锁驱动器:ah=45h3.弹出驱动器:ah=46h4.取得驱动器参数:ah=48h5.取得扩展驱动器改变状态:ah=49h****************************************************************我们采用的是ah=41h,bx=0x55aa,dl=0x80,所以是检查扩展是否存在。这个操作会改变CF标志位的值。如果支持LBA,那么CF=0,否则CF=1。*/00007C90B441movah,0x4100007C92BBAA55movbx,0x55aa00007C95CD13int0x13/**%dlmayhavebeenclobberedbyINT13,AH=41H.*Thishappens,forexample,withASTBIOS1.04.*/00007C975Apopdx00007C9852pushdx/**下面的三个跳转语句都到0x7cd8位置,那个位置是CHS部分*有下面几种情况*1)探查结果CF=1(0x7c99jc0x7cd8),二话不说,跳转到CHS模式*2)CF=0是否就采用LBA呢?也不一定,还需要判断bx==0x55aa,如果不等则CHS模式*3)有一个FORCE_LBAByte(INT13返回寄存器cx中),如果这个位是1,那么直接采用LBAMODE*/00007C99723Djc0x7cd800007C9B81FB55AAcmpbx,0xaa5500007C9F7537jnz0x7cd800007CA183E101andcx,byte+0x100007CA47432jz0x7cd8/*由于现在硬盘都是LBA模式,这里我们就不在对CHS模式介绍了,直接进入LBA*/Step4采用LBA加载core.img第一个扇区/*对于BIOSLBA读来说,最重要的是设置SI所在内存块的值由si及其偏移量指向的内存保存着磁盘参数块SI在上面7.2.3中被设置为0x7c05,根据下面的偏移量来设置如下:******************************************************************偏移 地址 大小 位数 描述 值00h 0x7c05 BYTE 8 数据块的大小(10hor18h) 0x1001h 0x7c06 BYTE 8 保留,必须为0 0x0002h 0x7c07 WORD 16 传输数据块数,传输完成后保存传输的块数 0x0104h 0x7c09 DWORD 32 传输时的数据缓存地址 0x7000:[0x0000]08h 0x7c0d QWORD 64 起始绝对扇区号(即起始扇区的LBA号码)0x01******************************************************************下面的很多代码都是在初始化SI所指向的内存注意[si+0x4]表示的是segment:offsetpointertothememorybuffertowhichsectorswillbetransferred(notethatx86is\o"Little-endian"little-endian:ifdeclaringthesegmentandoffsetseparately,theoffsetmustbedeclaredbeforethesegment)*//*下面这个首先把内存中si+0x4的位置,传输数据时的数据缓存地址*也就是0x7c09~0x7c0a16bit置为0*/00007CA631C0xorax,ax00007CA8894404mov[si+0x4],ax/*AX现在值为0x0001*/00007CAB40incax/*setthemodetonon-zero也就是把内存[si-1]0x7c04的值置为1*(也就是mode被置1,表示LBA扩展读;如果是0,就是CHS寻址读)*/00007CAC8844FFmov[si-0x1],al/*把内存0x7c07-0x7c0816bit的值置为1*也就是需要传输数据块数,这里我们将要传输core.img中第一个扇区*/00007CAF894402mov[si+0x2],ax/*thesizeandthereservedbyte*把内存0x7c05的值置为0x10(固定)*把内存0x7c06的值置为0x00(固定)*/00007CB2C7041000movword[si],0x10/*theabsoluteaddress起始绝对扇区号(即起始扇区的LBA-1号码)0x7c0d~0x7c1132bit:内存0x7c5c值为010000000x7c12~0x7c1532bit:内存0x7c60值为00000000*最后就是制定LBA地址为LBA1,也就是第二个扇区,在前面我么说了这个/00007CB6668B1E5C7Cmovebx,[0x7c5c]00007CBB66895C08mov[si+0x8],ebx00007CBF668B1E607Cmovebx,[0x7c60]00007CC466895C0Cmov[si+0xc],ebx/*thesegmentofbufferaddress传输时的数据缓存地址*也就是0x7c0b~0x7c0c16bit置为0x7000*0x7c09~0x7c0a16bit置为在前面已经被置为0*数据缓存地址为:0x7000:[0x0000]*注意0x7000为段地址,偏移为0x0000,实际物力地址将是0x70000*/00007CC8C744060070movword[si+0x6],0x7000/**调用BIOS功能"INT0x13Function0x42"*从硬盘读指定扇区到内存中*参数如下 %ah=0x42(在上面一节中2.扩展读:ah=42h)* %dl=drivenumber(在7.2.2中已经被置为0x80)* %ds:%si=segment:offsetofdiskaddresspacket* (DS在7.2.2中已经被初始化为0,SI在上面被置为0x7c05)*返回:* %al=0x0成功;errcodeonfailure*/00007CCDB442movah,0x4200007CCFCD13int0x13/*LBA扩展读失败,可能不支持LBA,跳转采用CHS方式*/00007CD17205jc0x7cd8/*进入下一步,准备拷贝刚读入的core.img第一个扇区数据到指定位置*/00007CD3BB0070movbx,0x700000007CD6EB76jmpshort0x7d4e/*总结,上面这段这么多的汇编代码就是完成一个功能:调用BIOSINT14ah=0x42把硬盘LBA-1的512字节传输到内存0x7000:[0x0000]位置注意:0x7000:[0x0000]实际上是段地址:[段内偏移]实际地址为0x70000*/Step5拷贝core.img第一个扇区到内存指定位置/**Weneedtosave%cxand%sibecausethestartupcodein*kernelusesthemwithoutinitializingthem.*/00007D4E60pushaw00007D4F1Epushds/*循环256次:0x100*/00007D50B90001movcx,0x100/*bx在上面被置为0x7000,也就是从硬盘拷贝过来的地址*/00007D538EDBmovds,bx00007D5531F6xorsi,si/*di是我们目标地址0x8000,也就是core.img要从这个位置开始执行*/00007D57BF0080movdi,0x8000/*初始化es为0*/00007D5A8EC6moves,si/*重复前固定操作,清除

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论