pintos project 2
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
我们以/BIN/LS –L FOO BAR为例
Pre Knowledge
System Call (系统调用)
第十组:金磊磊, 吴 俊,许沛豪, 陆懿庭
什么是系统调用?
操作系统的主要功能是为应用程序的运行创建良 好的环境,为了达到这个目的,内核提供一系列 具备预定功能的多内核函数,通过一组称为系统 调用(SYSTEM CALL)的接口呈现给用户。系 统调用把应用程序的请求传给内核,调用相应的 的内核函数完成所需的处理,将处理结果返回给 应用程序,如果没有系统调用和内核函数,用户 将不能编写大型应用程序。用户程序想要访问内 存或者IO设备,都需要使用系统调用。
两个判断函数
• You can use file_deny_write() to prevent writes to an open file. Calling file_allow_write() on the file will reenable them (unless the file is denied writes by another opener).Closing a file will also re-enable writes. Thus, to deny writes to a process’s executable, you must keep it open as long as the process is still running. • file_deny_write()相当于read() • file_allow_write()相当于write()
/* cat.c Compares two files. */ #include <stdio.h> #include <syscall.h> int main (int argc, char *argv[]) { int fd[2]; if (argc != 3) { printf ("usage: cmp A B\n"); return EXIT_FAILURE; }
如何启动线程 userprog/process.c
(线程的名字,优先级,该线程所执行的函数, 参数)
进程的结束
磁盘中读文件失败的情况 load失败,执行exit() thread-exit()执行process-exit()
• Thank you • 10102510242 • 许沛豪
Denying Writes to Executables
for (i = 0; i < min_read; i++) if (buffer[0][i] != buffer[1][i]) { printf ("Byte %d is %02hhx ('%c') in %s but %02hhx ('%c') in %s\n", pos + i, buffer[0][i], buffer[0][i], argv[1], buffer[1][i], buffer[1][i], argv[2]); return EXIT_FAILURE; }
/userpro/syscall.c
void syscall_init (void) { intr_register_int (0x30, 3, INTR_ON, syscall_handler, "syscall"); } static void syscall_handler (struct intr_frame *f UNUSED) { printf ("system call!\n"); thread_exit (); }
已学过的同步互斥问题
main ( ) { semaphore Sa=0; semaphore Sb=1; cobegin cp( ); iop( ); coend; }
void cp( ) { while (计算未完成) { 得到一个计算结果; wait(Sb); 将计算结果送缓冲区 buffer中; signal(Sa); } } void iop( ) { while (打印工作未完成) { wait (Sa); 从缓冲区buffer中取出 信息; signal ( Sb); 打印输出结果; } }
系统调用的具体过程
当一个用户程序call一个系统调用的时候, 他实际上是对通过其包含的 /lib/usr/syscall.h来操作其对应c文件中的 syscall( )汇编函数,将指定的系统调用号 写入到当前用户线程的调用栈顶,同时开 启0x30号中断,将控制权转给kernel(这 一步同样由syscall()函数完成)。
/lib/user/syscall.c
#define syscall0(NUMBER) ({ int retval; asm volatile ("pushl %[number]; int $0x30; addl $4, %%esp" "=a" (retval) [number] "i" (NUMBER) "memory"); retval; })是一个80x86的汇编代码,将number变量push到 当前函数的 esp(是一个调用栈)中,并执行30号中断, 也就是一个系统调用
if (min_read < bytes_read[1]) printf ("%s is shorter than %s\n", argv[1], argv[2]); else if (min_read < bytes_read[0]) printf ("%s is shorter than %s\n", argv[2], argv[1]); } printf ("%s and %s are identical\n", argv[1], argv[2]); return EXIT_SUCCESS;}
2. Kernel在得到控制权之后。会从cpu中取出一个中断帧, 这个中断帧保存了cpu当前的全部寄存器的状态(保护现 场)。其中最重要的有三个: Esp 指向当前用户程序的调用栈。指向的地址为虚地 址,指向用户的虚地址空间。 Eip 程序计数器,指向当前运行的操作代码。 Eax返 回值
/* Compare data. */ for (;;) { int pos; char buffer[2][1024]; int bytes_read[2]; int min_read; int i; pos = tell (fd[0]); bytes_read[0] = read (fd[0], buffer[0], sizeof buffer[0]); bytes_read[1] = read (fd[1], buffer[1], sizeof buffer[1]); min_read = bytes_read[0] < bytes_read[1] ? bytes_read[0] : bytes_read[1]; if (min_read == 0) break;
Process Termination Messages
第十组:金磊磊 吴 俊 许沛豪 陆懿庭
Whenever a user process terminates, because it called exit or for any other reason, print the process’s name and exit code, formatted as if printed by printf ("%s: exit(%d)\n",...);. The name printed should be the full name passed to process_execute(), omitting command-line arguments.
系统调用的过程
首先,用户程序中包括一个/lib/usr/syscall.h的头文件, 当一个用户程序使用一个系统调用的时候,他实际上是
1.默认调用了这个头文件对应的c文件中的syscall() 汇编
函数,将指定的系统调用号写入到当前用户线程的调用
栈顶,同时开启0X30号中断,将控制权转给kernel。
lib/user/syscall.c
int write (int fd, const void *buffer, unsigned size) { return syscall3 (SYS_WRITE, fd, buffer, size); } void seek (int fd, unsigned position) { syscall2 (SYS_SEEK, fd, position); } unsigned tell (int fd) { return syscall1 (SYS_TELL, fd); } void close (int fd) { syscall1 (SYS_CLOSE, fd); }
之后,系统会转向/usrprog/syscall.c中的 syscall_handler()函数。这个函数的参数是一个中断帧。 syscall_handler()的执行过程如下: 将interrupt frame中的指针读出 通过esp求出压在用户程序调用栈中的系统调用号和参 数(都是int)。 通过调用号转向特定的系统调用函数。并将参数传入 此调用函数。 待系统调用函数返回之后,将返回值写到eax寄存器中。
/* Open files. */
fd[0] = open (argv[1]); if (fd[0] < 0) { printf ("%s: open failed\n", argv[1]); return EXIT_FAILURE; } fd[1] = open (argv[2]); if (fd[1] < 0) { printf ("%s: open failed\n", argv[1]); return EXIT_FAILURE; }
系统调用有哪些呢?
Halt (停止系统) Exit(终止当前用户程序并且返回内核一个状态) Exec(运行命令行给的可执行的文件,通过给定任何 参数返回一个新进程) Wait (等待子进程完成后返回状态) Create&Remove (创建和删掉文件) Read &Write(从内存中读取和写入到文件中) Filesize(查询文件的大小) Seek(从文件中找position的地址) Tell(返回当前文件所处地址的指针) Open&Close(打开和关闭文件的读写)
Argument passing (参数传递)
第十组:金磊磊 (吴 俊 许沛豪 陆 懿庭)
• 设计: • 传参数,也可以理解为压栈。 • 1. 必须用户线程被创建以及初始化完 毕之后(因为这样才有栈的存在)。 • 2. 也必须在用户main函数被执行之前, 完成对应参数的传递。
• 每一个用户程序的入口函数main()都有两 个参数,int argc 和 char** argv。 • 这两个参数需要我们手动的传导用户线程 的条用栈中去。 • 要注意的是,在32位操作系统的计算机中 ,无论是地址char*,还是地址的地址 char**,在存储是和int都是等价的。这为 我们提供了方便。
第十组:金磊磊 吴 俊 许沛豪 陆懿庭
概述
• Add code to deny writes to files in use as executables. • Many OSes do this because of the unpredictable results if a process tried to run code that was in the midst of being changed on disk. • This is especially important once virtual memory is implemented in project 3, but it can’t hurt even now.