编写操作系统:第一天:引导扇区

作者在 2016-05-02 02:24:37 发布以下内容
[附件262]



直接进入正题,再考虑过操作系统的具体的功能分块后,第一件需要考虑的事情就是引导扇区了。引导扇区位于硬盘的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编译器。



默认分类 | 阅读 2868 次
文章评论,共0条
游客请输入验证码
浏览2868次
文章分类
文章归档
最新评论