GeekOS课程设计报告.docx
- 文档编号:3828642
- 上传时间:2022-11-25
- 格式:DOCX
- 页数:27
- 大小:312.26KB
GeekOS课程设计报告.docx
《GeekOS课程设计报告.docx》由会员分享,可在线阅读,更多相关《GeekOS课程设计报告.docx(27页珍藏版)》请在冰豆网上搜索。
GeekOS课程设计报告
编号:
GeekOS操作系统的研究与实现
题目:
GeekOS操作系统的研究与实现
系别:
计算机科学与工程学院
专业:
网络工程
学生姓名:
学号:
指导教师:
2011年3月5日
(三号、黑体、居中、目录两字空四格、与正文空一行)
一、课程设计环境……………………………………………………4
二、设计项目0……………………………………………………5
三、设计项目1………………………………………………………7
四、设计项2……………………………………………………………9
五、遇到问题及解决方法.……………………………………………23
六、总结…………………………………………………………………24
一、课程设计环境
本次课设是在虚拟机上安装Linux进行开发调试,具体安装使用方法如下:
<1>、安装linux虚拟机
本次课设的虚拟机是运行在VmwareWorkStation上的,网上下载及安装好
Vmware后,下载Linux镜像文件后,即可按提示即可安装。
<2>、GeekOS:
是一个基于X86架构的PC机上运行的微操作系统内核,由美国
马理兰大学的教师开发,是一个用C语言开发的操作系统,GeekOS主要
用于操作系统课程设计,目的是使学生能够实际动手参与到一个操作系统的
开发工作中。
GeekOS的使用:
打开linux虚拟机,直接解压GeekOS压缩包就可使用,
无需安装。
<3>、Bochs安装和使用:
在Linux系统中需先解压软件包,然后再配置编译生成系统文件。
二、设计项目0
一、项目设计目的
熟悉GeekOS的项目编译、调试和运行环境,掌握GeekOS运行工作过程。
二、设计任务
熟悉键盘操作函数,编程实现一个内核进程。
该进程的功能是:
接收键盘输入的字符并显示到屏幕上,当输入ctrl+d时,结束进程的运行。
三、具体过程
1、------------------------修改main.c的代码--------------------------------
//在main.c内增加该函数
voidproject0()
{
Print("ToExithitCtrl+d.\n");
Keycodekeycode;
while
(1)
{
if(Read_Key(&keycode))//读取键盘按键状态
{
if(!
((keycode&KEY_SPECIAL_FLAG)||(keycode&KEY_RELEASE_FLAG)))//只处理非特殊按键的按下事件
{
intasciiCode=keycode&0xff;//低位为Ascii码
if((keycode&KEY_CTRL_FLAG)==KEY_CTRL_FLAG&&asciiCode=='d')//按下Ctrl键
{
Print("\n---------BYE!
--------\n");
Exit
(1);
}else
{
Print("%c",(asciiCode=='\r')?
'\n':
asciiCode);
}
}
}
}
}
//在main函数体内调用Start_Kernel_Thread函数
structKernel_Thread*thread;
thread=Start_Kernel_Thread(&project0,0,PRIORITY_NORMAL,false);
----------------------------------------------------
2、在build目录下编译得到镜像文件fd.img
#make
3、编写brochs配置文件
vgaromimage:
file=/usr/share/bochs/VGABIOS-lgpl-latest
romimage:
file=/usr/share/bochs/BIOS-bochs-latest,address=0xf0000
megs:
8
boot:
a
floppya:
1_44=fd.img,status=inserted
#floppya:
1_44=fd_aug.img,status=inserted
log:
./bochs.out
keyboard_serial_delay:
200
floppy_command_delay:
500
vga_update_interval:
300000
ips:
1000000
mouse:
enabled=0
private_colormap:
enabled=0
i440fxsupport:
enabled=0
4、在brochs中运行GeekOS系统显示结果
3、设计项目1
一、项目设计目的
熟悉ELF文件格式,了解GeekOS系统如何将ELF格式的可执行程序装
入到内存,建立内核进程并运行的实现技术。
2、具体过程
修改/geekos/elf.c文件:
在函数Parse_ELF_Executable()中添加代码,分析
ELF格式的可执行文件(包括分析得出ELF文件头、程序头,获取可执行文
件长度,代码段、数据段等信息),并填充Exe_Format数据结构中的域值
1、elf.c:
将ELF格式的可执行程序装入到内存,建立内核进程并运行.
----------------------------------elf.c------------------------------------------
intParse_ELF_Executable(char*exeFileData,ulong_texeFileLength,structExe_Format*exeFormat)
{
inti;
elfHeader*head=(elfHeader*)exeFileData;
programHeader*proHeader=(programHeader*)(exeFileData+head->phoff);
KASSERT(exeFileData!
=NULL);
KASSERT(exeFileLength>head->ehsize+head->phentsize*head->phnum);
KASSERT(head->entry%4==0);
exeFormat->numSegments=head->phnum;
exeFormat->entryAddr=head->entry;
for(i=0;i
{
exeFormat->segmentList[i].offsetInFile=proHeader->offset;
exeFormat->segmentList[i].lengthInFile=proHeader->fileSize;
exeFormat->segmentList[i].startAddress=proHeader->vaddr;
exeFormat->segmentList[i].sizeInMemory=proHeader->memSize;
exeFormat->segmentList[i].protFlags=proHeader->flags;
proHeader++;
}
return0;
}
--------------------------------------------------------------------------------
2、编译,成功后生成两个镜像文件:
fd.img和diskc.img。
其中,Diskc.img为模拟器能引导的操作系统镜像。
3、编写相应的bochs配置文件
由于生成了diskc.img,因此配置文件需加上以下内容
config_interface:
textconfig
megs:
8
vgaromimage:
file=$BXSHARE/VGABIOS-lgpl-latest
romimage:
file=$BXSHARE/BIOS-bochs-latest
floppya:
1_44=./fd.img,status=inserted
ata0:
enabled=1,ioaddr1=0x1f0,ioaddr2=0x3f0,irq=14
ata1:
enabled=0,ioaddr1=0x170,ioaddr2=0x370,irq=15
#ata2:
enabled=0,ioaddr1=0x1e8,ioaddr2=0x3e0,irq=11
#ata3:
enabled=0,ioaddr1=0x168,ioaddr2=0x360,irq=9
ata0-master:
type=disk,path="diskc.img",mode=flat,cylinders=40,heads=8,spt=64
#ata0-slave:
type=cdrom,path="/dev/cdrom",status=inserted
boot:
a
ips:
1000000
log:
./bochs.out
vga_update_interval:
300000
keyboard_serial_delay:
250
keyboard_paste_delay:
100000
private_colormap:
enabled=0
4、在brochs中运行GeekOS系统显示结果
4、设计项目二
一、项目设计目的
扩充GeekOS操作系统内核,使得系统能够支持用户级进程的动态创建和执行。
二、项目2要求用户对以下几个文件进行修改:
(1)“user.c”文件中的函数Spawn(),其功能是生成一个新的用户级进程;
(2)“user.c”文件中的函数Switch_To_User_Context(),调度程序在执行
一个新的进程前调用该函数以切换用户地址空间;
(3)“elf.c”文件中的函数Parse_ELF_Executable()。
该函数的实现要求
和项目1相同。
(4)“userseg.c”文件中主要是实现一些为实现对“src/GeekOS/user.c”中高层
操作支持的函数。
Destroy_User_Context()函数的功能是释放用户态进程占用的内存资源。
Load_User_Program()函数的功能通过加载可执行文件镜像创建新进程的
User_Context结构。
Copy_From_User()和Copy_To_User()函数的功能是在用户地址空间和内核地址空间之间复制数据,在分段存储器管理模式下,只要段有效,调用memcpy函数就可以实现这两个函数的功能。
Switch_To_Address_Space()函数的功能是通过将进程的LDT装入到LDT寄存器来激活用户的地址空间;
3、具体代码修改情况
-----------------------------elf.c--------------------------------------------
intParse_ELF_Executable(char*exeFileData,ulong_texeFileLength,structExe_Format*exeFormat)
{
inti;
elfHeader*hdr=(elfHeader*)exeFileData;
programHeader*phdr=(programHeader*)(exeFileData+hdr->phoff);
structExe_Segment*segment=exeFormat->segmentList;
for(i=0;i
{
segment->offsetInFile=phdr->offset;
segment->lengthInFile=phdr->fileSize;
segment->startAddress=phdr->vaddr;
segment->sizeInMemory=phdr->memSize;
phdr++;
segment++;
}
exeFormat->numSegments=hdr->phnum;
exeFormat->entryAddr=hdr->entry;
return0;
TODO("ParseanELFexecutableimage");
}
------------------------------------------------------------------------------
----------------------------------------------------------------------------
-----------------------------kthred.c-------------------------------------------
--------------------------------------------------------------------------
//kthread.c文件中主要是实现用户程序要求内核进行服务的一些系统调用函数定义
---------------------------------------------------------------------------------------------------------------
//为进程初始化内核堆栈
//堆栈中是为进程首次进入用户态运行时设置处理器状态要使用的数据
//该函数内部调用Attach_User_Context加载用户上下文
voidSetup_User_Thread(structKernel_Thread*kthread,structUser_Context*userContext)
{
//TODO("Createanewthreadtoexecuteinusermode");
ulong_teflags=EFLAGS_IF;
unsignedcsSelector=userContext->csSelector;//CS选择子
unsigneddsSelector=userContext->dsSelector;//DS选择子
Attach_User_Context(kthread,userContext);//调用Attach_User_Context加载用户上下文
//初始化用户态进程堆栈,使之看上去像刚被中断运行一样
//分别调用Push函数将以下数据压入堆栈
Push(kthread,dsSelector);//数据选择子
Push(kthread,userContext->stackPointerAddr);//堆栈指针
Push(kthread,eflags);//Eflags
Push(kthread,csSelector);//文本选择子
Push(kthread,userContext->entryAddr);//程序计数器
Push(kthread,0);//错误代码(0)
Push(kthread,0);//中断号(0)
//初始化通用寄存单元,将ESI用户传递参数块地址
Push(kthread,0);/*eax*/
Push(kthread,0);/*ebx*/
Push(kthread,0);/*edx*/
Push(kthread,0);/*edx*/
Push(kthread,userContext->argBlockAddr);/*esi*/
Push(kthread,0);/*edi*/
Push(kthread,0);/*ebp*/
//初始化数据段寄存单元
Push(kthread,dsSelector);/*ds*/
Push(kthread,dsSelector);/*es*/
Push(kthread,dsSelector);/*fs*/
Push(kthread,dsSelector);/*gs*/
}
----------------------------------------------------------------------------------------------------------------------------------------
//该函数使用User_Context对象开始一个新进程
//若成功,指针返回一个新进程
//Spawn函数调用该函数,以初始化一个用户态进程(包括初始化进程的Kernal_Thread结构以及调用Setup_User_Thread初始化用户态进程的内核堆栈)
structKernel_Thread*
Start_User_Thread(structUser_Context*userContext,booldetached)
{
//调用Create_Thread()建立新进程对象
//调用Setup_User_Thread()函数初始化新进程
//TODO("Startuserthread");
structKernel_Thread*kthread=Create_Thread(PRIORITY_USER,detached);//调用Create_Thread()建立新用户态进程对象
if(kthread!
=0){
Setup_User_Thread(kthread,userContext);//调用Setup_User_Thread()函数初始化新用户态进程的内核堆栈
Make_Runnable_Atomic(kthread);
}
returnkthread;//创建成功,指针返回一个新进程
}
---------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------
---------------------------------------user.c--------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------------------
//导入用户程序并初始化(包括调用Load_User_Program进行User_Context的初始化及用户态进程空间的分配、用户程序各段的装入)
//Spawn函数主要完成的主要功能是:
//调用Read_Fully函数将名为program的可执行文件全部读入内存缓冲区
//调用Parse_ELF_Executable函数分析ELF格式文件
//调用Load_User_Program将可执行程序的程序段和数据段装入内存,初始化User_Context数据结构
//调用Start_User_Thread函数创建一个进程并使其进入准备运行队列
intSpawn(constchar*program,constchar*command,structKernel_Thread**pThread)//生成新的用户级进程
{
//TODO("Spawnaprocessbyreadinganexecutablefromafilesystem");
intrc;//标记各函数的返回值,为则表示成功,否则失败
char*exeFileData=0;//保存在内存缓冲中的用户程序可执行文件
ulong_texeFileLength;//可执行文件的长度
structUser_Context*userContext=0;//指向User_Conetxt的指针
structKernel_Thread*process=0;//指向Kernel_Thread*pThread的指针
structExe_FormatexeFormat;//调用Parse_ELF_Executable函数得到的可执行文件信息
if((rc=Read_Fully(program,(void**)&exeFileData,&exeFileLength))!
=0)//调用Read_Fully函数将名为program的可执行文件全部读入内存缓冲区
{
Print("FailedtoReadFile%s!
\n",program);
gotofail;
}
if((rc=Parse_ELF_Executable(exeFileData,exeFileLength,&exeFormat))!
=0)//调用Parse_ELF_Executable函数分析ELF格式文件
{
Print("FailedtoParseELFFile!
\n");
gotofail;
}
if((rc=Load_User_Program(exeFileData,exeFileLength,&exeFormat,command,&userContext))!
=0)//调用Load_User_Program将可执行程序的程序段和数据段装入内存,初始化User_Context数据结构
{
Print("Failedto
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- GeekOS 课程设计 报告