操作系统Geek OS.docx
- 文档编号:23813443
- 上传时间:2023-05-21
- 格式:DOCX
- 页数:15
- 大小:227.08KB
操作系统Geek OS.docx
《操作系统Geek OS.docx》由会员分享,可在线阅读,更多相关《操作系统Geek OS.docx(15页珍藏版)》请在冰豆网上搜索。
操作系统GeekOS
目录
一、实验目的2
二、项目设计要求2
1.project0:
2
2.project1:
2
三、实验工具及环境配置介绍2
1.GeekOS简介2
2.BochsPC模拟器简介3
3.VMware虚拟机介绍3
4.环境配置3
四、项目实现4
1.Project04
1.1项目设计原理4
1.2代码实现5
1.3编译运行6
1.4运行结果图6
2.Project17
2.1项目要求及分析7
2.2设计原理7
2.3具体实现8
2.4编译运行9
2.5运行结果9
3.存在的问题:
9
4.小结:
10
一、实验目的
熟悉GeekOs的项目编译、调试和运行环境,掌握GeekOs运行工作过程。
熟悉ELF文件格式,了解GeekOs系统如何将ELF格式的用户可执行程序装入到内存,建立内核线程并运行的实现技术。
扩充GeekOs操作系统内核,使得系统能过支持用户级进程的动态创建和执行。
通过对一个教学操作系统GEEKOS的编译过程,形成磁盘映射文件,并在Bochs模拟器下模拟启动,来了解操作系统的基本原理和系统的启动过程。
二、项目设计要求
本次实验需要完成以下2个项目:
1.project0:
目的:
熟悉GeekOS的项目编译、调试和运行环境,掌握GeekOS运行工作过程。
要求:
(1)搭建GeekOS的编译和调试平台,掌握GeekOS的内核进程工作原理。
(2)熟悉键盘操作函数,编程实现一个内核进程。
该进程的功能是:
接收键盘输入的字符并显示到屏幕上,当输入CTRL+D时,结束进程。
2.project1:
目的:
熟悉ELF文件格式,了解GeekOS系统如何将ELF格式的用户可执行程序装入到内存,建立内核进程并运行的实现技术。
要求:
(1)修改/GeekOS/elc.c文件:
在函数Parse_ELF_Executable()中添加代码,分析ELF格式的可执行文件,并填充Exe_Format数据结构中的域。
(2)掌握GeekOS在核心态运行用户程序原理,为项目2的实现做准备。
三、实验工具及环境配置介绍
1.GeekOS简介
GeekOS是一个教育操作系统内核,它由Maryland大学DavidHovemeyer所开发的基于X86的微内核操作系统。
它尽量的简化了系统,但却提供了现代操作系统必须的最基本的功能,例如,虚拟内存,一个文件系统和交互进程通信。
GeekOS有以下的重要特征:
1.中断处理
2.堆栈存储分配
3.基于静态优选权时序安排的时间片内核线程
4.用于系统线程同步的互斥和条件变量
5.基于段式内存保护的用户模式和简单的系统调用接口
6.键盘驱动和VGA文本显示模式驱动
目前,除上述所列的之外,还缺少虚拟内存、存储设备驱动和文件系统。
在这系统中采用分段原理实现用户模式的内存保护。
用户分段采用32位的内存模式并通过实模式的段寻址和偏移寻址来避免内存访问冲突。
由于没有文件系统,GeekOS系统将用户应用程序当作数据对象直接编译连接到内核。
这系统也能被用来实现一个基于RAM的文件系统。
因为GeekOS不使用分页,所有的内核代码运行都使用物理地址。
下图3.1表明GeekOS和它的数据结构是怎样占据物理内存的。
引导扇区将内核放在物理地址为10000H(64K)的地方。
初始化程序和数据放在地址为90000H的地方;但是,一旦进入内核的Main()函数,初始化程序就不会再被使用,并且它所占据的内存被回收。
在GeekOS中,会发生线程现场切换,原因有两个:
首先,一个线程可以通过调用Yield()或Wait()函数自动放弃CPU。
在这些函数里,当前线程都被放到一个线程队列中,同时一个新线程通过调用Schedule()函数被选中。
Yield()函数把要调用的线程放到运行队列中,在那里它可能会被重新调度。
Wait()函数把要调用的线程放到等待队列中,该线程保持等待直到其他线程或中断处理器调用Wake_Up()函数把它重新放回到运行队列中。
为了同步核心线程,GeekOS提供了模仿POSIX线程提供的那些互斥和条件变量,互斥变量用来决定谁能单独访问可为多个线程共享的数据结构。
条件变量允许线程去等待一个条件被满足,或者发出信号说某条件已经被满足。
任何OS内核的作用在于它可以运行其它程序。
它必须以一种方式在用户程序中保护核心,和用户程序之间不相互干扰。
因此,GeekOS的用户模式基本上是按顺序来实现的。
为了获得更快的运行速度,采用x86扇区为用户模式程序创建一个严格的环境。
用户代码可以访问和修改它自身的数据并且创建系统调用命令,但是对于其它OS资源是受到限制。
用户程序访问代码或者访问外部数据这两种企图都会导致一个一般的保护性的错误,这个错误会让该线程中止。
GeekOS并没有现成的存储设备和文件系统。
然而,它提供了一种把用户程序作为数据对象连接到内核的方法。
用户的执行首先链接到起始的0地址。
对于每一步的执行,都会产生一个平整的二进制映像。
一个perl脚本随后把映像转换成C的数据机构体。
这些数据结构体集中在一个表里,通过这个表内核可以通过名字查找它们。
2.BochsPC模拟器简介
Bochs是一个x86硬件平台的模拟器。
换句话说,它可以模拟各种硬件的配置。
当启动到Bochs时,看起来就好像你在自己的PC上启动了另外一个PC。
Bochs模拟的是整个PC平台,包括I/O设备、内存和BIOS。
更为有趣的是,甚至可以不使用PC硬件来运行Bochs。
事实上,它可以在任何编译运行Bochs的平台上模拟x86硬件。
通过改变配置,可以指定使用的CPU(386、486或者586),以及内存大小等。
一句话,Bochs是电脑里的“PC”。
根据需要,Bochs还可以模拟多台PC。
目前,Bochs可以模拟386,486,PentiumPro或者AMD64CPU,包括可选的MMX,SSE,SSE2和3DNow指令。
Bochs的模拟环境中可以运行大部分的操作系统,包括Linux,Windows95,DOS,WindowsNT4,FreeBSD,MINIX等。
目前的GEEKOS操作系统只能在BOCHS虚拟机上调试运行。
3.VMware虚拟机介绍
VMware是一个具有创新意义的应用程序通过VMware独特的虚拟功能,用户可以在同一个窗口运行多个全功能的虚拟机操作系统。
4.环境配置
①下载并安装VMware6.0;
②建立虚拟机,在VMware中新建NewVirtualMachine,按系统提示安装好redhat9.0Linux系统;
③安装VMwareTools实现WindowsXP系统与Linux系统下的文件共享;
④安装Bochs,并对不同项目相应创建配置文件;
⑤检查Linux系统下是否已经安装了GNUgcc,nasm汇编语言编译器,gdb调试器,若已安装激活他们,如未安装,下载并安装他们。
⑥下载并解压GeekOS-0.3.0,至此实验开发环境搭建完成。
四、项目实现
1.Project0
1.1项目设计原理
熟悉键盘操作函数,编程实现新建一个内核进程。
该进程的功能是:
接受键盘输入的字符并显示到屏幕,当输入ctrl+d时,结束进程。
在这个项目里面主要了解两部分的内容:
内核线程和键盘处理,相应的文件是kthread.c和keyboard.c。
程序里的EchoCount部分,有需要用的函数来完成项目。
1)Start_Kernel_Thread函数
①Start_Kernel_Thread函数(在kthread.c中)主要功能:
建立一个内核线程。
内核线程结构的定义如下:
structKernel_Thread{
unsignedlongesp;
volatileunsignedlongnumTicks;
intpriority;
DEFINE_LINK(Thread_Queue,Kernel_Thread);
void*stackPage;
structUser_Context*userContext;
structKernel_Thread*owner;
intrefCount;
Booleanalive;
structMutexjoinLock;
structConditionjoinCond;
};
esp字段用来存放一个线程挂起的堆栈指针;stackPage字段指向内核线程的堆栈页面;numTicks和priority分别被调度程序用来实现基于先占权和基于优先权的时间片调度;DEFINE_LINK宏定义一个内核线程在线程队列上时的前一个和后一个字段;userContext字段如果不为空,则指向一个线程用户环境,它是一个允许线程执行用户模式的代码和数据的组合段;其余字段用来实现Join()函数,该函数允许父线程等待子线程退出。
内核线程有两种方式创建。
在内核里独立运行的线程可通过Start_Kernel_Thread()函数来创建,该函数通过一个指针指向一个执行线程体的启动函数。
线程所执行的用户模式的程序由Start_User_Thread()函数创建,并且用一指针指向一个用户环境和用户环境内存中代码入口点的地址。
调用Exit()函数销毁内核线程。
首先在主程序里调用Start_Kernel_Thread开始创建一条内核线程:
Mythread=Start_Kernel_Thread(&MyFunction,0,PRIORITY_NORMAL,false);入口参数分别为:
函数地址,函数参数(无参数就写0),优先级设定,线程属性(false为内核线程,true为用户线程),返回值Mythread的数据类型是staticstructKernel_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)
Setup_Kernel_Thread(kthread,startFunc,arg)//配置内核线程的初始化
Make_Runnable_Atomic(kthread);//设置线程运行的原子性操作
Disable_Interrupts();//禁止中断
Make_Runnable(kthread);//线程运行
Enable_Interrupts();//使能中断
2)编写线程子程序voidEchoCount()
3)Geekos是如何处理键盘代码
在keyboard.c里面提供了一个功用函数KeycodeWait_For_Key(void),循环等待一个键盘事件,然后返回一个16位的数据Keycode型的,在keyboard.h里定义了所有的键盘代码。
Read_Key(Keycode*keycode)函数可以处理队列键盘按键,可以保存到队列中并输出。
关于Keycode的定义是:
低8位用来表示键盘值,通过s_scanTableNoShift和s_scanTableWithShift这两个数组来转换相应的键盘码为所表示字符的ASCII码,高六位分别是:
KEY_SPECIAL_FLAG(特殊键,比如F1,F2)用返回的值key&0x0100就可以判断是否按下特殊健,1为有效,说明是特殊健,0则不是,以下的几种情况类似
KEY_KEYPAD_FLAG(小键盘键)0x0200
KEY_SHIFT_FLAG(左,右SHIFT)0x1000
KEY_ALT_FLAG(左,右ALT)0x2000
KEY_CTRL_FLAG(左,右CTRL)0x4000
KEY_RELEASE_FLAG(键弹起来标志位)0x8000
1.2代码实现
①输入并回显函数的实现
staticvoidkeyin(void)
{
Keycodekeycode;
Print("\n--------Waitforyourinput,Ctrl+dtoexit--------\n");
while
(1)
{
keycode=Wait_For_Key();//读取键盘按键状态
//Print("%d\n",keycode);
if(!
((keycode&0x0100)||(keycode&0x8000)))
//处理非特殊按键的按下事件
{
intasciiCode=keycode&0x03ff;//低8位为Ascii码
if((keycode&0x4000)==0x4000&&asciiCode=='d')
//按下Ctrl键
{
Print("\nCtrl+dpressed!
Ended\n");
Exit
(1);
}
else
{
Print("%c",(asciiCode=='\r')?
'\n':
asciiCode);
}
}
}
}
②修改main.c
在main.c中添加:
Start_Kernel_Thread(keyin,0,PRIORITY_NORMAL,false);其中参数0表示新建的为内核进程,若为1表示新建用户级进程。
1.3编译运行
进入Build目录下:
$makedepend
$make
运行bochs。
1.4运行结果图
配置好Boch的bochsrc.txt。
启动Boch仿真,程序正常运行结果如下图:
2.Project1
2.1项目要求及分析
主要是分析ELF文件的格式,了解操作系统执行一个应用程序的工作原理,然后在Parse_ELF_Executable()中添加代码,实现对ELF文件的解释,装入到内存运行,得到指定的结果。
并掌握GeekOS的在核心态运行用户程序的原理。
2.2设计原理
①ELF文件格式
连接程序视图
执行程序视图
ELF头部
ELF头部
程序头部表(可选)
程序头部表
节区1
段1
...
节区n
段2
...
...
...
节区头部表
节区头部表(可选)
②内存中的可执行文件镜像
③内核线程的建立流程
④Spawn_Program函数的功能
根据Exe_Format中的Exe_Segment结构提供的用户程序段信息,及用户进程堆栈大小计算用户进程所需的最大内存空间,即要分配给用户进程的内存空间;为用户程序分配内存空间,并全部初始化为零,否则系统后面运行可能出错;根据段信息将用户程序中的各段内容复制到分配的用户内存空间。
根据Exe_Segment提供的用户段信息初始化代码段、数据段以及堆栈段的段描述符和段选择子。
⑤Parse_ELF_Excutable函数
intParse_ELF_Executable(char*exeFileData,ulong_texeFileLength,
structExe_Format*exeFormat)
参数:
exeFileData——已装入内存的可执行文件所占用空间的起始地址
exeFileLength——可执行文件长度
exeFormat——保存分析得到的elf文件信息的结构体指针
根据ELF文件格式,用户可以从exeFileData指向的内容中得到ELF文件头,继续分析可以得到程序头,程序代码段等信息。
2.3具体实现
修改elf.c文件:
intelfDebug=0;
intParse_ELF_Executable(char*exeFileData,ulong_texeFileLength,
structExe_Format*exeFormat)
{
intk;
elfHeader*head=(elfHeader*)exeFileData;
programHeader*proHeader=(programHeader*)(exeFileData+head->phoff);
for(k=0;k
{
exeFormat->segmentList[k].offsetInFile=proHeader->offset;
exeFormat->segmentList[k].lengthInFile=proHeader->fileSize;
exeFormat->segmentList[k].startAddress=proHeader->vaddr;
exeFormat->segmentList[k].sizeInMemory=proHeader->memSize;
exeFormat->segmentList[k].protFlags=proHeader->flags;
proHeader++;
}
exeFormat->numSegments=head->phnum;
exeFormat->entryAddr=head->entry;
return0;
}
2.4编译运行
进入Build目录下:
$makedepend
$make
运行bochs。
2.5运行结果
程序正常运行结果如下图:
3.存在的问题:
在本次课程设计中到规定的时间为止,项目0和项目1两个项目按时顺利完成,项目2也运行成功,但没有参加验收,因为只是运行出结果,并没有进行消化分析。
而且,在进行项目任务的时候,有些操作是根据书本来做,当出现错误时,就不知如何进一步查错。
所以,在以后的时间里,会进一步学习OS的内部机理。
4.小结:
通过认真阅读project0中的keyboard.h,懂得了如按下一个键时产生的键码(keycode)是16位等一些细节问题。
总之,通过这次的课程设计,我不仅掌握了OS的工作原理,了解了linux下的一些命令,同时也体会到了Bochs虚拟机功能特点。
通过对GeekOS教学平台系统的分析、编译和仿真,我对操作系统的整个结构组成及操作系统的相关原理有了比较深入的了解,对于内存的分配、内核线程、中断和调度、线程同步、用户模式等技术有了比较清晰的概念,另外,对于操作系统如何从磁盘启动加载到系统运行的整个过程有了全面的了解。
在此次课程设计中,非常感谢我的指导老师--黄廷辉和帮助我的同学们。
这次课程设计不仅使我在知识层面上得到提高,更使我在计算机科学领域的思想上有了很大的收获。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 操作系统Geek OS 操作系统 Geek
![提示](https://static.bdocx.com/images/bang_tan.gif)