操作系统课程设计8.doc

上传人:文库蛋蛋多 文档编号:4193041 上传时间:2023-04-09 格式:DOC 页数:24 大小:290.50KB
返回 下载 相关 举报
操作系统课程设计8.doc_第1页
第1页 / 共24页
操作系统课程设计8.doc_第2页
第2页 / 共24页
操作系统课程设计8.doc_第3页
第3页 / 共24页
操作系统课程设计8.doc_第4页
第4页 / 共24页
操作系统课程设计8.doc_第5页
第5页 / 共24页
点击查看更多>>
资源描述

《操作系统课程设计8.doc》由会员分享,可在线阅读,更多相关《操作系统课程设计8.doc(24页珍藏版)》请在三一办公上搜索。

1、操作系统课程设计报告题 目:Geekos操作系统的研究与实现 专 业: 学 号: 学生姓名: 指导教师: 2012年3月16日目录一、 实验目的2二、 项目设计要求3三、 开发环境的建立41 开发环境的介绍42 开发环境的构建4四、 项目设计原理5五、 项目设计的实现61 Project0项目的具体实现62 Project1项目的具体实现83 Project2项目的具体实现9六、 系统编译运行的结果20七、 遇到的问题和解决方法23八、 课程设计总结24一、 实验目的1 Project0:熟悉GeekOS的项目编译、调试和运行环境,掌握GeekOS运行工作过程。2 Project1:熟悉ELF

2、文件格式,了解GeekOS系统如何将ELF格式的可执行程序装入到内存,建立内核进程并运行的实现技术。3 Project2:扩充GeekOS操作系统内核,使得系统能够支持用户级进程的动态创建和执行。二、 项目设计要求1 Project0(1) 搭建GeekOS的编译和调试平台,掌握GeekOS的内核进程工作原理。(2) 熟悉键盘操作函数,编程实现一个内核进程。该进程的功能是:接收键盘输入的字符并显示到屏幕上,当输入ctrl+d时,结束进程的运行。2 Project1(1) 修改/geekos/elf.c文件:在函数Parse_ELF_Executable( )中添加代码,分析ELF格式的可执行文

3、件(包括分析得出ELF文件头、程序头,获取可执行文件长度,代码段、数据段等信息),并填充Exe_Format数据结构中的域值。(2) 在Linux环境下编译系统得到GeekOS镜像文件。(3) 编写一个相应的bochs配置文件。(4) 在bochs中运行GeekOS系统显示结果。3 Project2:要求用户对以下几个文件进行修改:(1) “src/GeekOS/user.c”文件中的函数Spawn(),其功能是生成一个新的用户级进程;(2) “src/GeekOS/user.c”文件中的函数Switch_To_User_Context(),调度程序在执行一个新的进程前调用该函数以切换用户地址

4、空间;(3) “src/GeekOS/elf.c”文件中的函数Parse_ELF_Executable()。该函数的实现要求和项目1相同。(4) “src/GeekOS/userseg.c”文件中主要是实现一些为实现对“src/GeekOS/user.c”中高层操作支持的函数。(5) “src/GeekOS/kthread.c”文件中的Start_User_Thread函数和Setup_User_Thread函数。Setup_User_Thread()函数的功能是为进程初始化内核堆栈,堆栈中是为进程首次进入用户态运行时设置处理器状态要使用的数据。Start_User_Thread()是一个高层

5、操作,该函数使用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) 。三、 开发环境的建立1

6、 开发环境的介绍(1) Geekos是一个基于X86架构的PC机上运行的微操作系统内核,由美国马理兰大学的教师开发,是一个用C语言开发的操作系统,GeekOS主要用于操作系统课程设计,目的是使学生能够实际动手参与到一个操作系统的开发工作中。学生可以在Linux或Unix环境下对其进行功能扩充,也可以在windows下使用Cygwin工具进行开发,其主要特点是:简单、实用、易懂,便于学生们理解操作系统的设计思想和实现过程。出于教学目的,这个系统内核设计简单,却又兼备实用性,它可以运行在真正的X86 PC硬件平台。(2)VMware WorkstationVMware Workstation 是一

