05月09, 2014

MBR引导详解

注意:这是一篇从旧博客恢复的文章。

原地址:http://freemeepo.com/blog/archives/122


硬盘基本知识

参考维基百科:硬盘

alt

A:磁道

B:扇面

C:扇区

D:(扇区组)

硬盘有数个盘片,每盘片两个面,每个面一个磁头。

当磁盘旋转时,磁头若保持在一个位置上,则每个磁头都会在磁盘表面划出一个圆形轨迹,这些圆形轨迹就叫做磁道。

处于同一半径圆的多个磁道组成一个柱面。

每面磁道数=柱面数

容量=面(磁头)数每面磁道数每磁道扇区数*每扇区字节数

每扇区字节数通常为512字节

计算机启动过程

参考:计算机是如何启动的?

引用回复中的一段话(有修改):

  1. 计算机开机时,CPU(x86架构)默认执行0ffffh:0000h处的指令,而此内存地址应该存放的就是bios rom
  2. bios执行完post等后,将引导设备的mbr复制到内存地址0:7c00h处,跳转执行此处指令
  3. 现在一般引导设备中的mbr是grub或lilo这样的引导程序,这样的程序首先将自己复制到0:6c00h处执行,在主分区表中搜索活动分区,将用户选择的活动分区的第一个扇区读入到07c00h处,调转到07c00h处执行。注:以上均在实模式中执行,还未进入保护模式
  4. 为加载内核做准备,并将控制权交给kernel,系统启动成功。注:这一步进入保护模式

当然这是现在一般的启动流程,当然如果自己写os,可以直接在引导设备的mbr中写直接加载内核的代码,将编译的代码dd入引导设备的mbr中即可。

我们需要知道的是,执行完BIOS之后,就会把硬盘的0面0磁道1扇区(扇区从1开始计数)的512字节复制到0:7c00h,并修改CS:IP到此处。

MBR的结构

参考维基百科:主引导记录(Master Boot Record,缩写:MBR)

地址 描述 长度 (字节)
Hex Oct Dec
0000 0000 0 代码区 440 (最大 446)
01B8 0670 440 选用磁盘标志 4
01BC 0674 444 一般为空值; 0x0000 2
01BE 0676 446 标准 MBR 分区表规划 (四个16 byte的主分区表入口) 64
01FE 0776 510 55h MBR 有效标志: 0x55AA 2
01FF 0777 511 AAh
MBR, 总大小: 446 + 64 + 2 = 512

也就是说,CPU复制到0:7c00h的512字节,包括了代码和分区表。

其中,代码区的内容就是一段16位汇编程序,内容是一个boot loader,即引导加载程序,在windows中就是一个选操作系统的菜单。而在linux中普遍使用grub,grub程序就存在于这个代码区。

从MBR的格式中可以看出,MBR格式的分区表结构,分区可以精确到扇区。不过鸟哥的书中说是只能精确到柱面。为此我在虚拟机中测试了一下,用DiskGenius分区,确认确实是可以精确到扇区的。

分区表结构

MBR分区表提供4个分区表项位置,每个分区用16个字节描述。这16个字节的组成如下:

硬盘分区结构信息
偏移 长度(字节) 意义
00H 1 分区状态:00-->非活动分区;80--> 活动分区; 其它数值没有意义
01H 1 分区起始磁头号(HEAD),用到全部8位
02H 2 分区起始扇区号(SECTOR),占据02H的位0-5; 该分区的起始磁柱号(CYLINDER),占据 02H的位6-7和03H的全部8位
04H 1 文件系统标志位
05H 1 分区结束磁头号(HEAD),用到全部8位
06H 2 分区结束扇区号(SECTOR),占据06H的位0-5; 该分区的结束磁柱号(CYLINDER),占据 06H的位6-7和07H的全部8位
08H 4 分区起始相对扇区号
0CH 4 分区总的扇区数

其中文件系统标志位可以参考维基百科:文件系统标志位

MBR只有4个分区表项位置,也就是说,只能有4个分区。但是MBR使用扩展分区的方法实现了多分区。

引用维基百科的一段话:

从主引导记录的结构可以知道,它仅仅包含一个64个字节的硬盘分区表。由于每个分区信息需要16个字节,所以对于采用MBR型分区结构的硬盘,最多只能识别4个主要分区(Primary partition)。所以对于一个采用此种分区结构的硬盘来说,想要得到4个以上的主要分区是不可能的。这里就需要引出扩展分区了。扩展分区也是主要分区的一种,但它与主分区的不同在于理论上可以划分为无数个逻辑分区。

