操作系统课程设计_第1页
操作系统课程设计_第2页
操作系统课程设计_第3页
操作系统课程设计_第4页
操作系统课程设计_第5页
已阅读5页,还剩23页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、 课程设计说明书学 院: 计算机科学与工程学院 专 业: 计算机科学与技术 姓 名: 杨天驹 学 号: 0900310327 指导教师: 黄廷辉 2012年 3 月 5 日操作系统课程设计报告GeekOS操作系统的研究与实现(项目0-项目2)一、 实验目的:熟悉GeekOS项目编译运行环境、核态进程的实现、用户态进程的实现、进程调度策略和算法实现、分页存储管理的实现和文件系统的实现等。二、 项目设计要求:GeekOS设计项目0:1. 搭建GeekOS的编译和调试平台,掌握GeekOS的内核进程工作原理。2. 熟悉键盘操作函数,编程实现一个内核进程。该进程的功能是:接受键盘输入的字符并显示到屏幕

2、上,当输入Ctrl+D时,结束进程的运行。GeekOS设计项目1:1.修改/geekos/elf.c文件:在函数Parse_ELF_Executable()中添加代码,分析ELF格式的可执行文件(包括分析得出ELF文件头、程序头,获取可执行文件长度、代码段、数据段等信息),并填充Exe_Format数据结构中的域值。2.掌握GeekOS在核心态运行用户程序的原理,为项目2的实现做准备。GeekOS设计项目2:本项目要求用户对以下几个文件进行修改:1. src/GeekOS/user.c文件中的函数Spawn(),其功能是生成一个新的用户级进程。2. src/GeekOS/usre.c文件中的函

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

4、rom_User()和Copy_To_User()函数的功能是在用户地址空间和内核地址空间之间复制函数,在分段存储器管理模式下,只要段有效,调用memcpy函数就可以实现这两个函数的功能。 (4)Switch_To_Address_Space()函数的功能是通过将进程的LDT装入到LDT寄存器来激活用户的地址空间。5. src/GeekOS/kthread.c文件中的Start_User_Thread函数和Setup_User_Thread函数。 (1)Setup_User_Thread()函数的功能是为进程初始化内核堆栈,堆栈中是为进程首次进入用户态运行时设置处理器状态要使用的数据。 (2)

5、Start_User_Thread()是一个高层操作,该函数使用User_Context对象开始一个新进程 6. src/GeekOS/Syscall.c文件中主要是实现用户程序要求内核进行服务的一些系统调用函数定义。要求用户实现的有Sys_Exit()函数、Sys_PrintString()函数、Sys_GetKey()、Sys_SetAttr()、Sys_Getcursor()、Sys_PutCursor()函数、Sys_Wait()函数和Sys_GetPID()函数。这些函数在文件中有详细的注释,按照提示用户可以很好实现它们的功能。 最后,需要在main.c文件中改写生成第一个用户态进程

6、的函数调用:Spawn_Init_Process(void)。需要注意的是:作为与用户沟通的界面,GeekOS提供了一个简单的Shell,保存在PFAT文件系统内,所以GeekOS系统启动后,应启动shell程序/c/shell.exe运行,所以需要将/c/shell.exe作为可执行文件传递给Spawn函数的program参数,创建第一个用户态进程,然后由它来创建其他进程。 添加代码运行成功后,GeekOS就可以挂载shell,并能运行测试文件c.exe和b.exe。三、 如何建立开发环境:(一) 利用linux安装盘安装了ubuntu10.10版本的linux操作系统环境;(二) 联网后通

7、过系统里的更新管理器更新了系统,并安装了语言包和必要的驱动。(三) 在ubuntu软件中心下载安装了NASM汇编器、Bochs PC模拟器以及bochs-x插件(保证ubuntu10.10环境下的bochs正常运行)。四、 项目设计原理:Make工作原理:在默认的方式下,只要输入make命令就可以工作。具体的处理过程如下:(1)make会在当前目录下找文件名为“Makefile”或“makefile”的文件。 (2)如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,它会找到“edit”这个文件,并把这个文件作为最终的目标文件。 (3)如果edit文件不存在,或是edit所

