GeekOS操作系统实验报告文档格式.docx

上传人:b****6 文档编号:21723153 上传时间:2023-01-31 格式:DOCX 页数:23 大小:168.21KB
下载 相关 举报
GeekOS操作系统实验报告文档格式.docx_第1页
第1页 / 共23页
GeekOS操作系统实验报告文档格式.docx_第2页
第2页 / 共23页
GeekOS操作系统实验报告文档格式.docx_第3页
第3页 / 共23页
GeekOS操作系统实验报告文档格式.docx_第4页
第4页 / 共23页
GeekOS操作系统实验报告文档格式.docx_第5页
第5页 / 共23页
点击查看更多>>
下载资源
资源描述

GeekOS操作系统实验报告文档格式.docx

《GeekOS操作系统实验报告文档格式.docx》由会员分享,可在线阅读,更多相关《GeekOS操作系统实验报告文档格式.docx(23页珍藏版)》请在冰豆网上搜索。

GeekOS操作系统实验报告文档格式.docx

为达到实验目的效果,实验要求针对进程管理等操作系统核心内容进行相应的3项目要求。

其项目和要求为:

1.project0

1)建GeekOs的编译和调试平台,掌握GeekOs的内核进程工作原理;

2)熟悉键盘操作函数,编程实现一个内核进程。

该进程的功能是:

接收键盘输入的字符并显示到屏幕中,当输入Ctrl+D时,结束进程运行。

2.project1

1)修改/geekos/elf.c文件:

在函数Parse_ELF_Executable()中添加代码,分析ELF格式文件(包括分析得出ELF文件头、程序头,获取可执行文件长度,代码段、数据段等信息),并填充Exe_Format数据结构中的域值。

2)掌握GeekOs在核心态用户程序的原理,为实现项目2的实现做准备。

3.project2

本项目需要阅读/src/geekos目录中的entry.c、lowlevel.asm、kthread.c、userseg.c,其中在userseg.c中主要关注Destroy_User_Context()和Load_User_Program()两个函数。

项目要求为:

1)user.c:

完成函数Spawn()和Switch_To_User_Context()。

2)elf.c:

完成函数Parse_ELF_Executable(),要求与项目1相同。

3)userseg.c:

完成函数Destroy_User_Context()、Load_User_Program()、Copy_From_User()、Copy_To_User()和Switch_To_Address_Space()。

4)kthread.c:

完成函数Setup_User_Thread()和Start_User_Thread()。

5)syscall.c:

完成函数Sys_Exit()、Sys_PrintString()、Sys_GetKey()、Sys_SetAttr()、Ss_GetCursor()、Sys_PutCursor()、Sys_Spawn()、Sys_Wait()和Sys_GetPID()。

6)main.c:

改写Spawn_Init_Process(void),改写时将“/c/shell.exe”作为可执行文件传递给Spawn函数的program参数,创建第一个用户态进程,然后由它来创建其它进程。

四、项目设计原理

Cygwin是一个在Windows平台上运行的UNIX模拟环境,是CygnusSolution公司开发的自由软件。

Cygwin把gcc、gdb、gas等开发工具进行改进,使它们能生成并解释Win32目标文件,然后写了一个共享库,把Win32中没有的UNIX风格的调用封装在里面,把封装的工具源代码与共享库连接在一起,皆可以使用类UNIX主机上的交叉编译器来生成Windows平台上运行的工具集。

因此,可以使用Windows上的Cygwin作为开发环境。

要创建开发环境,也可以使用Linux作为GeekOS开发调试环境,可以使用RedHat7.0以上的Linux版本。

而安装Linux平台可以直接安装Linux操作系统到主机上,也可以先在Windows上安装VMware虚拟机,在通过在VMware虚拟机安装Linux操作系统。

拥有可以编译GeekOS的操作环境,还需要一个可以调试GeekOS的PC虚拟机,由于目前GeekOS只能支持在Bochs虚拟机上运行,因此,需要安装Bochs。

项目0中,要求实现接收键盘输入的字符并显示到屏幕中的内核进程。

而键盘设备驱动程序提供了一系列的高级接口来使用键盘。

键盘事件的逻辑关系为:

用户按键引发键盘中断,根据是否按下Shift键,分别在键值表中寻找扫描码对应的按键值,经过处理后将键值放入键盘缓冲区s_queue中,最后通知系统重新调度进程。

若用户进程需要从键盘输入信息,可调用Wait_For_Key()函数,该函数首先检查键盘缓冲区是否有按键。

如果有,就读取一个键码,如果此时键盘缓冲区中没有按键,就将进程放入键盘事件等待队列s_waitQueue,由于按键触发了键盘中断,键盘中断处理函数Keyboard_Interrupt_Handler就会读取用户按键,将低级键扫描码转换为含ASCII字符的高级代码,并刷新键盘缓冲区,最后唤醒等待按键的进程继续运行。

