直接进入正题,再考虑过操作系统的具体的功能分块后,第一件需要考虑的事情就是引导扇区了。引导扇区位于硬盘的0磁头,0柱面上的第一个扇区,并由电脑在开启电源,完成BIOS自检后加载到内存并执行,我们现在并不需要过多了解BIOS自检时的过程(因为这对于编写操作系统来说没什么意义),但我们需要了解一下关于引导扇区的知识点:
-引导扇区的最后两个字节必须为55H,AAH,这两字节为BIOS检查该硬盘是否为可引导硬盘的唯一条件。若硬盘最后这两个字节不为此,则BIOS将视其为不可引导硬盘
-引导扇区由BIOS加载到内存地址0000:7C00处,因此在设置编译器是必须将程序的偏移设为0x7C00
-引导扇区的长度只能为一个扇区(512字节),这个限制虽然非常不人性,但是足够引导操作系统的加载程序
-在引导扇区被加载到内存后,DL寄存器中将存放目前硬盘(引导的硬盘),这可以用来进行后面对操作系统硬盘的读写
此外关于硬件中断的内容我们在写操作系统本身时再提及
那么了解了基本的知识点后,我们正式开始编写引导扇区的代码。在这里,你需要的工具有(推荐):
-Disk Explorer for NTF-下载地址:https://www.runtime.org/ntexpl.zip ;用于对IMG文件进行读写(这个软件我之后会破解,顺便制作破解教程)本文暂时不需要
-NASM-下载地址:http://www.nasm.us/pub/nasm/releasebuilds/2.12/nasm-2.12.zip ; 用于编译汇编语言
-BOCHS-下载地址:https://sourceforge.net/projects/bochs/files/bochs/2.6.8/
-任何文本编辑器,这里推荐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 [DRVNUM],DL
CHECKOSDISK:
MOV SI,CODMSG
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,CODERMSG
CALL WRITESTRING
JMP ENDDELAY
CODNEXT:
MOV SI,CODOKMSG
CALL WRITESTRING
LOADOSMAIN:
MOV SI,LOMMSG
CALL RESETDRIVE
CALL WRITESTRING
MOV BX,[OSMENOFF]
MOV CX,2
MOV AL,[OSMSECOU]
CALL READSECTOR
JNC JUMPOSMAIN
LOMERROR:
MOV SI,LOMERMSG
CALL WRITESTRING
JMP ENDDELAY
JUMPOSMAIN:
MOV SP,BP
JMP FAR [OSMENADD]
ENDDELAY:
MOV SI,EDMSG
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,NUMTABLE
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(BITS 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(BITS 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
DRVINFO:
DRVNUM:
DB 0
MCYLNNUM:
DW 0
MSECTNUM:
DB 0
MHEADNUM:
DB 0
OSMINFO:
OSMENOFF:
DW 7E00H
OSMSECOU:
DB 4
OSMENADD:
DD 07E00000H
TABLES:
CHATABLE:
DB "ABCDEFGHIJKLMNOPQRSTUVWXYZ",0
NUMTABLE:
DB "0123456789ABCDEF",0
STRINGS:
EDMSG:
DB "SYSTEM PENDING...",0DH,0AH,0
CODMSG:
DB "CHECKING OS DRIVE...",0DH,0AH,0
CODOKMSG:
DB "OS DRIVE IS NORMAL.",0DH,0AH,0
LOMMSG:
DB "LOADING OS MAIN, SYSTEM KERNEL...",0DH,0AH,0
CODERMSG:
DB "ERROR: CURRENT DRIVE UNAVAILABLE.",0DH,0AH,0
LOMERMSG:
DB "ERROR: OS MAIN LOAD FAILED.",0DH,0AH,0
BSSIGN:
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
在新弹出的窗口中我们使用如下设置:
在保存设置后我们就可以点击start来开始调试了
开始调试后会弹出两个窗口,可以输入命令行的窗口是调试窗口,以及另一个是引导程序输出的窗口
我们首先往调试窗口中输入“b 0x7C00",在偏移0x7C00处放下一个断点
然后我们输入两次“c”来继续(一次是BOCHS加载程序后挂起用,一次是遇上了断点来继续程序)
随后效果如下:
可以看到输出窗口处成功的输出了我们引导程序的信息,但是输出后似乎挂起了,原因是我的代码内最后一条引导程序里的指令是JMP FAR [OSENADDR](意义是跳转至OSENADDR即7E00H:0000H处),一条跳转至主操作系统的程序代码,但是我们还没有编写出主操作系统,其在我们的IMG镜像文件中是不存在的,所以7E00H:0000H处是没有代码的(全是00H)。
-查看更多BOCHS调试命令行:http://www.cnblogs.com/hongzg1982/articles/2111254.html
当然有兴趣的朋友可以自己试着编写自己的子程序和完全属于自己的操作系统,我在这里为你们提供:
-BIOS中断大全查询的网址(全英文):http://www.ctyme.com/intr/int.htm
了解硬件I/O的朋友可以在以下网址查询到各个BOCHS的I/O端口:
-硬件I/O端口大全(全英文):http://bochs.sourceforge.net/techspec/PORTS.LST
另外,可以将NASM编译器的文件夹添加到系统环境目录的PATH项下,这样以后无论在哪个目录打开命令行,都可以运行NASM编译器。