通过分析、编译GeekOS系统的源代码并生成磁盘映射文件,来进一步了解操作系统的原理。并在Bochs模拟器下模拟启动,来了解操作系统的基本原理和系统的启动过程。程序在Linux系统环境下使用。当然你也可以在Windows下安装虚拟机。
1 实验目的
通过分析、编译GeekOS系统的源代码并生成磁盘映射文件,来进一步了解操作系统的原理。并在Bochs模拟器下模拟启动,来了解操作系统的基本原理和系统的启动过程。
2 实验要求
project0:系统配置/启动
目的:了解GeekOS的源代码,配置系统运行环境,并在Bochs模拟器下面运行。
任务:在内核中加入代码,打印出“Hello From Sensory! Mrl CopyRights”。然后根据代码要求,回显键盘输入并统计输入的字符数,直到终止键(Control+d)结束,打印”Ctrl+d Is Entered! Program Ended!”结束。
3 主要开发资源介绍
本实验所需资源:Fedora Core 3、Geekos-0.3.0、Bochs 2.2.6、Gedit、SourceInsight 3.50、 Nasm汇编语言编译器等。
3.1 操作系统
Linux操作系统。Redhat 自9.0以后,不再发布桌面版的,而是把这个项目与开源社区合作,于是就有了Fedora 这个 Linux 发行版。Fedora 可以说是Redhat 桌面版本的延续,只不过是与开源社区合作。
3.2 实验系统
GeekOS 是一个教育操作系统内核,它由Maryland大学David Hovemeyer所开发的基于X86的微内核操作系统。它尽量的简化了系统,但却提供了现代操作系统必须的最基本的功能,例如,虚拟内存,一个文件系统和交互进程通信。本实验使用的是geekos-0.3.0版。
3.3 仿真器介绍
Bochs是一个x86硬件平台的模拟器。换句话说,它可以模拟各种硬件的配置。当启动到Bochs时,看起来就好像你在自己的PC上启动了另外一个PC。Bochs模拟的是整个PC平台,包括I/O设备、内存和BIOS。更为有趣的是,甚至可以不使用PC硬件来运行Bochs。事实上,它可以在任何编译运行Bochs的平台上模拟x86硬件。通过改变配置,可以指定使用的CPU(386、486或者586),以及内存大小等。一句话,Bochs是电脑里的“PC”。根据需要,Bochs还可以模拟多台PC,此外,它甚至还有自己的电源按钮。注释行用#开头.
对Bochs的手动配置主要通过Bochsrc.txt文件来实现。可通过该文件的修改来规定启动方式(软盘、硬盘),用来模拟软盘或硬盘的映像文件等。
4 软件安装步骤
4.1 系统安装
光盘启动Linux安装程序,格式化linux分区和swap分区。安装过程可以选择安装。如果自定义可以安装开发工具包。其中默认安装包含本试验需要的开发工具。除了nasm软件。如果自定义,也可以选中安装。安装完重启即可。
4.2 等软件的安装
开发工具包里,有nasm软件。选中安装即可。如果安装系统没有安装。可以在以后的添加删除程序里安装,不过要安装盘。和windows安装其他软件类似。安装即可。
4.3 下载解压
网上下载Geekos-0.3.0。http://nchc.dl.sourceforge.net/sourceforge/geekos/geekos-0.3.0.zip
在linux下载为Geekos-0.3.0.tar.gz可以通过linux下的解压打开文件。或者通过如下命令解压:
gunzip Geekos-0.3.0.tar.gz
这样你将会看到Geekos-0.3.0.tar文件
tar Geekos-0.3.0.tar
这样你就会看到Geekos-0.3.0目录。
解压成功。
4.4 下载安装
下载解压类似Geekos。我下载的是bin文件。运行./*.bin后需要进入其目录运行安装命令:./configure
后可以运行bochs。在安装时需要用到make install可是我用的时候运行不成功,但bochs可以使用了。如果不是下载的bin文件,可以下载rpm文件,可以直接运行安装。
5 实践Project0
5.1 项目分析
在这个项目里面主要了解两部分的内容:内核线程和键盘处理,相应的文件是kthread.c和keyboard.c。程序里的EchoCount部分,有需要用的函数来完成项目。
1)Start_Kernel_Thread函数
①Start_Kernel_Thread函数(在kthread.c中)主要功能:建立一个内核线程。
内核线程结构的定义如下:
struct Kernel_Thread {
unsigned long esp;
volatile unsigned long numTicks;
int priority;
DEFINE_LINK( Thread_Queue, Kernel_Thread );
void* stackPage;
struct User_Context* userContext;
struct Kernel_Thread* owner;
int refCount;
Boolean alive;
struct Mutex joinLock;
struct Condition joinCond;
};
esp字段用来存放一个线程挂起的堆栈指针;
stackPage字段指向内核线程的堆栈页面
numTicks和priority分别被调度程序用来实现基于先占权和基于优先权的时间片调度。
DEFINE_LINK宏定义一个内核线程在线程队列上时的前一个和后一个字段。
userContext字段如果不为空,则指向一个线程用户环境,它是一个允许线程执行用户模式的代码和数据的组合段。
内核线程有两种方式创建。在内核里独立运行的线程可通过Start_Kernel_Thread()函数来创建,该函数通过一个指针指向一个执行线程体的启动函数。线程所执行的用户模式的程序由Start_User_Thread()函数创建,并且用一指针指向一个用户环境和用户环境内存中代码入口点的地址。调用Exit()函数销毁内核线程。
首先在主程序里调用Start_Kernel_Thread 开始创建一条内核线程:Mythread=Start_Kernel_Thread (&MyFunction,0,PRIORITY_NORMAL,false);
入口参数分别为:函数地址,函数参数(无参数就写0),优先级设定,线程属性(false为内核线程,true为用户线程),返回值Mythread 的数据类型是static struct Kernel_Thread* thread
②Start_Kernel_Thread 完成的工作:
◎ Create_Thread(priority, detached) //根据优先级创建一条线程
kthread = Alloc_Page() //为线程分配内存空间
stackPage = Alloc_Page()
Init_Thread(kthread, stackPage, priority, detached)
Add_To_Back_Of_All_Thread_List(&s_allThreadList, kthread)
◎