2. text mode下的vga驱动

这篇文章分为两部分,前部分是写简单的vga驱动程序,后部分进行测试。但是kernel测试不同于普通的应用程序,首先要让kernel跑起来然后才能观测结果,所以后半部分又可分为两个部分 —— 制作引导盘和运行kernel。所以简单点儿,就分为三个部分吧:

1:  编写vga驱动程序

2:  制作引导盘 (此部分非常重要,写简单的kernel难点不在于程序的编写,而在于工具的使用)

3:  测试驱动程序


第一部分: 编写vga驱动程序


 

首先要定义下整个开发过程中都要用到的数据类型

types.h

 

因为在写终端驱动时要对IO设备的寄存器进行操作,所以再建立一个头文件 io.h

1 #ifndef __IO_H__
2 #define __IO_H__
3 
4 #define outb(data,port) __asm__ __volatile__("outb %%al, %%dx"::"a"(data),"d"(port))
5 #endif

 

OK,现在正式进军终端驱动程序了。这个驱动提供什么功能呢,很简单,清屏以及打印字符串。注意程序向外提供的函数应该声明在.h文件中,只供内部使用的函数应该直接在 .c 文件中声明。好吧,实现以上两个功能的函数显然要声明在 console.h 中

1 #ifndef __CONSOLE_H__
2 #define __CONSOLE_H__
3 
4 void cons_write(const char* str);
5 void cons_clear(void);
6 
7 #endif

 

最后来真正实现这些功能吧。实现驱动必须了解硬件的相关信息:从b8000到bffff的32K地址空间是显存,屏幕是80*25的规格(即每行80字符,总共25行),屏幕上的每个字符在显存中用两个字节表示,高字节是字符的ASCII值,低字节是字符的属性(0x07代表背景黑前景白)。注意80*25*2=4000,比4K略小,而显存空间为32K,这说明屏幕只能显示一部分显存。这就说明显示控制器中肯定有个寄存器来说明到底显示显存的那一部分,显存通常划分为页,那个寄存器存放的就是要显示的页码。在Tinux(我取的名字)中,为了保持简单,我只使用从b8000开始的4000字节,当打印不下时就向上滚动。

console.c

至此,这一节的代码全部完成,有3个头文件types.h io.h console.h, 1个源文件 console.c


 

第二部分: 制作引导盘


 

下面我们来测试console.c, 不要小看测试, 我觉得在写OS kernel时,测试比写正式代码重要得多。记得上一节的helloworld程序的加载过程吗,不过很遗憾,那种自己写引导程序的方式很费时间,所以我准备采用Grub来引导我的Kernel,下面就跟着我一步一步做Grub引导盘吧。

1. Create the floppy disk image (1.44M capacity)

    $ dd if=/dev/zero of=floppy.img bs=1024 count=1440

2. Create and attach a loopback device to floppy.img

        $ sudo losetup /dev/loop1 floppy.img

3. Format floppy.img with ext2 file system.

        $ sudo mke2fs /dev/loop1

4. Mount the device, so we can read or write to it.

        $ sudo mount -o loop /dev/loop1 /mnt

5. Copy the stage1 and stage2 from /boot/grub to that /mnt/boot/grub

        $ sudo mkdir -p /mnt/boot/grub

        $ sudo cp /boot/grub/stage1 /boot/grub/stage2 /mnt/grub/

6. Create the Grub configuration file

        $ sudo vi /mnt/boot/grub/menu.lst

        Edit menu.lst like this:     

            1 title=Tinux
            2 root (fd0)
            3 kernel /boot/kernel.bin

7. Unmount the device

       $ sudo umount /mnt

8. Install and embed grub into floppy.img

       $ sudo grub --device-map=/dev/null

       Upon which you should get the grub interface. Enter the following commands into it:

            grub> device (fd0) /dev/loop1

            grub> root (fd0)

            grub> setup (fd0)              /* 这一步grub可能会说有分区表的问题,不要理会它 */

            grub> quit

9. Detach the loopback device.

        $ sudo losetup -d /dev/loop1

 引导盘floppy.img已制作完成,我们以后要加载内核只要将内核映像kernel.bin拷进floppy.img就可以了。但是floppy.img毕竟不是一个真软盘,想要拷贝仍然要借助losetup和mount命令。

 

 

第三部分:  编写测试文件


 

最后来写测试文件吧,setup.S用来引导内核(这个引导只是为grub提供一些参数), test.c是真正的测试程序, Makefile文件用控制整个编译过程, kernel.ld则是Makefile要用到的链接脚本。

setup.S

 

test.c

 

Makefile

 

kernel.ld

 

OK, 加上这4个,现在你的目录下应该有8个文件了,在当前目录下运行make就可以得到包含kernel.bin的floppy.img文件了,接下来要做的就是用bochs虚拟机来运行floppy.img,所以我们还要写最后一个文件 bochsrc。我的bochsrc很长,但大部分是注释。

bochsrc

 

 

终于Complete了,你可以先make编译($ make) 再用bochs看结果了($ bochs),截图如下。不过这仅仅是完成了文本终端驱动,后面的路还长着呢, 只能慢慢地老汉推车了。

           

 

ps: 关于第二部分我主要参考http://sig9.com/bochs-grub,本想直接给个链接就完了,但是觉得它有些地方没说清楚,所以就做了些许改动,贴了上来。上面整个过程我都实验过了,如有问题可发邮件至 JohnWaken@163.com

源码下载: Tinux2.tar.gz

posted on 2009-10-21 17:37  John Waken  阅读(2174)  评论(0编辑  收藏  举报

导航