📄 mbr.asm
字号:
;goto batend
;==================================================================================
; Bats 硬盘主引导记录源代码文件
;文件名: mbr.s
;位 置: \batsdev\src\bootsect
;版 本: 测试版,0.01
;功 能: 读入Bats分区或活动分区引导记录到 0000:7c00,并转移控制权
;入口参数: dl=驱动器号,由int19h提供
;出口参数: 自举驱动器号=[ss:bp-2]=0000:7bfe
; cf=1
; [ss:bp-4]='BF'
; 满足以上两条说明为本引导程序所引导,否则,BFS分区引导记录
; 需要从新读卷索引到 0000:7e00
;配置要求: 80386及以上CPU
;编 译: nasm 0.98
;命 令: nasm -fbin fat12.s -o fat12.bin
;说 明:
; 1: 关于.struc,char,unsigned宏的定义在 .\inc\macro.inc中已有说明。
; 2: PART_TAB(硬盘分区表) ,在 .\inc\disk.inc中有定义
; Bats工作组2004年7月
;另外说一下:这个程序有待完善。能正常引导计算机,而且能正常启动,也有正常的错误处理
;但还不知道对linux的兼容性如何
;==================================================================================
%include ".\inc\macro.inc"
%include ".\inc\disk.inc"
%define Offset_BatsF [bp-8]
%define Extint13Flag [bp-6]
%define BatsMBRFlag [bp-4]
%define BootDriver [bp-2]
%define PBRSectFlag [0x7dfa]
;==================================================================================
COUNT_Retry EQU 5 ;出现错误的最多重试次数
IP_BootMove EQU 0x0600 ;代码被移动后的偏移地址 0000:0600
IP_BootBase EQU 0x7c00 ;移动数据前的偏移地址 0000:7c00
Quan_Sector EQU 2 ;读2个扇区,专为 BATS分
;区引导程序而设计
OldInt13_SectQuan EQU 0x202 ;使用旧的INT13H读盘功能号及扇区数
;----------------------------------------------------------------------------------
org 0x600
Realboot:
xor ax,ax
mov es,ax
mov ds,ax
mov di,IP_BootMove
mov bp,IP_BootBase
cli
mov ss,ax
mov sp,bp
sti
mov si,bp
mov ch,1
cld
repnz movsw ;将代码本身移到 0000:0600
jmp near $+IP_BootMove+3-IP_BootBase
;转移到新的代码地址
;======================================================================================
push dx ;BootDriver
push word 'BF' ;BatsMBRFlag
push word 0x0a13 ;Extint13Flag
mov si,@MBR_PART ;取分区表地址
mov cl,4 ;设置检索分区表的次数
Check_BATS:
cmp byte [si .PT_SystFlag],Flag_BATSPART
;检查分区的操作系统是否是 BATS
;Flag_BATSPART=0xbf
jz BATS_PartBOOT ;是--->从 BFS 分区启动
add si,size_PART_TAB ;检查下一个表,size_PART_TAB=0x10
loop Check_BATS
push bp
BATS_Active: ;如果从BATS分区读出的引导记录不正确,
;则从活动分区引导
mov word Extint13Flag,bp
mov word BatsMBRFlag,bp
push word 0x80 ;设置标志,从活动分区引导
mov si,@MBR_PART ;找不到 BATS 分区就从活动分区启动
mov cl,4
Check_Active:
cmp byte [si],Flag_HdiskActive
;检查是否活动分区
jz Check_EXTint13
add si,size_PART_TAB ;检查下一个表
loop Check_Active
mov si,@No_Active ;没有活动分区:显示错误信息
jmp ERROR_MESSAGE
BATS_PartBOOT:
mov ax,IP_BootBase-0x600+4
add ax,si
push ax ;Offset_BatsF
push word 0xbf ;设置标志,从BFS分区引导
Check_EXTint13: ;检查是否可以使用扩展int13h读盘
mov ah,0x41
mov bx,0x55aa
int 0x13
jc Old_Int13_Read ;驱动器不支持扩展int13h--->转
cmp bh,0xaa
jnz Old_Int13_Read ;BIOS无扩展int13h--->转
test cl,1
jnz Old_Int13_Read ;不支持第一个子集--->转
;==========================================================================
USE_ExtInt13: ;采用扩展int13h读盘
mov word Extint13Flag,0x0e13;标志。可以使用扩展INT13H
mov cx,Quan_Sector ;把要读的扇区数保存到 cx 中
mov bx,bp ;读到 0000:7c00
mov eax,[si .PT_LStasect]
;取分区第一个扇区的绝对扇区号
call Fun_ExtInt13 ;调用子过程
jc Old_Int13_Read ;不正确,转int13h(旧)读盘
Read_True:
pop ax
cmp al,0x80 ;
jz CHECK_SECTFLAG ;是活动分区:无法在确定从其他分区引导
cmp dword PBRSectFlag,0x73746142;[0x7dfa]
jnz BATSFLAGERROR ;有一个不是则跳转错误处理
jmp short CHECK_SECTFLAG
BATSFLAGERROR:
mov dx,BootDriver ;dx=[bp-2]=引导的物理驱动器号
jmp BATS_Active ;不是?选择活动分区再次重试
;==========================================================================
CHECK_SECTFLAG:
cmp word [MBR_BootFlag],Flag_BootSect
;分区引导扇区的最后2个字节是否0xaa55
jnz Inva_BootFlag ;否--->检查上一次的引导分区(是否是BFS分区)
push cs ;CS入栈 0000
push bp ;BP入栈 7c00
stc ;设置标志
retf ;转到 0000:7c00 开始执行分区引导程序
Old_Int13_Read: ;int13h读盘
mov bx,bp ;读到 0000:7c00
mov dh,[si .PT_StartTra];取磁道号
mov cx,[si .PT_StartSec];取柱面号和扇区号
mov si,COUNT_Retry ;读5次
Error_Next:
mov ax,OldInt13_SectQuan
;读盘功能号及扇区数
int 0x13
jnc Read_True ;读成功--->转
dec si ;不成功计数器减1
jnz Error_Next ;不到5次,继续读
mov si, @Bad_Disk ;很遗憾,5次都没有读成功,肯定买到Y硬盘...
jmp ERROR_MESSAGE ;显示错误信息
;===========================================================================
Inva_BootFlag: ;无效的分区引导扇区标志
mov si, @Sect_Error
jmp ERROR_MESSAGE
;===========================================================================
Fun_ExtInt13: ;使用扩展int13读盘子程序
push si ;保存si到堆栈(si指向活动分区表地址)
push cs ;cs=0
push cs ;cs=0
push eax ;eax=绝对扇区号
push es ;读数据到指定的段
push bx ;段内的偏移
push cx ;读多少扇区
push word 0x10 ;说明这个数据包的大小为 16字节
mov si,sp ;ds:si指向数据包的位置
push dx ;保存驱动器号到堆栈
mov ah,0x42 ;扩展int13h的读盘功能号
int 0x13 ;扩展读盘
pop dx ;弹出驱动器号
add sp,0x10 ;跳过堆栈中的数据包位置
pop si ;弹出 活动分区表地址
ret ;返回
ERROR_MESSAGE:
lodsb ;从 ds:si中读入一个字符到 al
or al,al ;检测字符是否为0
jz ReBoot ;显示完毕, 退出过程
mov bl, 12
mov ah, 0eh
int 10h
jmp short ERROR_MESSAGE ;重复操作
ReBoot:
xor ax,ax
int 0x16
int 0x18
;=======================================================================
;是错误信息
@Sect_Error EQU $-0
DB 0dh,0ah,"Invalid Partition Boot Sector ...",0
@Bad_Disk EQU $-0
DB 0dh,0ah,"Disk I/O error or bad disk ...",0
@No_Active EQU $-0
DB 0dh,0ah,"Can't find Active Parttion ..."
;=======================================================================
;分区表
SETADD 442
DB "Bats"
SETADD Offset_PARTAB
.PART_TAB MBR_PART, 4
;=======================================================================
;引导扇区有效的结束标志
MBR_BootFlag EQU $-0
dw Flag_BootSect
;:batend
;\batsdev\bin\nasm -fbin %0 -o mbr.bin -E \batsdev\src\debug\mbr.err
;\batsdev\bin\nasm -e %0 -o \batsdev\src\debug\mbr.dbg
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -