动手写操作系统 -- 单任务系统


再说下,我们的需求就是写个支持多任务,分时调度的操作系统。

这一节,先写个单任务的系统,开机能能够加载并执行即可。

OK,先上代码: funnyos_onetask.7z,文件列表如下:

pic

编译命令:

#build.bat的内容:
tcc -I. -Ic:\tcc\include -Lc:\tcc\lib -c -ml -1 -G -O -Z -d -k- -v -vi- -wpro PC.C
tcc -I. -Ic:\tcc\include -Lc:\tcc\lib -c -ml -1 -G -O -Z -d -k- -v -vi- -wpro Test.C
tlib my +pc+test
tlink /v /s /c c0l,test,test,my+cl.lib
exeflat TEST.EXE TEST.SYS 0x60
ndisasm -o 0x600 TEST.SYS > a.asm 
rename TEST.SYS KERNEL.SYS

nasm -dISFAT12 boot.asm -o boot.bin

tcc -Ic:\tcc\include -Lc:\tcc\lib buildimg.c
buildimg.exe

只需双击执行build.bat即可生成Test.exe及FunnyOS.img。 FunnyOS.img是由buildimg.exe生成的。

FunnyOS.img为1.44M的虚拟软盘,即系统是放在软盘里的,可以用VirtualBox,Bochs,JPC运行。

FunnyOS.img的大致结构如下,前面512字节为引导扇区,开机BIOS执行完毕后会读取软盘加载执行这512个字节的引导代码。

引导代码会读取然盘的FAT12文件系统找出KERNEL.SYS文件,KERNEL.SYS文件是由exeflat.com程序将TEST.EXE转成BIN格式而来。

pic


可以看到FunnyOS.img运行结果和Test.exe一致,如下:

在windows下运行的截图:

pic

在virtualbox上运行FunnyOS.img截图:

pic


OK,下面就是代码分析 test.c代码如下,很简单,先清空屏幕,然后在第一行显示” Funny OS Demo “。

#include "pc.h"
void  main (void) {
    PC_DispClrScr(DISP_FGND_WHITE + DISP_BGND_BLACK);      /* Clear the screen                         */

    PC_DispStr( 0,  0, "                              Funny OS Demo                                     ", DISP_FGND_WHITE + DISP_BGND_RED + DISP_BLINK);
	for(;;);
}

main函数调用了PC.C中的函数,PC.C来自UCOS系统,

基础知识:

段地址0xB800是字符模式下显存的基地址,支持25行,80列显示。往0xB8000地址里面写如0x41,就能显示字符'A',
具体显示部分请查看PC.C
我这里主要说明如何将一个EXE文件变成一个操作系统的"内核":
EXE文件除了包含二进制代码,还包含其它信息,如文件头和可重定位信息,这些是方便Windows操作系统加载运行的,
对于自己写的操作系统,这些信息没有意义,只需要其中的二进制代码即可。

将EXE文件转换成二进制文件,即BIN文件,可以用exeflat.com,但是默认转后BIN文件的入口地址为0x0,
也就是说将这个文件放在内存开始部分才能正确运行。

但要知道,内存的前1024个字节(0-0x3FF)是存放中断向量的,这部分内存不能被占用。
不仅如此,地址(0x400-0x5FF)这部分空间还存放了BIOS的基本数据,如当前时间等。

所以只有从0x600开始的内存空间才允许放置程序,所以生成BIN文件的命令为: exeflat TEST.EXE TEST.SYS 0x60

如之前所述,引导代码将KERNEL从软盘中读取到内存0x600处,然后就跳到test.c的main()函数执行,那引导代码是如何知道main()函数地址的呢?

看下生成的TEST.MAP,其中DATA段的段地址为0x1160,main()函数地址为0x113D。



OK,要执行main()函数,须将CS:IP设置为0x60:0x113D,DS设置为0x116,手动修改跳转代码,简单粗暴的跳到了main函数,下面的运行和test.exe就一样了。



上篇: 动手写操作系统 -- 前言 下篇: 动手写操作系统 -- 定时器中断