#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/process.h" #include "threads/init.h" #include "threads/malloc.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); printf("%s: exit(%d)\n", thread->name, status); thread_exit (); } 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 *file_name) { return process_execute (file_name); } // cast to TYPE and deref argument N from f->esp #define INTR_ESP(N, TYPE) *(TYPE *)(f->esp+(4*(N))) static void syscall_handler (struct intr_frame *f UNUSED) { int syscall_number = INTR_ESP (0, int); switch (syscall_number) { case 0: // halt halt (); break; case 1: // exit exit (INTR_ESP (1, int)); break; case 2: // exec f->eax = exec (INTR_ESP (1, char *)); break; case 4: // create f->eax = create (INTR_ESP (1, char *), INTR_ESP (2, off_t)); break; case 6: // open f->eax = open (INTR_ESP (1, char *)); break; case 8: // read f->eax = read (INTR_ESP (1, int), INTR_ESP (2, void *), INTR_ESP (3, unsigned)); break; case 9: // write f->eax = write (INTR_ESP (1, int), INTR_ESP (2, const void *), INTR_ESP (3, unsigned)); break; case 12: // close close (INTR_ESP (1, int)); break; default: printf ("kernel: unknown syscall '%d'\n", syscall_number); break; } } #undef INTR_ESP