diff --git a/src/userprog/syscall.c b/src/userprog/syscall.c new file mode 100644 index 0000000000000000000000000000000000000000..3263c73c867712dc3b3ee5b75076966feee894c3 --- /dev/null +++ b/src/userprog/syscall.c @@ -0,0 +1,170 @@ +#include "devices/shutdown.h" +#include "devices/input.h" +#include "userprog/syscall.h" +#include "userprog/process.h" +#include "filesys/filesys.h" +#include "filesys/file.h" +#include "threads/palloc.h" +#include <stdio.h> +#include <syscall-nr.h> +#include "threads/interrupt.h" +#include "threads/thread.h" +#include "threads/vaddr.h" +#include "threads/synch.h" +#include "lib/kernel/list.h" + +static void syscall_handler (struct intr_frame *); + +static void check_user (const uint8_t *uaddr); +static int32_t get_user (const uint8_t *uaddr); +static bool put_user (uint8_t *udst, uint8_t byte); +static int memread_user (void *src, void *des, size_t bytes); + +static struct file_desc* find_file_desc(struct thread *, int fd); + +unsigned sys_tell(int fd); + + +struct lock filesys_lock; + +void +syscall_init (void) +{ + lock_init (&filesys_lock); + intr_register_int (0x30, 3, INTR_ON, syscall_handler, "syscall"); +} + +static void fail_invalid_access(void) { + if (lock_held_by_current_thread(&filesys_lock)) + lock_release (&filesys_lock); + + sys_exit (-1); + NOT_REACHED(); +} + +static void +syscall_handler (struct intr_frame *f) +{ + int syscall_number; + + ASSERT( sizeof(syscall_number) == 4 ); + memread_user(f->esp, &syscall_number, sizeof(syscall_number)); + + switch (syscall_number) { + case SYS_TELL: + { + int fd; + unsigned return_code; + + memread_user(f->esp + 4, &fd, sizeof(fd)); + + return_code = sys_tell(fd); + f->eax = (uint32_t) return_code; + break; + } + default: + printf("System call %d is unimplemented!\n", syscall_number); + sys_exit(-1); + break; + } + +} + +void sys_exit(int status) { + printf("%s: exit(%d)\n", thread_current()->name, status); + + struct process_control_block *pcb = thread_current()->pcb; + if(pcb != NULL) { + pcb->exited = true; + pcb->exitcode = status; + } + + thread_exit(); +} + +unsigned sys_tell(int fd) { + lock_acquire (&filesys_lock); + struct file_desc* file_d = find_file_desc(thread_current(), fd); + + unsigned ret; + if(file_d && file_d->file) { + ret = file_tell(file_d->file); + } + else + ret = -1; + + lock_release (&filesys_lock); + return ret; +} + + +static void +check_user (const uint8_t *uaddr) { + if(get_user (uaddr) == -1) + fail_invalid_access(); +} + +static int32_t +get_user (const uint8_t *uaddr) { + if (! ((void*)uaddr < PHYS_BASE)) { + return -1; + } + int result; + asm ("movl $1f, %0; movzbl %1, %0; 1:" + : "=&a" (result) : "m" (*uaddr)); + return result; +} + +static bool +put_user (uint8_t *udst, uint8_t byte) { + if (! ((void*)udst < PHYS_BASE)) { + return false; + } + + int error_code; + + asm ("movl $1f, %0; movb %b2, %1; 1:" + : "=&a" (error_code), "=m" (*udst) : "q" (byte)); + return error_code != -1; +} + +static int +memread_user (void *src, void *dst, size_t bytes) +{ + int32_t value; + size_t i; + for(i=0; i<bytes; i++) { + value = get_user(src + i); + if(value == -1) + fail_invalid_access(); + + *(char*)(dst + i) = value & 0xff; + } + return (int)bytes; +} + +static struct file_desc* +find_file_desc(struct thread *t, int fd) +{ + ASSERT (t != NULL); + + if (fd < 3) { + return NULL; + } + + struct list_elem *e; + + if (! list_empty(&t->file_descriptors)) { + for(e = list_begin(&t->file_descriptors); + e != list_end(&t->file_descriptors); e = list_next(e)) + { + struct file_desc *desc = list_entry(e, struct file_desc, elem); + if(desc->id == fd) { + return desc; + } + } + } + + return NULL; +} +