主引导扇区代码(MBR)分析(转)

 
MBR( Master Boot Record )主引导记录包含两部分的内容,前446字节为启动代码及数据,而
; 从446(0x1BE)开始则是分区表,分区表由四个分区项组成,每个分区项数据为16字节,记录了
; 启动时需要的分区参数。
;
; 在CPU上电之后,若由硬盘启动,则BIOS将硬盘的主引导记录(位于0柱面、0磁道、1扇区)读
; 入7C00处,然后将控制权交给主引导代码。主引导代码的任务包括:
; (1) 扫描分区表,找到一个激活(可引导)分区;
; (2) 找到激活分区的起始扇区;
; (3) 将激活分区的引导扇区装载到内存7C00处;
; (4) 将控制权交给引导扇区代码;

; 如果主引导代码无法完成上述任务,它将显示以下错误信息之一:
; No active partition.
; Invalid partition table.
; Error loading operating system.
; Missing operating system.
;
;====================================================================================
; FAT16分区尺寸与LBA
;====================================================================================
; LBA   HeadsPerCylinder SectorsPerTrack  Maximum Size for Boot Partition
; Disabled 64     32     1GB
; Enabled  255     63     4GB
;
; 为了适应超过8G的硬盘,Windows2000忽略了Start CHS和End CHS,而使用StartLBA和TotalSector   
; 来确定分区在整个磁盘中的位置和大小。

;====================================================================================
;     分区表项结构(16字节)
;====================================================================================
;
; typedef struct _PARTITION_ENTRY
; {
;  UCHAR BootIndicator;  // 能否启动标志
;  UCHAR StartHead;   // 该分区起始磁头号
;  UCHAR StartSector;  // 起始柱面号高2位:6位起始扇区号
;  UCHAR StartCylinder;  // 起始柱面号低8位
;  UCHAR PartitionType;  // 分区类型
;  UCHAR EndHead;   // 该分区终止磁头号
;  UCHAR EndSector;   // 终止柱面号高2位:6位终止扇区号
;  UCHAR EndCylinder;  // 终止柱面号低8位
;  ULONG StartLBA;   // 起始扇区号
;  ULONG TotalSector;  // 分区尺寸(总扇区数)
; }PARTITION_ENTRY,*PPARTITION_ENTRY;
;
;====================================================================================
;    主引导记录(MBR)结构
;====================================================================================
; typedef struct _MASTER_BOOT_RECORD
; {
;  UCHAR    BootCode[446];
;  PARTITION_ENTRY  Partition[4];
;  USHORT    Signature;
; }MASTER_BOOT_RECORD,*PMASTER_BOOT_RECORD;
;
;==================================================================================== BITS   16   ; 生成16位代码而不是32位代码
SECTION  .text   ; 代码段
ORG   0600H  ; 指定程序被装入内存的起始位置
;====================================================================
;
; 宏和常量定义
;
;====================================================================
?     EQU  0  ; NASM不支持DW ?这样的语法,可以使用这样的定义
        ; 模拟,以使代码的可读性更强
ACTIVE_FLAG  EQU  80H  ; 激活(可引导)分区标志
NOT_ACTIVE_FLAG EQU  00H  ; 不激活标志
MBR_MOVE_ADDR EQU  0600H ; MBR先移动自身到该位置然后再运行
BOOT_SIGNATURE EQU  0AA55H ; 启动标志
SEC_SIG_OFF  EQU  01FEH ; 启动扇区的标志位置
;====================================================================
; 分区表项结构偏移
;====================================================================
BootIndicator EQU  0  ; 能否启动标志
StartHead  EQU  1  ; 该分区起始磁头号
StartSector  EQU  2  ; 起始柱面号高2位:6位起始扇区号
StartCylinder EQU  3  ; 起始柱面号低8位
PartitionType EQU  4  ; 分区类型
EndHead   EQU  5  ; 该分区终止磁头号
EndSector  EQU  6  ; 终止柱面号高2位:6位终止扇区号
EndCylinder  EQU  7  ; 终止柱面号低8位
StartLBA  EQU  8  ; 起始扇区号
TotalSector  EQU  12  ; 分区尺寸(总扇区数)
;====================================================================
; 常用的分区类型
;====================================================================
PARTITION_TYPE_EMPTY  EQU  00H ; 空分区
PARTITION_TYPE_FAT12  EQU  01H ; FAT12 ( < 32680 sectors )
PARTITION_TYPE_FAT16  EQU  04H ; FAT16 ( 32680 - 65535 sectors )
PARTITION_TYPE_EXTENDED  EQU  05H ; DOS EXTENDED
PARTITION_TYPE_BIGDOS_FAT16 EQU  06H ; FAT16 ( 33MB - 4GB )
PARTITION_TYPE_NTFS   EQU  07H ; NTFS
PARTITION_TYPE_FAT32  EQU  0BH ; FAT32
PARTITION_TYPE_FAT32_LBA EQU  0CH ; FAT32 LBA
PARTITION_TYPE_FAT16_LBA EQU  0EH ; FAT16 LBA
PARTITION_TYPE_EXTENDED_LBA EQU  0FH ; LBA EXTENDED
PARTITION_TYPE_DYNAMIC_DISK EQU  42H ; Dynamic Disk Volume

