MBR由三部分构成:
1.主引导程序代码,占446字节
2.硬盘分区表DPT,占64字节
3.主引导扇区结束标志AA55H
0. BIOS自动把第一扇区加载到内存0000:7C00 处, 从0000:7C00开始执行
1. 初始化
2. 把第一扇区代码0000:7C1B复制到0000:061B处, 并跳去0000:061B执行
3. 从分区表首地址开始检查,
找活动分区表,没有活动分区,多个活动分区, 提示错误
如果有且只有一个分区表,继续
4. 把活动分区的指向的第一个扇区加载到0000:7C00处,
加载失败,连续试5次, 全部失败提示错误
加载成功,继续
5. 检查扇区标识是否是 55 AA, 否提示错误
6. 跳到0000:7C00 去执行
文章结束了.
但是,如果觉的不够,下面是详细
0000:;(0000:7c00)
;初始化操作 -------------------------------------------------------------
;清零
xor ax,ax
mov ss,ax
mov sp,7c00 ;Set Stack Pointer to 0000:7C00
;因为代码加载到7c00
;这里应该是指定7c00之前的区域,用来放堆栈,堆栈减法计算
sti ;开中断保护
push ax
pop es ;==mov es,ax (此时ax=0)
push ax
pop ds ;==mov ds,ax (此时=0)
cld ;CLD是清方向标志,把标识寄存器的D位置呈零
;ds,es,ss =0
;清零结束
;代码转移,为什么呢,
;为什么要拷贝到之前地址呢,为了加载后面DPT的时候也同样加载到7C00地址
mov si,7c1b
mov di,061b
push ax ;返回位置用
push di ;返回位置用
mov cx,01e5
repz movsb es:[di],[si] ;拷贝代码到0000:061b, 拷贝di到si,拷贝长度=cx
retf ;代码返回到 0000:061b (此操作后,堆栈+4)
001b:;(0000:061b)
;代码一样的,但位置不相同,因为是拷贝的位置,不是原始位置
;这部分作用据说是 在分区表寻找一个活动的X,
;4条目录都没找到就显示一条消息
mov bp,07be ;分区表首地址(也是引导标记符位置,是否有效的判断)
;引导标记1 磁头1 扇区柱面2 系统指示1 磁头结束1 扇区柱面结束2 空余扇区数4 扇区总数4
0020:;(0000:0620)
mov cl,04 ;一共4条目录
;loop跳到这里,不是上一句,奇怪了
cmp byte ptr [bp],ch ;判断标记号,初始值0,检查是否是活动分区
;[1be-1fd]这个区域是4个表的位置
;分成4个表,每个表10h大小
;第一个字节80表示活动分区,0表非活动分区
;( rcx: 0x00000000_00090004
;0x00000000000007be <bogus+ 0>: 0x00010100)
jl 002e ┏ ;0<0吗,80(-127<0)吗, <则跳
jnz 003a ┃ ┏ "Invalid partition table"
add bp,10 ┃ ┃ ;next (第一次我这=0,执行到这)
loop 0020 ┃ ┃ ;cx-1,如cx>0,则跳到20 (不能用n执行下一步,用s)--->>>>>>>>
int 18 ┃ ┃ ;
┃ ┃ ;Checked all 4; NONE of them
┃ ┃ ; were bootable, so start 调用bios,按任意键重启
┃ ┃ ; ROM-BASIC (only available on some IBM machines!)
┃ ┃ ; Many BIOS simply display "PRESS A KEY TO REBOOT" when an
┃ ┃ ; Interrupt 18h is executed.
002e:;(0000:062e) ┛ ┃
mov si,bp ┃ ;Copy Base Pointer value of 07BE;每一条的首地址
0030: ┓ ┃
add si,10 ┃ ┃ ;判断下一条,为什么这样判断,不是找出一个就行了吗
dec cx ┃ ┃ ;目录数-1
jz 004f ┃ ┃ ;检查目录数,是否遍历完成=======>>>>>>>>>>
cmp [si],ch ┃ ┃ ;检查是否为0,为零,非活动 rsi: 0x00000000_000e07de
jz 0030 ┗ ┃ ;
003a: ┛ ;非0到这,(第二次循环,我的值=80) ;看看是否存在第二个活动分区
mov al,byte ptr [07b5] ;听说[7b5]=2c
003d:
mov ah,07 "Invalid partition table" ;=7B5: ★多个活动分区会出现这样的!!!!
mov si,ax ; 有活动分区,但读磁盘失败会这样
0041: ;
lodsb [si] ;串操作指令LODSB/LODSW是块装入指令
;把SI指向的存储单元读入累加器,其中LODSB是读入AL,LODSW是读入AX中,
;然后SI自动增加或减小1或2位.
;当方向标志位D=0时,则SI自动增加;D=1时,SI自动减小
; 我这 [si]=[702]=6a,al=0
; 所以显示就是个"j"
0042: ┓
cmp al,00 ┃
jz 0042 ┗ ;不等于,会一直死循环吧,是 显示完成了,就停止不动(我这里bochs调试img显示j)
mov bx,0007
mov ah,0e
int 10 ;一次只显示一个字符
jmp 0041 ;继续下一个字符
;==========================================================
004f: ;目录遍历完成
mov [bp+0010],cl ;当前剩余目录数,覆盖到下一个的值???什么意思,保存遍历剩余的结果数
; 也就是多个活动的无论如何只留一个的意思吧,其实已经检查过了,应该没必要这样了
call 009b ;★子函数:::读磁盘(测试5次)
jnb 0081 ;磁盘读取能用,则跳...
0057:
inc byte ptr [bp+0010]
cmp byte ptr [bp+0004],0b ;分区表系统指示符,一般好像为7, :和b比较什么意思???
jz 006b
cmp byte ptr [bp+0004],0c ;分区表系统指示符:和c比较
jz 006b
mov al,byte ptr [07b6] ;[7B6] = 44 + 700 -> 744
jnz 003d ;Display: "Error loading operating system"
;这里的jnz相当于jmp
006b:
add byte ptr [bp+0002],06
add word ptr [bp+0008],06
add word ptr [bp+000a],00
call 009b
jnb 0081
mov al,byte ptr [07b6] ;[7B6] = 44 + 700 -> 744
jmp 003d ;Display: "Error loading operating system"
0081:;;能用的话,直接跳到这里检查
cmp word ptr [7dfe],aa55;Check for "Magic Number" at end of sector and jump to Boot Record...
jz 0094 ;符合检查则跳
cmp byte ptr [bp+0010],00
jz 0057
mov al,byte ptr [07b7] ;[7B7] = 63 + 700 -> 763
jmp 003d ;Display: "Missing operating system"
0094:
; AL=扇区数
; CH,CL=磁盘号,扇区号
; DH,DL=磁头号,驱动器号
; ES:BX=数据缓冲区地址
; 00H~7FH:软盘;
; 80H~0FFH:硬盘
; 读完磁盘没做其他事,这里的都能用
mov di,sp ;sp=7c00
push ds
push di
mov si,bp
retf ;retf 弹出2个参数,一个给 ip,一个给 cs
;相当于 pop ip
; pop cs
;cs:ip= ds:di
; =ds:sp
; =0000:7c00 下一句
;扇区被加载到 0000:7C00处了
;开始向其他扇区之旅了......................>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;--------------------------
009b:
mov di,0005 ;设置尝试计数5次 Set 'Try Count' to 5 times
mov dl,byte ptr [bp] ;bp保存分区表的第一条活动分区首地址(一条10H字节),80表示是硬盘
mov ah,08 ;
int 13 ;获取驱动器参数 Get Drive Parameters
jb 00ca ;失败则跳
mov al,cl ;获取成功
and al,3f ;
cbw ;转换字节到word Convert Byte to Word.
mov bl,dh
mov bh,ah
inc bx
mul ax,bx
mov dx,cx
xchg dh,dl
mov cl,06
shr dh,cl
inc dx
mul ax,dx
cmp word ptr [bp+000a],dx
jnbe 00e6
jb 00ca
cmp word ptr [bp+0008],ax
jnb 00e6
00ca:
;难道是因为不是硬盘所以失败吗?直接跳到这
mov ax,0201 ;读取扇区数,1个
mov bx,7c00 ;加载到 ES:BX 也就是 0000:7C00 处
mov cx,word ptr [bp+0002] ;获得,分区引导记录的扇区和柱面号
mov dx,word ptr [bp] ;获得磁头号,问题,80问题呀!!!!,难道前面覆盖的是这个吗,不像
;dl:驱动器 80
;dh:0
;ch:ff cl:c1
int 13 ;int 13/02 读磁盘
;AL=扇区数
;CH,CL=磁盘号,扇区号
;DH,DL=磁头号,驱动器号
;ES:BX=数据缓冲区地址
jnb 012b
dec di ;失败,怎么总失败... ;-1
jz 012b
xor ah,ah
mov dl,byte ptr [bp] ;??
int 13 ;int 13/00 软盘系统复位? 注此时Dl=多少?
jmp 00ca ;复位之后再跳到
00e6:
mov dl,byte ptr [bp]
pusha
mov bx,55aa
mov ah,41
int 13
;1) 检验扩展功能是否存在
;入口:
;AH = 41h
;BX = 55AAh
;DL = 驱动器号
;返回:
;CF = 0
;AH = 扩展功能的主版本号
;AL = 内部使用
;BX = AA55h
;CX = API 子集支持位图
;CF = 1
;AH = 错误码 01h,无效命令
;这个调用检验对特定的驱动器是否存在扩展功能。
;如果进位标志置 1则此驱动器不支持扩展功能。
;如果进位标志为 0,同时 BX = AA55h,则存在扩展功能。
;此时 CX 的 0 位表示是否支持第一个子集,
;1位表示是否支持第二个子集.
;对于 1.x 版的扩展 Int13H 来说,主版本号 AH = 1。
;AL 是副版本号,但这仅限于 BIOS 内部使用,
;任何软件不得检查 AL 的值。
jb 0129
cmp bx,5555
jnz 0129
test cl,01
jz 0129
popa
00ff:
pusha
push 00
push 00
push word ptr [bp+000a]
push word ptr [bp+0008]
push 00
push 7c00
push 01
push 10
mov ah,42
mov si,sp
int 13
;2) 扩展读
;入口:
;AH = 42h
;DL = 驱动器号
;DS:DI = 磁盘地址数据包(Disk Address Packet)
;返回:
;CF = 0,AH = 0 成功
;CF = 1,AH = 错误码
;这个调用将磁盘上的数据读入内存。
;如果出现错误,
; DAP 的 BlockCount项中则记录了出错前实际读取的数据块个数
popa
popa
jnb 012b
dec di
jz 012b
xor ah
mov al,byte ptr [bp]
int 13
jmp 00ff
0129:
popa
stc
012b:
ret