static void syscall_handler (struct intr_frame *f) { int syscall_num; VALIDATE_AND_GET_ARG (f->esp, syscall_num, f); void *cur_sp = f->esp + sizeof (void *); /* store user program stack pointer to the thread's user_esp before changing to kernel mode */ struct thread *t = thread_current (); t->user_esp = f->esp; switch (syscall_num) { case SYS_HALT: syscall_halt (f, cur_sp); break; case SYS_EXIT: syscall_exit (f, cur_sp); break; case SYS_EXEC: syscall_exec (f, cur_sp); break; case SYS_WAIT: syscall_wait (f, cur_sp); break; case SYS_CREATE: syscall_create (f, cur_sp); break; case SYS_REMOVE: syscall_remove (f, cur_sp); break; case SYS_OPEN: syscall_open (f, cur_sp); break; case SYS_FILESIZE: syscall_filesize (f, cur_sp); break; case SYS_READ: syscall_read (f, cur_sp); break; case SYS_WRITE: syscall_write (f, cur_sp); break; case SYS_SEEK: syscall_seek (f, cur_sp); break; case SYS_TELL: syscall_tell (f, cur_sp); break; case SYS_CLOSE: syscall_close (f, cur_sp); break; case SYS_MMAP: syscall_mmap (f, cur_sp); break; case SYS_MUNMAP: syscall_unmmap (f, cur_sp); break; default : printf ("Invalid system call! #%d\n", syscall_num); syscall_thread_exit (f, -1); break; } }
static void syscall_handler (struct intr_frame *f) { /* Validate the first addr of the stack frame */ void *esp = utok_addr (f->esp, NULL); if (esp == NULL) { syscall_exit (-1); return; } enum SYSCALL_NUMBER call_number = *(enum SYSCALL_NUMBER *) esp; if (call_number < syscall_first_call || call_number > syscall_last_call) { syscall_exit (-1); return; } /* Buffer the arguments for validation */ int argc = syscall_argc[call_number]; uint32_t argbuf[3]; int i = 0; for (; i < argc; i++) { /* Validate each argument */ void *vaddr = uptr_valid((uint32_t *) f->esp + 1 + i, f->esp); if (vaddr == NULL) { syscall_exit (-1); return; } /* Translate the argument to kernel virtual (== physical) memory */ argbuf[i] = *(uint32_t *) vaddr; } int retval = 0; /* Switch based on call_number to delegate to corresponding syscall. Have not implemented several syscalls as of this project. Use validation methods to check user-provided arguments. */ switch (call_number) { case SYS_HALT: syscall_halt (); break; case SYS_EXIT: syscall_exit ((int) argbuf[0]); break; case SYS_EXEC: if (str_valid ((void *) argbuf[0], f->esp) == NULL) { syscall_exit (-1); return; } retval = syscall_exec ((char *) argbuf[0]); break; case SYS_WAIT: retval = syscall_wait ((int) argbuf[0]); break; case SYS_CREATE: if (str_valid ((char *) argbuf[0], f->esp) == NULL) { syscall_exit (-1); return; } retval = (int) syscall_create ((char *) argbuf[0], (unsigned) argbuf[1]); break; case SYS_REMOVE: if (!uptr_valid ((char *) argbuf[0], f->esp)) { syscall_exit (-1); return; } retval = (int) syscall_remove ((char *) argbuf[0]); break; case SYS_OPEN: if (str_valid ((char *) argbuf[0], f->esp) == NULL) { syscall_exit (-1); return; } retval = (int) syscall_open ((char *) argbuf[0]); break; case SYS_FILESIZE: retval = syscall_filesize ((int) argbuf[0]); break; case SYS_READ: if (buffer_valid ((void *) argbuf[1], f->esp, (unsigned) argbuf[2]) == NULL) { syscall_exit (-1); return; } retval = syscall_read ((int) argbuf[0], (void *) argbuf[1], (unsigned) argbuf[2]); break; case SYS_WRITE: if (buffer_valid ((void *) argbuf[1], f->esp, (unsigned) argbuf[2]) == NULL) { syscall_exit (-1); return; } retval = syscall_write ((int) argbuf[0], (void *) argbuf[1], (unsigned) argbuf[2]); break; case SYS_SEEK: syscall_seek ((int) argbuf[0], (unsigned) argbuf[1]); break; case SYS_TELL: retval = (int) syscall_tell ((int) argbuf[0]); break; case SYS_CLOSE: syscall_close ((int) argbuf[0]); break; #ifdef VM case SYS_MMAP: // addr will be checked internally inside mmap retval = (int) syscall_mmap ((int) argbuf[0], (void *) argbuf[1]); break; case SYS_MUNMAP: syscall_munmap ((int) argbuf[0]); break; #endif default: printf("unhandled system call!\n"); thread_exit(); } f->eax = retval; }