diff --git a/.gitignore b/.gitignore
index b3ddb41aedfbab8bc3f8b59716dae0f5caa67134..fe0418548e417b12762d21108b1480b3e67fb620 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,4 @@ examples/libc.a
 examples/my
 # Visual Studio folder
 /.vs
+/CppProperties.json
diff --git a/Makefile.build b/Makefile.build
index 823d5af3f240461c01f294d8907cfee38a496ac4..c54f871c82dabe39e188a5015efd728a413cc9cd 100644
--- a/Makefile.build
+++ b/Makefile.build
@@ -62,6 +62,20 @@ userprog_SRC += userprog/exception.c	# User exception handler.
 userprog_SRC += userprog/syscall.c	# System call handler.
 userprog_SRC += userprog/gdt.c		# GDT initialization.
 userprog_SRC += userprog/tss.c		# TSS management.
+userprog_SRC += userprog/syscall_exec.c
+userprog_SRC += userprog/syscall_exit.c
+userprog_SRC += userprog/syscall_open.c
+userprog_SRC += userprog/syscall_halt.c
+userprog_SRC += userprog/syscall_wait.c
+userprog_SRC += userprog/syscall_create.c
+userprog_SRC += userprog/syscall_remove.c
+userprog_SRC += userprog/syscall_write.c
+userprog_SRC += userprog/file_descriptors_map.c
+userprog_SRC += userprog/syscall_read.c
+userprog_SRC += userprog/syscall_filesize.c
+userprog_SRC += userprog/syscall_tell.c
+userprog_SRC += userprog/syscall_seek.c
+userprog_SRC += userprog/syscall_close.c
 
 # No virtual memory code yet.
 #vm_SRC = vm/file.c			# Some file.
diff --git a/examples/Makefile b/examples/Makefile
index 41a663d610cb89d30b7aa0277a644b0f63a2c0c5..37678a85f28246985ca2e24a445363f93de84999 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -3,14 +3,15 @@ SRCDIR = ..
 # Test programs to compile, and a list of sources for each.
 # To add a new test, put its name on the PROGS list
 # and then add a name_SRC line that lists its source files.
-PROGS = cat cmp cp echo halt hex-dump ls mcat mcp mkdir pwd rm shell \
-	bubsort insult lineup matmult recursor my
+PROGS = cat cmp cp echo exit halt hex-dump ls mcat mcp mkdir pwd rm shell \
+	bubsort insult lineup matmult recursor my touch
 
 # Should work from project 2 onward.
 cat_SRC = cat.c
 cmp_SRC = cmp.c
 cp_SRC = cp.c
 echo_SRC = echo.c
+exit_SRC = exit.c
 halt_SRC = halt.c
 hex-dump_SRC = hex-dump.c
 insult_SRC = insult.c
@@ -31,5 +32,8 @@ mkdir_SRC = mkdir.c
 pwd_SRC = pwd.c
 shell_SRC = shell.c
 
+# Joshua Saxby special additions!
+touch_SRC = touch.c
+
 include $(SRCDIR)/Make.config
 include $(SRCDIR)/Makefile.userprog
diff --git a/examples/echo.c b/examples/echo.c
index 5621b69f409eaf1f180461fbc963922393538730..920fb9ef5b390ddd9f0e33c1fdc023f09e028d6b 100644
--- a/examples/echo.c
+++ b/examples/echo.c
@@ -10,5 +10,5 @@ main (int argc, char **argv)
     printf ("%s ", argv[i]);
   printf ("\n");
 
-  return EXIT_SUCCESS;
+  return 5;
 }
