版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、PAGE PAGE 17西北工业大学 操作系统实验 实验报告一、实验目的掌握在GeekOS系统用户态模式下加载并运行可执行程序的方法。二、实验要求1. 按照实验讲义P127页中的设计要求,实现在用户态模式下加载并运行可执行程序的代码,给出关键函数的代码以及实验结果。三、实验过程及结果答:核心函数代码如下:= user.c =/产生一个进程(用户态)int Spawn(const char *program, const char *command, struct Kernel_Thread *pThread)/TODO(Spawn a process by reading an executa
2、ble from a filesystem);int rc; char *exeFileData = 0;ulong_t exeFileLength;struct User_Context *userContext = 0;struct Kernel_Thread *process = 0;struct Exe_Format exeFormat;if (rc = Read_Fully(program, (void*) &exeFileData, &exeFileLength) != 0 )Print(Failed to Read File %s!n, program);goto fail;if
3、(rc = Parse_ELF_Executable(exeFileData, exeFileLength, &exeFormat) != 0 )Print(Failed to Parse ELF File!n);goto fail;if(rc = Load_User_Program(exeFileData, exeFileLength, &exeFormat, command, &userContext) != 0)Print(Failed to Load User Program!n);goto fail;/在堆分配方式下释放内存并再次初始化exeFileDataFree(exeFileD
4、ata);exeFileData = 0;/* 开始用户进程,调用Start_User_Thread函数创建一个进程并使其进入准备运行队列*/process = Start_User_Thread(userContext, false);if (process != 0) KASSERT(process-refCount = 2);/* 返回核心进程的指针 */*pThread = process; rc = process-pid;/记录当前进程的ID elserc = ENOMEM;return rc;fail: /如果新进程创建失败则注销User_Context对象if (exeFile
5、Data != 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)static struct User_Context* s_currentUserContext; /* last user context used */extern int userDebu
6、g;struct User_Context* userContext = kthread-userContext;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_Space(userContext);/为用户态进程时则切换地址空间esp0 = (
7、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 =int Parse_ELF_Executable(char *exeFileData, ulong_t exeFileLength, struct Exe_Format *exeForm
8、at)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;i
9、phnum;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;= userse
10、g.c =/需在此文件各函数前增加一个函数,此函数的功能是按给定的大小创建一个用户级进程上下文,具体实现如下:/函数功能:按给定的大小创建一个用户级进程上下文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
11、) UserContext-memory = 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
12、 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) UserCo
13、ntext-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, f
14、alse, 1); /将引用数清0 UserContext-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); /释放占用的LDT Free_Segment_Desc
15、riptor(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_Co
16、ntext *pUserContext) /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) /e
17、lf.hstruct 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;argB
18、lockAddr = 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, exeFileD
19、ata + segment-offsetInFile,segment-lengthInFile);/格式化参数块Format_Argument_Block(userContext-memory + argBlockAddr, numArgs, argBlockAddr, command);/初始化数据段,堆栈段及代码段信息userContext-entryAddr = exeFormat-entryAddr;userContext-argBlockAddr = argBlockAddr;userContext-stackPointerAddr = argBlockAddr;/将初始化完毕的Us
20、er_Context赋给*pUserContext*pUserContext = userContext;return 0;/成功/将用户态的进程复制到内核缓冲区bool Copy_From_User(void* destInKernel, ulong_t srcInUser, ulong_t bufSize) struct User_Context * UserContext = g_currentThread-userContext;/-: check if memory if validatedif (!Validate_User_Memory(UserContext,srcInUser
21、, bufSize)return false;memcpy(destInKernel, UserContext-memory + srcInUser, bufSize); return true;/将内核态的进程复制到用户态bool Copy_To_User(ulong_t destInUser, void* srcInKernel, ulong_t bufSize)struct User_Context * UserContext = g_currentThread-userContext;if (!Validate_User_Memory(UserContext, destInUser,
22、bufSize)return false;memcpy(UserContext-memory + destInUser, srcInKernel, bufSize);return true;/切换到用户地址空间void Switch_To_Address_Space(struct User_Context *userContext) ushort_t ldtSelector= userContext-ldtSelector;/* Switch to the LDT of the new user context */_asm_ _volatile_ (lldt %0:a(ldtSelector
23、);= kthread.c =添加头文件 #include /创建一个用户进程/*static*/ void Setup_User_Thread(struct Kernel_Thread* kthread, struct User_Context* userContext) ulong_t eflags = EFLAGS_IF; unsigned csSelector=userContext-csSelector;/CS选择子 unsigned dsSelector=userContext-dsSelector;/DS选择子 Attach_User_Context(kthread, userC
24、ontext);/初始化用户态进程堆栈,使之看上去像刚被中断运行一样/分别调用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); /中断号(
25、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(
26、kthread, dsSelector); /* es */ Push(kthread, dsSelector); /* fs */ Push(kthread, dsSelector); /* gs */ /开始用户进程struct Kernel_Thread* Start_User_Thread(struct User_Context* userContext, bool detached)struct Kernel_Thread* kthread = Create_Thread(PRIORITY_USER, detached);if (kthread != 0)Setup_User_Thr
27、ead(kthread, userContext);Make_Runnable_Atomic(kthread);return kthread; = syscall.c =/需在此文件别的函数前增加一个函数,函数名为Copy_User_String,它被函数Sys_PrintString调用,具体实现如下:static int Copy_User_String(ulong_t uaddr, ulong_t len, ulong_t maxLen, char *pStr) int rc = 0; char *str; if (len maxLen) /超过最大长度 return EINVALID;
28、 str = (char*) Malloc(len+1); /为字符串分配空间 if (0 = str) rc = ENOMEM; goto fail; if (!Copy_From_User(str, uaddr, len) /从用户空间中复制数据 rc = EINVALID; Free(str); goto fail; strlen = 0; /成功 *pStr = str;fail: return rc;static int Sys_Exit(struct Interrupt_State* state)Exit(state-ebx);static int Sys_PrintString(
29、struct Interrupt_State* state)int rc = 0;/返回值uint_t length = state-ecx;/字符串长度uchar_t* buf = 0;if (length 0) if (rc = Copy_User_String(state-ebx, length, 1023, (char*) &buf) != 0)goto done;Put_Buf(buf, length);done:if (buf != 0)Free(buf);return rc;static int Sys_GetKey(struct Interrupt_State* state)
30、return Wait_For_Key(); /返回按键码keyboard.c/Wait_For_Key()static int Sys_SetAttr(struct Interrupt_State* state) Set_Current_Attr(uchar_t) state-ebx);return 0;static int Sys_GetCursor(struct Interrupt_State* state) int row, col;Get_Cursor(&row, &col);if (!Copy_To_User(state-ebx, &row, sizeof(int) |!Copy_
31、To_User(state-ecx, &col, sizeof(int)return -1;return 0;static int Sys_PutCursor(struct Interrupt_State* state) return Put_Cursor(state-ebx, state-ecx) ? 0 : -1;static int Sys_Spawn(struct Interrupt_State* state) int rc; /函数返回值 char *program = 0; /进程名称 char *command = 0; /用户命令struct Kernel_Thread *pr
32、ocess;if (rc = Copy_User_String(state-ebx, state-ecx, VFS_MAX_PATH_LEN, &program) != 0)goto fail;if(rc = Copy_User_String(state-edx, state-esi, 1023, &command) != 0)/从用户空间复制用户命令goto fail;Enable_Interrupts(); /开中断rc = Spawn(program, command, &process);/得到进程名称和用户命令后便可生成一个新进程if (rc = 0) /若成功则返回新进程ID号KA
33、SSERT(process != 0);rc = process-pid;Disable_Interrupts();/关中断fail:/返回小于0的错误代码if (program != 0)Free(program);if (command != 0)Free(command);return rc;static int Sys_Wait(struct Interrupt_State* state) /TODO(Wait system call);int exitCode;struct Kernel_Thread *kthread = Lookup_Thread(state-ebx);if (k
34、thread = 0)return -12;Enable_Interrupts();exitCode = Join(kthread);Disable_Interrupts();return exitCode;static int Sys_GetPID(struct Interrupt_State* state) /TODO(GetPID system call);return g_currentThread-pid;= main.c =static void Spawn_Init_Process(void) /TODO(Spawn the init process); struct Kerne
35、l_Thread *pThread; Spawn(/c/shell.exe,/c/shell.exe,&pThread);实验结果如图所示:原理:Geekos 提供了一个简单的shell,保存在PFAT文件系统内,所以geekos系统启动后,启动shell程序/c/shell.exe运行,将/c/shell.exe作为可执行文件传递给spawn函数的program参数,创建第一个用户态进程,然后由它来创建其他进程。运行后,geekos就可以挂在这shell,并能运行测试文件c.exe和b.exe。四、实验分析GeekOS系统最早创建的内核进程有Idle、Reaper和Main三个进程,它们由Init_Scheduler函数创建:最先初始化一个核态进程mainThread,并将该进程作为当前运行进程,函数最后还调用Start_Kernel_Thread 函数创建了两个系统进程Idle和R
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025版冷链物流车辆租赁合作协议2篇
- 安徽事业单位二零二五年度聘用合同范本3篇
- 2025年度个人股权质押股权分割合同(公平版)4篇
- 2025版房地产开发商逾期交房违约责任担保合同4篇
- 二零二五版绿色家居墙面涂料采购与应用合同3篇
- 二零二五版毛竹林资源承包与加工利用合同2篇
- 2025年度宅基地使用权流转纠纷处理服务合同4篇
- 2025年度电子商务平台运营维护外包服务合同协议2篇
- 2025年度别墅铜门定制与市场推广活动合同3篇
- 2025年度轮胎销售区域保护与市场垄断协议4篇
- 定额〔2025〕1号文-关于发布2018版电力建设工程概预算定额2024年度价格水平调整的通知
- 2024年城市轨道交通设备维保及安全检查合同3篇
- 【教案】+同一直线上二力的合成(教学设计)(人教版2024)八年级物理下册
- 湖北省武汉市青山区2023-2024学年七年级上学期期末质量检测数学试卷(含解析)
- 单位往个人转账的合同(2篇)
- 科研伦理审查与违规处理考核试卷
- GB/T 44101-2024中国式摔跤课程学生运动能力测评规范
- 高危妊娠的评估和护理
- 2024年山东铁投集团招聘笔试参考题库含答案解析
- 2023年高考全国甲卷数学(理)试卷【含答案】
- 数独题目A4打印版无答案
评论
0/150
提交评论