项目2要求熟悉ELF文件格式,了解GeekOS系统如何将ELF格式的用户可执行文件程序装入到内存,并建立内核进程并运行的实现技术。

ELF(Executableandlinkingformat)文件是UNIX系统实验室作为应用程序二进制接口而开发的可执行文件,是x86Linux系统下的一种常用目标文件(objectfile)格式。

ELF文件格式如下表1。

表1ELF目标文件格式

连接程序视图

执行程序视图

ELF头部

ELF头部

程序头部表(可选)

程序头部表

节区1

段1

...

节区n

段2

节区头部表

节区头部表(可选)

ELF文件在磁盘中的映象和在内存中的执行程序镜像的对应关系如下图:

图1ELF文件和内存中的可执行文件镜像

内核进程的创建流程如下图:

图2内核进程流程图

Parse_ELF_Excutable函数的定义为:

intParse_ELF_Executable(char*exeFileData,ulong_texeFileLength,tructExe_Format*exeFormat)

参数:

exeFileData——已装入内存的可执行文件所占用空间的起始地址

exeFileLength——可执行文件长度

exeFormat——保存分析得到的elf文件信息的结构体指针根据ELF文件格式,用户可以从exeFileData指向的内容中得到ELF文件头,继续分析可以得到程序头,程序代码段等信息。

进程是在计算机系统引入多道程序设计技术后,为描述和控制系统内部各程序运行而引入的一个概念。

后来为提高程序运行的并行度和系统的执行效率,又引进了线程的概念。

而GeekOS的线程实质上是进程,GeekOS的内核只提供核心级进程,但可以开发扩展使之支持核心级进程和用户级进程。

ⅰ、GeekOS进程状态及转化

在操作系统中,可以多个任务可以共享CPU,但一个进程在整个生命周期中有时候能占有CPU,有时候并不能占用CPU。

GeekOS系统中,进程在一个生命周期中分为3中不同的状态。

即当前运行态、准备运行态和等待状态。

其住哪个台之间的转化如图3所示

图3GeekOS进程状态转换

ⅱ、GeekOS初始化的进程

在GeekOS中最早初始化的Main进程,由Main执行初始化调度函数Init_Scheduler()来执行Start_Kernel_Thread()函数来创建Idle和Reaper。

其中Idel实际上什么都没做,但它的作用是保证准备运行的进程队列中有可调度的进程。

而Reaper是负责消亡进程的善后工作,负责释放消亡进程所占有资源,内存、堆栈等等。

ⅲ、进程的调度

GeekOS会在以下几种情况下调度进程切换:

1)时间片用完;

2)执行内核进程Idel;

3)进程退出调用Exit函数时;

4)进入等待状态Wait函数被调用时。

后三中情况都会调用Sceduler()函数。

而Sceduler()函数是调用底层操作lowllevel.asm里的Switch_To_Thread函数切换内核进程。

用户进程的调度比内核江南城调度复杂,原因是用户进程又有自己的地址空间,并不在内核的代码段范围内。

用户进程的切换同样适用到Switch_To_Thread函数,但在此过程中多了对Activate_User_Context的调用,负责检测当前进程是否为用户进程,若是则切换到用户进程空间。

ⅳ、进程调度的策略

GeekOS的初始进程调度策略是时间片轮换调度,所有准备运行的进程都放在一个FIFO的队列里,按先来先出的顺序排队。

当发生进程调度时,系统在这个队列中查找最高级别的进程进入运行。

五、项目设计的具体实现

ⅰ、在Windows上安装VMware

从网上下载VMware,笔者下载的是汉化版的VMware,压缩包内含有免费的License。

解压压缩包,按照提示完成安装。

值得注意的一点是,在设置虚拟磁盘时,建议初学者使用Createanewvirtualdisk。

ⅱ、在虚拟机VMware安装Linux

安装VMware完成后,当点击VMware上的开机按钮时,虚拟机将开机运行,但可以看到机器没有操作系统无法继续运行。

本实验采用RedHat9.0作为操作系统安装虚拟机。

具体安装步骤在此不做详细说明。

但值得一提的是在“选择软件包组”的时候,必须选择在“开发工具”里勾选GCC和NASM以保证编译环境正确建立。

ⅲ、BochsPC模拟器的安装

GeekOS是运行于Linux下的BochsPC模拟器上,Bochs是使用C++开发的可一直的IA-32PC模拟器,几乎可以运行在所有主流平台上。

a.从上下载一个bochs-2.1.1.i386.rpm,

b.开始安装,如:

[root@localhostsh]#rpm-ivhbochs-2.1.1.i386.rpm

Preparing... 

