GeekOS课程设计报告

上传人:沈*** 文档编号:103496229 上传时间:2022-06-08 格式:DOC 页数:23 大小:378KB
收藏 版权申诉 举报 下载
GeekOS课程设计报告_第1页
第1页 / 共23页
GeekOS课程设计报告_第2页
第2页 / 共23页
GeekOS课程设计报告_第3页
第3页 / 共23页
资源描述:

《GeekOS课程设计报告》由会员分享,可在线阅读,更多相关《GeekOS课程设计报告(23页珍藏版)》请在装配图网上搜索。

1、编号: GeekOS操作系统的研究与实现 题 目: GeekOS操作系统的研究与实现 系 别: 计算机科学与工程学院 专 业: 网络工程 学生姓名: 学 号: 指导教师: 2011年 3 月 5 日目 录(三号、黑体、居中、目录两字空四格、与正文空一行)一、课程设计环境 4二、设计项目0 5三、设计项目1 7四、设计项29五、遇到问题和解决方法.23六、总结24一、课程设计环境本次课设是在虚拟机上安装Linux进行开发调试,具体安装使用方法如下:、安装linux虚拟机本次课设的虚拟机是运行在Vmware WorkStation上的,网上下载和安装好 Vmware 后,下载Linux镜像文件后,

2、即可按提示即可安装。、GeekOS:是一个基于X86架构的PC机上运行的微操作系统内核,由美国 马理兰大学的教师开发,是一个用C语言开发的操作系统, GeekOS主要用于操作系统课程设计,目的是使学生能够实际动手参与到一个操作系统的开发工作中。GeekOS的使用:打开linux虚拟机,直接解压GeekOS压缩包就可使用,无需安装。、Bochs安装和使用:在Linux系统中需先解压软件包,然后再配置编译生成系统文件。二、设计项目0一、项目设计目的 熟悉GeekOS的项目编译、调试和运行环境,掌握GeekOS运行工作过程。二、设计任务 熟悉键盘操作函数,编程实现一个内核进程。该进程的功能是:接收键

3、盘输入的字符并显示到屏幕上,当输入ctrl+d时,结束进程的运行。三、具体过程 1、 -修改main.c的代码- /在main.c内增加该函数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; /低位为As

4、cii码 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函数struct Kernel_Thread *thread;thread = Start_Kernel_Thread(&project0,0,PRIORITY_NORMAL,false);-2、在build目录下编译得到镜像文件fd.img #m

5、ake3、 编写brochs 配置文件 vgaromimage: romimage: , address=0xf0000megs: 8boot: afloppya: 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

6、=0i440fxsupport: enabled=0 4、在brochs中运行GeekOS系统显示结果 三、 设计项目1一、项目设计目的 熟悉ELF文件格式,了解GeekOS系统如何将ELF格式的可执行程序装 入到内存,建立内核进程并运行的实现技术。二、 具体过程 修改/geekos/elf.c文件:在函数Parse_ELF_Executable( )中添加代码,分析 ELF格式的可执行文件(包括分析得出ELF文件头、程序头,获取可执行文 件长度,代码段、数据段等信息),并填充Exe_Format数据结构中的域值1、elf.c:将ELF格式的可执行程序装入到内存,建立内核进程并运行.-elf.

7、c- int Parse_ELF_Executable(char *exe, ulong_t exe, struct Exe_Format *exeFormat) int i; elfHeader *head=(elfHeader*)exe; programHeader *proHeader=(programHeader *)(exephoff); KASSERT(exe); KASSERT(exehead-ehsize+head-phentsize*head-phnum); KASSERT(head-entry%4=0); exeFormat-numSegments=head-phnum;

8、exeFormat-entryAddr=head-entry; for(i=0;iphnum;i+) exeFormat-segmentListi.offsetInoffset; exeFormat-segmentListi.lengthIn; exeFormat-segmentListi.startAddress=proHeader-vaddr; exeFormat-segmentListi.sizeInMemory=proHeader-memSize; exeFormat-segmentListi.protFlags=proHeader-flags; proHeader+;return 0

9、; -2、 编译,成功后生成两个镜像文件:fd.img和diskc.img。 其中,Diskc.img为模拟器能引导的操作系统镜像 。3、编写相应的bochs配置文件 由于生成了diskc.img,因此配置文件需加上以下内容config_interface: textconfigmegs: 8vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latestromimage: file=$BXSHARE/BIOS-bochs-latestfloppya: 1_44=./fd.img, status=insertedata0: enabled=1, ioaddr1=0x

10、1f0, 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, heads=8, spt=64#ata0-slave: type=cdrom, path=/dev

