在自学操作系统的过程中,试图自己实现。参考了一些文献(《30天自制操作系统》、《现代操作系统》等),决定将零散的信息进行一下整理,梳理一下思路。并一点点的开始实现自己的操作系统。我将已经实现的部分上传到了我的GitHub,代码中不足之处还请路过的大神们指点。(希望我能写完)
具体的信息在计算机是如何启动的——阮一峰博客的文章中记录的非常详细,在这里仅简单列举一下相关内容
在《30天自制操作系统》中,作者使用了一个自制的软件以生成img镜像,实际上就是作者实现的一个简单的FAT12文件系统生成的程序。有关于FAT12文件系统的具体内容可以参考FAT12文件系统。
在这里需要了解的包括:
由上图可知,在第一个扇区即引导扇区中存储着软盘的相关内容,根目录区(存放着文件名称、大小、修改日期等)开始于第19个扇区(0x2600)。根目录区每个条目的大小为32个字节,所以根目录区的长度为:BPB_RootEntCnt*32(字节)。这样就可以确定出数据区的开始扇区。按默认情况计算开始的地址为(0x8200)。
上图为引导扇区中的参数。
按照以上FAT12的原理,我也实现了一个“极简版的FAT12文件生成程序”,内有彩(bug)蛋,详见GitHub ExtUtils/createImg。
在开机时,系统会进入实模式,这个时候系统只用1M空间可以使用。具体分配情况如下:
在开机时,会自动将引导程序加载至0x7c00处。
按照常规使用汇编+C作为编写语言。采用nasm和gcc对代码进行编译。首先将代码编译为二进制文件,再写入“软盘”中。
编译指令为:
nasm -f bin filename.s -o filename.bin
BIOS中断内容较多,可以查阅BIOS中断大全。
以下代码已上传至GitHub。
CYLS EQU 10
ORG 0x7C00 ;起始地址
JMP start ;短转移
DB 0x90 ;无意义
DB "MY OS " ; BS_OEMName
DW 512 ; BPB_BytesPerSec
DB 1 ; BPB_SecPerClus
DW 1 ; BPB_ResvdSecCnt
DB 2 ; BPB_NumFATs
DW 224 ; BPB_RootEntCnt
DW 2880 ; BPB_TotSec16
DB 0xF0 ; BPB_Media
DW 9 ; BPB_FATSz16
DW 18 ; BPB_SecPerTrk
DW 2 ; BPB_NumHeads
DD 0 ; BPB_HiddSec
DD 2880 ; BPB_TotSec32
DB 0,0,0x29 ; BS_DrvNum
DD 0xffffffff ; BS_VolID
DB "HELLO-OS " ; BS_VolLab
DB "FAT12 " ; BS_FileSysType
RESB 18 ; 无意义
; 以上部分为引导扇区的描述,均按照默认设置。
; 下面开始引导程序
start:
MOV AX, 0
MOV SS, AX
MOV SP, 0x7C00
MOV DS, AX
MOV AX, 0x0820
MOV ES, AX
; 以上初始化堆栈、数据、附加段寄存器。
MOV CH, 0 ; 柱面
MOV DH, 0 ; 磁头
MOV CL, 2 ; 扇区
; 开始将软盘中的启动程序读入系统内存中
read:
MOV SI, 0
retry:
MOV AL, 1
MOV AH, 0x02
MOV BX, 0
MOV DL, 0x00
INT 0x13
; 依次读入每个扇区的内容;若读入失败超过5次,则转至错误处理
JNC next
INC SI
CMP SI, 5
JAE error
MOV AH, 0x00
MOV DL, 0x00
INT 0x13
JMP retry
next:
MOV AX, ES
ADD AX, 0x0020
MOV ES, AX
INC CL
CMP CL, 18
JBE read
MOV CL, 1
INC DH
CMP DH, 2
JB read
MOV DH, 0
INC CH
CMP CH, CYLS ; 共读取CYLS个扇区
JB read
;JMP error ;用来判断是否跳出循环
MOV [0x0FF0], CH
JMP 0xC200
; 转至后续执行程序
; 0x7c00 + 0x8000 = 0xc200
final:
HLT
JMP final
; 显示错误信息
error:
MOV SI, msg
; 逐字符打印错误信息
print:
MOV AL, [SI]
INC SI
CMP AL, 0
JE final
MOV AH, 0x0E
MOV BX, 15
INT 0x10
JMP print
msg:
DB 0x0a, 0x0a
DB "load error"
DB 0x0a
DB 0
RESB 510 - ($ - $$) ; 空余补0
DB 0x55, 0xaa
PS:不用debug调试汇编程序真累心。少写了一条指令检查了一整天。