######################[100%]

1:

bochs 

[root@localhostsh]#

已经安装目录/usr/share/bochs下。

c.编辑.bochsrc文件:

#Anexample.bochsrcfile.

#Youwillneedtoedittheselinestoreflectyoursystem.

vgaromimage:

/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:

i440fxsupport:

#newharddrivesupport:

enabled=1

#Uncommentthistowriteallbochsdebuggingmessagesto

#bochs.out.Thisproducesalotofoutput,butcanbevery

#usefulfordebuggingthekernel.

#debug:

action=report

到此bochs安装完毕。

ⅳ、编写键盘功能函数

在/project0/src/geekos/main.c的代码文件中添加一个函数,主要是用于接收键盘输入,并显示已输入字符串的功能。

函数名为project0(),其代码为:

voidproject0()

{Print("

ToExithitCtrl+d.\n"

);

inti=0;

Keycodekeycode;

while

(1){

if(Read_Key(&

keycode))

{//读取键盘按键状态

if(!

((keycode&

KEY_SPECIAL_FLAG)||(keycode&

KEY_RELEASE_FLAG)))

{//只处理非特殊按键的按下事件

intasciiCode=keycode&

0xff;

//低8位为Ascii码

if((keycode&

KEY_CTRL_FLAG)==KEY_CTRL_FLAG&

&

asciiCode=='

d'

{//按下Ctrl键

Print("

\n---------BYE!

--------\n"

Exit

(1);

}else{

//统计字数

if(asciiCode!

='

\r'

{Print("

%c"

keycode);

i++;

}

else

{

%s%d%s"

"

\nYouhavepress("

i,"

)keys\n"

i=0;

}

}

然后再main函数中作相应的修改,即在TODO("

Startakernelthreadtoechopressedkeysandprintcounts"

下面添加程序为:

structKernel_Thread*thread;

thread=Start_Kernel_Thread(&

project0,0,PRIORITY_NORMAL,false);

并把TODO提示语句给注释掉。

该项目需要实现对/geekos/elf.c文件,在函数Parse_ELF_Excuteable()中添加代码。

其代码实现为:

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;

entryAddr=head->

entry;

for(i=0;

i<

i++)

segmentList[i].offsetInFile=proHeader->

offset;

segmentList[i].lengthInFile=proHeader->

fileSize;

segmentList[i].startAddress=proHeader->

vaddr;

segmentList[i].sizeInMemory=proHeader->

memSize;

segmentList[i].protFlags=proHeader->

flags;

proHeader++;

return0;

ⅰ、修改user.c文件的Spawn()函数,生成一个新的用户级进程,其代码:

intSpawn(constchar*program,constchar*command,structKernel_Thread**pThread)

{

//TODO("

Spawnaprocessbyreadinganexecutablefromafilesystem"

intrc;

//标记各函数的返回值,为0则表示成功,否则失败

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的可执行文件全部读入内存缓冲区

FailedtoReadFile%s!

\n"

program);

gotofail;

if((rc=Parse_ELF_Executable(exeFileData,exeFileLength,&

exeFormat))!

{//调用Parse_ELF_Executable函数分析ELF格式文件

FailedtoParseELFFile!

if((rc=Load_User_Program(exeFileData,exeFileLength,&

exeFormat,command,&

userContext))!

=0)

{//调用Load_User_Program将可执行程序的程序段和数据段装入内存

FailedtoLoadUserProgram!

//在堆分配方式下释放内存并再次初始化exeFileData

Free(exeFileData);

exeFileData=0;

/*开始用户进程,调用Start_User_Thread函数创建一个进程并使其进入准备运行队列*/

process=Start_User_Thread(userContext,false);

if(process!

=0){//不是核心级进程(即为用户级进程

KASSERT(process->

refCount==2);

/*返回核心进程的指针*/

*pThread=process;

rc=process->

pid;

//记录当前进程的ID

}else//超出内存project2\include\geekos\errno.h

rc=ENOMEM;

returnrc;

fail:

//如果新进程创建失败则注销User_Context对象

if(exeFileData!

//释放内存

if(userContext!

Destroy_User_Context(userContext);

//销毁进程对象

ⅱ、src/geekos/user.c中的Swith_To_User_Context()函数,其实现代码为:

voidSwitch_To_User_Context(structKernel_Thread*kthread,structInterrupt_State*state)

/*

*Hint:

Beforeexecutinginusermode,youwillneedtocall

*theSet_Kernel_Stack_Pointer()andSwitch_To_Address_Space()

*functions.

*/

Switchtoanewuseraddressspace,ifnecessary"

staticstructUser_Context*s_currentUserContext;

/*lastusercontextused*/

//externintuserDebug;

structUser_Context*userContext=

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 公共行政管理

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1