11、/cdrom, status=insertedboot: aips: 1000000log:./bochs.outvga_update_interval: 300000keyboard_serial_delay: 250keyboard_paste_delay: 100000private_colormap: enabled=0 4、在brochs中运行GeekOS系统显示结果四、 设计项目二一、项目设计目的 扩充GeekOS操作系统内核,使得系统能够支持用户级进程的动态创建和执行。二、项目2要求用户对以下几个文件进行修改: (1)“user.c” 文件中的函数Spawn(),其功能是生成一个

12、新的用户级进程;(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结构

13、。 Copy_From_User()和Copy_To_User()函数的功能是在用户地址空间和内核地址空间之间复制数据,在分段存储器管理模式下,只要段有效,调用memcpy函数就可以实现这两个函数的功能。 Switch_To_Address_Space()函数的功能是通过将进程的LDT装入到LDT寄存器来激活用户的地址空间;三、 具体代码修改情况 -elf.c-int Parse_ELF_Executable(char *exe, ulong_t exe Exe_Format *exeFormat) int i; elfHeader *hdr =(elfHeader*) exe; progra

14、mHeader *phdr=(programHeader *)(exe + hdr-phoff); struct Exe_Segment * segment= exeFormat-segmentList; for( i=0; iphnum; i+) segment-offsetInFile = phdr-offset; segment-lengthInFile = phdr-; segment-startAddress = phdr-vaddr; segment-sizeInMemory = phdr-memSize; phdr+; segment+; exeFormat-numSegment

15、s = hdr-phnum; exeFormat-entryAddr = hdr-entry; return 0; TODO(Parse an ELF executable image);-kthred.c-/kthread.c文件中主要是实现用户程序要求内核进行服务的一些系统调用函数定义-/为进程初始化内核堆栈/堆栈中是为进程首次进入用户态运行时设置处理器状态要使用的数据/该函数内部调用Attach_User_Context加载用户上下文 void Setup_User_Thread(struct Kernel_Thread* kthread, struct User_Context* us

16、erContext) /TODO(Create a new thread to execute in user mode); ulong_t eflags = EFLAGS_IF; unsigned csSelector=userContext-csSelector;/CS选择子 unsigned dsSelector=userContext-dsSelector;/DS选择子 Attach_User_Context(kthread, userContext);/调用Attach_User_Context加载用户上下文 /初始化用户态进程堆栈,使之看上去像刚被中断运行一样 /分别调用Push函

17、数将以下数据压入堆栈 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)

18、; /* 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,

19、 dsSelector); /* fs */ Push(kthread, dsSelector); /* gs */- /该函数使用User_Context对象开始一个新进程 /若成功,指针返回一个新进程 /Spawn函数调用该函数,以初始化一个用户态进程(包括初始化进程的Kernal_Thread结构以和调用Setup_User_Thread初始化用户态进程的内核堆栈) struct Kernel_Thread*Start_User_Thread(struct User_Context* userContext, bool detached) /调用Create_Thread()建立新进程对

20、象 /调用Setup_User_Thread()函数初始化新进程 /TODO(Start user thread); struct Kernel_Thread* kthread = Create_Thread(PRIORITY_USER, detached);/调用Create_Thread()建立新用户态进程对象 if (kthread != 0) Setup_User_Thread(kthread, userContext);/调用Setup_User_Thread()函数初始化新用户态进程的内核堆栈 Make_Runnable_Atomic(kthread); return kthrea

21、d;/创建成功,指针返回一个新进程- -user.c-/导入用户程序并初始化(包括调用Load_User_Program进行User_Context的初始化和用户态进程空间的分配、用户程序各段的装入)/Spawn函数主要完成的主要功能是:/调用Read_Fully函数将名为program的可执行文件全部读入内存缓冲区/调用Parse_ELF_Executable函数分析ELF格式文件/调用Load_User_Program将可执行程序的程序段和数据段装入内存,初始化User_Context数据结构/调用Start_User_Thread函数创建一个进程并使其进入准备运行队列int Spawn(

22、const char *program, const char *command, struct Kernel_Thread *pThread)/生成新的用户级进程 /TODO(Spawn a process by reading an executable from a ); int rc; /标记各函数的返回值,为则表示成功,否则失败 char *exe = 0;/保存在内存缓冲中的用户程序可执行文件 ulong_t exe可执行文件的长度 struct User_Context *userContext = 0;/指向User_Conetxt的指针 struct Kernel_Threa

