第一天直接给了一个helloos.img,让虚拟机直接运行,虚拟机直接运行后,在屏幕上显示“hello world"
这就是我们这个所谓的操作系统的最简单的形式了。这个“操作系统”功能简单到,只能打印出“hello world"
这个操作系统实际上是:helloos.img这个文件里的二进制数组成的。
文件helloos.img其实就是操作系统的映像文件。
那么今天我们就看看如何写代码来生成helloos.img这个映像文件。
除了我们用二进制编辑器,直接写来生成helloos.img外,我们还可以用汇编来写:
文件:helloos.nas
DB0xeb, 0x4e, 0x90, 0x48, 0x45, 0x4c, 0x4c, 0x4fDB0x49, 0x50, 0x4c, 0x00, 0x02, 0x01, 0x01, 0x00DB0x02, 0xe0, 0x00, 0x40, 0x0b, 0xf0, 0x09, 0x00DB0x12, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00DB0x40, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x29, 0xffDB0xff, 0xff, 0xff, 0x48, 0x45, 0x4c, 0x4c, 0x4fDB0x2d, 0x4f, 0x53, 0x20, 0x20, 0x20, 0x46, 0x41DB0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00RESB16DB0xb8, 0x00, 0x00, 0x8e, 0xd0, 0xbc, 0x00, 0x7cDB0x8e, 0xd8, 0x8e, 0xc0, 0xbe, 0x74, 0x7c, 0x8aDB0x04, 0x83, 0xc6, 0x01, 0x3c, 0x00, 0x74, 0x09DB0xb4, 0x0e, 0xbb, 0x0f, 0x00, 0xcd, 0x10, 0xebDB0xee, 0xf4, 0xeb, 0xfd, 0x0a, 0x0a, 0x68, 0x65DB0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72DB0x6c, 0x64, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00RESB368DB0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaaDB0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00RESB4600DB0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00RESB1469432
然后再用
nask.exe helloos.nas helloos.img
把汇编代码编译成二进制就行了。
因为直接写二进制太繁琐,所以就用汇编代码来生成二进制了。
这就是汇编代码最直接的意义。
要想控制机器,必须使用二进制,但是我们人对二进制不敏感,所以,我们发明了一个编译器:nask.exe
这个编译器可以把我们人写的语句,翻译成机器需要的二进制编码。
我们人写这种语句,必须按照一定的格式,一定的语法,对于我们人来说,所以它是一门专门的语言了,这门语言的名字是什么呢?汇编语言
汇编中,万能的DB指令
代码中,每行的DB 就是写了一个字节的数据。
汇编中,补零的RESB指令
程序写成这样后,我们其实还是不知道这些数据的意义。我们没有看到跟"hello world"直接相关的语句。
我们利用汇编语言的语法,将以上映像的内容,写的我们人类能看得更加清楚一些:
; hello-os; TAB=4; 以下这段是标准FAT12格式软盘专用的代码DB0xeb, 0x4e, 0x90DB"HELLOIPL"; 启动区的名称可以是任意的字符串(8字节)?DW512; 每个扇区(sector)的大小(必须为512字节)DB1; 簇(cluster)的大小(必须为1个扇区)DW1; FAT的开始位置(一般是从第一个扇区开始)DB2; FAT的个数,必须为2DW224; 跟目录的大小(一般设置成224项)DW2880; 该磁盘的大小(必须是2880扇区)DB0xf0; 磁盘的种类(必须是0xf0)DW9; FAT的长度,必须是9扇区DW18; 1个磁道(track)有几个扇区(必须是18)DW2; 磁头数(必须是2)DD0; 不使用分区,必须是0DD2880; 重写一次磁盘大小DB0,0,0x29; 意义不明,固定DD0xffffffff; 可能是卷标号码DB"HELLO-OS "; 磁盘的名称(11字节)DB"FAT12 "; 磁盘格式名称(8字节)RESB18; 先空出18字节-; 程序主体DB0xb8, 0x00, 0x00, 0x8e, 0xd0, 0xbc, 0x00, 0x7cDB0x8e, 0xd8, 0x8e, 0xc0, 0xbe, 0x74, 0x7c, 0x8aDB0x04, 0x83, 0xc6, 0x01, 0x3c, 0x00, 0x74, 0x09DB0xb4, 0x0e, 0xbb, 0x0f, 0x00, 0xcd, 0x10, 0xebDB0xee, 0xf4, 0xeb, 0xfd; 信息显示部分DB0x0a, 0x0a; 让程序启动后,两个换行DB"hello, world" ;然后写个字符串hello worldDB0x0a; 再写一个换行DB0RESB0x1fe-$; 0x001fe位置之前的单元,都写成0x00DB0x55, 0xaa; 启动区以外的输出部分DB0xf0, 0xff, 0xff,电脑 0x00, 0x00, 0x00, 0x00, 0x00RESB4600DB0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00RESB1469432
可以看到,在这种写法中,我们清晰地知道每句汇编代码的意义,
也知道了,要更改输出一些内容,只要更改这个汇编代码的第37行即可。
但是这个代码里,依然有大量的DB语句,我们不太清楚其意义。
我们就继续改写这个代码,将其改为更加让我们人类能够理解的格式:
; hello-os; TAB=4ORG0x7c00; 指明程序装在抵制; 以下记述用于标准FAT12格式的软盘JMPentryDB0x90DB"HELLOIPL"DW512DB1DW1DB2DW224DW2880DB0xf0DW9DW18DW2DD0DD2880DB0,0,0x29DD0xffffffffDB"HELLO-OS 电脑 "DB"FAT12 "RESB18; 核心程序entry:MOVAX,0; 初始化寄存器MOVSS,AXMOVSP,0x7c00MOVDS,AXMOVES,AXMOVSI,msgputloop:MOVAL,[SI]ADDSI,1; 给SI加1CMPAL,0JEfinMOVAH,0x0e; 显示一个文字MOVBX,15; 指定字符颜色INT0x10; 调用显卡BIOSJMPputloopfin:HLT; 让cpu停止;等待指令JMPfin; 无限循环msg:DB0x0a, 0x0a; 换行2次DB"hello, world"DB0x0a; 换行DB0RESB0x7dfe-$; 0x7dfe?ü???e0x00??–????é–?—?DB0x55, 0xaa; 启动区以外的输出部分DB0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00RESB4600DB0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00RESB1469432
考虑的后面操作系统比较庞大,我们就不用汇编来开发整个操作系统了,但是512字节以内的启动区可以用汇编来写。
所以我们会先把汇编写的启动区程序写好,编译成二进制,
然后再将操作系统用其他语言写好,编译成二进制。
最后再将二者合成一个映像。
..\z_tools\edimg.exe imgin:../z_tools/fdimg0at.tek wbinimg src:ipl.bin len:512 from:0 to:0 imgout:helloos.img
此句就是将fdimg0at.tek和ipl.bin合并成helloos.img
fdimg0at.tek是用其他语言编辑好的二进制操作系统
ilp.bin是启动区程序。
然后,
为了操作方便,作者用了Makefile来实现自动编译,自动合并操作系统映像,自动运行操作系统模拟器:
代码位置:https://gitee.com/mingminglaoshi/MakeComputerOperateSystemin30Days/blob/master/projects/02_day/helloos5/Makefile
make run,就是调用make.exe -C ../z_tools/qumu 模拟器就会加载操作系统映像fdimage0.bin了。
make install 是将映像制作出来。
make img,就是将启动区和操作系统合并起来,由代码21行指向代码12行。
make asm将启动区程序制作出来。
这就是第二天的内容了:我们解析了那个二进制映像helloos.img里的具体内容。用汇编语言的形式,也用了C语言的形式。
并且代码中还使用了make工具,把编译,运行等工作自动化起来了,方便了很多。
电脑