实例介绍
帮助你详细理解user program!绝杀!
10版权信息 23 11修订版本 24 1小组人员组成与分工1 小组人员组成与分工 小组成员 4p小组由4名08cs成员组成,列表如下 陈歌,C,<Oliⅴia200705@126.com> 李梦阳,L,<may1i.he@gmai1.com> 王盛,W,<wstnapagmai1.com> 肖天骏,x,<xiaot]1990327e9mai1.com> 开发代号是每人姓氏的首字母 1.2 任务分工 仼务分工由一系列表格组成,并且有较强的松散自由度。 日期‖内容 人员 结果 11.27阅读需求文档,初步规划任务 0 12.6提出并实现第一题解法 Cw 延期12.9 12.6提出第二题解法 延期129 126设计第三题 129初步实现 Syscall 成成 1210代码上传合并 WXL 完成 12.12|调试测试样例 延期12.13 12.13整理代码并提交 完成 1218文档清理上传 CLWX 1220文档合并 成成 73 版本控制 由于多人同时贡献代码,所以决定在项目中采用版本控制。 代码托管于 googlecode,采用S进行控制,可以在以下页面找到项目信息: http://pintosof4p.googlecode.com 额外的参考资料 在作业完成的过程中除了压缩包中的资料,还参考了 pintos官方文档:hp:/www.scs.stanfordedu/10wics140/pintos minix3源码:http://www.minix3.org/source.htm 运行用户程序 这一部分主要由LX构思,W实现,L做出测试提出修改意见。Ⅹ整理了这部分文档。 3运行用户程序2 pintos操作系统的用户程序是要基于文件系统才能运行的,我们需要先做一些文件系统的操作, 其步骤为:1·创建disk;2.格式化disκ;3.将可执行文件e1f装裝入disk pintos操作系统的用户程序运行流程: start create user thread Allocate ard activate page d irect run start_ proce Open executa ble fle oad executable fl Read and verry exec utable header wait ard sleep ad Programe heade oa success go on sleep SUCCES S be waker rcturn 1 get pid t up th store in arguments cal intr exit CKCutc uscr programm 插图1:用户程序运行 如图,用户程序的运行遵循以上几个步骤 1.操作系统启动与初始化,其中包括内核程序的存储空间分配; 2.加载用户可执行文件,为用户程序分配内存地址空间,由于目前操作系统下没有安装编译器, 我们只能加载e1f可执行文件; 3运行用户程序 3.我们在载入eLf文件时需要做一系列检查,主要是为了确认e1f文件的存储空间占用情况, 代码段入口等。这些信息一般都保存在eLf文件的 executab1 e header和 program header 里。在这里,我们遇到了一个小问题导致载入e1£文件失败,需要载入的ef文件的 header中标明, 第一个1 ader部分占用虚存从0x000000开始,然而 pintos操作系统默认虚存的低0x1000位 置不被映射,即第0页不被映射,但是我们注意到,首个1 oader段实际用到的地址是从 offset开 始的,正好是0x1000,那么函数 validate segment()的判别机制要有所修改,将if (phdx-> p vaddr<PGS工zE)改为if(phdr-> p offset<PGS工zE)。这样做的话可 以成功载入e]f文件,不过这么做的后果是分配用户內存空间时,仍就会映射到虚存的第0页,这是 pintos所不允许的,为了解决这个问题,我们在函数1oad()里做一下修改,如果我们发现读出的 men page==0,我们需要手动将其设置为0x1000,这样做实际上是将一个条件判断所作的工作手动 实现了,因为我们无法控制由make得到的eLf文件,我们只能从load函数中做修改。 4在用户内存空间指定之后,我们就可以向用户内存的堆栈传递参数了。具体的实现方法将在下 章进行介绍。 5.在用户进程载入完毕之后,通过中断返回的方式进入用户程序的代码段进行执行。但实际上我 们发现操作系统很快地关杋了,经过分析,由于用户进程与操作系统main线程的优先级相同,造成的 运行效果就是两者交替运行,而main函数执行 process walt()迅速返回之后,就调用 shutdown关机了,所以初期的做法是将 process wait()中加入一个循环,不断的去检查该用户 线程是否执行结朿,如果结朿就跳岀循环,这是该 project前期的实现方法,该方法会造成忙等待, 更好地实现我们会在后面的几章进行说明。 6.用户程序运行之后会传回返回值 ret status,将其作为 process wait()的返回值传 回,main线程关机,执行结束。 进程退出信息 需求分析 在运行用户程序结束时,我们需要得到进程退出信息,以反映给用户进程的运行情况,这些进 程退岀信息有时是用户需要计算机来运算的结果,有时是用户文件操作是否成功的标志,当用户进程因 为不当操作被终止时,我们需要通知用户来修改自己的程序,可见,进程退出信息是十分必要的。 4.2设计与实现 该功能具体实现涉及 exit system cal1,以及错误处理机制。exit对应于大多数运行 正常的用户进程,而当用户进程发生错误时,我们也要有相应的机制来返回执行信息。 4.2.1数据结构 在 thread.h中为 struct thread添加成员变量: int ret status,该成员变量用来 保存该线程的退出信息,以供别的代码段寻访。 在 thread.h中为 struct thread添加成员变量: struct1 ist child1ist,该成 员变量使得一个用户进程的推出信息在该进程执行完毕之后仍然可以被得到,这个成员变量主要被利用 在wait这个 system ca11中,将在后文详细介绍。 4.2.2处理方法 当用户进程执行到 return的语句时,系统调用 exit system ca11,并将 return value压到堆栈中,所以我们可以通过指针访问堆栈得到正常退出信息,通过 thread name()函数 4进程退出信息4 得到对应进程的进程名。而对于被内核终止的用户进程,我们手动地将该进程的 ret status设置 为-1,然后输出。 参数传递 5, 需求分析 执行一个可执行文件,常常需要传入参数来控制程序运行,比如用哪种模式运行,需要用到的文件名 称与路径是什么,所以, pintos操作系统在执行用户进程的时候需要有参数传递的能力。 C程序的风格是为main函数设置两个默认的参数 int argc与char*argv[],argc代 表参数个数,而argv则是用字符串形式传入的指针数组。参数的摆放位置应该是用户堆栈的栈顶,拜访 的格式应该为 Adress Name Data Type Oxbffffffc argv[3][∴.] a char[41 Oxbffffff8 Argv[2][.] i foo\O' char[ 4] Oxbffffff5 argv[1][∴] \0 char[31 Oxbfffffed argv[0][∴..] /bin/lso char[81 Oxbfffffec word-align uint8 t Oxbfffffe8 argv[ 4] 0 char* Oxbfffffe4 argv[3] oxbffffffc chark Oxbfffffe0 argv[2] Oxbffffff8 char* Oxbffffedc argv[1] Oxbffffff5 chari Oxbfffffd8 argv[0] Oxbfffffed char* Oxbfffffd4 argv Oxbfffffd8 char*x Oxbfffffdo argc in七 Oxbfffffcc return address 0 void (*)( 需要注意几点 字对齐,这样做的好处是访存速度加快 argvlargc】要为0; 堆栈向低地址空间扩展。 52 数据结构 解决该问题的方法是字符串处理,涉及的数据结构有: process exec的参数字符串 parser; 局部变量 int Stop(代表 Stack top),用来记录参数传递过程中,用户堆栈顶端的地址; 局部变量 int argc用来记录字符串解析出的子串个数,即参数个数; 5参数传递5 局部变量char*argv门用来记录各个参数字符串在内存中的起始位置。 53 算法与实现 5.3.1预处理 我们先要提取岀可执行文件的路径与文件名,采用的做法是从字符串头部开始,找到第一个空格或者 字符串结束标志即可,该文件名用来寻找ef文件以及为进程命名; 5.3.2参数传递的时机 我们知道用户地址空间是0~PHYS_BASE,但是 pintos在初始化时并不会为用户地址空间建立 实存与虚存的映射,在操作系统做这个工作之前,我们访问用户地址空间会产生 page fault 由上一章的说明可知, process_exeC进行用户线程创建时,用户程序并不是立刻开始执行的,当 运转到该线程的时间片时,进入的是 start process(函数,在这个函数中,调用了 load函数,之 后,通过一个中断返回,进入用户的ef文件入口,而操作系统为用户分配地址空间是在load(函数中, 所以在 start processO调用load(结束之后,我们就可以往栈顶写值了。 argument passing process exec( create thread start process odi Intr exit 插图2:参数传递 5.3.3实现 我们这里利用源代码中已有函数 strtok r(来进行处理,以防止代码冗余。该函数的功能是将目标 字符串分解为前缀串与剩下的串,前缀串即使从字符串头部读到第一个空格或者字符串终结符的串。在 此处加一个循环,当前缀串为空时得到字符串解析成功。 我们每得到一个前缀串,即将该串放入用户堆栈的栈顶,这里有两种方法来做这样一个操作:1.内联 汇编: asm volatile("mo%0,%‰ah; pushl%‰ah"::"g"(&*( token+ offset): " memory");2.C语言风格直接读写内存:*(char*)(Stop))=*( token+1);这里Stop是用户 堆栈顶端地址, token是前缀串,i表示该前缀串传到第ⅰ个字符。为了增加程序的可读性,我们使用第 二种方法。 534esp指针设置 在参数传递实现前,我们将esp值设置为 PHYS BASE12,这个12代表着返回地址, 5参数传递6 argc,argⅴ分别4^字节,而在参数传递实现之后,我们就需要根据参数的个数与长短来确定堆栈顶 指针,其实我们在解析字符串,向內存空间中传值的过程中,就已经保存了堆栈顶的信息,于是,在参 数放置完毕后,将eSp设置为Stop的值,整个参数传递功能就是实现了。 6 Sysco设计与实现 这部分由L设计,ⅹ提出修改意见,L整理书写文档 61 数据结构 数据结构是由在 process和 thread中添加的。主要有: Thread.h中 struct list fd list int ret status: struct semaphore tsem, wsem; struct list child list: struct file* elffile; bool awaited /*L: fd elem * struct file desc int fd; / L:file descriptor * struct file *file: truct list elemelem; 62机制设计 系统调用是由系统提供的一组完成底层操作的函数集合,由用户程序通过中断调用,系统根据中断向 量表和中断服务号确定函数调用,调用相应的函数完成相应的服务。 62 Pintos的 sysco!流程 pintos中的 syscall的中断向量号是30h,一个典型 syscal的过程 SYS HALT调用如下(通 过反汇编echo得到) void halt ( void) 8049ba0: push ebp 8049ba1: 89e5 moV Esp, ebp 8049ba3: 83ec18 sub $0x18, %esp 6 Syscall设计与实现7 syscalls (SYS HALT)i 8049ba6: 6a00 push $OxO 8049ba8: cd 30 1n七 SOx30 8049baa: 83c404 add SOx4, esp NOT REACHED 8049bad: c744240ce4a104mov1$0x804a1e4,0xc(8esp) 8049bb4: 08 8049bb5 c744240805a004mov1 s0x804a005,0x8(esp) 8049bbc: 08 8049bbd: c7442404440000mov1s0x44,0x4(esp) 8049bc4: 00 8049bc5: c7 04 24 be al 04 08 movl $0x804albe ,(esp) 8049bcc: e8王 f fd ff ff call 80499do <debug panic> 8049bd1: 90 8049ba2: 90 nop 8049bd3: 90 nop 08049bd4<f1ush>: 分析上面可以知道在执行 SYS HALT这个系统调用时,实际是把 SYS HALT的值0压入堆栈 然后就进行了中断30h的调用,接下来系统的中断服务函数从堆栈里获取相关信息(如 SYS HALT),接管剩余的过程,并完成相应的功能。 个较完整的中断调用 SYS WRITE,以由 printf(产生为例* Kernel PANIc at ././userprog/syscall.c: 215 in syscall handler(): [KP HERE J Ca1 stack:0xc00288990xc002c0580xc0021d260xc0021e630x8049ad4 0x8049c200x8049c6c0x8049c950x8048c270x804810e0x8048160 backtrace In kernel. o 0xc0028899: debug panic (././lib/kernel/debug.c: 38) 0xc002c058: syscall handler (../userprog/syscall. C: 222) oxc0021d26: intr handler (../threads/interrupt. c: 367) 0xc002le63: intr entry (threads/intr-stubs. S: 38) In ././examples/echo 0x08049ad4: write (../lib/user/syscall. C: 123) 0x08049c20:f1ush /./lib/user/console. C: 93) 0x08049c6c: vhprintf (././lib/user/console.C: 73 0x08049c95: vprintf (././lib/user/console. C: 12 0x08048c27: printf (. amples/./lib/stdio. c: 89 0x0804810e: main (. tos/src/examples/echo. C: 8) 0x08048160: start (.les/./lib/user/entry. c: 9) *这个例子由人为在 SYS WRITE的 STD OL产生一次 Kernel panio生成。 用户程序和内核交互的流程图如下 【实例截图】
【核心代码】
标签:
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明
网友评论
我要评论