pintos Lab2 实验报告
- 格式:pdf
- 大小:614.48 KB
- 文档页数:15
华东师范大学软件学院实验报告实验课程:操作系统实践年级:大二实验成绩:实验名称:Pintos-User Programs 姓名:实验编号:学号:实验日期:2018/12/27指导教师:组号:实验时间:4学时一、实验目的当前, 我们已经完成了pintos 的第一部分(熟悉了其基础结构和线程包), 现在是开始处理系统中允许运行用户程序的部分的时候了。
基本代码已经支持加载和运行用户程序, 但不能加载和运行或交互性。
在此项目中, 我们将使程序能够通过系统调用与操作系统进行交互。
我们将在"userprog" 目录中进行工作, 但我们也将与pintos 的几乎所有其他部分进行交互。
具体目的如下:(1)了解Pintos操作系统的功能流程及内核的软件工程结构。
(2)通过Pintos操作系统内核的剖析,了解现有Pintos操作系统在处理用户程序方面中存在的参数传递问题,有效解决其参数传递的问题。
(3)通过Pintos内核剖析,了解其中断处理的机制,学会操作系统中断功能的编写方法。
(4)了解现有Pintos操作系统的系统调用功能,根据其中断机制,完善系统调用功能,使Pintos系统具有处理用户中断请求的功能。
(5)通过Pintos内核剖析,解决现有Pintos操作系统中存在的进程终止时缺少终端提示的问题。
(6)通过Pintos内核剖析,解决现有Pintos操作系统中存在的运行文件禁止写操作的问题。
二、实验内容与实验步骤实验内容如下:(1)在分析内核的基础上,对Pintos操作系统的参数传递问题提出有效的策略,设计算法,分步跟踪和调试,通过实践,有效解决参数传递问题,并对实验结果进行分析。
(2)通过Pintos操作系统内核的剖析,了解其中断处理的机制,在此基础上,完善Pintos的系统调用功能,设计算法,分步跟踪和调试,通过测试分析完善的系统调用功能。
(3)在分析内核的基础上,对现有Pintos操作系统进行完善,增加进程终止的终端提示功能,设计算法,分步跟踪和调试,通过实践,验证终端提示功的有效性。
(4)在分析内核的基础上,对现有Pintos操作系统进行完善,增加运行文件禁止写操作的功能,设计算法,分步跟踪和调试,通过实践,验证禁止写操作功能的有效性。
具体步骤:(1)进程终止的终端提示每当用户进程终止时,不管是自愿退出或出于任何其他原因, 请打印进程的名称和退出代码, 格式为printf ("%s: exit(%d)\n", ...)。
打印的名称应该是传递给process_execute() 的全名, 省略了命令行参数。
当不是用户进程的内核线程终止或调用停止系统调用时, 不要打印这些消息。
当进程加载失败时, 该消息是可选的。
除此之外, 不要打印任何其他消息。
(2)参数传递目前, process_execute() 不支持将参数传递给新进程。
实现此功能, 通过扩展process_execute(), 使其不是简单地将程序文件名作为其参数, 而是将其划分为空格中的单词。
第一个单词是程序名称, 第二个单词是第一个参数, 依此类推。
也就是说, process_execute ("grep foo bar") 应该运行grep 传递两个参数foo 和bar。
在命令行中, 多个空格等效于单个空格, 因此process_execute("grep foo bar")相当于我们最初的示例。
我们可以对命令行参数的长度施加合理的限制。
(3)系统调用在"userprogsecalls. c" 中实现系统调用处理程序。
我们通过终止进程提供"句柄" 系统调用的骨架实现。
它将需要检索系统调用号码, 然后检索任何系统调用参数, 并执行适当的操作。
实现以下系统调用。
列出的原型是由一个用户程序看到的, 其中包括"lib/usersicl. h"(此h文件以及“lib/user“中的所有其他h文件仅供用户程序使用)。
每个系统调用的系统调用编号在"libsicall-nr. h" 中定义:1.void halt (void) ;2.void exit (int status) ;3.tid_t exec (const char *cmd_line) ;4.int wait (tid_t pid) ;5.bool create (const char *file, unsigned initial_size) ;6.bool remove (const char *file) ;7.int open (const char *file) ;8.int filesize (int fd) ;9.int read (int fd, void *buffer, unsigned size) ;10.int write (int fd, const void *buffer, unsigned size) ;11.void seek (int fd, unsigned position) ;12.unsigned tell (int fd) ;13.void close (int fd) ;若要实现syscalls, 我们需要提供在用户虚拟地址空间中读取和写入数据的方法。
我们需要此能力, 然后才能获得系统呼叫号码, 因为该系统的数量是用户的虚拟地址空间。
我们必须同步系统调用, 以便任何数量的用户进程都可以同时进行调用。
特别是, 一次从多个线程调用"filesys" 目录中提供的文件系统代码是不安全的。
我们的系统调用实现必须将文件系统代码视为关键部分,不要忘记进process_execute() 也会访问文件。
现在, 我们建议不要修改"file" 目录中的代码。
我们已经拥有了一个用户级函数, 用于"lib/usideslixl. c" 中的每个系统调用。
它们为用户进程提供了一种从c 程序调用每个系统调用的方法。
每个都使用少量内联程序集代码来调用系统调用, 并且(如果适当) 返回系统调用的返回值。
我们需要记住的是,用户程序所能做的任何事情都不会导致操作系统崩溃、崩溃、断言失败或以其他方式出现故障。
实验需要强调的是: pintos的测试将尝试以许多、许多方式中断我们的系统调用。
我们需要考虑所有的角落案件, 并处理它们。
用户程序应该能够导致操作系统停止的唯一方式是调用停止系统调用。
如果系统调用传递的是无效参数, 则可接受的选项包括返回错误值(对于返回值的调用)、返回未定义的值或终止进程。
(4)运行文件禁止写操作添加代码以拒绝对用作可执行文件的文件写入。
许多操作系统之所以这样做, 是因为如果进程试图运行磁盘上正在更改的代码, 则会产生不可预知的结果。
一旦在项目3中实现了虚拟内存, 这一点尤其重要, 但即使是现在也不会造成伤害。
可以使用file_deny_write()来防止写入打开的文件。
在文件上调用file_allow_ write()将重新启用它们(除非该文件被另一个打开程序拒绝写入)。
关闭文件也将重新启用写入。
因此, 要拒绝对进程的可执行文件的写入, 只要进程仍在运行, 就必须使其保持打开状态。
三、实验环境操作系统:Ubuntu 18.04软件要求:VScode、GCC、GNU、Perl、QEMU、X、BochsPintos为/下载的最新版本(Pintos-anon),与老版本pintos可能会略有区别。
四、实验过程与分析首先我们注意到syscall-nr.h中的系统调用枚举类型:1.enum2. {3./* Projects 2 and later. */4. SYS_HALT, /* Halt the operating system. */5. SYS_EXIT, /* Terminate this process. */6. SYS_EXEC, /* Start another process. */7. SYS_WAIT, /* Wait for a child process to die. */8. SYS_CREATE, /* Create a file. */9. SYS_REMOVE, /* Delete a file. */10. SYS_OPEN, /* Open a file. */11. SYS_FILESIZE, /* Obtain a file's size. */12. SYS_READ, /* Read from a file. */13. SYS_WRITE, /* Write to a file. */14. SYS_SEEK, /* Change position in a file. */15. SYS_TELL, /* Report current position in a file. */16. SYS_CLOSE, /* Close a file. */17. };因此我们可以在syscall.c中完善如下框架:(注意系统调用的返回值保存在f->eax中)1.static void2.syscall_handler (struct intr_frame *f)3.{4. esp=f->esp;5. check_uadd_r(esp);6.switch (*esp){7.case SYS_HALT:8. halt();9.break;10.case SYS_EXIT:11. check_uadd_r(esp+1);12. exit(*(esp+1));13.break;14.case SYS_EXEC:15. check_uadd_r(esp+1);16. check_uadd_r(*(esp+1));17. lock_acquire(&filesys_lock);18. f->eax=exec(*(esp+1));19. lock_release(&filesys_lock);20.break;21.case SYS_WAIT:22. check_uadd_r(esp+1);23. f->eax=wait(*(esp+1));24.break;25.case SYS_CREATE:26. check_uadd_r(esp+1);27. check_uadd_r(esp+2);28. check_uadd_r(*(esp+1));29. f->eax=create(*(esp+1),*(esp+2));30.break;31.case SYS_REMOVE:32. check_uadd_r(esp+1);33. check_uadd_r(*(esp+1));34. f->eax=remove(*(esp+1));35.break;36.case SYS_OPEN:37. check_uadd_r(esp+1);38. check_uadd_r(*(esp+1));39. f->eax=open(*(esp+1));40.break;41.case SYS_FILESIZE:42. f->eax=filesize(*(esp+1));43.break;44.case SYS_READ:45. check_uadd_r(esp+1);46. check_uadd_r(esp+2);47. check_uadd_r(esp+3);48. check_uadd_r(*(esp+2));49. check_uadd_r(*(esp+2)+*(esp+3)-1);50. f->eax=read(*(esp+1),*(esp+2),*(esp+3));51.break;52.case SYS_WRITE:53. check_uadd_r(esp+1);54. check_uadd_r(esp+2);55. check_uadd_r(esp+2);56. check_uadd_r(*(esp+2));57. f->eax=write(*(esp+1),*(esp+2),*(esp+3));58.break;59.case SYS_SEEK:60. check_uadd_r(esp+1);61. check_uadd_r(esp+2);62. seek(*(esp+1),*(esp+2));63.break;64.case SYS_TELL:65. check_uadd_r(esp+1);66. f->eax=tell(*(esp+1));67.break;68.case SYS_CLOSE:69. check_uadd_r(esp+1);70. close(*(esp+1));71.break;72.default:73. exit(-1);74.break;75. }76.}当然我们要注意以下虚拟内存保护,当进程访问非法的内存区是要及时把它kill掉(exit(-1)):1./* Reads a byte at user virtual address UADDR.2.UADDR must be below PHYS_BASE.3.Returns the byte value if successful,4. -1 if a segfault occurred. */5.static int get_user (const uint8_t *uaddr) {6.int result;7. asm ("movl $1f, %0; movzbl %1, %0; 1:" : "=&a" (result) : "m" (*uaddr));8.return result;9.}10.11./* Writes BYTE to user address UDST.12.UDST must be below PHYS_BASE.13.Returns true if successful,14.false if a segfault occurred. */15.static bool put_user (uint8_t *udst, uint8_t byte) {16.int error_code;17. asm ("movl $1f, %0; movb %b2, %1; 1:" : "=&a" (error_code), "=m" (*udst) : "q" (byte));18.return error_code != -1;19.}(1)进程终止的终端提示在exit()中差入如下代码即可:1.struct thread *cur=thread_current();2.printf ("%s: exit(%d)\n",cur->name,status);(2)参数传递根据实验手册提供的参数传递例子与所学知识我们可以写出如下代码。