8、依赖的后面的.o文件的修改时间要比edit这个文件新,那么,就会执行后面所定义的命令来生成edit这个文件。 (4)如果edit所依赖的.o文件也不存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件(这有点像一个堆栈的过程)。 (5)如果指定的C文件和H文件是存在的, make会生成.o文件,然后再用.o文件生成make的最终任务,也就是链接生成执行文件edit。 GeekOS的makefile文件功能:(1) 指定GeekOS如何被编译,哪些源文件被编译,哪些用户程序被编译等等。通常不同项目的编译仅仅需要修改这一部分。(2) 定义了编译GeekO

9、S要用到的工具程序。(3) 指定规则:描述系统如何编译源程序。(4) 指定系统编译生成的指定文件 。GeekOS项目的开发流程:1. 开始一个GeekOS项目,第一步是添加相应的代码 。2. 在Linux下利用make命令编译系统,生成系统镜像文件。 $ cd /project0/build $ make depend $ make 3. 编写每个项目相应的Bochs的配置文件。4. 运行Bochs模拟器,执行GeekOS内核。 $ cd /bochs $ bochs 运行后,屏幕上会有一些提示。运行GeekOS选择Begin simulation,如果GeekOS 编译成功,并且bochs的

10、配置也没问题,将会看到一个模拟VGA的文本窗口,Geekos就能运行程序输出相应信息 (每个环境具体运行的命令格式会有一些不同)内核线程的建立流程: 用户态进程创建流程 五、 项目设计的具体实现(程序代码):GeekOS设计项目0:Main.c文件:#include #include #include #include #include #include #include #include #include #include #include /* * Kernel C code entry point. * Initializes kernel subsystems, mounts file

