自己动手写操作系统( 二 )


把程序写至启动扇区
下面写一个C程序,把我的操作系统写入软盘第一扇区 。程序内容如下:#include/* unistd.h 需要这个文件 */
#include /* 包含有read和write函数 */
#include
int main()
{
char boot_buf[512];
int floppy_desc, file_desc;
file_desc = open("./boot", O_RDONLY);
read(file_desc, boot_buf, 510);
close(file_desc);
boot_buf[510] = 0x55;
boot_buf[511] = 0xaa;
floppy_desc = open("/dev/fd0", O_RDWR);
lseek(floppy_desc, 0, SEEK_CUR);
write(floppy_desc, boot_buf, 512);
close(floppy_desc);
}
首先,以只读模式打开boot文件,然后在打开文件时把文件描述符复制到file_desc变量中 。从文件中读取510个字符,或者读取直到文件结束 。在本例中由于文件很小,所以是读取至文件结束 。然后关闭文件 。最后4行代码打开软盘驱动设备(一般来说是/dev/fd0) 。使用lseek找到文件开始处,然后从缓冲中向软盘写512个字节 。在read、write、open和lseek的帮助页中,可以看到与函数所有有关的参数及其使用方法 。程序中有两行比较难懂:boot_buf[510] = 0x55;
boot_buf[511] = 0xaa;
该信息是用于BIOS的,如果它识别出该设备是一个可启动的设备,那么在第510和511的位置,该值就应该是0x55和0xaa 。程序会把文件boot读至名为boot_buf的缓冲中 。它要求改变第510和第511字节,然后把boot_buf写至软盘之上 。如果执行代码,软盘上的前512字节就包含了启动代码 。最后,把文件存为write.c 。
编译运行
使用下面的命令把文件变为可执行文件:as86 boot.s -o boot.o
ld86 -d boot.o -o boot
cc write.c -o write
首先将boot.s文件编译成目标文件boot.o,然后将该文件连接成最终的boot文件 。最后C程序编译成可执行的write文件 。插入一个空白软盘,运行以下程序:./write
重新启动电脑,进行BIOS的界面设置,并且把软盘设为第一个启动的设备 。然后插入软盘,电脑从软盘上启动 。启动完成后,在屏幕上可以看到一个字母A(蓝底白字),启动速度很快,几乎是在瞬间完成 。这就意味着系统已经从我们制作的软盘上启动了,并且执行了刚才写入启动扇区的程序 。现在,它正处在一个无限循环的状态 。所以,如果想进入Linux,必需拿掉软盘,并且重启机器 。至此,这个操作系统就算完成了,虽然它没有实现什么功能,但是它已经可以启动机器了 。
上一期,我讲述了如何在软盘的启动扇区写一些代码,然后再从软盘启动的过程 。制作好一个启动扇区,在切换到保护模式之前,我们还应该知道如何使用BIOS中断 。BIOS中断是一些由BIOS提供的、为了使操作系统的创建更容易的低级程序 。在本文中,我们将学习处理BIOS的中断 。
为什么要用BIOS
BIOS会把启动扇区拷贝至RAM中,并且执行这些代码 。除此之外,BIOS还要做很多其它的事情 。当一个操作系统刚开始启动时,系统中并没有显卡驱动、软盘驱动等任何驱动程序 。因此,启动扇区中不可能包含任何一个驱动程序,我们要采取其它的途径 。这个时候,BIOS就可以帮助我们了 。BIOS中包含有各种可以使用的程序,包括检测安装的设备、控制打印机、计算内存大小等用于各种目的的程序 。这些程序就是所说的BIOS中断 。
如何调用BIOS中断
在一般的程序设计语言中,函数的调用是一件非常容易的事情 。比如在C语言中,如果有一个名为display的程序,它带有两个参数,其中参数noofchar表示显示的字符数,参数attr表示显示字符的属性 。那么要调用它,只需给出程序的名称即可 。对于中断的调用,我们使用的是汇编语言中的int指令 。比如,在C语言中要显示一些东西时,使用的指令如下所示:display(nofchar,attr);

推荐阅读