7、款功能强大的桌面虚拟计算机软件,提供用户可在单一的桌面上同时运行不同的操作系统,和进行开发、测试 、部署新的应用程序的最佳解决方案。它可以使你在一台机器上同时运行二个或更多Windows、DOS、LINUX系统。与“多启动”系统相比,VMWare采用了完全不同的概念。多启动系统在一个时刻只能运行一个系统,在系统切换时需要重新启动机器。VMWare是真正“同时”运行,多个操作系统在主系统的平台上,就象标准Windows应用程序那样切换。而且每个操作系统你都可以进行虚拟的分区、配置而不影响真实硬盘的数据,你甚至可以通过网卡将几台虚拟机用网卡连接为一个局域网,极其方便。安装在VMware操作系统性能

8、上比直接安装在硬盘上的系统低不少,因此,比较适合学习和测试。(3)Bochs PC 模拟器 GeekOS运行于Windows(或Linux)下的Bochs PC模拟器,Bochs 是用 C+ 开发的可移植的 IA-32 (x86) PC 模拟器,Bochs仿真器其实质就是一台虚拟PC机,它包括对 Intel x86 CPU 、通用 I/O 设备和可定制的 BIOS 的模拟,几乎可以运行在所有流行的平台上。目前, Bochs 可以模拟 386, 486, Pentium Pro 或者 AMD64 CPU 。Bochs 的模拟环境中也可以运行大部分的操作系统,包括 Linux, Windows 9

9、5, DOS, Windows NT 4, FreeBSD, MINIX 等。2 开发环境的构建(1)下载并安装VMware虚拟机;(2)在VMware虚拟机上安装CentOS版本的linux操作系统。(3)在VMware虚拟机上的linux环境下对GeekOS源文件进行编译和链接,编译成功后生成fd.img软盘映射文件和hd.img硬盘映射文件;(4)下载并安装系统仿真工具Bochs;(5)在终端打开bochs-2.3-pre3$ ./configure 配置bochs的文件(6)make 工具无论是在Linux还是在UNIX环境中,make都是一个非常重要的系统开发工具。利用make工具,

10、可以将大型的开发项目分解成为多个更易于管理的模块,对于一个包括几百个源文件的应用程序,使用make和makefile工具就可以简洁明快地理顺各个源文件之间纷繁复杂的相互关系。 make能够按照规则自动完成编译工作,并且可以只对程序员在上次编译后修改过的文件进行编译,减少重复编译的工作量。 它就是字符操作方式下的项目管理工具。bochs-2.3-pre3$ makebochs-2.3-pre3$ make install(7)配置Bochs环境配置文件Bochsrc.txt:vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latestromimage: file=

11、$BXSHARE/BIOS-bochs-latest, address=0xf0000megs: aboot: cfloppya: 1_44=fd.img, status=inserted#floppya: 1_44=fd_aug.img, status=insertedlog: ./bochs.outkeyboard_serial_delay: 200floppy_command_delay: 500vga_update_interval: 300000ips: 1000000mouse: enabled=0private_colormap: enabled=0i440fxsupport:

12、enabled=0(8)启动Boch环境,在提示的出现GeekOS的欢迎界面。(9)GeekOS系统编译和仿真成功。四、 项目设计原理1. Project0利用bochs模拟计算机执行一个操作系统软件。其中BIOS-bochs-lastest文件模拟bochs硬件的BIOS。VGABIOS-lgpl-lastest文件模拟bochs显示系统的BIOS。bochsrc.txt描述模拟器硬件配置的配置。利用GeekOS提供的键盘处理函数keyboard.h与keyboard.c等进行键盘常用功能的模拟。其中,在keyboard.c里面提供了一个功用函数Keycode Wait_For_Key(vo

13、id),循环等待一个键盘事件,然后返回一个16位的数据 Keycode型的, 在keyboard.h里定义了所有的键盘代码。Read_Key(Keycode* keycode)函数可以处理队列键盘按键,可以保存到队列中并输出2. Project1在函数Parse_ELF_Executable( )中添加代码,分析ELF格式的可执行文件(包括分析得出ELF文件头、程序头,获取可执行文件长度,代码段、数据段等信息),并填充Exe_Format数据结构中的域值。可执行文件是通过源程序被编译成目标文件,多给目标文件连接生成的,然后被加载到内存运行。可执行文件包含一些基本的要素代码、数据、重定位信息和符