23、d *process = 0;/指向Kernel_Thread *pThread的指针 struct Exe_Format exeFormat;/调用Parse_ELF_Executable函数得到的可执行文件信息 if (rc = Read_Fully(program, (void*) &exe, &exe) != 0 )/调用Read_Fully函数将名为program的可执行文件全部读入内存缓冲区 Print(Failed to Read !n, program); goto fail; if(rc = Parse_ELF_Executable(exe, exe, &exeFormat)

24、 != 0 )/调用Parse_ELF_Executable函数分析ELF格式文件 Print(Failed to Parse ELF File!n); goto fail; if(rc = Load_User_Program(exe, exe, &exeFormat, command, &userContext) != 0)/调用Load_User_Program将可执行程序的程序段和数据段装入内存,初始化User_Context数据结构 Print(Failed to Load User Program!n); goto fail; /在堆分配方式下释放内存并再次初始化exe Free(e

25、xe); exe = 0; process = Start_User_Thread(userContext, false);/开始用户进程,调用Start_User_Thread函数创建一个进程并使其进入准备运行队列 if (process != 0)/不是核心级进程(即为用户级进程) KASSERT(process-refCount = 2); *pThread = process;返回核心进程的指针 rc = process-pid;/记录当前进程的ID else/超出内存project2includegeekoserrno.h rc = ENOMEM; return rc; fail:

26、/如果新进程创建失败则注销User_Context对象 if (exe != 0) Free(exe);/释放内存 if (userContext != 0) Destroy_User_Context(userContext);/销毁进程对象 return rc;-void Switch_To_User_Context(struct Kernel_Thread* kthread, struct Interrupt_State* state)/执行新进程前,调用该函数以切换用户地址空间 /* * Hint: Before executing in user mode, you will need

27、 to call * the Set_Kernel_Stack_Pointer() and Switch_To_Address_Space() * functions. */ /TODO(Switch to a new user address space, if necessary); static struct User_Context* s_currentUserContext; /* last user context used */ /extern int userDebug; struct User_Context* userContext = kthread-userContex

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

29、tackPage) + PAGE_SIZE; /if (userDebug) / Print(S%lxn, esp0);/* 新进程的核心栈. */ Set_Kernel_Stack_Pointer(esp0);/设置内核堆栈指针/* New user context is active */ s_currentUserContext = userContext; -userseg.c-/userseg.c文件中主要为实现一些为实现对user.c中高层操作支持的函数-/新建一个给定长度的User_Context,参数是User_Context结构的大小/User_Context的新建stati

30、c 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 = Malloc(size); else/为核心态进程 goto fail; if (0 = UserConte

31、xt-memory)/内存为空 goto fail; memset(UserContext-memory, 0, size); UserContext-size = size; /以下为用户态进程创建LDT(段描述符表),步骤如下: /调用函数Allocate_Segment_Descriptor()新建一个LDT描述符 /调用函数selector()新建一个LDT选择子 /调用函数Init_Code_Segment_Descriptor()新建一个文本段描述符 /调用函数Init_Data_Segment_Descriptor()新建一个数据段 /调用函数selector()新建一个数据段选

