#include "userprog/syscall.h" #include #include #include "threads/interrupt.h" #include "threads/thread.h" #include "devices/input.h" #include "filesys/file.h" #include "filesys/filesys.h" #include "filesys/off_t.h" #include "lib/pid_t.h" #include "userprog/pagedir.h" #include "userprog/process.h" #include "threads/init.h" #include "threads/malloc.h" #include "threads/vaddr.h" static void syscall_handler (struct intr_frame *); void syscall_init (void) { intr_register_int (0x30, 3, INTR_ON, syscall_handler, "syscall"); } static void halt (void) { power_off(); } static bool create (const char *filename, off_t initial_size) { return filesys_create (filename, initial_size); } static int open (const char *filename) { struct thread *t = thread_current (); if (!t->fds) { t->fds = (struct file **) calloc (MAX_FDS, sizeof (struct file *)); } struct file *file = filesys_open (filename); if (!file) { return -1; } for (int i = 0; i < MAX_FDS; i++) { struct file **fd = t->fds + i; if (*fd == NULL) { *fd = file; return i + 2; // 0 and 1 are reserved for stdin and stdout } } free (file); return -1; } static struct file ** get_fd (struct thread *thread, int fd_i) { if (!thread->fds) { return NULL; } return thread->fds + fd_i - 2; // -2 since 0 and 1 are reserved and not present in the array } static void exit (int status) { struct thread *thread = thread_current (); if (thread->fds) { for (int i = 0; i < MAX_FDS; i++) { struct file **fd = thread->fds + i; if (fd && *fd) { file_close (*fd); *fd = NULL; } } free (thread->fds); } lock_acquire (&thread->parent->l); thread->parent->exit_status = status; lock_release (&thread->parent->l); thread_exit (); } static int wait (tid_t child_tid) { return process_wait (child_tid); } static int read (int fd_i, void *buf, unsigned size) { struct thread *thread = thread_current (); if (fd_i == 0) { // stdin unsigned i; for (i = 0; i < size; i++) { ((char *)buf)[i] = input_getc (); } return i; } else if (fd_i == 1) { // can't read from stdout return -1; } struct file **fd = get_fd (thread, fd_i); if (fd && *fd) { return file_read (*fd, buf, size); } else { return -1; } } static int write (int fd_i, const void *buf, unsigned size) { struct thread *thread = thread_current (); if (fd_i == 1) { // stdout putbuf ((const char *)buf, size); return size; } else if (fd_i == 0) { // can't write to stdout return -1; } struct file **fd = get_fd (thread, fd_i); if (fd && *fd) { return file_write (*fd, buf, size); } else { return -1; } } static void close (int fd_i) { struct thread *thread = thread_current (); struct file **fd = get_fd (thread, fd_i); if (fd && *fd) { file_close (*fd); *fd = NULL; } } static pid_t exec (const char *filename) { return process_execute (filename); } static bool ptr_is_valid (const void *ptr) { // uintptr_t ptr = _ptr; if (!is_user_vaddr (ptr)) return false; struct thread *t = thread_current (); if (pagedir_get_page (t->pagedir, ptr) == NULL) return false; return true; } // cast argument N from f->esp to TYPE without dereferencing #define INTR_ESP(N, TYPE) (TYPE *)(f->esp+(4*(N))) #define CHECK_PTR_AND_MAYBE_EXIT(PTR) \ do { \ if (!ptr_is_valid (PTR)) { \ exit (-1); \ return; \ } \ } while (0) static void syscall_handler (struct intr_frame *f UNUSED) { // check esp int *syscall_number = INTR_ESP (0, int); CHECK_PTR_AND_MAYBE_EXIT (syscall_number); char **filename; int *status, *fd_i; off_t *initial_size; tid_t *child_tid; unsigned *size; void **buf; switch (*syscall_number) { case 0: // halt halt (); break; case 1: // exit status = INTR_ESP (1, int); CHECK_PTR_AND_MAYBE_EXIT (status); exit (*status); break; case 2: // exec filename = INTR_ESP (1, char *); CHECK_PTR_AND_MAYBE_EXIT (filename); CHECK_PTR_AND_MAYBE_EXIT (*filename); f->eax = exec (*filename); break; case 3: // wait child_tid = INTR_ESP (1, tid_t); CHECK_PTR_AND_MAYBE_EXIT (child_tid); f->eax = wait (*child_tid); break; case 4: // create filename = INTR_ESP (1, char *); initial_size = INTR_ESP (2, off_t); CHECK_PTR_AND_MAYBE_EXIT (filename); CHECK_PTR_AND_MAYBE_EXIT (*filename); CHECK_PTR_AND_MAYBE_EXIT (initial_size); f->eax = create (*filename, *initial_size); break; case 6: // open filename = INTR_ESP (1, char *); CHECK_PTR_AND_MAYBE_EXIT (filename); CHECK_PTR_AND_MAYBE_EXIT (*filename); f->eax = open (*filename); break; case 8: // read fd_i = INTR_ESP (1, int); buf = INTR_ESP (2, void *); size = INTR_ESP (3, unsigned); CHECK_PTR_AND_MAYBE_EXIT (fd_i); CHECK_PTR_AND_MAYBE_EXIT (buf); CHECK_PTR_AND_MAYBE_EXIT (*buf); CHECK_PTR_AND_MAYBE_EXIT (size); f->eax = read (*fd_i, *buf, *size); break; case 9: // write fd_i = INTR_ESP (1, int); buf = INTR_ESP (2, void *); size = INTR_ESP (3, unsigned); CHECK_PTR_AND_MAYBE_EXIT (fd_i); CHECK_PTR_AND_MAYBE_EXIT (buf); CHECK_PTR_AND_MAYBE_EXIT (*buf); CHECK_PTR_AND_MAYBE_EXIT (size); f->eax = write (*fd_i, *buf, *size); break; case 12: // close fd_i = INTR_ESP (1, int); close (*fd_i); break; default: printf ("kernel: unknown syscall '%d'\n", *syscall_number); break; } } #undef INTR_ESP