14、合信息。以及一些可选辅助信息,如调试信息、硬件信息等。因此,通过分析可执行文件的信息,然后为其分配内存并载入建立内核线程,供系统调度运行。3. Project2与priject1一样,Entry.c为用户程序外壳,并与用户程序一起编译。再根据传递的中断向量查找并调用相关的中断处理程序,并实现调度进程的选择。五、 项目设计的实现1 Project0项目的具体实现(1)打开在geekos-0.3.0/src/project0/src/geekos/main.c修改main.c函数#include #include #include #include #include #include #inclu

15、de #include #include #include #include void project0() Print(To Exit hit Ctrl + d.n); Keycode keycode; while(1) if( Read_Key(&keycode) ) /读取键盘按键状态 if(!( (keycode & KEY_SPECIAL_FLAG) | (keycode & KEY_RELEASE_FLAG) ) /只处理非特殊按键的按下事件 int asciiCode = keycode & 0xff; /低8位为Ascii码 if( (keycode & KEY_CTRL_FL

16、AG)=KEY_CTRL_FLAG & asciiCode=d) /按下Ctrl键 Print(n-BYE!-n); Exit(1); else Print(%c,(asciiCode=r) ? n : asciiCode); void Main(struct Boot_Info* bootInfo) Init_BSS(); Init_Screen(); Init_Mem(bootInfo); Init_CRC32(); Init_TSS(); Init_Interrupts(); Init_Scheduler(); Init_Traps(); Init_Timer();Init_Keyboa

