想做一个操作系统首先要了解电脑内部工作机制。
当按下主机上面的电源开关后,CPU会首先执行主板上BIOS芯片内的程序,之后是调用BIOS 19H号中断,将设定的某个磁盘设备的第一个扇区内容复制到内存中0:0x7c00h开始的内存单元,然后检查这个扇区最后的两个字节内容。如果是0x55AA就表示确实是可以引导的。然后跳转到0:0x7c00h处开始执行引导程序。
因为现在内存中就一个扇区的程序,CPU执行到末尾时就会因没有继续执行的程序而出错。所以在引导程序中要加入一段将整个操作系统所在扇区复制到内存的代码。这样要在第一个扇区的程序末尾加入一句跳转指令跳转到操作系统所在的内存地址然后执行。
接下来开始编码实践:
引导程序代码:ipl.nas
功能:将第第二个扇区的内容复制到0:0x7E00h开始的地方。
ORG 0x7c00
JMP ENTRY ;跳转
DB 0x90 ;占位一个字节
DB "HELLOIPL" ;厂商名(格式化此磁盘的操作系统名)
DW 512 ;每扇区字节数
DB 1 ;每簇扇区数
DW 1 ;引导扇区占用扇区数
DB 2 ;共有几个FAT表
DW 224 ;根目录记录数最大值
DW 2880 ;扇区总数
DB 0xf0 ;介质描述,3.5寸高密码软盘
DW 9 ;每个FAT表占用扇区数
DW 18 ;每个磁道扇区数
DW 2 ;磁头数
DD 0 ;隐藏扇区数
DD 2880 ;扇区总数
DB 0 ;中断0x13的驱动器号,第一个软盘驱动器设置为0
DB 0
DB 0x29 ;操作系统用它来识别引导信息,值可以是28h或29h
DD 0xffffffff ;卷序列号,在格式化磁盘时所产生的一个随机序号,有助于区分磁盘,可以为0
DB "HELLO-OS ";磁盘卷的标识符,再次设置的时候被保存到根目录中作为一个特殊的文件来储存
DB "FAT12 " ;文件系统类型
RESB 18
ENTRY:
MOV AX,0 ;0x7c00h+512=0x7e00h
MOV ES,AX
MOV CH,0 ;柱面
MOV DH,0 ;磁头
MOV CL,2 ;扇区
MOV AH,0x02;读磁盘
MOV AL,1 ;读一个扇区
MOV BX,0x7e00;es:bx 表示目标存放地址
MOV DL,0x00;驱动器名A
INT 13H;调用磁盘BIOS中断
JMP 0x7e00
RESB 0x7dfe-$;表示从0x1fe到上一行要写多少个0x00
DB 0x55,0xaa
操作系统代码:os.nas
功能:在屏幕上显示英文Hello operation system。然后执行HLT。
ORG 0x7e00 ;因为下面有标号
MOV AX,0 ;这里很关键
MOV DS,AX ;
MOV SI,msg
show:
MOV AL,[SI] ;读入字符串
ADD SI,1
CMP AL,0 ;判断是否字符串结束
JE fin
MOV AH,0x0e ;显示字符模式
MOV BX,15 ;字符颜色
INT 0x10 ;调用显卡BIOS
JMP show
fin:
HLT
JMP fin
msg:
DB 0x0a ;换行
DB "hello operation system!"
DB 0x0a
DB 0 ;结束标志
代码敲完后,用nasm.exe 编译成 bin文件。
Nasm ipl.nas ipl.bin
Nasm os.nas os.bin
执行这两条指令编译,编译成功后生成ipl.bin os.bin 这两个文件。
接着制作一个软盘镜像文件。这次用的是 edimg.exe
edimg imgin:fdimg0at.tek wbinimg src:ipl.bin len:512 from:0 to:0 imgout:ipl.img
执行这一条指令,把ipl.bin 放到镜像文件的第一个扇区中。(当然也可以是用U盘在做,具体方法也不难)。From: 0 to: 0 表示ipl.bin的前几个字节不写入。例如from: 1 to:1 表示ipl.bin 的第一个字节空着 剩下的照常写入。fdimg0at.tek表示一个空的软盘文件。
上面操作完成后,会产生一个ipl.img 的映像文件。
接下来把os.bin 的内容写到映像文件的第二个扇区中。
我用的BZ二进制编辑软件。打开ipl.img 然后打开os.bin 把os.bin 内容复制到ipl.img 的第二个扇区中(也就是0x55aa后面)。
接下来设置qemu虚拟机从软盘启动。
做一个批处理文件名字是qemu.bat,内容是:
@set SDL_VIDEODRIVER=windib
@set QEMU_AUDIO_DRV=none
@set QEMU_AUDIO_LOG_TO_MONITOR=0
qemu.exe -L . -m 32 -localtime -std-vga -fda ipl.img
这样,双击qemu.bat 就会显示运行结果了。
运行结果:
调试过程中遇到的问题:
1.开始在用edimg.exe 把ipl.bin 做成img 文件时总是提示 BPB error!,直到后来在ipl.nas jmp entry 这一行代码下面添加FAT12文件格式后才不提示错误。具体原因现在还不理解。
2.起初做成的ipl.img 在虚拟机中运行不显示 hello operation system!,最后发现是地址写错了。第一扇区复制到0x7c00 段地址是0,以前一直是想反了。
3.要显示的内容最初是放到了可运行代码的前面了,因为不是可以执行的代码所以起初总出错。应该放到最后面。
总结的经验:
这部分的内容之前看过好多遍书,以为已经完全掌握和理解了,结果还是花了一整个宝贵的周末的下午,才算调试成功。所以说:光看还不行,在实践中才能真正的检验一个只是是否掌握。