扩展分区中逻辑驱动器的引导记录是链式的。每一个逻辑分区都有一个和MBR结构类似的扩展引导记录(EBR),其分区表的第一项指向该逻辑分区本身的引导扇区,第二项指向下一个逻辑驱动器的EBR,分区表第三、第四项没有用到。

也就是说,一个扩展分区相当于一个链式结构,只需要有头指针就可以得到这一串分区的信息。

在MBR分区表中最多4个主分区或者3个主分区+1个扩展分区。 扩展分区只能有一个,它可以串起来多个逻辑分区。

意思就是扩展分区也要占用4个分区位置当中的一个,但是这个位置所表示的分区可以是一个串。

MBR引导代码

在虚拟机里创建一个硬盘,启动PE,使用Paragon Partition Manager读取出0面0磁道1扇区(当然也可以启动linux,用linux的工具),数据如下:

在这里是windows的boot loader

alt

(上图中的MBR的分区情况是1个主分区,3个逻辑分区)

对代码反汇编如下(注释在代码中):

点击图标↔可以expand code

0:7C00 33C0          XOR     AX,AX
0:7C02 8ED0          MOV     SS,AX
0:7C04 BC007C        MOV     SP,7C00                ;ss:sp -> 0:7c00
0:7C07 FB            STI                            ;屏蔽中断
0:7C08 50            PUSH    AX
0:7C09 07            POP     ES
0:7C0A 50            PUSH    AX
0:7C0B 1F            POP     DS                     ;es=ds=0
0:7C0C FC            CLD
0:7C0D BE1B7C        MOV     SI,7C1B
0:7C10 BF1B06        MOV     DI,061B
0:7C13 50            PUSH    AX
0:7C14 57            PUSH    DI
0:7C15 B9E501        MOV     CX,01E5
0:7C18 F3            REPZ
0:7C19 A4            MOVSB                          ;复制[0:7c1bh,0:7E00)的01e5字节到0:061b
0:7C1A CB            RETF                           ;cs:ip -> 0:061b
;原0:7C1B 下面偏移地址记录为复制的代码的地址 相当于偏移了-7600
0:061B BDBE07        MOV     BP,07BE
0:061E B104          MOV     CL,04
0:0620 386E00        CMP     [BP+00],CH             ;由于之前repz movsb操作,cx为0结束循环,ch为0
0:0623 7C09          JL      062E                   ;80h是负数,因此是判断是否为活动分区,是则跳转
0:0625 7513          JNZ     063A                   ;判断是否为非活动分区,不是则跳转
0:0627 83C510        ADD     BP,+10                 ;BP指向下一个分区表项
0:062A E2F4          LOOP    0620                   ;循环对4个分区表项操作
0:062C CD18          INT     18                     ;如果4个分区表项全都是非活动分区,则会执行到此,执行ROM BASIC
0:062E 8BF5          MOV     SI,BP                  ;是活动分区则跳转至此
0:0630 83C610        ADD     SI,+10
0:0633 49            DEC     CX
0:0634 7419          JZ      064F                   ;分区检测完后跳转
0:0636 382C          CMP     [SI],CH
0:0638 74F6          JZ      0630                   ;判断是否为非活动分区,是则检测下一个分区表项
0:063A A0B507        MOV     AL,[07B5]              ;不是活动分区也不是非活动分区则跳转至此,显示错误信息
0:063D B407          MOV     AH,07                  ;这个分区表不完整,显示的信息可能也有些问题
0:063F 8BF0          MOV     SI,AX
0:0641 AC            LODSB                          ;从[si]读入一个字节到al
0:0642 3C00          CMP     AL,00
0:0644 74FC          JZ      0642                   ;如果当前处理的字节是0,则向上跳转,相当于while(1)
0:0646 BB0700        MOV     BX,0007
0:0649 B40E          MOV     AH,0E
0:064B CD10          INT     10                     ;与上面对bx ah的设置一起,显示一个al字符
0:064D EBF2          JMP     0641
0:064F 884E10        MOV     [BP+10],CL             ;分区检测完后跳转至此
;接下来实现的功能是把活动分区对应的第一个扇区的512个字节数据读到0000:7C00处
;cs:ip指向0000:7c00,执行活动分区的系统引导程序
;实在无力逐句翻译了……
0:0652 E84600        CALL    069B
0:0655 732A          JNB     0681
0:0657 FE4610        INC     BYTE PTR [BP+10]
0:065A 807E040B      CMP     BYTE PTR [BP+04],0B
0:065E 740B          JZ      066B
0:0660 807E040C      CMP     BYTE PTR [BP+04],0C
0:0664 7405          JZ      066B
0:0666 A0B607        MOV     AL,[07B6]
0:0669 75D2          JNZ     063D
0:066B 80460206      ADD     BYTE PTR [BP+02],06
0:066F 83460806      ADD     WORD PTR [BP+08],+06
0:0673 83560A00      ADC     WORD PTR [BP+0A],+00
0:0677 E82100        CALL    069B
0:067A 7305          JNB     0681
0:067C A0B607        MOV     AL,[07B6]
0:067F EBBC          JMP     063D
0:0681 813EFE7D55AA  CMP     WORD PTR [7DFE],AA55
0:0687 740B          JZ      0694
0:0689 807E1000      CMP     BYTE PTR [BP+10],00
0:068D 74C8          JZ      0657
0:068F A0B707        MOV     AL,[07B7]
0:0692 EBA9          JMP     063D
0:0694 8BFC          MOV     DI,SP
0:0696 1E            PUSH    DS
0:0697 57            PUSH    DI
0:0698 8BF5          MOV     SI,BP
0:069A CB            RETF
0:069B BF0500        MOV     DI,0005
0:069E 8A5600        MOV     DL,[BP+00]
0:06A1 B408          MOV     AH,08
0:06A3 CD13          INT     13
0:06A5 7223          JB      01CA
0:06A7 8AC1          MOV     AL,CL
0:06A9 243F          AND     AL,3F
0:06AB 98            CBW
0:06AC 8ADE          MOV     BL,DH
0:06AE 8AFC          MOV     BH,AH
0:06B0 43            INC     BX
0:06B1 F7E3          MUL     BX
0:06B3 8BD1          MOV     DX,CX
0:06B5 86D6          XCHG    DL,DH
0:06B7 B106          MOV     CL,06
0:06B9 D2EE          SHR     DH,CL
0:06BB 42            INC     DX
0:06BC F7E2          MUL     DX
0:06BE 39560A        CMP     [BP+0A],DX
0:06C1 7723          JA      01E6
0:06C3 7205          JB      01CA
0:06C5 394608        CMP     [BP+08],AX
0:06C8 731C          JNB     01E6
0:06CA B80102        MOV     AX,0201
0:06CD BB007C        MOV     BX,7C00
0:06D0 8B4E02        MOV     CX,[BP+02]
0:06D3 8B5600        MOV     DX,[BP+00]
0:06D6 CD13          INT     13
0:06D8 7351          JNB     022B
0:06DA 4F            DEC     DI
0:06DB 744E          JZ      022B
0:06DD 32E4          XOR     AH,AH
0:06DF 8A5600        MOV     DL,[BP+00]
0:06E2 CD13          INT     13
0:06E4 EBE4          JMP     01CA
0:06E6 8A5600        MOV     DL,[BP+00]
0:06E9 60            DB      60
0:06EA BBAA55        MOV     BX,55AA
0:06ED B441          MOV     AH,41
0:06EF CD13          INT     13
0:06F1 7236          JB      0229
0:06F3 81FB55AA      CMP     BX,AA55
0:06F7 7530          JNZ     0229
0:06F9 F6C101        TEST    CL,01
0:06FC 742B          JZ      0229
0:06FE 61            DB      61
0:06FF 60            DB      60
;原7D00
0:0700: 6A 00 6A 00 FF 76 0A FF 76 08 6A 00 68 00 7C 6A ;                 
0:0710: 01 6A 10 B4 42 8B F4 CD 13 61 61 73 0E 4F 74 0B ;                 
0:0720: 32 E4 8A 56 00 CD 13 EB D6 61 F9 C3 49 6E 76 61 ;          a  Inva
0:0730: 6C 69 64 20 70 61 72 74 69 74 69 6F 6E 20 74 61 ; lid partition ta
0:0740: 62 6C 65 00 45 72 72 6F 72 20 6C 6F 61 64 69 6E ; ble.Error loadin
0:0750: 67 20 6F 70 65 72 61 74 69 6E 67 20 73 79 73 74 ; g operating syst
0:0760: 65 6D 00 4D 69 73 73 69 6E 67 20 6F 70 65 72 61 ; em.Missing opera
0:0770: 74 69 6E 67 20 73 79 73 74 65 6D 00 00 00 00 00 ; ting system     
0:0780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0:0790: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0:07A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0:07B0: 00 00 00 00 00 00 00 00 
;非代码区(分区表等,根据分区不同而不同)
;原7D88
0:07B0:                (07B8->) E2 B6 E2 B6 00 00 80 01
0:07C0: 01 00 07 07 FF 3B 3F 00 00 00 E1 5D 06 00 00 00
0:07D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0:07E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0:07F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA ;至此512字节结束
0:0800: ;原7E00

本文链接:https://debug.fanzheng.org/post/detailed-MBR-boot.html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。