17、rd(); Set_Current_Attr(ATTRIB(BLACK, GREEN|BRIGHT); Print(Welcome to GeekOS!n); Set_Current_Attr(ATTRIB(BLACK, GRAY); struct Kernel_Thread *thread;thread = Start_Kernel_Thread(&project0,0,PRIORITY_NORMAL,false); Exit(0);(2)编译文件终端打开 $ cd project0/build 的目录: 在其目录下:$ make $ make depend 编译,生成文件 depend.m

18、ak和fd.img (3)建立配置文件bochsrc终端打开 $ cd project0/build 的目录:建立配置文件: $ gedit .bochs修改其内容如下:vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latestromimage: file=$BXSHARE/BIOS-bochs-latest, address=0xf0000megs: 8boot: afloppya: 1_44=fd.img, status=inserted#floppya: 1_44=fd_aug.img, status=insertedlog: ./bochs.outke

19、yboard_serial_delay: 200floppy_command_delay: 500vga_update_interval: 300000ips: 1000000mouse: enabled=0private_colormap: enabled=0i440fxsupport: enabled=0(4)运行在build目录下输入:$ bochs f bochsrc 2 Project1项目的具体实现(1)终端打开 $geekos-0.3.0/src/project1/src/geekos/elf.c修改elf.c函数#include #include #include #inclu

20、de /* for debug Print() statements */#include #include #include #include int Parse_ELF_Executable(char *exeFileData, ulong_t exeFileLength,struct Exe_Format *exeFormat) int i; elfHeader *hdr =(elfHeader*) exeFileData; programHeader *phdr=(programHeader *)(exeFileData + hdr-phoff); struct Exe_Segment

21、 * segment= exeFormat-segmentList; for( i=0; iphnum; 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; return 0;(2)

22、编译文件终端打开目录: $ cd project1/build 在其目录下:$ make $ make depend 编译,生成文件 depend.mak和fd.img (3)建立配置文件bochsrc终端打开目录: $ cd project1/build建立配置文件: $ gedit .bochs修改其内容如下:config_interface: textconfigromimage: file=$BXSHARE/BIOS-bochs-latestmegs: 8vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest floppya: 1_44=./fd.

23、img, status=insertedata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14ata1: 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=9ata0-master: type=disk, path=diskc.img, mode=flat, cylinders=40, he

24、ads=8, spt=64#ata0-slave: type=cdrom, path=/dev/cdrom, status=insertedboot: aips: 1000000log:./bochs.outvga_update_interval: 300000keyboard_serial_delay: 250keyboard_paste_delay: 100000private_colormap: enabled=0 (4)运行在build目录下输入:$ bochs f bochsrc3 Project2项目的具体实现1 添加代码(1)修改src/GeekOS/user.c文件中的函数Sp

25、awn(),其功能是生成一个用户级进程。(2)src/GeekOS/user.c文件中的函数Switch_To_User_Contex(),调度程序在执行一个新的进程前调用该函数以切换用户地址空间。(3)src/GeekOS/elf.c文件中的函数Prase_ELF_Executable()。该函数的实现要求和项目1相同。(4)src/GeekOS/userseg.c文件主要是实现一些为实现对src/GeekOS/user.c中高层操作支持的函数。 Destroy_User_Context()函数的功能是释放用户态进程占用的内存资源。 Load_User_Program()函数的功能通过加载可

26、执行文件镜像创建新进程的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()函数的功能是为进程初始化内核堆栈,堆栈中是为进程首次

27、进入用户态运行时设置处理器状态要使用的数据。 Start_User_Thread()是一个高层操作,该函数使用User_Context对象开始一个新进程。(6)src/GeekOS/kthread.c相关函数的修改。(7)src/GeekOS/syscall.c”文件中主要是实现用户程序要求内核进行服务的一些系统调用函数定义。 要求用户实现的有Sys_Exit()函数、Sys_PrintString()函数、Sys_GetKey()、Sys_SetAttr()、Sys_GetCursor()、Sys_PutCursor()、Sys_Spawn()函数、Sys_Wait()函数和Sys_GetP

28、ID( )函数。(8)在main.c文件中改写生成第一个用户态进程的函数调用:Spawn_Init_Process(void) = user.c =/产生一个进程(用户态)int Spawn(const char *program, const char *command, struct Kernel_Thread *pThread) /TODO(Spawn a process by reading an executable from a filesystem); int rc; /标记各函数的返回值,为0则表示成功,否则失败 char *exeFileData = 0;/保存在内存缓冲中的

29、用户程序可执行文件 ulong_t exeFileLength;/可执行文件的长度 struct User_Context *userContext = 0;/指向User_Conetxt的指针 struct Kernel_Thread *process = 0;/指向Kernel_Thread *pThread的指针 struct Exe_Format exeFormat;/调用Parse_ELF_Executable函数得到的可执行文件信息 if (rc = Read_Fully(program, (void*) &exeFileData, &exeFileLength) != 0 ) /

30、调用Read_Fully函数将名为program的可执行文件全部读入内存缓冲区 Print(Failed to Read File %s!n, program); goto fail; if(rc = Parse_ELF_Executable(exeFileData, exeFileLength, &exeFormat) != 0 ) /调用Parse_ELF_Executable函数分析ELF格式文件 Print(Failed to Parse ELF File!n); goto fail; if(rc = Load_User_Program(exeFileData, exeFileLeng

31、th, &exeFormat, command, &userContext) != 0) /调用Load_User_Program将可执行程序的程序段和数据段装入内存 Print(Failed to Load User Program!n); goto fail; /在堆分配方式下释放内存并再次初始化exeFileData Free(exeFileData); exeFileData = 0;/* 开始用户进程,调用Start_User_Thread函数创建一个进程并使其进入准备运行队列*/ process = Start_User_Thread(userContext, false); if

32、 (process != 0) /不是核心级进程(即为用户级进程) KASSERT(process-refCount = 2);/* 返回核心进程的指针 */ *pThread = process; rc = process-pid;/记录当前进程的ID else/超出内存 project2includegeekoserrno.h rc = ENOMEM; return rc;fail: /如果新进程创建失败则注销User_Context对象 if (exeFileData != 0) Free(exeFileData);/释放内存 if (userContext != 0) Destroy_

33、User_Context(userContext);/销毁进程对象 return rc;-/切换至用户上下文void Switch_To_User_Context(struct Kernel_Thread* kthread, struct Interrupt_State* state) /TODO(Switch to a new user address space, if necessary); static struct User_Context* s_currentUserContext; /* last user context used */ /extern int userDebu

34、g; struct User_Context* userContext = kthread-userContext;/指向User_Conetxt的指针,并初始化为准备切换的进程 KASSERT(!Interrupts_Enabled(); if (userContext = 0) /userContext为0表示此进程为核心态进程就不用切换地址空间 return; if (userContext != s_currentUserContext) ulong_t esp0; /if (userDebug) Print(A%pn, kthread); Switch_To_Address_Spac

35、e(userContext);/为用户态进程时则切换地址空间 esp0 = (ulong_t) kthread-stackPage) + PAGE_SIZE; /if (userDebug) / Print(S%lxn, esp0);/* 新进程的核心栈. */ Set_Kernel_Stack_Pointer(esp0);/设置内核堆栈指针/* New user context is active */ s_currentUserContext = userContext; = elf.c =copy project1 = userseg.c =/需在此文件各函数前增加一个函数,此函数的功能

36、是按给定的大小创建一个用户级进程上下文,具体实现如下:/函数功能:按给定的大小创建一个用户级进程上下文static struct User_Context* Create_User_Context(ulong_t size) struct User_Context * UserContext; size = Round_Up_To_Page(size); UserContext = (struct User_Context *)Malloc(sizeof(struct User_Context); /为用户态进程 if (UserContext != 0) UserContext-memory

37、 = Malloc(size); /为核心态进程 else goto fail; /内存为空 if (0 = UserContext-memory) goto fail; memset(UserContext-memory, 0, size); UserContext-size = size; /以下为用户态进程创建LDT(段描述符表) /新建一个LDT描述符 UserContext-ldtDescriptor = Allocate_Segment_Descriptor(); if (0 = UserContext-ldtDescriptor) goto fail; /初始化段描述符 Init

38、_LDT_Descriptor(UserContext-ldtDescriptor, UserContext-ldt, NUM_USER_LDT_ENTRIES); /新建一个LDT选择子 UserContext-ldtSelector = Selector(KERNEL_PRIVILEGE, true, Get_Descriptor_Index(UserContext-ldtDescriptor); /新建一个文本段描述符 Init_Code_Segment_Descriptor( &UserContext-ldt0, (ulong_t) UserContext-memory, size /

39、 PAGE_SIZE, USER_PRIVILEGE ); /新建一个数据段 Init_Data_Segment_Descriptor( &UserContext-ldt1, (ulong_t) UserContext-memory, size / PAGE_SIZE, USER_PRIVILEGE ); /新建数据段和文本段选择子 UserContext-csSelector = Selector(USER_PRIVILEGE, false, 0); UserContext-dsSelector = Selector(USER_PRIVILEGE, false, 1); /将引用数清0 Us

40、erContext-refCount = 0; return UserContext;fail: if (UserContext != 0) if (UserContext-memory != 0) Free(UserContext-memory); Free(UserContext); return 0;-/摧毁用户上下文void Destroy_User_Context(struct User_Context* userContext) /TODO(Destroy a User_Context);/ KASSERT(userContext-refCount = 0);/* Free the

41、 contexts LDT descriptor */ Free_Segment_Descriptor(userContext-ldtDescriptor);/* Free the contexts memory */ Disable_Interrupts();/ Free(userContext-memory);/ Free(userContext);/ Enable_Interrupts(); /释放占用的LDT Free_Segment_Descriptor(userContext-ldtDescriptor); userContext-ldtDescriptor=0; /释放内存空间 Free(userContext-memory); userContext-memory=0; /释放userContext本身占用的内存 Free(userContext); userContext=0;-int Load_User_Program(char *exeFileData, ulong_t exeFileLength,struct Exe_Format *exeFormat, const char *command, struct User_Context *pUserContext) /TODO(Load a user executable into a u

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

当前位置:首页 > 办公文档 > 其他范文


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号