11、systems, * and spawns init process. */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_Keyboard(); Set_Current_Attr(ATTRIB(BLACK, GREEN|BRIGHT); Print(Welcome to GeekOS

12、!n); Set_Current_Attr(ATTRIB(BLACK, GRAY); void EchoCount() Keycode keycode; int count; count=0; while (1) if ( Read_Key( &keycode ) ) if(keycode & 0x4000) = 0x4000) if(Wait_For_Key() & 0x00ff) = d) /Print(%c,Wait_For_Key(); Set_Current_Attr(ATTRIB(BLACK, RED); Print(Ctrl+d Is Entered! Program Ended

13、!); Exit(1); else if ( !(keycode & KEY_SPECIAL_FLAG) & !(keycode & KEY_RELEASE_FLAG) ) keycode &= 0xff; count=count+1; Set_Current_Attr(ATTRIB(BLACK, CYAN); Print( %c, (keycode = r) ? n : keycode ); if(keycode=r) count=count-1; Set_Current_Attr(ATTRIB(AMBER, BLUE); Print(The counnts is %d ,count); P

14、rint(n); count=0; struct Kernel_Thread *kerThd;kerThd = Start_Kernel_Thread(&EchoCount, 0 , PRIORITY_NORMAL, false); /* Now this thread is done. */ Exit(0);GeekOS设计项目1:Elf.c文件:#include #include #include #include /* for debug Print() statements */#include #include #include #include /* * From the data

15、 of an ELF executable, determine how its segments * need to be loaded into memory. * param exeFileData buffer containing the executable file * param exeFileLength length of the executable file in bytes * param exeFormat structure describing the executables segments * and entry address; to be filled

16、in * return 0 if successful, phoff); KASSERT(exeFileData!=NULL); KASSERT(exeFileLengthhead-ehsize+head-phentsize*head-phnum); KASSERT(head-entry%4=0); exeFormat-numSegments=head-phnum; exeFormat-entryAddr=head-entry; for(i=0;iphnum;i+) exeFormat-segmentListi.offsetInFile=proHeader-offset; exeFormat-

17、segmentListi.lengthInFile=proHeader-fileSize; exeFormat-segmentListi.startAddress=proHeader-vaddr; exeFormat-segmentListi.sizeInMemory=proHeader-memSize; exeFormat-segmentLtFlags=proHeader-flags; proHeader+;return 0;GeekOS设计项目2:Src/GeekOS/user.c文件中的函数Spawn():int Spawn(const char *program, co

18、nst char *command, struct Kernel_Thread *pThread) /* * Hints: * - Call Read_Fully() to load the entire executable into a memory buffer * - Call Parse_ELF_Executable() to verify that the executable is * valid, and to populate an Exe_Format data structure describing * how the executable should be load

19、ed * - Call Load_User_Program() to create a User_Context with the loaded * program * - Call Start_User_Thread() with the new User_Context * * If all goes well, store the pointer to the new thread in * pThread and return 0. Otherwise, return an error code. */ int rc; char *exeFileData = 0; ulong_t ex

20、eFileLength; struct User_Context *userContext = 0; struct Kernel_Thread *process = 0; struct Exe_Format exeFormat; /* * Load the executable file data, parse ELF headers, * and load code and data segments into user memory. */ if (rc = Read_Fully(program, (void*) &exeFileData, &exeFileLength) != 0 | (

21、rc = Parse_ELF_Executable(exeFileData, exeFileLength, &exeFormat) != 0 | (rc = Load_User_Program(exeFileData, exeFileLength, &exeFormat, command, &userContext) != 0) goto fail; /* * User program has been loaded, so we can free the * executable file data now. */ Free(exeFileData); exeFileData = 0; /*

22、 Start the process! */ process = Start_User_Thread(userContext, false); if (process != 0) KASSERT(process-refCount = 2); /* Return Kernel_Thread pointer */ *pThread = process; else rc = ENOMEM; return rc;fail: if (exeFileData != 0) Free(exeFileData); if (userContext != 0) Destroy_User_Context(userCo

23、ntext); return rc;Src/GeekOS/user.c文件中的函数Switch_To_User_Context():void Switch_To_User_Context(struct Kernel_Thread* kthread, struct Interrupt_State* state) /* * Hint: Before executing in user mode, you will need to call * the Set_Kernel_Stack_Pointer() and Switch_To_Address_Space() * functions. */ s

24、tatic struct User_Context* s_currentUserContext; /* last user context used */ struct User_Context* userContext = kthread-userContext; /* * FIXME: could avoid resetting ss0/esp0 if not returning * to user space. */ KASSERT(!Interrupts_Enabled(); if (userContext = 0) /* Kernel mode thread: no need to

25、switch address space. */ return; /* Switch only if the user context is indeed different */ if (userContext != s_currentUserContext) ulong_t esp0; /* Switch to address space of user context */ Switch_To_Address_Space(userContext); /* * By definition, when returning to user mode there is no * context

26、remaining on the kernel stack. */ esp0 = (ulong_t) kthread-stackPage) + PAGE_SIZE; /* Change to the kernel stack of the new process. */ Set_Kernel_Stack_Pointer(esp0); /* New user context is active */ s_currentUserContext = userContext; src/GeekOS/elf.c文件中的函数Parse_ELF_Executable():int Parse_ELF_Exec

27、utable(char *exeFileData, ulong_t exeFileLength, struct Exe_Format *exeFormat) elfHeader *hdr; programHeader *phdr; int i; hdr = (elfHeader *) exeFileData; /* * FIXME: when checking offsets, we really ought to be * checking overflow cases. Need to use functions from * range.h (which needs to be impl

28、emented, too) */ if (exeFileLength phnum EXE_MAX_SEGMENTS) if (elfDebug) Print(Too many segments (%d) in ELF executablen, hdr-phnum); return ENOEXEC; if (exeFileLength phoff + (hdr-phnum * sizeof(programHeader) if (elfDebug) Print(Not enough room for program headern); return ENOEXEC; exeFormat-numSe

29、gments = hdr-phnum; exeFormat-entryAddr = hdr-entry; phdr = (programHeader *) (exeFileData + hdr-phoff); for (i = 0; i phnum; +i) struct Exe_Segment *segment = &exeFormat-segmentListi; /* * Fill in segment offset, length, address * FIXME: should check that segments are valid */ segment-offsetInFile

30、= phdri.offset; segment-lengthInFile = phdri.fileSize; segment-startAddress = phdri.vaddr; segment-sizeInMemory = phdri.memSize; if (segment-lengthInFile segment-sizeInMemory) if (elfDebug) Print(Segment %d: length in file (%lu) exceeds size in memory (%lu)n, i, segment-lengthInFile, segment-sizeInM

31、emory); return ENOEXEC; /* Groovy */ return 0;src/GeekOS/userseg.c文件中的函数Destroy_User_Context()void Destroy_User_Context(struct User_Context* userContext) /* * Hints: * - you need to free the memory allocated for the user process * - dont forget to free the segment descriptor allocated * for the proc

32、esss LDT */ / TODO(Destroy a User_Context); /* Free the contexts LDT descriptor */ Free_Segment_Descriptor(userContext-ldtDescriptor);userContext-ldtDescriptor=0; /* Free the contexts memory */ Free(userContext-memory);userContext-memory=0; Free(userContext);userContext=0;src/GeekOS/userseg.c文件中的函数L

33、oad_User_Program()int Load_User_Program(char *exeFileData, ulong_t exeFileLength, struct Exe_Format *exeFormat, const char *command, struct User_Context *pUserContext) /* * Hints: * - Determine where in memory each executable segment will be placed * - Determine size of argument block and where it m

34、emory it will * be placed * - Copy each executable segment into memory * - Format argument block in memory * - In the created User_Context object, set code entry point * address, argument block address, and initial kernel stack pointer * address */ int i; ulong_t maxva = 0; unsigned numArgs; ulong_t

35、 argBlockSize; ulong_t size, argBlockAddr; struct User_Context *userContext = 0; /* Find maximum virtual address */ for (i = 0; i numSegments; +i) struct Exe_Segment *segment = &exeFormat-segmentListi; ulong_t topva = segment-startAddress + segment-sizeInMemory; /* FIXME: range check */ if (topva ma

36、xva) maxva = topva; /* Determine size required for argument block */ Get_Argument_Block_Size(command, &numArgs, &argBlockSize); /* * Now we can determine the size of the memory block needed * to run the process. */ size = Round_Up_To_Page(maxva) + DEFAULT_USER_STACK_SIZE; argBlockAddr = size; size +

37、= argBlockSize; /* Create User_Context */ userContext = Create_User_Context(size); if (userContext = 0) return -1; /* Load segment data into memory */ for (i = 0; i numSegments; +i) struct Exe_Segment *segment = &exeFormat-segmentListi; memcpy(userContext-memory + segment-startAddress, exeFileData +

38、 segment-offsetInFile, segment-lengthInFile); /* Format argument block */ Format_Argument_Block(userContext-memory + argBlockAddr, numArgs, argBlockAddr, command); /* Fill in code entry point */ userContext-entryAddr = exeFormat-entryAddr; /* * Fill in addresses of argument block and stack * (They h

39、appen to be the same) */ userContext-argBlockAddr = argBlockAddr; userContext-stackPointerAddr = argBlockAddr; *pUserContext = userContext; return 0;src/GeekOS/kthread.c文件中的函数Setup_User_Thread()void Setup_User_Thread( struct Kernel_Thread* kthread, struct User_Context* userContext) /* * Hints: * - C

40、all Attach_User_Context() to attach the user context * to the Kernel_Thread * - Set up initial thread stack to make it appear that * the thread was interrupted while in user mode * just before the entry point instruction was executed * - The esi register should contain the address of * the argument

41、block */ /* * Interrupts in user mode MUST be enabled. * All other EFLAGS bits will be clear. */ ulong_t eflags = EFLAGS_IF; unsigned csSelector = userContext-csSelector; unsigned dsSelector = userContext-dsSelector; Attach_User_Context(kthread, userContext); /* * Make the threads stack look like it

42、 was interrupted * while in user mode. */ /* Stack segment and stack pointer within user mode. */ Push(kthread, dsSelector); /* user ss */ Push(kthread, userContext-stackPointerAddr); /* user esp */ /* eflags, cs, eip */ Push(kthread, eflags); Push(kthread, csSelector); Push(kthread, userContext-ent

43、ryAddr); Print(Entry addr=%lxn, userContext-entryAddr); /* Push fake error code and interrupt number. */ Push(kthread, 0); Push(kthread, 0); /* * Push initial values for general-purpose registers. * The only important register is esi, which we use to * pass the address of the argument block. */ Push

44、(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 initial values for the data segment registers. */ Push(kthread, dsSelector);

45、/* ds */ Push(kthread, dsSelector); /* es */ Push(kthread, dsSelector); /* fs */ Push(kthread, dsSelector); /* gs */src/GeekOS/kthread.c文件中的函数Start_User_Thread()struct Kernel_Thread*Start_User_Thread(struct User_Context* userContext, bool detached) /* * Hints: * - Use Create_Thread() to create a new raw thread object * - Call Setup_User_Thread() to get the thread ready to * execute in user mode * - Call Make_Runnable_Atomic() to schedule the process * for execution */ struct Kernel_Thread* kthread = Create_Thread(PRI

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论