#2
wmf20142016-03-25 13:56
|
-引导扇区的最后两个字节必须为55H,AAH,这两字节为BIOS检查该硬盘是否为可引导硬盘的唯一条件。若硬盘最后这两个字节不为此,则BIOS将视其为不可引导硬盘
-引导扇区由BIOS加载到内存地址0000:7C00处,因此在设置编译器是必须将程序的偏移设为0x7C00
-引导扇区的长度只能为一个扇区(512字节),这个限制虽然非常不人性,但是足够引导操作系统的加载程序
-在引导扇区被加载到内存后,DL寄存器中将存放目前硬盘(引导的硬盘),这可以用来进行后面对操作系统硬盘的读写
此外关于硬件中断的内容我们在写操作系统本身时再提及
那么了解了基本的知识点后,我们正式开始编写引导扇区的代码。在这里,你需要的工具有(推荐):
-Disk Explorer for NTF-下载地址:https://www. ;用于对IMG文件进行读写(这个软件我之后会破解)本文暂时不需要
-NASM-下载地址:http://www.nasm.us/pub/nasm/releasebuilds/2.12/nasm-2.12.zip ; 用于编译汇编语言
-BOCHS-下载地址:https://
-任何文本编辑器,这里推荐NOTEPAD++
以下是BOOTLOADER.ASM(引导程序)的代码
ORG 7C00H
ENTRY:
XOR BX,BX
MOV DS,BX
MOV SS,BX
MOV ES,BX
MOV BP,0FFFFH
MOV SP,BP
MOV [DriveNumber],DL
CHECKOSDISK:
MOV SI,CODMessage0
CALL WRITESTRING
CALL RESETDRIVE
MOV BX,513
MOV CX,1
MOV AL,1
CALL READSECTOR
JC CODERROR
CMP BYTE [BX+508],42H
JNE CODERROR
CMP BYTE [BX+509],5AH
JE CODNEXT
CODERROR:
MOV SI,CODErrorMsg
CALL WRITESTRING
JMP ENDDELAY
CODNEXT:
MOV SI,CODOKMessage
CALL WRITESTRING
LOADOSMAIN:
MOV SI,LOMessage
CALL RESETDRIVE
CALL WRITESTRING
MOV BX,[OSMEntryOffset]
MOV CX,2
MOV AL,[OSMSectorCount]
CALL READSECTOR
JNC JUMPOSMAIN
LOMERROR:
MOV SI,LOMErrorMsg
CALL WRITESTRING
JMP ENDDELAY
JUMPOSMAIN:
MOV SP,BP
JMP FAR [OSMEntryAddress]
ENDDELAY:
MOV SI,EDMessage
CALL WRITESTRING
JMP $
WRITECHAR: ;AL = Character ASCII
PUSH BX
PUSH AX
MOV BX,0FH
MOV AH,0EH
INT 10H
POP AX
POP BX
RETN
WRITESTRING: ;DS:SI = Address Of String
PUSH AX
WSLOOP:
CLD
LODSB
TEST AL,AL
JZ WSRET
CALL WRITECHAR
JMP WSLOOP
WSRET:
POP AX
RETN
WRITEHEXNUM: ;AX = Hex Number To Output
PUSHAW
CLD
MOV CL,16
MOV DX,AX
MOV DI,HexNumTable
WHLOOP:
MOV AX,DX
MOV SI,DI
SUB CL,4
JZ WHNEXT
SHR AX,CL
WHNEXT:
AND AX,0000000000001111B
ADD SI,AX
LODSB
CALL WRITECHAR
TEST CL,CL
JNZ WHLOOP
POPAW
RETN
WRAPTEXT:
MOV AL,0DH
CALL WRITECHAR
MOV AL,0AH
CALL WRITECHAR
RETN
RESETDRIVE: ;DL = Drive Number
XOR AH,AH
INT 13H
RETN ;Succeed: CF = 0, AH = 0; Failed: CF = 1, AH = Error Code
READSECTOR: ;AL = Number Of Sectors To Read, CH = Low 8 Bits Of Cylinder Number, CL = Sector Number(Bit 0-5) High 2 Bits Of Cylinder Number, DH = Head Number, DL = Drive Number, ES:BX = Address Of Buffer
PUSH BP
PUSH 2
MOV BP,SP
RSLOOP:
PUSHAW
MOV AH,2
INT 13H
JNC RSRET
RSRETRY:
DEC WORD [BP]
POPAW
JNZ RSLOOP
RSRET:
ADD SP,18
POP BP
RETN ;Succeed: CF = 0, AH = 0, AL = Number Of Sectors Transferred; Failed: CF = 1, AH = Error Code
WRITESECTOR: ;AL = Number Of Sectors To Write, CH = Low 8 Bits Of Cylinder Number, CL = Sector Number(Bit 0-5) High 2 Bits Of Cylinder Number, DH = Head Number, DL = Drive Number, ES:BX = Address Of Buffer
PUSH BP
PUSH 2
MOV BP,SP
WSELOOP:
PUSHAW
MOV AH,3
INT 13H
JNC WSERET
WSERETRY:
DEC WORD [BP]
POPAW
JNZ WSELOOP
WSERET:
ADD SP,18
POP BP
RETN ;Succeed: CF = 0, AH = 0, AL = Number Of Sectors Transferred; Failed: CF = 1, AH = Error Code
DriveInfo:
DriveNumber:
DB 0
MaxCylinderNum:
DW 0
MaxSectorNum:
DB 0
MaxHeadNum:
DB 0
OSMainInfo:
OSMEntryOffset:
DW 7E00H
OSMSectorCount:
DB 4
OSMEntryAddress:
DD 07E00000H
Tables:
CharTable:
DB "ABCDEFGHIJKLMNOPQRSTUVWXYZ",0
HexNumTable:
DB "0123456789ABCDEF",0
Strings:
EDMessage:
DB "SYSTEM PENDING...",0DH,0AH,0
CODMessage0:
DB "CHECKING OS DRIVE...",0DH,0AH,0
CODOKMessage:
DB "OS DRIVE IS NORMAL.",0DH,0AH,0
LOMessage:
DB "LOADING OS MAIN, SYSTEM KERNEL...",0DH,0AH,0
CODErrorMsg:
DB "ERROR: CURRENT DRIVE UNAVAILABLE.",0DH,0AH,0
LOMErrorMsg:
DB "ERROR: OS MAIN LOAD FAILED.",0DH,0AH,0
BootSectSignature:
TIMES 508-($-$$) DB 0
DB 42H,5AH
DB 55H,0AAH
ENTRY:
XOR BX,BX
MOV DS,BX
MOV SS,BX
MOV ES,BX
MOV BP,0FFFFH
MOV SP,BP
MOV [DriveNumber],DL
CHECKOSDISK:
MOV SI,CODMessage0
CALL WRITESTRING
CALL RESETDRIVE
MOV BX,513
MOV CX,1
MOV AL,1
CALL READSECTOR
JC CODERROR
CMP BYTE [BX+508],42H
JNE CODERROR
CMP BYTE [BX+509],5AH
JE CODNEXT
CODERROR:
MOV SI,CODErrorMsg
CALL WRITESTRING
JMP ENDDELAY
CODNEXT:
MOV SI,CODOKMessage
CALL WRITESTRING
LOADOSMAIN:
MOV SI,LOMessage
CALL RESETDRIVE
CALL WRITESTRING
MOV BX,[OSMEntryOffset]
MOV CX,2
MOV AL,[OSMSectorCount]
CALL READSECTOR
JNC JUMPOSMAIN
LOMERROR:
MOV SI,LOMErrorMsg
CALL WRITESTRING
JMP ENDDELAY
JUMPOSMAIN:
MOV SP,BP
JMP FAR [OSMEntryAddress]
ENDDELAY:
MOV SI,EDMessage
CALL WRITESTRING
JMP $
WRITECHAR: ;AL = Character ASCII
PUSH BX
PUSH AX
MOV BX,0FH
MOV AH,0EH
INT 10H
POP AX
POP BX
RETN
WRITESTRING: ;DS:SI = Address Of String
PUSH AX
WSLOOP:
CLD
LODSB
TEST AL,AL
JZ WSRET
CALL WRITECHAR
JMP WSLOOP
WSRET:
POP AX
RETN
WRITEHEXNUM: ;AX = Hex Number To Output
PUSHAW
CLD
MOV CL,16
MOV DX,AX
MOV DI,HexNumTable
WHLOOP:
MOV AX,DX
MOV SI,DI
SUB CL,4
JZ WHNEXT
SHR AX,CL
WHNEXT:
AND AX,0000000000001111B
ADD SI,AX
LODSB
CALL WRITECHAR
TEST CL,CL
JNZ WHLOOP
POPAW
RETN
WRAPTEXT:
MOV AL,0DH
CALL WRITECHAR
MOV AL,0AH
CALL WRITECHAR
RETN
RESETDRIVE: ;DL = Drive Number
XOR AH,AH
INT 13H
RETN ;Succeed: CF = 0, AH = 0; Failed: CF = 1, AH = Error Code
READSECTOR: ;AL = Number Of Sectors To Read, CH = Low 8 Bits Of Cylinder Number, CL = Sector Number(Bit 0-5) High 2 Bits Of Cylinder Number, DH = Head Number, DL = Drive Number, ES:BX = Address Of Buffer
PUSH BP
PUSH 2
MOV BP,SP
RSLOOP:
PUSHAW
MOV AH,2
INT 13H
JNC RSRET
RSRETRY:
DEC WORD [BP]
POPAW
JNZ RSLOOP
RSRET:
ADD SP,18
POP BP
RETN ;Succeed: CF = 0, AH = 0, AL = Number Of Sectors Transferred; Failed: CF = 1, AH = Error Code
WRITESECTOR: ;AL = Number Of Sectors To Write, CH = Low 8 Bits Of Cylinder Number, CL = Sector Number(Bit 0-5) High 2 Bits Of Cylinder Number, DH = Head Number, DL = Drive Number, ES:BX = Address Of Buffer
PUSH BP
PUSH 2
MOV BP,SP
WSELOOP:
PUSHAW
MOV AH,3
INT 13H
JNC WSERET
WSERETRY:
DEC WORD [BP]
POPAW
JNZ WSELOOP
WSERET:
ADD SP,18
POP BP
RETN ;Succeed: CF = 0, AH = 0, AL = Number Of Sectors Transferred; Failed: CF = 1, AH = Error Code
DriveInfo:
DriveNumber:
DB 0
MaxCylinderNum:
DW 0
MaxSectorNum:
DB 0
MaxHeadNum:
DB 0
OSMainInfo:
OSMEntryOffset:
DW 7E00H
OSMSectorCount:
DB 4
OSMEntryAddress:
DD 07E00000H
Tables:
CharTable:
DB "ABCDEFGHIJKLMNOPQRSTUVWXYZ",0
HexNumTable:
DB "0123456789ABCDEF",0
Strings:
EDMessage:
DB "SYSTEM PENDING...",0DH,0AH,0
CODMessage0:
DB "CHECKING OS DRIVE...",0DH,0AH,0
CODOKMessage:
DB "OS DRIVE IS NORMAL.",0DH,0AH,0
LOMessage:
DB "LOADING OS MAIN, SYSTEM KERNEL...",0DH,0AH,0
CODErrorMsg:
DB "ERROR: CURRENT DRIVE UNAVAILABLE.",0DH,0AH,0
LOMErrorMsg:
DB "ERROR: OS MAIN LOAD FAILED.",0DH,0AH,0
BootSectSignature:
TIMES 508-($-$$) DB 0
DB 42H,5AH
DB 55H,0AAH
如上代码是我编写的引导扇区,其中包括一些有必要的子程序和一些可扩展用的子程序,若部分子程序不需要可以去除。
将如上代码保存为.ASM文件后,我们用命令行(在NASM文件的文件夹里SHIFT加右键鼠标并选择“OPEN COMMAND WINDOWS HERE“)打开NASM并输入命令行:
nasm -f bin -o [路径/目标文件名] [路径/源代码文件名]
在这里,我输入
nasm -f bin -o BOOTLOADER.IMG BOOTLOADER.ASM
若没有不编译错误,则生成目标文件
随后我们运行位于BOCHS文件夹下的BOCHSDBG来调试我们的引导扇区
首先设置硬盘与引导,选择Disk & Boot, 并在新弹出的窗口中我们使用如下设置一下虚拟镜像:将只需将"Type of Floppy Media"设置成1.44M,然后将映象的路径添加到"First floppy image/device",并把"Type of Floppy Media"也设置为1.44M,最后把"Status"设置为"inserted"即可
在保存设置(保存至BOCHS目录下)后我们就可以点击start来开始调试了
开始调试后会弹出两个窗口,可以输入命令行的窗口是调试窗口,以及另一个是引导程序输出的窗口
我们首先往调试窗口中输入“b 0x7C00",在偏移0x7C00处放下一个断点
然后我们输入两次“c”来继续(一次是BOCHS加载程序后挂起用,一次是遇上了断点来继续程序)
可以看到输出窗口处成功的输出了我们引导程序的信息,但是输出后似乎挂起了,原因是我的代码内最后一条引导程序里的指令是JMP FAR [OSENADDR](意义是跳转至07E0:0000处,因为[OSENADDR]为07E00000),一条跳转至主操作系统的程序代码,但是我们还没有编写出主操作系统,其在我们的IMG镜像文件中是不存在的,所以0x7E00处是没有代码的。
-查看更多BOCHS调试命令行:http://
当然有兴趣的朋友可以自己试着编写自己的子程序和完全属于自己的操作系统,我在这里为你们提供:
-实模式内存布局(全英文):http://wiki.(x86)
-BIOS中断大全查询的网址(全英文):http://www.
了解硬件I/O的朋友可以在以下网址查询到各个I/O端口:
-硬件I/O端口大全(全英文):http://bochs.
另外,可以将NASM编译器的文件夹添加到系统环境目录的PATH项下,这样以后无论在哪个目录打开命令行,都可以运行NASM编译器。
以下为各个文件的备用下载地址:
-WinHex(代替NtExplorer)-下载地址:
只有本站会员才能查看附件,请 登录
-NASM-下载地址:
只有本站会员才能查看附件,请 登录
-BOCHS-下载地址:
只有本站会员才能查看附件,请 登录
-NotePad++-下载地址:
只有本站会员才能查看附件,请 登录
-BOOTLOADER.ASM和BOOTLOADER.IMG-下载地址:
只有本站会员才能查看附件,请 登录
[此贴子已经被作者于2016-5-8 02:55编辑过]