diff options
Diffstat (limited to 'src/userprog/syscall.c')
| -rw-r--r-- | src/userprog/syscall.c | 334 |
1 files changed, 332 insertions, 2 deletions
diff --git a/src/userprog/syscall.c b/src/userprog/syscall.c index 370c89b..c1308ca 100644 --- a/src/userprog/syscall.c +++ b/src/userprog/syscall.c @@ -4,6 +4,17 @@ #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 @@ -13,8 +24,327 @@ syscall_init (void) } static void -syscall_handler (struct intr_frame *f UNUSED) +halt (void) +{ + power_off(); +} + +static bool +create (const char *filename, off_t initial_size) +{ + return filesys_create (filename, initial_size); +} + +static bool +remove (const char *filename) +{ + return filesys_remove (filename); +} + +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) { - printf ("system call!\n"); + 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 int +filesize (int fd_i) +{ + struct thread *thread = thread_current (); + struct file **fd = get_fd (thread, fd_i); + if (fd && *fd) { + return file_length (*fd); + } + return -1; +} + +static void +seek (int fd_i, unsigned position) +{ + struct thread *thread = thread_current (); + struct file **fd = get_fd (thread, fd_i); + if (fd && *fd) { + file_seek (*fd, position); + } +} + +static unsigned +tell (int fd_i) +{ + struct thread *thread = thread_current (); + struct file **fd = get_fd (thread, fd_i); + if (fd && *fd) { + return file_tell (*fd); + } + return 0; +} + + +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, *position; + 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 5: + // remove + filename = INTR_ESP (1, char *); + CHECK_PTR_AND_MAYBE_EXIT (filename); + CHECK_PTR_AND_MAYBE_EXIT (*filename); + f->eax = remove (*filename); + 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 7: + // filesize + fd_i = INTR_ESP (1, int); + CHECK_PTR_AND_MAYBE_EXIT (fd_i); + f->eax = filesize (*fd_i); + 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); + CHECK_PTR_AND_MAYBE_EXIT (*buf + *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); + CHECK_PTR_AND_MAYBE_EXIT (*buf + *size); + f->eax = write (*fd_i, *buf, *size); + break; + case 10: + // seek + fd_i = INTR_ESP (1, int); + position = INTR_ESP (2, unsigned); + CHECK_PTR_AND_MAYBE_EXIT (fd_i); + CHECK_PTR_AND_MAYBE_EXIT (position); + seek (*fd_i, *position); + break; + case 11: + // tell + fd_i = INTR_ESP (1, int); + CHECK_PTR_AND_MAYBE_EXIT (fd_i); + f->eax = tell (*fd_i); + 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 |
