操作系统课设论文桂电版.docx
- 文档编号:3990665
- 上传时间:2022-11-27
- 格式:DOCX
- 页数:39
- 大小:336.15KB
操作系统课设论文桂电版.docx
《操作系统课设论文桂电版.docx》由会员分享,可在线阅读,更多相关《操作系统课设论文桂电版.docx(39页珍藏版)》请在冰豆网上搜索。
操作系统课设论文桂电版
操作系统
课程设计说明书
题目:
GeekOS操作系统的研究与实现
学院:
计算机科学与工程学院
专业:
信息安全
姓名:
学号:
*******
2014年3月25日
1Geekos系统概述
操作系统是管理系统软、硬件资源,控制程序运行,改善人机界面,提供各种服务,合理组织计算机工作流程和为用户有效使用计算机提供良好运行环境的系统软件,它为用户使用计算机提供一个灵活、安全、可靠的工作环境,也是其他应用软件赖以存在的基础。
操作系统是计算机系统的重要组成部分,操作系统课程是计算机教育的必修课程,作为计算机专业的核心课程,不但高校计算机相关专业的学生必须学习操作系统,从事计算机行业的从业人员也需深入了解它。
GeekOS是一个基于X86架构的PC机上运行的微操作系统内核,由美国马理兰大学的教师开发,是一能够个用C语言开发的操作系统,GeekOS主要用于操作系统课程设计,目的是使学生能够实际动手参与到一个操作系统的开发工作中。
出于教学目的,这个系统内核设计简单,却又兼备实用性,它可以运行在真正的X86PC硬件平台。
作为一个课程设计平台,Geekos由一个基本的操作系统内核作为基础,提供了操作系统与硬件之间的所有必备接口,实现了系统引导、实模式到保护模式的转换、中断调用及异常处理、基于段式的内存管理、FIFO进程调度算法以及内核进程、基本输入输出(键盘作为输入设备,显示器作为输出设备),以及一个用于存放用户程序的只读文件系统PFAT。
2建立开发环境
1.在虚拟机上安装Linux操作系统
GeekOS是一个基于X86架构的PC机上运行的微操作系统内核,内核简单却又兼备实用性,是一个用C语言开发的操作系统,可以运行在真正的X86PC硬件平台。
每个项目需要在Linux环或者UNIX环境下对其进行功能扩充。
Ubuntu是一个由社区开发的基于linux的操作系统,其包含了我们一般所需的所有程序:
无论是文字处理和电子邮件,还是Web服务和编程工具。
所以选择其作为Linux系统进行安装。
首先先安装VMwareworkstation,运行Vmware,新建一个虚拟机,以便安装Linux系统。
然后在虚拟机上安装Ubuntu系统。
系统安装的时候会默认安装了GCC,所以后面不必再重新安装GCC。
2.安装编译软件
(1)修改使用国内镜像更新源。
把镜像下下来之后,修改的方法可以在Synaptic PackageManager图形界面中设置,或者在命令行终端中输入sudogedit/etc/apt/sources.list,使用文本编辑器编辑源列表。
在Synaptic PackageManager中reload或终端中输入sudoapt-getupdate重新获取软件包列表。
(2)在终端输入sudoapt-getinstallbuild-essential下载安装build-essential包。
(4)安装NASM
在终端执行sudoapt-getinstallnasm,
(5)安装Bochs:
在终端执行sudoapt-getinstallbochs
在终端执行sudoapt-getinstallbochs-x
在终端执行sudoapt-getinstallbochs-sdl
(6)修改geekos文件
①gedit../include/geekos/segment.h打开segment.h文件,把43行的uchar_tbaseHighPACKED;改成uint_tbaseHigh:
8PACKED;
②Makefile文件修改:
CC_GENERAL_OPTS:
=$(GENERAL_OPTS)-Werror这一行改成
CC_GENERAL_OPTS:
=$(GENERAL_OPTS)-O0
在gcc后面加上-fno-stack-protector
3项目0
3.1实验目的
熟悉GeekOS的项目编译、调试和运行环境,掌握GeekOS运行工作过程。
3.2项目设计要求
搭建Geekos的编译和调试平台,掌握Geekos的内核进程工作原理。
(1)熟悉键盘操作函数,编程实现一个内核进程。
该进程的功能是:
接收键盘输入的字符并显示到屏幕上,当输入Ctrl+D时,结束进程的运行。
(2)编写一个C语言函数,函数功能是:
接收键盘输入的按键,并将键值在显示器显示出来,当输入ctrl+d就退出;
(3)在Main函数体内调用Start_Kernel_Thread函数,将步骤1编写的函数地址传递给参数startFunc,利用Setup_Kernel_Thread函数建立一个待运行的线程。
(4)在Linux环境下编译系统得到GeekOS镜像文件。
(5)编写一个相应的bochs配置文件。
(6)在bochs中运行GeekOS系统显示结果。
3.3项目设计原理
Geekos的键盘处理函数是定义在keyboard.h与keyboard.c两个文件中。
在keyboard.c中定义了F1~F12,shift,alt等功能键常量,还定义了一个用于存放键盘扫描码的缓冲区。
键盘处理初始化是在main函数中调用Init_Keyboard函数进行的,Init_Keyboard主要功能是设置初始状态下存放键盘扫描码的缓冲区,并为键盘中断设置处理函数。
从Init_Keyboard函数代码可以看到,任何的按键操作都会引发键盘中断处理。
键盘中断处理过程是:
首先从相应I/O端口读取键盘扫描码,根据是否按下shift键,分别在键值表中寻找扫描码对应的按键值,经过处理后将键值放入键盘缓冲区,最后通知系统重新调度进程。
进程若需要获得键盘输入,只需要调用函数Wait_For_Key即可,进程调用该函数后,会阻塞进入按键操作的等待队列,直到按键操作结束,进程才被唤醒。
3.4项目设计的具体实现
(1)在geekos-0.3.0\src\project0\src\geekos\main.c中添加一个函数。
函数的功能是:
接收键盘输入的按键,并将键值显示到显示器的函数,当输入Ctrl+D就退出。
具体函数代码如下:
voidproject0()
{
Print("ToExithitCtrl+d.\n");
Keycodekeycode;
while
(1)
{
if(Read_Key(&keycode))
{
if(!
((keycode&KEY_SPECIAL_FLAG)||(keycode&KEY_RELEASE_FLAG)))
{
intasciiCode=keycode&0xff;
if((keycode&KEY_CTRL_FLAG)==KEY_CTRL_FLAG&&asciiCode=='d')
{
Print("\n----------------------BYE!
-------------------------\n");
Exit
(1);
}
else
{
Print("%c",(asciiCode=='\r')?
'\n':
asciiCode);
}
}
}
}
}
(2)注释Main()函数中TODO,调用Start_Kernel_Thread函数,将步骤1编写的函数地址传递给参数startFunc,建立一个内核级进程。
structKernel_Thread*thread;
thread=Start_Kernel_Thread(&project0,0,PRIORITY_NORMAL,false);
(3)运行终端,在geekos-0.3.0\src\project0\build,执行makedepend及make命令,此时会在build目录下生成fd.img。
(4)在geekos-0.3.0\src\project0\build目录下,在终端输入ls-a会看到.bochsrc文件,编写.bochsrc配置文件
romimage:
file=$BXSHARE/BIOS-bochs-latest
megs:
8
boot:
a
floppya:
1_44=fd.img,status=inserted
log:
./bochs.out
display_library:
sdl
3.5系统编译运行的原理及结果
在geekos-0.3.0\src\project0\build目录下,在终端输入bochs,即可看见以下界面。
图3-1project0运行结果
4项目1
4.1实验目的
熟悉ELF文件格式,了解GeekOS系统如何将ELF格式的可执行程序装入到内存,建立内核进程并运行的实现技术。
4.2项目设计要求
(1)修改/geekos/elf.c文件:
在函数Parse_ELF_Executable()中添加代码,分析ELF格式的可执行文件(包括分析得出ELF文件头、程序头,获取可执行文件长度,代码段、数据段等信息),并填充Exe_Format数据结构中的域值。
(2)在Linux环境下编译系统得到GeekOS镜像文件。
(3)编写一个相应的bochs配置文件。
(4)在bochs中运行GeekOS系统显示结果。
4.3项目设计原理
可执行文件有三个重要概念:
编译、连接、加载。
源程序文件首先被编译成目标文件,多个文件被连接成一个可执行文件,最后可执行文件被加载到内存运行。
ELF(Executableandlinkingformat)文件是UNIX系统实验室作为应用程序二进制接口而开发的可执行文件,是x86Linux系统下的一种常用目标文件(objectfile)格式。
ELF文件内容有两个平行视图,一个是从装入运行角度,另一个是从连接角度,格式如下表1。
表1ELF目标文件格式
连接程序视图
执行程序视图
ELF头部
ELF头部
程序头部表(可选)
程序头部表
节区1
段1
...
节区n
段2
...
...
...
节区头部表
节区头部表(可选)
ELF文件在磁盘中的映象和在内存中的执行程序镜像的对应关系如下图:
图4-1ELF文件和内存中的可执行文件镜像
内核进程的创建流程如下图2:
图4-2内核进程流程图
ELF文件头的结构定义在头文件elf.h中,用于描述整个文件的总体结构。
程序头部对可执行文件和共享目标文件有意义,可执行文件或者共享目标文件的程序头部是一个结构数组,每个结构描述了一个段或者系统准备程序执行所必需的其他信息。
在ELF头部的e_phentsize和e_phnum成员中给出了程序头部的大小和数量。
Geekos用户程序是用户态进程的原型,由外壳程序与主程序组成,外壳程序在Entry.c中定义。
4.4项目设计的具体实现
修改project/project1/src/geekos/elf.c文件:
在函数Parse_ELF_Executable()中添加代码,分析ELF格式的可执行文件(包括分析得出ELF文件头、程序头,获取可执行文件长度,代码段、数据段等信息),并填充Exe_Format数据结构中的域值。
1、elf.c:
将ELF格式的可执行程序装入到内存,建立内核进程并运行。
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;
}
(5)运行终端,在geekos-0.3.0\src\project1\build,执行makedepend及make命令,此时会在build目录下生成fd.img,diskc.img。
(6)在geekos-0.3.0\src\project1\build目录下,在终端输入ls-a会看到.bochsrc文件,编写.bochsrc配置文件
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
display_library:
sdl
4.5系统编译运行的原理及结果
在geekos-0.3.0\src\project1\build目录下,在终端输入bochs,即可看见以下界面。
图4-3project1运行结果
5项目2
5.1实验目的
扩充GeekOS操作系统内核,使得系统能够支持用户级进程的动态创建和执行。
5.2项目设计要求
(1)“src/GeekOS/user.c”文件中的函数Spawn(),其功能是生成一个新的用户级进程;
(2)“src/GeekOS/user.c”文件中的函数Switch_To_User_Context(),调度程序在执行一个新的进程前调用该函数以切换用户地址空间;
(3)“src/GeekOS/elf.c”文件中的函数Parse_ELF_Executable()。
该函数的实现要求和项目1相同。
(4)“src/GeekOS/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寄存器来激活用户的地址空间;
(5)“src/GeekOS/kthread.c”文件中的Start_User_Thread函数和Setup_User_Thread函数。
Setup_User_Thread()函数的功能是为进程初始化内核堆栈,堆栈中是为进程首次进入用户态运行时设置处理器状态要使用的数据。
Start_User_Thread()是一个高层操作,该函数使用User_Context对象开始一个新进程。
(6)“src/GeekOS/kthread.c”文件中主要是实现用户程序要求内核进行服务的一些系统调用函数定义。
要求用户实现的有Sys_Exit()函数、Sys_PrintString()函数、Sys_GetKey()、Sys_SetAttr()、Sys_GetCursor()、Sys_PutCursor()、Sys_Spawn()函数、Sys_Wait()函数和Sys_GetPID()函数。
(7)在main.c文件中改写生成第一个用户态进程的函数调用:
Spawn_Init_Process(void)。
5.3项目设计原理
Geekos进程状态及转化:
图5-1GeekOS进程状态转换
GeekOS系统最早创建的内核进程有Idle、Reaper和Main三个进程,它们由Init_Scheduler函数创建:
最先初始化一个核态进程mainThread,并将该进程作为当前运行进程,函数最后还调用Start_Kernel_Thread函数创建了两个系统进程Idle和Reaper。
所以,Idle、Reaper和Main三个进程是系统中最早存在的进程。
在GeekOS中为了区分用户态进程和内核进程,在Kernel_Thread结构体中设置了一个字段userContext,指向用户态进程上下文。
对于内核进程来说,这个指针为空,而用户态进程都拥有自己的用户上下文(User_Context)。
因此,在GeekOS中要判断一个进程是内核进程还是用户态进程,只要通过userContext字段是否为空来判断就可以了。
每个用户态进程都拥有属于自己的内存段空间,如:
代码段、数据段、堆栈段等,每个段有一个段描述符(segmentdescriptor),并且每个进程有一个段描述符表(LocalDescriptorTable),用于保存该进程的所有段描述符。
操作系统中还设置一个全局描述符表(GDT,GlobalDescriptorTable),用于记录了系统中所有进程的ldt描述符。
图5-3GDT、LDT和User_Context的关系
用户态进程创建LDT的步骤:
(1)调用函数Allocate_Segment_Descriptor()新建一个LDT描述符;
(2)调用函数Selector()新建一个LDT选择子;
(3)调用函数Init_Code_Segment_Descriptor()新建一个文本段描述符;
(4)调用函数Init_Data_Segment_Descriptor()新建一个数据段;
(5)调用函数Selector()新建一个数据段选择子;
(6)调用函数Selector()新建一个文本(可执行代码)段选择子。
用户态进程创建流程:
图5-4进程创建流程图
5.4项目设计的具体实现
(1)“src/GeekOS/user.c”文件中的函数Spawn(),其功能是生成一个新的用户级进程;
intSpawn(constchar*program,constchar*command,structKernel_Thread**pThread)
{
//TODO("Spawnaprocessbyreadinganexecutablefromafilesystem");
intrc;
char*exeFileData=0;
ulong_texeFileLength;
structUser_Context*userContext=0;
structKenrnel_Thread*process=0;
structExe_FormatexeFormat;
if((rc=Read_Fully(program,(void**)&exeFileData,&exeFileLength))!
=0)
{
Print("FailedtoReadFile%s!
\n",program);
gotofail;
}
if((rc=Parse_ELF_Executable(exeFileData,exeFileLength,&exeFormat))!
=0)
{
Print("FailedtoParseELFFile!
\n");
gotofail;
}
if((rc=Load_User_Program(exeFileData,exeFileLength,&exeFormat,command,&userContext))!
=0)
{
Print("FailedtoLoadUserProgram!
\n");
gotofail;
}
Free(exeFileData);
exeFileData=0;
process=Start_User_Thread(userContext,false);
if(process==0)
{
rc=ENOMEM;
Print("Start_User_Threaderror\n");
}
else
//KASSERT(process->refCount==2);
*pThread=process;
//rc=process->pid;
returnrc;
fail:
if(exeFileData!
=0)
Free(exeFileData);
if(userContext!
=0)
Destroy_User_Context(userContext);
returnrc;
}
(2)“src/GeekOS/user.c”文件中的函数Switch_To_User_Context(),调度程序在执行一个新的进程前调用该函数以切换用户地址空间;
voidSwitch_To_User_Context(structKernel_Thread*kthread,structInterrupt_State*state)
{
//
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 操作系统 论文 桂电版