


版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、西北工业大学操作系统实验实验报告一、实验目的掌握在GeekOS系统用户态模式下加载并运行可执行程序的方法。二、实验要求1.按照实验讲义P127页中的设计要求,实现在用户态模式下加载并运行可 执行程序的代码,给出关键函数的代码以与实验结果。三、实验过程与结果答:核心函数代码如下:= user.c =/产生一个进程用户态int Spaw n(const char *program, const char *ma nd, struct Kern el_Thread *pThread)TODO(Spaw n a process by read ing an executable from a file
2、system); int rc;char *exeFileData = 0;ulong_t exeFileLe ngth;struct User_C on text *userC on text = 0;struct Kern el_Thread *process = 0;struct Exe_Format exeFormat;if (rc = Read_Fully(program, (void*) & exeFileData, & exeFileLe ngth) != 0 )Print(Failed to Read File %s!n, program);goto fail;if(rc =
3、Parse_ELF_Executable(exeFileData, exeFileLe ngth, &exeFormat) != 0 )Prin t(Failed to Parse ELF File!n ”);goto fail;if(rc = Load_User_Program(exeFileData, exeFileLe ngth, &exeFormat, mand, & userC on text) != 0)Prin t(Failed to Load User Program!n);goto fail;/在堆分配方式下释放内存并再次初始化exeFileDataFree(exeFileD
4、ata);exeFileData = 0;/*开始用户进程,调用Start_User_Thread函数创建一个进程并使其进入准备运行队列*/process = Start_User_Thread(userC on text, false);if (process != 0) KASSERT(process-refCou nt = 2);/*返回核心进程的指针*/*pThread = process;rc = process-pid;记录当前进程的IDelserc = ENOMEM;return rc;fail: /如果新进程创建失败如此注销User_Context对象if (exeFileDa
5、ta != 0)Free(exeFileData);/ 释放内存if (userCo ntext != 0)Destroy_User_Context(userContext);/ 销毁进程对象return rc; /切换至用户上下文void Switch_To_User_C on text(structKernel_Thread* kthread, struct In terrupt_State*state)static struct User_C on text* s_curre ntUserC on text; /* last user con text used */exter n in
6、t userDebug;struct User_C on text* userC on text = kthread-userC on text;KASSERT(!I nterrupts_E nabled();if (userCo ntext = 0) /userC on text为0表示此进程为核心态进程就不用切换地址空间return;if (userC on text != s_curre ntUserC on text) ulong_t esp0;/if (userDebug) Prin t(A%pn, kthread);Switch_To_Address_Space(userConte
7、xt);/为用户态进程时如此切换地址空间esp0 = (ulo ng_t) kthread-stackPage) + PAGE_SIZE;/if (userDebug)/ Prin t(S%lxn, esp0);/*新进程的核心栈 */Set_Kernel_Stack_Poi nter(espO);/ 设置内核堆栈指针/* New user con text is active */s_curre ntUserC on text = userC on text;= elf.c =int Parse_ELF_Executable(char *exeFileData, ulong_t exeFil
8、eLength, struct Exe_Format *exeFormat)int i;elfHeader *head=(elfHeader*)exeFileData;programHeader *proHeader=(programHeader *)(exeFileData+head-phoff);KASSERT(exeFileData!=NULL);KASSERT(exeFileLe ngthhead-ehsize+head-phe ntsize*head-ph nu m);KASSERT(head-e ntry%4=0);exeFormat-nu mSegme nts=head-ph n
9、um;exeFormat-e ntryAddr=head-e ntry;for(i=0;iph nu m;i+)exeFormat-segme ntListi.offset InF ile=proHeader-offset;exeFormat-segme ntListien gthI nFile=proHeader-fileSize;exeFormat-segme ntListi.startAddress=proHeader-vaddr;exeFormat-segme ntListi.sizel nM emory=proHeader-memSize;exeFormat-segme ntList
10、tFlags=proHeader-flags;proHeader+;return 0;= userseg.c =需在此文件各函数前增加一个函数,此函数的功能是按给定的大小创建一个用户级进程上下文,具体实现如下:函数功能:按给定的大小创建一个用户级进程上下文static struct User_C on text* Create_User_C on text(u long_t size)struct User_C on text * UserC on text;size = Roun d_Up_To_Page(size);UserCo ntext = (struct User_Co n
11、text *)Malloc(sizeof(struct User_Co ntext);if (UserCo ntext != 0)UserC on text-memory = Malloc(size);/为核心态进程elsegoto fail;内存为空if (0 = UserC on text-memory)goto fail;memset(UserC on text-memory, 0, size);UserC on text-size = size;/以下为用户态进程创建LDT(段描述符表)新建一个LDT描述符UserC on text-ldtDescriptor = Allocate_S
12、egme nt_Descriptor();if (0 = UserC on text-ldtDescriptor)goto fail;/初始化段描述符In it_LDT_Descriptor(UserCo ntext-ldtDescriptor,UserCo ntext-ldt,NUM_USER_LDT_ENTRIES);新建一个LDT选择子UserCo ntext-ldtSelector=Selector(KERNEL_PRIVILEGE,true,Get_Descriptor_I ndex(UserC on text-ldtDescriptor);/新建一个文本段描述符Ini t_Code
13、_Segme nt_Descriptor(& UserCo ntext-ldt0,(ulon g_t) UserC on text-memory,size / PAGE_SIZE,USER_PRIVILEGE);/新建一个数据段Ini t_Data_Segme nt_Descriptor(& UserCo ntext-ldt1,(ulon g_t) UserC on text-memory,size / PAGE_SIZE,USER_PRIVILEGE);/新建数据段和文本段选择子UserC on text-csSelector = Selector(USER_PRIVILEGE, false
14、, 0);UserCo ntext-dsSelector = Selector(USER_PRIVILEGE, false, 1);/将引用数清0UserC on text-refCou nt = 0;retur n UserC on text;fail:if (UserCo ntext != 0)if (UserC on text-memory != 0)Free(UserC on text-memory);Free(UserC on text);return 0; /摧毁用户上下文void Destroy_User_C on text(struct User_C on text* user
15、C on text) TODO(Destroy a User_Co ntext);/释放占用的LDTFree_Segme nt_Descriptor(userC on text-ldtDescriptor);userC on text-ldtDescriptor=0;/释放内存空间Free(userC on text-memory); userC on text-memory=0;/释放userContext本身占用的内存Free(userC on text);userC on text=0;int Load_User_Program(char *exeFileData,u long_texe
16、FileLe ngth,structExe_Format*exeFormat,c onst char *ma nd,struct User_C on text *pUserC on text)TODO(Load a user executable into a user memory space using segme ntati on ”);int i;ulong_t maxva = 0;/要分配的最大内存空间un sig ned nu mArgs;/ 进程数目ulong_t argBlockSize;/ 参数块的大小ulong_t size, argBlockAddr;/ 参数块地址str
17、uct User_C on text *userC on text = 0;/计算用户态进程所需的最大内存空间for (i = 0; i nu mSegme nts; +i) struct Exe_Segme nt *segme nt = & exeFormat-segme ntListi;ulong_t topva = segme nt-startAddress + segme nt-sizel nM emory; /* FIXME: range check */if (topva maxva)maxva = topva;Get_Argume nt_Block_Size(ma nd, &nu
18、 mArgs, &argBlockSize); 获取参数块信息size = Round_ Up_To_Page(maxva) + DEFAULT_USER_STACK_SIZE;argBlockAddr = size;size += argBlockSize;userContext = Create_User_Context(size);/ 按相应大小创建一个进程if (userContext = 0)/如果为核心态进程return -1;for (i = 0; i nu mSegme nts; +i) struct Exe_Segme nt *segme nt = & exeFormat-s
19、egme ntListi;/根据段信息将用户程序中的各段内容复制到分配的用户内存空间memcpy(userC on text-memory+segme nt-startAddress,exeFileData +segme nt-offsetl nFile,segme nt-le ngthl nFile);/格式化参数块Format_Argume nt_Block(userC on text-memory+ argBlockAddr, nu mArgs, argBlockAddr,man d);/初始化数据段,堆栈段与代码段信息userC on text-e ntryAddr = exeForm
20、at-e ntryAddr;userC on text-argBlockAddr = argBlockAddr;userC on text-stackPoi nterAddr = argBlockAddr;将初始化完毕的 User_Context赋给*pUserContext *pUserC on text = userC on text;return 0;/ 成功 /将用户态的进程复制到内核缓冲区bool Copy_From_User(void* dest InKern el, ulong_t srcInU ser, ulong_t bufSize) struct User_C on tex
21、t * UserC on text = g_curre ntThread-userC on text;/-: check if memory if validatedif (!Validate_User_Memory(UserCo ntext,srcl nU ser, bufSize)return false;memcpy(destl nKern el, UserC on text-memory + srcInU ser, bufSize);return true; /将内核态的进程复制到用户态bool Copy_To_User(u long_t destl nU ser, void* src
22、InKern el, ulong_t bufSize) struct User_C on text * UserC on text = g_curre ntThread-userC on text;if (!Validate_User_Memory(UserCo ntext, destI nU ser,bufSize)return false;memcpy(UserC on text-memory + destI nU ser, srcInKern el, bufSize); return true; /切换到用户地址空间void Switch_To_Address_Space(struct
23、User_C on text *userC on text)ushort_t ldtSelector= userC on text-ldtSelector;/* Switch to the LDT of the new user con text */_asmvolatile_ (lldt %0:a(ldtSelector);= kthread.c =添加头文件 #i nclude /创建一个用户进程/*static*/ void Setup_User_Thread(struct Kern el_Thread* kthread, struct User_C on text* userC on
24、text)ulo ng_t eflags = EFLAGS_IF;unsigned csSelector=userContext-csSelector;/CS 选择子unsigned dsSelector=userContext-dsSelector;/DS 选择子Attach_User_C on text(kthread, userC on text);初始化用户态进程堆栈,使之看上去像刚被中断运行一样分别调用Push函数将以下数据压入堆栈Push (kthread, dsSelector);Push(kthread, userC on text-stackPo in terAddr);Pu
25、sh(kthread, eflags);Push(kthread, csSelector);Push(kthread, userC on text-e ntryAddr);Push (kthread, 0);Push (kthread, 0);/数据选择子堆栈指针/Eflags文本选择子/程序计数器错误代码(0)中断号(0)/初始化通用存放单元,将ESI用户传递参数块地址Push(kthread, 0); /* eax */Push(kthread, 0); /* ebx */Push(kthread, 0); /* edx */Push(kthread, 0); /* edx */Push(
26、kthread, userC on text-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 */开始用户进程struct Kern el_Thread* Start_User_Thread(st
27、ruct User_C on text* userC on text, bool detached) struct Kernel_Thread* kthread = Create_Thread(PRIORITY_USER, detached);if (kthread != 0)Setup_User_Thread(kthread, userC on text);Make_Ru nn able_Atomic(kthread);return kthread;syscall.c/需在此文件别的函数前增加一个函数,函数名为Copy_User_String ,它被函数Sys_PrintString调用,具
28、体实现如下:static int Copy_User_Stri ng(u long_t uaddr, ulon g_t le n, ulong_t maxLe n, char *pStr) int rc = 0;char *str;if (le n maxLe n)/超过最大长度return EINV ALID;str = (char*) Malloc(le n+1);/ 为字符串分配空间if (0 = str)rc = ENOMEM;goto fail;if (!Copy_From_User(str, uaddr, le n)从用户空间中复制数据rc = EINV ALID;Free(str
29、);goto fail;strle n = 0:/成功*pStr = str;fail:return rc; static int Sys_Exit(struct Interrupt_State* state) Exit(state-ebx); static int Sys_PrintString(struct Interrupt_State* state)int rc = 0;/ 返回值uint_t length = state-ecx;/ 字符串长度uchar_t* buf = 0;if (le ngth 0) if (rc = Copy_User_String(state-ebx, le
30、ngth, 1023, (char*) &buf) != 0) goto done;Put_Buf(buf, le ngth);done:if (buf != 0)Free(buf);return rc; static int Sys_GetKey(struct Interrupt_State* state)return Wait_For_Key(); / 返回按键码 keyboard.c/Wait_For_Key() static int Sys_SetAttr(struct In terrupt_State* state) Set_Curre nt_Attr(uchar_t) state-
31、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( in t) |!Copy_To_User(state-ecx, &col, sizeof( in t) return -1;return 0; static int Sys_PutCursor(struct Interrupt_State* state) retur n Put_Cursor(st
32、ate-ebx, state-ecx) ? 0 : -1; static int Sys_Spaw n( struct In terrupt_State* state)int rc;/函数返回值char *program = 0;进程名称char *ma nd = 0;/ 用户命令struct Kern el_Thread *process;if (rc = Copy_User_Stri ng(state-ebx, state-ecx, VFS_MAX_PATH_LEN, & program) != 0) goto fail;if(rc = Copy_User_Stri ng(state-ed
33、x, state-esi, 1023, &man d) != 0)/从用户空间复制用户命令goto fail;En able_I nterrupts();/ 开中断rc = Spawn(program, mand, &process);/得到进程名称和用户命令后便可生成一个新进程if (rc = 0) /假如成功如此返回新进程 ID号KASSERT(process != 0);rc = process-pid;Disable_Interrupts();/ 关中断if (program != 0) Free(program);if (ma nd != 0)Free(ma nd); return
34、rc; static int Sys_Wait(struct Interrupt_State* state) /TODO(Wait system call);int exitCode;struct Kernel_Thread *kthread = Lookup_Thread(state-ebx); if (kthread = 0)return -12;En able_I nterrupts();exitCode = Join( kthread);Disable_I nterrupts();retur n exitCode; static int Sys_GetPID(struct Interr
35、upt_State* state) /TODO(GetPID system call);retur n g_curre ntThread-pid;= main.c = static void Spaw n_lni t_Process(void) /TODO(Spaw n the in it process);struct Kernel_Thread *pThread;Spaw n(”/c/shell.exe,/c/shell.exe,&pThread);实验结果如下列图:C Q dcKhs xB6 emulator, http:;/bochs.sourceforgcnetit- .| | ji
36、iTsijiirercWiSrfcgI ist 1G48E7G bytes in kernEi Jheapkry br)Ard .DHA Caintpoller.-. Cloppy contro1ier.06, hcods2, sectors 18IEE duh tibuller.1333313333 H |jlL,frZl. . FI7TTk35 *|蹿% 廉逊缓空,5.航*通耳百ij原理:Geekos提供了一个简单的shell,保存在PFAT文件系统内,所以geekos系统启动后,启动shell程序/c/shell.exe运行,将作为可执行文件传递给spawn函数的program参数,创建第一个用户态进程,然后由它来创建其他进程。运行后,geekos就可以挂在这shell,并能运行测试文件c.exe和b.exeo四、实验分析GeekOS系统最早创建的内核进程有Idle、Reaper和Main三个进程,它们 由Ini t
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 智能照明在医疗手术室照明中的应用考核试卷
- 矿物干燥剂生产考核试卷
- 森林植被恢复与重建考核试卷
- 糖尿病患者护理查房 2
- 一年级上册数学口算(每天5分钟60题)
- 2025年中考初三学业质量检测(一)物理模拟题答案
- 统编版语文五年级下册第9课《古诗三首》精美课件
- 三亚中瑞酒店管理职业学院《商贸英语听说上》2023-2024学年第二学期期末试卷
- 辽宁省朝阳市双塔区2024-2025学年五下数学期末复习检测模拟试题含答案
- 山东省济南市济阳县2025届初三毕业班模拟考试(五)英语试题含答案
- 2023中考道德与法治十大热点预测-2023年中考道德与法治考场速查宝典(部编版)
- 高中英语必背3500单词表(完整版)
- 农药代销协议书模板
- 2024年新人教版五年级数学下册《教材练习20练习二十附答案》教学课件
- 《电力中长期交易合同示范文本(2022年修订版)》
- 医院感染管理考试题及答案
- 小学班会 世界知识产权日知识产权宣传周主题班会 课件
- 3.2平均数的计算(1)(教学课件)五年级数学上册 沪教版
- 中医科胸痹(冠心病-心绞痛)中医诊疗方案
- 2023-2024全国初中物理竞赛试题:光的反射及折射(含答案)
- 福建省高速公路集团有限公司招聘笔试真题2023
评论
0/150
提交评论