;====================================================================
; 主引导记录的入口
;====================================================================
_ENTRY_POINT:

; 初始化相关寄存器及标志位
CLI      ; 先关掉中断
CLD      ; 方向为向前递增
XOR  AX,AX   ; AX = 0
MOV  DS,AX   ; 设置数据段寄存器 DS:SI
MOV  ES,AX   ; 设置附加段寄存器 ES:DI
MOV  SS,AX   ; 设置堆栈段寄存器
MOV  BP,7C00H  ; 设置基址寄存器
MOV  SP,BP   ; 设置堆栈栈顶

; 将MBR代码移动到0600H处
MOV  SI,BP   ; SI = 7C00H
MOV  DI,MBR_MOVE_ADDR; DI = 0600H
MOV  CX,512   ; 待移动的字节数
REP  MOVSB
JMP  0:.RealStart
; 真正开始  
.RealStart:
; 保存引导驱动器号
MOV  BYTE [ DriveNumber ] , DL

;==================================================================== 
; 检查是否支持磁盘中断INT 13H的扩展
;====================================================================
MOV  AH,41H
MOV  BX,055AAH
INT  13H
JC  .LookupActive   ; 如果失败,进位标志为1
MOV  BYTE[DiskExtension],01H ; 设置支持磁盘扩展标志
.LookupActive:

; 查找激活分区
MOV  BP,PartitionTable   ; 指向分区表
MOV  BL,4      ; 最多4个分区
;检查激活分区
.CheckNext:
CMP  BYTE [BP+BootIndicator],ACTIVE_FLAG  ; 检查该分区是否激活
JZ  .FoundActive       ; 找到激活分区
CMP  BYTE [BP+BootIndicator],NOT_ACTIVE_FLAG ; 检查该分区是否激活
JNZ  .InvalidTable       ; 无效值
ADD  BP,10H         ; 指向下一个分区表项
DEC  BL
JZ  .NoActive        ; 没有找到激活分区
JMP  .CheckNext
;找到了激活分区
.FoundActive:
; 保存分区表项
MOV  AL,4
SUB  AL,BL      ; AL = 4-BL = 第一个激活分区表项索引(0-3)
MOV  BYTE [ActivePartition],AL ; 保存激活分区表项索引
MOV  DI,BP      ; DI = 激活分区项
MOV  DH,BYTE[BP+StartHead]  ; 该分区起始磁头号
MOV  CL,BYTE[BP+StartSector]  ; 起始柱面号高2位:6位起始扇区号
MOV  CH,BYTE[BP+StartCylinder] ; 起始柱面号低8位

; 保存起始扇区号
MOV  AX,WORD[BP+StartLBA+2]
MOV  WORD[DAP_SECTOR_LOW+2],AX
MOV  AX,WORD[BP+StartLBA] 
MOV  WORD[DAP_SECTOR_LOW],AX

; 检查确信只有一个激活分区
.Recheck:    
ADD  BP,10H      ; 指向下一个分区项
DEC  BL
JZ  .LoadBootSector    ; 装载该分区的引导扇区
CMP  BYTE [BP+BootIndicator],NOT_ACTIVE_FLAG ; 检查该分区是否激活
JNZ  .InvalidTable    ; 无效值
JMP  .Recheck
; 装载激活分区的引导扇区
.LoadBootSector:

; 设置驱动器号
MOV  DL,BYTE [DriveNumber]

; 检查是否支持扩展磁盘调用
CMP  BYTE [DiskExtension],01H
JNZ  .NoDiskExtension

; 使用扩展磁盘调用读取引导扇区
;
; INT 13H
;  AH = 42H
;  DL = Drive Number
;  DS:SI = 指向磁盘地址包的指针
;
MOV  SI,DAP_PACKET_SIZE
MOV  AH,42H
INT  13H
JC  .ErrorLoadOS
JMP  .CheckBootSector
.NoDiskExtension:
;====================================================================
;
; INT 13H
;  AH = 2        柱面号:0 - 1023
;  AL = 要读取的扇区数     磁头号:0 - 255   
;  CH = 柱面号低8位     扇区号:1 - 63 
;  CL = 柱面号高2位 : 6位扇区号 
;  DH = 磁头号
;  DL = 驱动器号
;  ES:BX = 缓冲区
;
;====================================================================
; 读取引导扇区
MOV  BX,7C00H
MOV  AX,0201H
INT  13H
JC  .ErrorLoadOS

