entry start
start:
mov ax,#0xb800
mov es,ax
seg es
mov [0],#0x41
seg es
mov [1],#0x1f
loop1: jmp loop1
这是as86可以读懂的一段汇编程序。第一个句子指明了程序的入口点,声明整个过程从start处开始。第二行指明了start的位置,说明整个程序要从start处开始执行。0xb800是显存的开始地址。#表明其后是一个立即数。执行语句:
mov ax,#oxb800
ax寄存器的值就变为0xb800,这就是显存的地址。下面再将这个值移至es寄存器,es是附加段寄存器。请记住8086有一个分段的体系结构。它的各段寄存器为代码段、数据段、堆栈段和附加段,对应的寄存器名称分别为cs、ds、ss和es。事实上,我们把显存地址送入了附加段,因此,任何送入附加段的东西都会被送到显存中。
要在屏幕上显示字符,就需要向显存中写两个字节。前一个是所要显示字符的ASCⅡ值,第二个字节表示该字符的属性。属性包括字符的前景色、背景色及是否闪烁等等。seg es指明下一个将要执行的指令是指向es段的。所以,我们把值0x41(在ASCⅡ中表示的字符是A)送到显存的第一个字节中。接下来要把字符的属性送到下一个字节当中。在此输入的是0x1f,该属性指的是在蓝色背景下显示白色的字符。因此,如果执行这个程序,就可以在屏幕上得到显示在蓝底上的一个白色的A。接着是一个循环。因为在执行完显示字符的任务后,要么让程序结束,要么使用一个循环使其永远运行下去。把该文件命名为boot.s,然后存盘。
此处显存的概念说得不是很清楚,有必要进一步解释一下。假设屏幕由80列×25行组成,那么第一行就需要160字节,其中一个字节用于表示字符,另外一个字节用于表示字符的属性。如果要在第三行显示某一字符的话,就要跳过显存的第0和1字节(它们是用于显示第1列的),第2和3字节(它们是用于显示第2列的),然后把需要显示字符的ASCⅡ码值入第4字节,把字符的属性写入第5字节。
把程序写至启动扇区
下面写一个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中断、保护模式切换等等)。
本文地址:http://com.8s8s.com/it/it23459.htm