




已阅读5页,还剩20页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
编号: GeekOS操作系统的研究与实现 题 目: GeekOS操作系统的研究与实现 系 别: 计算机科学与工程学院 专 业: 网络工程 学生姓名: 学 号: 指导教师: 2011年 3 月 5 日目 录(三号、黑体、居中、目录两字空四格、与正文空一行)一、课程设计环境 4二、设计项目0 5三、设计项目1 7四、设计项29五、遇到问题及解决方法.23六、总结24一、课程设计环境本次课设是在虚拟机上安装Linux进行开发调试,具体安装使用方法如下:、安装linux虚拟机本次课设的虚拟机是运行在Vmware WorkStation上的,网上下载及安装好 Vmware 后,下载Linux镜像文件后,即可按提示即可安装。、GeekOS:是一个基于X86架构的PC机上运行的微操作系统内核,由美国 马理兰大学的教师开发,是一个用C语言开发的操作系统, GeekOS主要用于操作系统课程设计,目的是使学生能够实际动手参与到一个操作系统的开发工作中。GeekOS的使用:打开linux虚拟机,直接解压GeekOS压缩包就可使用,无需安装。、Bochs安装和使用:在Linux系统中需先解压软件包,然后再配置编译生成系统文件。二、设计项目0一、项目设计目的 熟悉GeekOS的项目编译、调试和运行环境,掌握GeekOS运行工作过程。二、设计任务 熟悉键盘操作函数,编程实现一个内核进程。该进程的功能是:接收键盘输入的字符并显示到屏幕上,当输入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; /低位为Ascii码 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 #make3、 编写brochs 配置文件 vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latestromimage: file=/usr/share/bochs/BIOS-bochs-latest, 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=0i440fxsupport: enabled=0 4、在brochs中运行GeekOS系统显示结果 3、 设计项目1一、项目设计目的 熟悉ELF文件格式,了解GeekOS系统如何将ELF格式的可执行程序装 入到内存,建立内核进程并运行的实现技术。2、 具体过程 修改/geekos/elf.c文件:在函数Parse_ELF_Executable( )中添加代码,分析 ELF格式的可执行文件(包括分析得出ELF文件头、程序头,获取可执行文 件长度,代码段、数据段等信息),并填充Exe_Format数据结构中的域值1、elf.c:将ELF格式的可执行程序装入到内存,建立内核进程并运行.-elf.c- int Parse_ELF_Executable(char *exeFileData, ulong_t exeFileLength, struct Exe_Format *exeFormat) int i; elfHeader *head=(elfHeader*)exeFileData; programHeader *proHeader=(programHeader *)(exeFileData+head-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-segmentListi.lengthInFile=proHeader-fileSize; exeFormat-segmentListi.startAddress=proHeader-vaddr; exeFormat-segmentListi.sizeInMemory=proHeader-memSize; exeFormat-segmentLtFlags=proHeader-flags; proHeader+;return 0; -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=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, heads=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、在brochs中运行GeekOS系统显示结果4、 设计项目二一、项目设计目的 扩充GeekOS操作系统内核,使得系统能够支持用户级进程的动态创建和执行。二、项目2要求用户对以下几个文件进行修改: (1)“user.c” 文件中的函数Spawn(),其功能是生成一个新的用户级进程;(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结构。 Copy_From_User()和Copy_To_User()函数的功能是在用户地址空间和内核地址空间之间复制数据,在分段存储器管理模式下,只要段有效,调用memcpy函数就可以实现这两个函数的功能。 Switch_To_Address_Space()函数的功能是通过将进程的LDT装入到LDT寄存器来激活用户的地址空间;3、 具体代码修改情况 -elf.c-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 * 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; TODO(Parse an ELF executable image);-kthred.c-/kthread.c文件中主要是实现用户程序要求内核进行服务的一些系统调用函数定义-/为进程初始化内核堆栈/堆栈中是为进程首次进入用户态运行时设置处理器状态要使用的数据/该函数内部调用Attach_User_Context加载用户上下文 void Setup_User_Thread(struct Kernel_Thread* kthread, struct User_Context* userContext) /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函数将以下数据压入堆栈 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); /* 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, 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()建立新进程对象 /调用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 kthread;/创建成功,指针返回一个新进程- -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(const char *program, const char *command, struct Kernel_Thread *pThread)/生成新的用户级进程 /TODO(Spawn a process by reading an executable from a filesystem); int rc; /标记各函数的返回值,为则表示成功,否则失败 char *exeFileData = 0;/保存在内存缓冲中的用户程序可执行文件 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 )/调用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, exeFileLength, &exeFormat, command, &userContext) != 0)/调用Load_User_Program将可执行程序的程序段和数据段装入内存,初始化User_Context数据结构 Print(Failed to Load User Program!n); goto fail; /在堆分配方式下释放内存并再次初始化exeFileData Free(exeFileData); exeFileData = 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: /如果新进程创建失败则注销User_Context对象 if (exeFileData != 0) Free(exeFileData);/释放内存 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 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-userContext;/指向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-stackPage) + 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的新建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 = Malloc(size); else/为核心态进程 goto fail; if (0 = UserContext-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()新建一个数据段选择子 /调用函数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(KERNEL_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_PRIVILEGE ); /新建数据段和文本(可执行代码)段选择子 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(UserContext); 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(userContext-memory); userContext-memory=0; /释放userContext本身占用的内存 Free(userContext); userContext=0;-/该函数完成后,即得到用户程序在系统中的用户态进程体,以及用户上下文的User_Context结构/该函数实现的主要功能如下:/计算需要分配给用户态进程的内存空间大小/为用户程序分配内存空间,并初始化/根据Exe_Sdgment提供的用户段信息初始化代码段、数据段以及堆栈段的段描述符和段选择子/根据短信息将用户程序的各段内容复制到分配的用户内存空间/初始化User_Context结构的用户打开列表,初始化完毕后,返回表示成功/参数含义如下/exeFileData:保存在缓冲区的可执行文件/Format:调用elf得到的格式信息/command:用户输入的命令/指向User_Context对象的指针int Load_User_Program(char *exeFileData, ulong_t exeFileLength,struct Exe_Format *exeFormat, const char *command, struct User_Context *pUserContext)/通过加载可执行文件镜像创建新进程的USER-CONTEX的结构 /TODO(Load a user executable into a user memory space using 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 = segment-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; userContext = 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, exeFileData + segment-offsetInFile,segment-lengthInFile); /格式化参数块 Format_Argument_Block(userContext-memory + argBlockAddr, numArgs, argBlockAddr, command); /初始化数据段,堆栈段及代码段信息 userContext-entryAddr = exeFormat-entryAddr; use
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025版蔬菜种植基地农业机械化推广承包协议
- 2025年度草原生态修复租赁项目合同
- 2025年度绿色蔬菜直销合作供应合同范本
- 2025年度特殊需求包车客运服务协议书
- 2025版节能涂料工程承包合同
- 2025年度文化创意产品动产质押融资协议
- 2025褚贞离婚协议书及财产分割与子女抚养费协议
- 金融行业CRM数字化升级在金融机构客户服务创新中的应用
- 2025年度节能环保型标准砖批发销售合同
- 产业园区建设资金申请报告2025年规划
- 文昌顺发畜牧有限公司养猪场项目 环评报告
- 四年级下册递等式计算练习400道及答案
- 2024年华能甘肃能源开发有限公司招聘笔试参考题库含答案解析
- 助产士在产时并发症处理中的助产安全
- 单片机的看门狗
- 市场营销(第2版)课件全套 王永贵 第1-17章-市场与市场营销概述及发展-顾客营销学
- 高中数学 人教A版 必修一 《集合与常用逻辑用语》 1.1集合的概念
- 深圳某电厂锅炉维修改造施工组织设计-new(常用版)
- GB/T 4950-2021锌合金牺牲阳极
- GB/T 15171-1994软包装件密封性能试验方法
- 证券从业考试基础模拟卷二(题目+解析)
评论
0/150
提交评论