; 检查引导扇区是否合法
.CheckBootSector:

; 装载引导扇区成功,检查引导标志
MOV  BX,7C00H
CMP  WORD [BX+SEC_SIG_OFF], BOOT_SIGNATURE  ; 检查引导标志
JNZ  .MissingOS    

; 准备跳转到激活扇区的引导扇区代码
; DL = 磁盘驱动器号
; DH = 激活分区号
; DI = 激活分区项
MOV  DL,BYTE [DriveNumber]
MOV  DH,BYTE [ActivePartition]
JMP  0:7C00H
; 没有激活分区
.NoActive:
MOV  SI,MsgNoActive
CALL ShowMessage
JMP  .Hang

; 无效分区表
.InvalidTable:
MOV  SI,MsgPartitionTable
CALL ShowMessage
JMP  .Hang

; 装载引导扇区失败
.ErrorLoadOS:
MOV  SI,MsgLoadingOS
CALL ShowMessage
JMP  .Hang

; 引导扇区不合法
.MissingOS:
MOV  SI,MsgMissingOS
CALL ShowMessage
.Hang:
JMP  .Hang

;====================================================================
;
; 显示一个字符串
; 输入:
;   DS:SI  = 字符串的起始地址(以NULL结束)
;  
;====================================================================
ShowMessage:
LODSB    ; AL = DS:[SI] SI = SI+1
OR  AL,AL    ; 检测是否遇到NULL字符串
JZ  .ShowEnd
MOV  AH,0EH
MOV  BX,07H
INT  10H
JMP  ShowMessage
.ShowEnd:
RET


;====================================================================
; 调试例程
;====================================================================
%IFDEF DEBUG

;====================================================================
;
; 显示一个字符
; 输入: AL = 待显示字符
;
;====================================================================
PrintChar:
PUSH AX
PUSH BX
MOV  AH,0EH
MOV  BX,7
INT  10H
POP  BX
POP  AX
RET


;====================================================================
;
; 显示16进制的值(将一个BYTE变为两个ASCII字符打印出来,用于调试)
; 输入: AL = 待显示的字节
;
;====================================================================
PrintByte:
PUSH BX
MOV  BH,AL

; 显示高4位
SHR  AL,4
AND  AL,0FH
ADD  AL,30H
CMP  AL,39H
JLE  .PrintIt
ADD  AL,07H
.PrintIt:
CALL PrintChar
; 显示低4位
MOV  AL,BH
AND  AL,0FH
ADD  AL,30H
CMP  AL,39H
JLE  .PrintItAgain
ADD  AL,07H
.PrintItAgain
CALL PrintChar
POP  BX
RET
%ENDIF ; DEBUG
;====================================================================
; 数据区
;====================================================================
MsgNoActive     DB  "No active partition.",00H
MsgPartitionTable   DB "Invalid partition table.",00H  
MsgLoadingOS    DB "Error loading operating system.",00H
MsgMissingOS    DB "Missing operating system.",00H
;====================================================================
;临时数据
;====================================================================
DriveNumber     DB 00H ; 启动磁盘启动器号
ActivePartition    DB 00H ; 激活分区表索引(0-3)
DiskExtension    DB 00H ; 是否支持磁盘扩展调用
;==================================================================== 
; 扩展磁盘服务所使用的地址包
;====================================================================
DAP_PACKET_SIZE    DB 10H  ; 包的大小为16字节
DAP_RESERVED1    DB 00H  ; 保留字节
DAP_READ_SECTORS   DB 01H  ; 要处理的扇区数(1 - 127 )
DAP_RESERVED2    DB 00H  ; 保留字节
DAP_BUFFER_OFF    DW 7C00H ; 缓冲区偏移
DAP_BUFFER_SEG    DW 0000H ; 缓冲区段地址
DAP_SECTOR_LOW    DD 0000H ; 起始扇区号的低32位
DAP_SECTOR_HIGH    DD 0000H ; 起始扇区号的高32位
;====================================================================
; 填充字节
Padding TIMES 440-($-$$) db  00H
;====================================================================
;====================================================================
; 标志字节
;====================================================================
UniqueMbrSignature   DD 4B43414AH
UnknownWord     DW 00H
;====================================================================
; 分区表(偏移为446)
;====================================================================
PartitionTable TIMES 64  DB 00H
;====================================================================
; 扇区最后的标记字节(NASM不支持重复ORG)
;====================================================================
BootSignature    dw 0AA55H

;====================================================================
; 代码结束
;====================================================================  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值