32、择子 /调用函数selector()新建一个文本(可执行代码)段选择子 /新建一个LDT描述符 UserContext-ldtDescriptor = Allocate_Segment_Descriptor(); if (0 = UserContext-ldtDescriptor) goto fail; /初始化段描述符 Init_LDT_Descriptor(UserContext-ldtDescriptor, UserContext-ldt, NUM_USER_LDT_ENTRIES); /新建一个LDT选择子 UserContext-ldtSelector = Selector(KERN

33、EL_PRIVILEGE, true, Get_Descriptor_Index(UserContext-ldtDescriptor); /新建一个文本段描述符 Init_Code_Segment_Descriptor(&UserContext-ldt0,(ulong_t) UserContext-memory,size / PAGE_SIZE,USER_PRIVILEGE); /新建一个数据段 Init_Data_Segment_Descriptor( &UserContext-ldt1,(ulong_t) UserContext-memory,size / PAGE_SIZE,USER_P

34、RIVILEGE ); /新建数据段和文本(可执行代码)段选择子 UserContext-csSelector = Selector(USER_PRIVILEGE, false, 0); UserContext-dsSelector = Selector(USER_PRIVILEGE, false, 1); /将引用数清 UserContext-refCount = 0; return UserContext;fail: if (UserContext != 0) if (UserContext-memory != 0) Free(UserContext-memory); Free(UserC

35、ontext); return 0;-/注销User_Contex对象的函数是该函数,参数是待注销的User_Contex对象指针/User_Context的注销void Destroy_User_Context(struct User_Context* userContext)/释放用户态进程占用的内存资源(包括占用的LDT、内存空间和userContext本身占用的内存) /释放占用的LDT Free_Segment_Descriptor(userContext-ldtDescriptor); userContext-ldtDescriptor=0; /释放内存空间 Free(userCo

36、ntext-memory); userContext-memory=0; /释放userContext本身占用的内存 Free(userContext); userContext=0;-/该函数完成后,即得到用户程序在系统中的用户态进程体,以和用户上下文的User_Context结构/该函数实现的主要功能如下:/计算需要分配给用户态进程的内存空间大小/为用户程序分配内存空间,并初始化/根据Exe_Sdgment提供的用户段信息初始化代码段、数据段以和堆栈段的段描述符和段选择子/根据短信息将用户程序的各段内容复制到分配的用户内存空间/初始化User_Context结构的用户打开列表,初始化完毕后

37、,返回表示成功/参数含义如下/exe:保存在缓冲区的可执行文件/Format:调用elf得到的格式信息/command:用户输入的命令/指向User_Context对象的指针int Load_User_Program(char *exe, ulong_t exe Exe_Format *exeFormat, const char *command, struct User_Context *pUserContext)/通过加载可执行文件镜像创建新进程的USER-CONTEX的结构 /TODO(Load a user executable into a user memory space usi

38、ng segmentation); int i; ulong_t maxva = 0;/要分配的最大内存空间 unsigned numArgs;/进程数目 ulong_t argBlockSize;/参数块的大小 ulong_t size, argBlockAddr;/参数块地址 struct User_Context *userContext = 0; for (i = 0; i numSegments; +i)/计算用户态进程所需的最大内存空间 struct Exe_Segment *segment = &exeFormat-segmentListi; ulong_t topva = se

39、gment-startAddress + segment-sizeInMemory; /* FIXME: range check */ if (topva maxva) maxva = topva; Get_Argument_Block_Size(command, &numArgs, &argBlockSize);/获取参数块信息 size = Round_Up_To_Page(maxva) + DEFAULT_USER_STACK_SIZE;/用户进程大小=参数块总大小+ 进程堆栈大小(8192) argBlockAddr = size; size += argBlockSize; user

40、Context = Create_User_Context(size);/按相应大小创建一个进程 if (userContext = 0)/如果为核心态进程 return -1; for (i = 0; i numSegments; +i) struct Exe_Segment *segment = &exeFormat-segmentListi; /根据段信息将用户程序中的各段内容复制到分配的用户内存空间 memcpy(userContext-memory + segment-startAddress, exe + segment-offsetInlengthInFile); /格式化参数块

41、 Format_Argument_Block(userContext-memory + argBlockAddr, numArgs, argBlockAddr, command); /初始化数据段,堆栈段和代码段信息 userContext-entryAddr = exeFormat-entryAddr; userContext-argBlockAddr = argBlockAddr; userContext-stackPointerAddr = argBlockAddr; /将初始化完毕的User_Context赋给*pUserContext *pUserContext = userCont

42、ext; return 0;/成功-bool Copy_From_User(void* destInKernel, ulong_t srcInUser, ulong_t bufSize)/在用户地址空间和内核地址空间之间复制数据,与Copy_To_User函数功能共同使用 /TODO(Copy memory from user buffer to kernel buffer); struct User_Context * UserContext = g_currentThread-userContext; /-: check if memory if validated if (!Valida

43、te_User_Memory(UserContext,srcInUser, bufSize) return false; /-:user-kernel memcpy(destInKernel, UserContext-memory + srcInUser, bufSize); return true; Validate_User_Memory(NULL,0,0); /* delete this; keeps gcc happy */- /成功,返回true;user buffer不存在,返回false bool Copy_To_User(ulong_t destInUser, void* sr

44、cInKernel, ulong_t bufSize)/在用户地址空间和内核地址空间之间复制数据 /TODO(Copy memory from kernel buffer to user buffer) struct User_Context * UserContext = g_currentThread-userContext; /-: check if memory if validated if (!Validate_User_Memory(UserContext, destInUser, bufSize) return false; /-:kernel-user memcpy(User

45、Context-memory + destInUser, srcInKernel, bufSize); return true;-void Switch_To_Address_Space(struct User_Context *userContext)/通过将进程的LDT装入到LDT寄存器来激活用户的地址空间 /TODO(Switch to user address space using segmentation/LDT); ushort_t ldtSelector= userContext-ldtSelector;/* Switch to the LDT of the new user context */ _asm_ _volatile_ (lldt %0:a(ldtSelector);-main.c-/在main.c文件内改写生成第一个用户态进程的函数调用:static void Spawn_Init_Process(void)static void Mount_Root_(void);static vo

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

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!