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;
+}
+