diff --git a/examples/exit b/examples/exit
new file mode 100755
index 0000000000000000000000000000000000000000..a6569c49fe418705632d054e3e5337cf83e9da29
Binary files /dev/null and b/examples/exit differ
diff --git a/examples/exit.c b/examples/exit.c
new file mode 100644
index 0000000000000000000000000000000000000000..960fe22452edaa8402db7e1df5b8783fa5898f5f
--- /dev/null
+++ b/examples/exit.c
@@ -0,0 +1,14 @@
+/* exit.c
+
+   Simple program to test whether running a user program works.
+ 	
+   Invokes the exit syscall to test if it works */
+
+#include <syscall.h>
+
+int
+main (void)
+{
+  exit (5);
+  /* not reached */
+}
diff --git a/examples/touch b/examples/touch
new file mode 100755
index 0000000000000000000000000000000000000000..f68795f860f0e445ef5ee631e95ee05b7bc9e8c5
Binary files /dev/null and b/examples/touch differ
diff --git a/examples/touch.c b/examples/touch.c
new file mode 100644
index 0000000000000000000000000000000000000000..d6d3684b61a5834637541a6313e9100eaaea3333
--- /dev/null
+++ b/examples/touch.c
@@ -0,0 +1,16 @@
+/* touch.c
+
+   Creates an empty file with the name given on the command-line.
+
+    Author: Joshua Saxby
+
+*/
+
+#include <stdio.h>
+#include <syscall.h>
+
+int main (int argc, char *argv[]) {
+    if (argc != 2) exit(1); // very basic error-handling
+    char* filename = argv[1];
+    return create(filename, 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/lib/kernel/stdio.h b/lib/kernel/stdio.h
index 3e5bae9b65b27d6008ee758df692da91e2b00b58..c7f9b392acc1aaac194b340560f8c57bbc75cb3f 100644
--- a/lib/kernel/stdio.h
+++ b/lib/kernel/stdio.h
@@ -1,5 +1,6 @@
 #ifndef __LIB_KERNEL_STDIO_H
 #define __LIB_KERNEL_STDIO_H
+#include <stddef.h>
 
 void putbuf (const char *, size_t);
 
diff --git a/threads/thread.h b/threads/thread.h
index 2feb8cc242719e1d684aef2108d9c8ca501a922f..ba4adf7f15cdb827a750759d6754c64f20d09109 100644
--- a/threads/thread.h
+++ b/threads/thread.h
@@ -6,8 +6,7 @@
 #include <stdint.h>
 
 /* States in a thread's life cycle. */
-enum thread_status
-  {
+enum thread_status {
     THREAD_RUNNING,     /* Running thread. */
     THREAD_READY,       /* Not running but ready to run. */
     THREAD_BLOCKED,     /* Waiting for an event to trigger. */
diff --git a/userprog/file_descriptors_map.c b/userprog/file_descriptors_map.c
new file mode 100644
index 0000000000000000000000000000000000000000..7ab7943c883ce468a76190a336fbfc7ef8172028
--- /dev/null
+++ b/userprog/file_descriptors_map.c
@@ -0,0 +1,55 @@
+/*
+ * File Descriptors mapper
+ *
+ * Authored by Joshua Saxby
+ */
+#include <stddef.h>
+#include "filesys/filesys.h"
+#include "system_calls.h"
+
+// this means we can't have more than 255 open file handles at a time
+#define MAX_FILE_POINTERS 255
+
+static struct file* FILE_POINTERS_MAP[MAX_FILE_POINTERS] = {0};
+
+struct file * get_associated_file_pointer(int fd) {
+    switch (fd) {
+    case 0: // keyboard (stdin)
+    case 1: // console (stdout)
+    case 2: // console (stderr)
+        return NULL;
+    default:
+        return FILE_POINTERS_MAP[fd - 3]; // exclude special fds
+    }
+}
+
+int associate_new_file_descriptor(struct file* file_pointer) {
+    // if we have been passed NULL, refuse (it's silly!)
+    if (file_pointer == NULL) return -1;
+    // find the first decriptor which points to NULL
+    for (size_t i = 0; i < MAX_FILE_POINTERS; i++) {
+        if (FILE_POINTERS_MAP[i] == NULL) {
+            FILE_POINTERS_MAP[i] = file_pointer;
+            return i + 3; // exclude special fds
+        }
+    }
+    // if we got here, we've run out of spare slots, return failure
+    return -1;
+}
+
+bool disassociate_file_descriptor(int fd) {
+    // clear the descriptor to NULL
+    switch (fd) {
+    case 0: // keyboard (stdin)
+    case 1: // console (stdout)
+    case 2: // console (stderr)
+        return false;
+    default:
+        if (FILE_POINTERS_MAP[fd - 3] != NULL) { // exclude special fds
+            FILE_POINTERS_MAP[fd - 3] = NULL;
+            return true;
+        } else {
+            return false;
+        }
+    }
+}
diff --git a/userprog/populate_stack.c b/userprog/populate_stack.c
index d82e18fb72b85a3ac7546f23e393812534d1f83a..19c995c54dffc4a9d2b7af1c8835a6a8323958fc 100644
--- a/userprog/populate_stack.c
+++ b/userprog/populate_stack.c
@@ -1,6 +1,5 @@
 /*
  * populates_stack.c --implements function for populating the program stack
- * 
  *
  * Authored by Alex Stratford
  */
@@ -23,8 +22,8 @@ void populate_stack(void** stack_pointer, int argc, char** argv) {
 	while (--i >= 0)
 	{
 		*stack_pointer = *stack_pointer - (strlen(argv[i]) + 1) * sizeof(char);
-
-		arr[i] = (uint32_t *)*stack_pointer;	// Assigns the current reference of the stack pointer to the array
+		// Assigns the current reference of the stack pointer to the array
+		arr[i] = (uint32_t *)*stack_pointer; 
 
 		memcpy(*stack_pointer, argv[i], strlen(argv[i]) + 1);
 	}
@@ -36,7 +35,7 @@ void populate_stack(void** stack_pointer, int argc, char** argv) {
 
 	while (--i >= 0)
 	{
-		move_stack_pointer(stack_pointer, -4); //32bit  Moves the stack pointer back 4
+		move_stack_pointer(stack_pointer, -4); //Moves the stack pointer back 4
 
 		(*(uint32_t **)(*stack_pointer)) = arr[i];
 	}
diff --git a/userprog/syscall.c b/userprog/syscall.c
index 04635159d30520fa11296dc922e622f2ad2553d5..845508adf10abcae3b2da8702c162ead639ca67a 100644
--- a/userprog/syscall.c
+++ b/userprog/syscall.c
@@ -1,9 +1,40 @@
 #include "userprog/syscall.h"
 #include <stdio.h>
 #include <syscall-nr.h>
+#include "system_calls.h"
 #include "threads/interrupt.h"
 #include "threads/thread.h"
 
+
+/* System call numbers. */
+typedef enum syscall_t {
+    /* Projects 2 and later. */
+    SYSCALL_HALT,                   /* Halt the operating system. */
+    SYSCALL_EXIT,                   /* Terminate this process. */
+    SYSCALL_EXEC,                   /* Start another process. */
+    SYSCALL_WAIT,                   /* Wait for a child process to die. */
+    SYSCALL_CREATE,                 /* Create a file. */
+    SYSCALL_REMOVE,                 /* Delete a file. */
+    SYSCALL_OPEN,                   /* Open a file. */
+    SYSCALL_FILESIZE,               /* Obtain a file's size. */
+    SYSCALL_READ,                   /* Read from a file. */
+    SYSCALL_WRITE,                  /* Write to a file. */
+    SYSCALL_SEEK,                   /* Change position in a file. */
+    SYSCALL_TELL,                   /* Report current position in a file. */
+    SYSCALL_CLOSE,                  /* Close a file. */
+
+    /* Project 3 and optionally project 4. */
+    SYSCALL_MMAP,                   /* Map a file into memory. */
+    SYSCALL_MUNMAP,                 /* Remove a memory mapping. */
+
+    /* Project 4 only. */
+    SYSCALL_CHDIR,                  /* Change the current directory. */
+    SYSCALL_MKDIR,                  /* Create a directory. */
+    SYSCALL_READDIR,                /* Reads a directory entry. */
+    SYSCALL_ISDIR,                  /* Tests if a fd represents a directory. */
+    SYSCALL_INUMBER                 /* Returns the inode number for a fd. */
+} syscall_t;
+
 static void syscall_handler (struct intr_frame *);
 
 void
@@ -16,6 +47,55 @@ syscall_init (void)
 static void
 syscall_handler (struct intr_frame *f UNUSED)
 {
-  printf ("system call!\n");
-  thread_exit ();
+  /*
+   * the syscall number is addressed by f->esp (pointer to void)
+   * here we cast it to a pointer to int and then dereference that
+   * to get the system call number
+   * --Joshua Saxby
+   */
+  int syscall_number = *((int*)f->esp);
+  switch (syscall_number) {
+  case SYSCALL_HALT:
+    syscall_halt(f);
+    break;
+  case SYSCALL_EXIT:
+    syscall_exit(f);
+    break;
+  case SYSCALL_EXEC:
+    syscall_exec(f);
+    break;
+  case SYSCALL_WAIT:
+    syscall_wait(f);
+    break;
+  case SYSCALL_CREATE:
+    syscall_create(f);
+	  break;
+  case SYSCALL_REMOVE:
+	  syscall_remove(f);
+	  break;
+  case SYSCALL_WRITE:
+    syscall_write(f);
+    break;
+  case SYSCALL_OPEN:
+    syscall_open(f);
+	  break;
+  case SYSCALL_READ:
+    syscall_read(f);
+    break;
+  case SYSCALL_FILESIZE:
+	  syscall_filesize(f);
+	  break;
+  case SYSCALL_TELL:
+    syscall_tell(f);
+    break;
+  case SYSCALL_SEEK:
+	  syscall_seek(f);
+	  break;
+  case SYSCALL_CLOSE:
+    syscall_close(f);
+    break;
+  default:
+    printf ("WARNING: Invalid Syscall (%d)\n", syscall_number);
+    thread_exit ();
+  }
 }
diff --git a/userprog/syscall_close.c b/userprog/syscall_close.c
new file mode 100644
index 0000000000000000000000000000000000000000..8508962b192b2548c16d014234cc2c19b29f37aa
--- /dev/null
+++ b/userprog/syscall_close.c
@@ -0,0 +1,28 @@
+/*
+ * Closes file descriptor fd. Exiting or terminating a process implicitly closes
+ * all its open file descriptors, as if by calling this function for each one.
+ *
+ * Authored by Alex Stratford
+ */
+
+#include "system_calls.h"
+#include <stddef.h> // Dependency for NULL
+#include "threads/interrupt.h" // Dependency for intr_frame struct
+#include "filesys/file.h" // Dependency for file_close
+#include "threads/malloc.h" // Dependency for free
+#include "lib/kernel/list.h" // Dependency for list_remove
+
+void syscall_close(struct intr_frame *f) {
+	// pop off first int argument from interrupt frame
+	int file_descriptor = *((int*)f->esp + 1);
+	// Get file associated with file_descriptor
+	struct file *file = get_associated_file_pointer(file_descriptor);
+	if (file == NULL) { // Checking if file is empty or non-existent
+		f->eax = -1; // Returning a failure state
+		return;
+	}
+	// Close the file using file_close, defined in file.h
+	file_close(file);
+	// Remove the file_descriptor
+	disassociate_file_descriptor(file_descriptor);
+}
diff --git a/userprog/syscall_create.c b/userprog/syscall_create.c
new file mode 100644
index 0000000000000000000000000000000000000000..dc631c0de393243e99bc0f5ed64a49b0c89c6c45
--- /dev/null
+++ b/userprog/syscall_create.c
@@ -0,0 +1,15 @@
+/*
+ * The Create System Call
+ *
+ * Authored by Joshua Saxby
+ */
+#include "filesys/filesys.h"
+#include "system_calls.h"
+#include "threads/interrupt.h"
+
+void syscall_create(struct intr_frame *f) {
+    // first argument is syscall code (already handled)
+    char* filename = (void*)(*((int*)f->esp + 1)); // filename is second argument
+    unsigned initial_size = *((unsigned*)((int*)f->esp + 2)); // third
+    f->eax = filesys_create(filename, initial_size);
+}
diff --git a/userprog/syscall_exec.c b/userprog/syscall_exec.c
new file mode 100644
index 0000000000000000000000000000000000000000..94a060b3f85b35ac063246e0d76f040517bb0f4f
--- /dev/null
+++ b/userprog/syscall_exec.c
@@ -0,0 +1,6 @@
+#include "system_calls.h"
+#include "threads/interrupt.h"
+
+void syscall_exec(struct intr_frame *f) {
+  (void*)0;
+}
\ No newline at end of file
diff --git a/userprog/syscall_exit.c b/userprog/syscall_exit.c
new file mode 100644
index 0000000000000000000000000000000000000000..22a63e3f5f6cefb8ddd7bcbc1c4c44221777dc95
--- /dev/null
+++ b/userprog/syscall_exit.c
@@ -0,0 +1,20 @@
+/*
+ * Terminates the current user program, returning status to the kernel. If the
+ * Process’s parent waits for it (see below), this is the status that will be
+ * Returned. Conventionally, a status of 0 indicates success and nonzero values
+ * Indicate errors.
+ *
+ * Authored by Alex Stratford
+ */
+
+#include "system_calls.h"
+#include "threads/interrupt.h" // Dependency for intr_frame struct
+#include "threads/thread.h" // Dependency for thread struct
+
+void syscall_exit(struct intr_frame *f) {
+	struct thread *current_thread = thread_current(); // Sets current thread
+	// pop off first int argument from interrupt frame
+	int exit_code = *((int*)f->esp + 1);
+	current_thread->exit_code = exit_code; // Returns exit code to kernel
+	thread_exit(); // Exiting current thread
+}
diff --git a/userprog/syscall_filesize.c b/userprog/syscall_filesize.c
new file mode 100644
index 0000000000000000000000000000000000000000..aff7fe7a80c3666fd4d69ac8d7a35aaab5eb06aa
--- /dev/null
+++ b/userprog/syscall_filesize.c
@@ -0,0 +1,20 @@
+/*
+ * Returns the size, in bytes, of the file open as fd.
+ *
+ * Authored by Alex Stratford
+ */
+#include <stddef.h>
+#include "system_calls.h"
+#include "filesys/file.h"
+
+void syscall_filesize(struct intr_frame *f) {
+	// pop off first int argument from interrupt frame
+	int file_descriptor = *((int*)f->esp + 1);
+	struct file *file = get_associated_file_pointer(file_descriptor);
+	if (file == NULL) { // Checking if file is empty or non-existent
+		f->eax -1; // Returning failure state
+	}
+	// Using the file_length function in file.h to get the length and store it
+	int size = file_length(file); 
+	f->eax = size;
+}
diff --git a/userprog/syscall_halt.c b/userprog/syscall_halt.c
new file mode 100644
index 0000000000000000000000000000000000000000..2698c31feafc6afc322f955a021938e95e259937
--- /dev/null
+++ b/userprog/syscall_halt.c
@@ -0,0 +1,13 @@
+/*
+ * The Halt System Call
+ *
+ * Authored by Joshua Saxby
+ */
+#include "devices/shutdown.h"
+#include "system_calls.h"
+#include "threads/interrupt.h"
+
+void syscall_halt(struct intr_frame *f UNUSED) {
+  // terminate Pintos right here and right now!
+  shutdown_power_off();
+}
diff --git a/userprog/syscall_open.c b/userprog/syscall_open.c
new file mode 100644
index 0000000000000000000000000000000000000000..54631b762fc52947d9d900a9cc722185b2f9334a
--- /dev/null
+++ b/userprog/syscall_open.c
@@ -0,0 +1,32 @@
+/*
+ * Opens the file called file. Returns a nonnegative integer handle called a 
+ * "file descriptor" (fd), or -1 if the file could not be opened.
+ *
+ * Authored by Alex Stratford
+ */
+
+
+#include "system_calls.h"
+#include <stddef.h> // Dependency for NULL
+#include "threads/interrupt.h" // Dependency for intr_frame struct
+#include "filesys/file.h" // Dependency for and file struct
+#include "filesys/filesys.h" // Dependency for filesys_open
+
+void syscall_open(struct intr_frame *f) {
+	// pop off first int argument from interrupt frame
+	char* file_name = (void*)*((int*)f->esp + 1);
+	// Described in filesys.h, opens the file
+	struct file *file = filesys_open(file_name);
+	if (file == NULL) { // Checking if file is empty or non-existent
+		f->eax = -1; // Returning a failure state
+		return;
+	}
+	// Described in system_calls.h, get a new file descriptor
+	int file_descriptor = associate_new_file_descriptor(file);
+
+	if (file_descriptor == -1) {
+		f->eax = -1; // Returning a failure state
+		return;
+	}
+	f->eax = file_descriptor; // Returning the file descriptor
+}
diff --git a/userprog/syscall_read.c b/userprog/syscall_read.c
new file mode 100644
index 0000000000000000000000000000000000000000..67f7d9858ea87ecc23b717a9b8dee1353d323abe
--- /dev/null
+++ b/userprog/syscall_read.c
@@ -0,0 +1,42 @@
+/*
+ * The Read System Call
+ *
+ * Authored by Joshua Saxby
+ */
+#include <stddef.h>
+#include "devices/input.h"
+#include "filesys/file.h"
+#include "system_calls.h"
+#include "threads/interrupt.h"
+
+void syscall_read(struct intr_frame *f) {
+    // first argument is syscall code (already handled)
+    int fd = *((int*)f->esp + 1); // file descriptor is second argument
+    char* buffer = (void*)(*((int*)f->esp + 2)); // buffer is third argument
+    unsigned size = *((unsigned*)((int*)f->esp + 3)); // size to read is fourth
+    // reading from stdin (keyboard) is a special case
+    switch (fd) {
+    case 0: {
+            // read from keyboard for as many bytes as requested
+            for (size_t i = 0; i < size; i++) {
+                *(buffer + i) = input_getc();
+            }
+            f->eax = size;
+            break;
+        }
+    case 1: // stdout
+    case 2: // stderr
+        f->eax = -1; // it is a mistake to attempt to read from stdout or stderr
+        break;
+    default: {
+            // otherwise, we need to read from a file denoted by fd
+            struct file* file_to_read = get_associated_file_pointer(fd);
+            if (file_to_read == NULL) {
+                f->eax = -1; // invalid file descriptor
+                break;
+            }
+            f->eax = file_read(file_to_read, buffer, size);
+            break;
+        }
+    }
+}
diff --git a/userprog/syscall_remove.c b/userprog/syscall_remove.c
new file mode 100644
index 0000000000000000000000000000000000000000..0b8d308cc49e759c008275f9b9eaba0c4a5bdab6
--- /dev/null
+++ b/userprog/syscall_remove.c
@@ -0,0 +1,25 @@
+/*
+ * Deletes the file called file. Returns true if successful, false otherwise. 
+ * A file may be removed regardless of whether it is open or closed, and 
+ * Removing an open file does not close it. See Removing an Open File, for
+ * Details.
+ *
+ * Authored by Alex Stratford
+ */
+
+
+#include "system_calls.h"
+#include "threads/interrupt.h" // Dependency for intr_frame struct
+#include "filesys/file.h" // Dependency for and file struct
+#include "filesys/filesys.h" // Dependency for filesys_remove
+
+void syscall_remove(struct intr_frame *f) {
+	// pop off first int argument from interrupt frame
+	char* file_name = (void*)*((int*)f->esp + 1);
+	// Described in filesys.h, opens the file
+	if (filesys_remove(file_name) == false) { // Checking if file is empty or non-existent
+		f->eax = false; // Returning a failure state
+		return;
+	}
+	f->eax = true;
+}
diff --git a/userprog/syscall_seek.c b/userprog/syscall_seek.c
new file mode 100644
index 0000000000000000000000000000000000000000..9a665a14a14c72a36a04c1fea7b5766130fdf09b
--- /dev/null
+++ b/userprog/syscall_seek.c
@@ -0,0 +1,22 @@
+/*
+* Changes the next byte to be read or written in open file fd to position, 
+* Expressed in bytes from the beginning of the file. (Thus, a position of 0
+* Is the file�s start.)
+*
+* Authored by Alex Stratford
+*/
+
+#include "system_calls.h"
+#include <stddef.h> // Dependency for NULL
+#include "threads/interrupt.h" // Dependency for intr_frame struct
+#include "filesys/file.h" // Dependency for file struct and file_seek function
+
+void syscall_seek(struct intr_frame *f) {
+	// pop off first int argument from interrupt frame
+	int file_descriptor = *((int*)f->esp + 1);
+	// pop off second int argument from interrupt frame
+	unsigned file_pos = *((unsigned*)((int*)f->esp + 2));
+	struct file *file = get_associated_file_pointer(file_descriptor);
+	// Seek through the file
+	file_seek(file, file_pos);
+}
diff --git a/userprog/syscall_tell.c b/userprog/syscall_tell.c
new file mode 100644
index 0000000000000000000000000000000000000000..4fa049a1344557df1bbe67642562d89a11f103e3
--- /dev/null
+++ b/userprog/syscall_tell.c
@@ -0,0 +1,19 @@
+/*
+ * Returns the current offset into the file that the given file descriptor is at
+ *
+ * Authored by Joshua Saxby
+ */
+#include <stddef.h>
+#include "system_calls.h"
+#include "filesys/file.h"
+
+void syscall_tell(struct intr_frame *f) {
+	// pop off first int argument from interrupt frame
+	int file_descriptor = *((int*)f->esp + 1);
+	struct file *file = get_associated_file_pointer(file_descriptor);
+    /*
+     * tell() return type is unsigned so we can't return a special error code if
+     * file descriptor passed is invalid. Instead, we return 0 silently.
+     */
+	f->eax = (file != NULL) ? file_tell(file) : 0;
+}
diff --git a/userprog/syscall_wait.c b/userprog/syscall_wait.c
new file mode 100644
index 0000000000000000000000000000000000000000..6ef4d52385c5be4ccd7352d681e289ad8acdc9e7
--- /dev/null
+++ b/userprog/syscall_wait.c
@@ -0,0 +1,6 @@
+#include "system_calls.h"
+#include "threads/interrupt.h"
+
+void syscall_wait(struct intr_frame *f) {
+  (void*)0;
+}
\ No newline at end of file
diff --git a/userprog/syscall_write.c b/userprog/syscall_write.c
new file mode 100644
index 0000000000000000000000000000000000000000..9c356db50727391fd00e5e6fa8e2837251227c54
--- /dev/null
+++ b/userprog/syscall_write.c
@@ -0,0 +1,59 @@
+/*
+ * The Write System Call
+ *
+ * Authored by Joshua Saxby
+ */
+#include <stdio.h>
+#include "filesys/file.h"
+#include "lib/kernel/stdio.h"
+#include "system_calls.h"
+#include "threads/interrupt.h"
+
+// the maximum number of characters to write to the console in one go
+static const size_t CONSOLE_WRITE_MAX_SIZE = 255;
+
+static void write_to_console(const char* buffer, size_t size);
+
+void syscall_write(struct intr_frame *f) {
+    // first argument is syscall code (already handled)
+    int fd = *((int*)f->esp + 1); // file descriptor is second argument
+    void* buffer = (void*)(*((int*)f->esp + 2)); // buffer is third argument
+    unsigned size = *((unsigned*)((int*)f->esp + 3)); // size to write is fourth
+    // writing to stdout or stderr (fd in {1, 2}) is a special case
+    switch (fd) {
+    case 1: // stdin
+    case 2: // stderr
+        write_to_console((const char*)buffer, size);
+        f->eax = size;
+        break;
+    default: {
+            // otherwise, we need to write to a file denoted by fd
+            struct file* file_to_write = get_associated_file_pointer(fd);
+            if (file_to_write == NULL) {
+                f->eax = 0; // invalid file descriptor
+                break;
+            }
+            f->eax = file_write(file_to_write, buffer, size);
+            break;
+        }
+    }
+}
+
+static void write_to_console(const char* buffer, size_t size) {
+    // refuse to write more than a certain limit of chars at a time to console
+    if (size <= CONSOLE_WRITE_MAX_SIZE) {
+        putbuf(buffer, size);
+    } else {
+        const char* cursor = buffer;
+        size_t chars_left = size;
+        do {
+            size_t write_amount = (
+                chars_left < CONSOLE_WRITE_MAX_SIZE
+                ? chars_left : CONSOLE_WRITE_MAX_SIZE
+            );
+            putbuf(cursor, write_amount);
+            cursor += write_amount;
+            chars_left -= write_amount;
+        } while (chars_left > 0);
+    }
+}
diff --git a/userprog/system_calls.h b/userprog/system_calls.h
new file mode 100644
index 0000000000000000000000000000000000000000..49b8145675f486ef12405293fa3d3678426006d5
--- /dev/null
+++ b/userprog/system_calls.h
@@ -0,0 +1,102 @@
+#include "filesys/file.h"
+#include "threads/interrupt.h"
+
+/*
+ * Terminates Pintos by calling shutdown_power_off()
+ * (declared in devices/shutdown.h).
+ */
+void syscall_halt(struct intr_frame *f);
+
+/*
+ * Terminates the current user program, returning status to the kernel. If the
+ * process's parent waits for it (see below), this is the status that will be
+ * returned. Conventionally, a status of 0 indicates success and nonzero
+ * values indicate errors. 
+ */
+void syscall_exit(struct intr_frame *f);
+
+/*
+ * Runs the executable whose name is given in cmd_line, passing any given
+ * arguments, and returns the new process's program id (pid). Must return pid
+ * -1, which otherwise should not be a valid pid, if the program cannot load or
+ * run for any reason. Thus, the parent process cannot return from the exec
+ * until it knows whether the child process successfully loaded its executable.
+ * You must use appropriate synchronization to ensure this.
+ */
+void syscall_exec(struct intr_frame *f);
+
+/*
+ * Waits for a child process pid and retrieves the child's exit status. 
+ */
+void syscall_wait(struct intr_frame *f);
+
+/*
+ * Creates a new file called file initially initial_size bytes in size.
+ * Returns true if successful, false otherwise.
+ */
+void syscall_create(struct intr_frame *f);
+
+/*
+ * Reads size bytes from the file open as fd into buffer.
+ * Returns the number of bytes actually read (0 at end of file), or -1 if the
+ * file could not be read (due to a condition other than end of file).
+ */
+void syscall_read(struct intr_frame *f);
+
+/*
+ * Writes size bytes from buffer to the open file fd.
+ * Returns the number of bytes actually written, which may be less than size if
+ * some bytes could not be written.
+ */
+void syscall_write(struct intr_frame *f);
+
+/*
+ * Opens the file called file. Returns a nonnegative integer handle called a
+ * "file descriptor" (fd), or -1 if the file could not be opened.
+ */
+void syscall_open(struct intr_frame *f);
+
+/*
+ * Returns the size, in bytes, of the file open as fd.
+ */
+void syscall_filesize(struct intr_frame *f);
+
+/*
+ * Deletes the file called file. Returns true if successful, false otherwise.
+ * A file may be removed regardless of whether it is open or closed, and
+ * Removing an open file does not close it. See Removing an Open File, for
+ * Details.
+ */
+void syscall_remove(struct intr_frame *f);
+
+/*
+ * Returns the position of the next byte to be read or written in open file fd,
+ * expressed in bytes from the beginning of the file. 
+ */
+void syscall_tell(struct intr_frame *f);
+
+/*
+* Changes the next byte to be read or written in open file fd to position,
+* Expressed in bytes from the beginning of the file. (Thus, a position of 0
+* Is the file�s start.)
+*/
+void syscall_seek(struct intr_frame *f);
+
+/*
+ * Closes file descriptor fd. Exiting or terminating a process implicitly closes
+ * all its open file descriptors, as if by calling this function for each one.
+ */
+void syscall_close(struct intr_frame *f);
+
+/*
+ * special additional stuff for handling file descriptors because they're annoying
+ */
+
+// returns NULL if the given file descriptor does not match a known file
+struct file * get_associated_file_pointer(int fd);
+// remembers the given file, and returns int of file descriptor
+// returns -1 if could not store it (means we've opened too many files)
+int associate_new_file_descriptor(struct file* file_pointer);
+// disassociates the given file descriptor (and its associated pointer)
+// returns false if this failed for some reason
+bool disassociate_file_descriptor(int fd);