diff --git a/defs.h b/defs.h
index 693fc20873f587bb32650c57108562d15183d3d0..8731c27b92aefdfc00bd0b4a1b80d7975d0beb00 100644
--- a/defs.h
+++ b/defs.h
@@ -42,6 +42,11 @@ int strncmp(const char*, const char*, uint);
 
 // syscall.c
 void syscall(void);
+int fetchint(struct proc*, uint, int*);
+int fetchbyte(struct proc*, uint, char*);
+int fetcharg(int, void*);
+int checkstring(uint);
+int putint(struct proc*, uint, int);
 
 // picirq.c
 void pic_init(void);
diff --git a/syscall.c b/syscall.c
index c6d459916696bf0ba63ca4d95048c4f94bb191e2..f75714afd5a418d78f6ff67c1f5e681fb36db8c7 100644
--- a/syscall.c
+++ b/syscall.c
@@ -81,523 +81,25 @@ putint(struct proc *p, uint addr, int x)
   return 0;
 }
 
-int
-sys_pipe(void)
-{
-  struct fd *rfd = 0, *wfd = 0;
-  int f1 = -1, f2 = -1;
-  struct proc *p = curproc[cpu()];
-  uint fdp;
-
-  if(pipe_alloc(&rfd, &wfd) < 0)
-    goto oops;
-  if((f1 = fd_ualloc()) < 0)
-    goto oops;
-  p->fds[f1] = rfd;
-  if((f2 = fd_ualloc()) < 0)
-    goto oops;
-  p->fds[f2] = wfd;
-  if(fetcharg(0, &fdp) < 0)
-    goto oops;
-  if(putint(p, fdp, f1) < 0)
-    goto oops;
-  if(putint(p, fdp+4, f2) < 0)
-    goto oops;
-  return 0;
-
- oops:
-  if(rfd)
-    fd_close(rfd);
-  if(wfd)
-    fd_close(wfd);
-  if(f1 >= 0)
-    p->fds[f1] = 0;
-  if(f2 >= 0)
-    p->fds[f2] = 0;
-  return -1;
-}
-
-int
-sys_write(void)
-{
-  int fd, n, ret;
-  uint addr;
-  struct proc *p = curproc[cpu()];
-
-  if(fetcharg(0, &fd) < 0 || fetcharg(1, &addr) < 0 || fetcharg(2, &n) < 0)
-    return -1;
-  if(fd < 0 || fd >= NOFILE)
-    return -1;
-  if(p->fds[fd] == 0)
-    return -1;
-  if(addr + n > p->sz)
-    return -1;
-
-  ret = fd_write(p->fds[fd], p->mem + addr, n);
-  return ret;
-}
-
-int
-sys_read(void)
-{
-  int fd, n, ret;
-  uint addr;
-  struct proc *p = curproc[cpu()];
-
-  if(fetcharg(0, &fd) < 0 || fetcharg(1, &addr) < 0 || fetcharg(2, &n) < 0)
-    return -1;
-  if(fd < 0 || fd >= NOFILE)
-    return -1;
-  if(p->fds[fd] == 0)
-    return -1;
-  if(addr + n > p->sz)
-    return -1;
-  ret = fd_read(p->fds[fd], p->mem + addr, n);
-  return ret;
-}
-
-int
-sys_close(void)
-{
-  int fd;
-  struct proc *p = curproc[cpu()];
-
-  if(fetcharg(0, &fd) < 0)
-    return -1;
-  if(fd < 0 || fd >= NOFILE)
-    return -1;
-  if(p->fds[fd] == 0)
-    return -1;
-  fd_close(p->fds[fd]);
-  p->fds[fd] = 0;
-  return 0;
-}
-
-int
-sys_fork(void)
-{
-  struct proc *np;
-
-  if((np = copyproc(curproc[cpu()])) == 0)
-    return -1;
-  np->state = RUNNABLE;
-  return np->pid;
-}
-
-int
-sys_exit(void)
-{
-  proc_exit();
-  return 0;  // not reached
-}
-
-int
-sys_wait(void)
-{
-  return proc_wait();
-}
-
-int
-sys_kill(void)
-{
-  int pid;
-
-  if(fetcharg(0, &pid) < 0)
-    return -1;
-  return proc_kill(pid);
-}
-
-int
-sys_open(void)
-{
-  struct proc *cp = curproc[cpu()];
-  struct inode *ip, *dp;
-  uint arg0, arg1;
-  int ufd;
-  struct fd *fd;
-  int l;
-  char *last;
-
-  if(fetcharg(0, &arg0) < 0 || fetcharg(1, &arg1) < 0)
-    return -1;
-  if((l = checkstring(arg0)) < 0)
-    return -1;
-
-  if(arg1 & O_CREATE){
-    dp = namei(cp->mem + arg0, NAMEI_CREATE, 0, &last, &ip);
-    if(dp){
-      ip = mknod1(dp, last, T_FILE, 0, 0);
-      iput(dp);
-      if(ip == 0)
-        return -1;
-    } else if(ip == 0){
-      return -1;
-    } else if(ip->type == T_DIR){
-      iput(ip);
-      return -1;
-    }
-  } else {
-    ip = namei(cp->mem + arg0, NAMEI_LOOKUP, 0, 0, 0);
-    if(ip == 0)
-      return -1;
-  }
-  if(ip->type == T_DIR && ((arg1 & O_RDWR) || (arg1 & O_WRONLY))){
-    iput(ip);
-    return -1;
-  }
-
-  if((fd = fd_alloc()) == 0){
-    iput(ip);
-    return -1;
-  }
-  if((ufd = fd_ualloc()) < 0){
-    iput(ip);
-    fd_close(fd);
-    return -1;
-  }
-
-  iunlock(ip);
-  fd->type = FD_FILE;
-  if(arg1 & O_RDWR) {
-    fd->readable = 1;
-    fd->writable = 1;
-  } else if(arg1 & O_WRONLY) {
-    fd->readable = 0;
-    fd->writable = 1;
-  } else {
-    fd->readable = 1;
-    fd->writable = 0;
-  }
-  fd->ip = ip;
-  fd->off = 0;
-  cp->fds[ufd] = fd;
-
-  return ufd;
-}
-
-int
-sys_mknod(void)
-{
-  struct proc *cp = curproc[cpu()];
-  struct inode *nip;
-  uint arg0, arg1, arg2, arg3;
-  int l;
-
-  if(fetcharg(0, &arg0) < 0 || fetcharg(1, &arg1) < 0 ||
-     fetcharg(2, &arg2) < 0 || fetcharg(3, &arg3) < 0)
-    return -1;
-
-  if((l = checkstring(arg0)) < 0)
-    return -1;
-
-  if(l >= DIRSIZ)
-    return -1;
-
-  nip = mknod(cp->mem + arg0, (short) arg1, (short) arg2, (short) arg3);
-  if(nip)
-    iput(nip);
-  return (nip == 0) ? -1 : 0;
-}
-
-int
-sys_mkdir(void)
-{
-  struct proc *cp = curproc[cpu()];
-  struct inode *nip;
-  struct inode *dp;
-  uint arg0;
-  int l;
-  struct dirent de;
-  char *last;
-
-  if(fetcharg(0, &arg0) < 0)
-    return -1;
-
-  if((l = checkstring(arg0)) < 0)
-    return -1;
-
-  dp = namei(cp->mem + arg0, NAMEI_CREATE, 0, &last, 0);
-  if(dp == 0)
-    return -1;
-
-  nip = mknod1(dp, last, T_DIR, 0, 0);
-  if(nip == 0){
-    iput(dp);
-    return -1;
-  }
-
-  dp->nlink += 1;
-  iupdate(dp);
-
-  memset(de.name, '\0', DIRSIZ);
-  de.name[0] = '.';
-  de.inum = nip->inum;
-  writei(nip, (char*) &de, 0, sizeof(de));
-
-  de.inum = dp->inum;
-  de.name[1] = '.';
-  writei(nip, (char*) &de, sizeof(de), sizeof(de));
-
-  iput(dp);
-  iput(nip);
-
-  return 0;
-}
-
-
-int
-sys_chdir(void)
-{
-  struct proc *cp = curproc[cpu()];
-  struct inode *ip;
-    uint arg0;
-  int l;
-
-  if(fetcharg(0, &arg0) < 0)
-    return -1;
-
-  if((l = checkstring(arg0)) < 0)
-    return -1;
-
-  if((ip = namei(cp->mem + arg0, NAMEI_LOOKUP, 0, 0, 0)) == 0)
-    return -1;
-
-  if(ip == cp->cwd) {
-    iput(ip);
-    return 0;
-  }
-
-  if(ip->type != T_DIR) {
-    iput(ip);
-    return -1;
-  }
-
-  idecref(cp->cwd);
-  cp->cwd = ip;
-  iunlock(cp->cwd);
-  return 0;
-}
-
-int
-sys_unlink(void)
-{
-  struct proc *cp = curproc[cpu()];
-  uint arg0;
-  int r;
-
-  if(fetcharg(0, &arg0) < 0)
-    return -1;
-  if(checkstring(arg0) < 0)
-    return -1;
-  r = unlink(cp->mem + arg0);
-  return r;
-}
-
-int
-sys_fstat(void)
-{
-  struct proc *cp = curproc[cpu()];
-  uint fd, addr;
-  int r;
-
-  if(fetcharg(0, &fd) < 0)
-    return -1;
-  if(fetcharg(1, &addr) < 0)
-    return -1;
-  if(fd < 0 || fd >= NOFILE)
-    return -1;
-  if(cp->fds[fd] == 0)
-    return -1;
-  if(addr + sizeof(struct stat) > cp->sz)
-    return -1;
-  r = fd_stat(cp->fds[fd], (struct stat*)(cp->mem + addr));
-  return r;
-}
-
-int
-sys_dup(void)
-{
-  struct proc *cp = curproc[cpu()];
-  uint fd, ufd1;
-
-  if(fetcharg(0, &fd) < 0)
-    return -1;
-  if(fd < 0 || fd >= NOFILE)
-    return -1;
-  if(cp->fds[fd] == 0)
-    return -1;
-  if((ufd1 = fd_ualloc()) < 0)
-    return -1;
-  cp->fds[ufd1] = cp->fds[fd];
-  fd_incref(cp->fds[ufd1]);
-  return ufd1;
-}
-
-int
-sys_link(void)
-{
-  struct proc *cp = curproc[cpu()];
-  uint name1, name2;
-  int r;
-
-  if(fetcharg(0, &name1) < 0 || checkstring(name1) < 0)
-    return -1;
-  if(fetcharg(1, &name2) < 0 || checkstring(name2) < 0)
-    return -1;
-  r = link(cp->mem + name1, cp->mem + name2);
-  return r;
-}
-
-int
-sys_getpid(void)
-{
-  struct proc *cp = curproc[cpu()];
-  return cp->pid;
-}
-
-
-int
-sys_sbrk(void)
-{
-  uint addr;
-  int n;
-  struct proc *cp = curproc[cpu()];
-
-  if(fetcharg(0, &n) < 0)
-    return -1;
-  if((addr = growproc(n)) == 0xffffffff)
-    return -1;
-  setupsegs(cp);
-  return addr;
-}
-
-int
-sys_exec(void)
-{
-  struct proc *cp = curproc[cpu()];
-  uint arg0, arg1, sz=0, ap, sp, p1, p2;
-  int i, nargs, argbytes, len;
-  struct inode *ip;
-  struct elfhdr elf;
-  struct proghdr ph;
-  char *mem = 0;
-
-  if(fetcharg(0, &arg0) < 0)
-    return -1;
-  if(fetcharg(1, &arg1) < 0)
-    return -1;
-  if(checkstring(arg0) < 0)
-    return -1;
-  ip = namei(cp->mem + arg0, NAMEI_LOOKUP, 0, 0, 0);
-  if(ip == 0)
-    return -1;
-
-  if(readi(ip, (char*)&elf, 0, sizeof(elf)) < sizeof(elf))
-    goto bad;
-
-  if(elf.magic != ELF_MAGIC)
-    goto bad;
-
-  sz = 0;
-  for(i = 0; i < elf.phnum; i++){
-    if(readi(ip, (char*)&ph, elf.phoff + i * sizeof(ph),
-             sizeof(ph)) != sizeof(ph))
-      goto bad;
-    if(ph.type != ELF_PROG_LOAD)
-      continue;
-    if(ph.memsz < ph.filesz)
-      goto bad;
-    sz += ph.memsz;
-  }
-
-  sz += 4096 - (sz % 4096);
-  sz += 4096;
-
-  mem = kalloc(sz);
-  if(mem == 0)
-    goto bad;
-  memset(mem, 0, sz);
-
-  // arg1 is a pointer to an array of pointers to string.
-  nargs = 0;
-  argbytes = 0;
-  for(i = 0; ; i++){
-    if(fetchint(cp, arg1 + 4*i, &ap) < 0)
-      goto bad;
-    if(ap == 0)
-      break;
-    len = checkstring(ap);
-    if(len < 0)
-      goto bad;
-    nargs++;
-    argbytes += len + 1;
-  }
-
-  // argn\0
-  // ...
-  // arg0\0
-  // 0
-  // ptr to argn
-  // ...
-  // 12: ptr to arg0
-  //  8: argv (points to ptr to arg0)
-  //  4: argc
-  //  0: fake return pc
-  sp = sz - argbytes - (nargs+1)*4 - 4 - 4 - 4;
-  *(uint*)(mem + sp) = 0xffffffff;
-  *(uint*)(mem + sp + 4) = nargs;
-  *(uint*)(mem + sp + 8) = (uint)(sp + 12);
-
-  p1 = sp + 12;
-  p2 = sp + 12 + (nargs + 1) * 4;
-  for(i = 0; i < nargs; i++){
-    fetchint(cp, arg1 + 4*i, &ap);
-    len = checkstring(ap);
-    memmove(mem + p2, cp->mem + ap, len + 1);
-    *(uint*)(mem + p1) = p2;
-    p1 += 4;
-    p2 += len + 1;
-  }
-  *(uint*)(mem + p1) = 0;
-
-  // commit to the new image.
-  kfree(cp->mem, cp->sz);
-  cp->sz = sz;
-  cp->mem = mem;
-  mem = 0;
-
-  for(i = 0; i < elf.phnum; i++){
-    if(readi(ip, (char*)&ph, elf.phoff + i * sizeof(ph),
-             sizeof(ph)) != sizeof(ph))
-      goto bad2;
-    if(ph.type != ELF_PROG_LOAD)
-      continue;
-    if(ph.va + ph.memsz > sz)
-      goto bad2;
-    if(readi(ip, cp->mem + ph.va, ph.offset, ph.filesz) != ph.filesz)
-      goto bad2;
-    memset(cp->mem + ph.va + ph.filesz, 0, ph.memsz - ph.filesz);
-  }
-
-  iput(ip);
-
-  cp->tf->eip = elf.entry;
-  cp->tf->esp = sp;
-  setupsegs(cp);
-
-  return 0;
-
- bad:
-  if(mem)
-    kfree(mem, sz);
-  iput(ip);
-  return -1;
-
- bad2:
-  iput(ip);
-  proc_exit();
-  return 0;
-}
+extern int sys_chdir(void);
+extern int sys_close(void);
+extern int sys_dup(void);
+extern int sys_exec(void);
+extern int sys_exit(void);
+extern int sys_fork(void);
+extern int sys_fstat(void);
+extern int sys_getpid(void);
+extern int sys_kill(void);
+extern int sys_link(void);
+extern int sys_mkdir(void);
+extern int sys_mknod(void);
+extern int sys_open(void);
+extern int sys_pipe(void);
+extern int sys_read(void);
+extern int sys_sbrk(void);
+extern int sys_unlink(void);
+extern int sys_wait(void);
+extern int sys_write(void);
 
 void
 syscall(void)
diff --git a/syscall.h b/syscall.h
index 4efd2555f5e22309fd168c01db7e22eca8fc154d..0ef0c870c331bd86711e22af55f3eb5d858a05ac 100644
--- a/syscall.h
+++ b/syscall.h
@@ -1,20 +1,20 @@
-#define SYS_fork 1
-#define SYS_exit 2
-#define SYS_wait 3
-#define SYS_pipe 4
-#define SYS_write 5
-#define SYS_read 6
-#define SYS_close 7
-#define SYS_kill 9
-#define SYS_exec 10
-#define SYS_open 11
-#define SYS_mknod 12
+#define SYS_fork    1
+#define SYS_exit    2
+#define SYS_wait    3
+#define SYS_pipe    4
+#define SYS_write   5
+#define SYS_read    6
+#define SYS_close   7
+#define SYS_kill    9
+#define SYS_exec   10
+#define SYS_open   11
+#define SYS_mknod  12
 #define SYS_unlink 13
-#define SYS_fstat 14
-#define SYS_link 15
-#define SYS_mkdir 16
-#define SYS_chdir 17
-#define SYS_dup 18
+#define SYS_fstat  14
+#define SYS_link   15
+#define SYS_mkdir  16
+#define SYS_chdir  17
+#define SYS_dup    18
 #define SYS_getpid 19
-#define SYS_sbrk 20
+#define SYS_sbrk   20
 
diff --git a/sysfile.c b/sysfile.c
new file mode 100644
index 0000000000000000000000000000000000000000..f533e0115405335ed6f9c2f121a43f7030001a79
--- /dev/null
+++ b/sysfile.c
@@ -0,0 +1,477 @@
+#include "types.h"
+#include "stat.h"
+#include "param.h"
+#include "mmu.h"
+#include "proc.h"
+#include "defs.h"
+#include "x86.h"
+#include "traps.h"
+#include "syscall.h"
+#include "spinlock.h"
+#include "buf.h"
+#include "fs.h"
+#include "fsvar.h"
+#include "elf.h"
+#include "fd.h"
+#include "fcntl.h"
+
+int
+sys_pipe(void)
+{
+  struct fd *rfd = 0, *wfd = 0;
+  int f1 = -1, f2 = -1;
+  struct proc *p = curproc[cpu()];
+  uint fdp;
+
+  if(pipe_alloc(&rfd, &wfd) < 0)
+    goto oops;
+  if((f1 = fd_ualloc()) < 0)
+    goto oops;
+  p->fds[f1] = rfd;
+  if((f2 = fd_ualloc()) < 0)
+    goto oops;
+  p->fds[f2] = wfd;
+  if(fetcharg(0, &fdp) < 0)
+    goto oops;
+  if(putint(p, fdp, f1) < 0)
+    goto oops;
+  if(putint(p, fdp+4, f2) < 0)
+    goto oops;
+  return 0;
+
+ oops:
+  if(rfd)
+    fd_close(rfd);
+  if(wfd)
+    fd_close(wfd);
+  if(f1 >= 0)
+    p->fds[f1] = 0;
+  if(f2 >= 0)
+    p->fds[f2] = 0;
+  return -1;
+}
+
+int
+sys_write(void)
+{
+  int fd, n, ret;
+  uint addr;
+  struct proc *p = curproc[cpu()];
+
+  if(fetcharg(0, &fd) < 0 || fetcharg(1, &addr) < 0 || fetcharg(2, &n) < 0)
+    return -1;
+  if(fd < 0 || fd >= NOFILE)
+    return -1;
+  if(p->fds[fd] == 0)
+    return -1;
+  if(addr + n > p->sz)
+    return -1;
+
+  ret = fd_write(p->fds[fd], p->mem + addr, n);
+  return ret;
+}
+
+int
+sys_read(void)
+{
+  int fd, n, ret;
+  uint addr;
+  struct proc *p = curproc[cpu()];
+
+  if(fetcharg(0, &fd) < 0 || fetcharg(1, &addr) < 0 || fetcharg(2, &n) < 0)
+    return -1;
+  if(fd < 0 || fd >= NOFILE)
+    return -1;
+  if(p->fds[fd] == 0)
+    return -1;
+  if(addr + n > p->sz)
+    return -1;
+  ret = fd_read(p->fds[fd], p->mem + addr, n);
+  return ret;
+}
+
+int
+sys_close(void)
+{
+  int fd;
+  struct proc *p = curproc[cpu()];
+
+  if(fetcharg(0, &fd) < 0)
+    return -1;
+  if(fd < 0 || fd >= NOFILE)
+    return -1;
+  if(p->fds[fd] == 0)
+    return -1;
+  fd_close(p->fds[fd]);
+  p->fds[fd] = 0;
+  return 0;
+}
+
+int
+sys_open(void)
+{
+  struct proc *cp = curproc[cpu()];
+  struct inode *ip, *dp;
+  uint arg0, arg1;
+  int ufd;
+  struct fd *fd;
+  int l;
+  char *last;
+
+  if(fetcharg(0, &arg0) < 0 || fetcharg(1, &arg1) < 0)
+    return -1;
+  if((l = checkstring(arg0)) < 0)
+    return -1;
+
+  if(arg1 & O_CREATE){
+    dp = namei(cp->mem + arg0, NAMEI_CREATE, 0, &last, &ip);
+    if(dp){
+      ip = mknod1(dp, last, T_FILE, 0, 0);
+      iput(dp);
+      if(ip == 0)
+        return -1;
+    } else if(ip == 0){
+      return -1;
+    } else if(ip->type == T_DIR){
+      iput(ip);
+      return -1;
+    }
+  } else {
+    ip = namei(cp->mem + arg0, NAMEI_LOOKUP, 0, 0, 0);
+    if(ip == 0)
+      return -1;
+  }
+  if(ip->type == T_DIR && ((arg1 & O_RDWR) || (arg1 & O_WRONLY))){
+    iput(ip);
+    return -1;
+  }
+
+  if((fd = fd_alloc()) == 0){
+    iput(ip);
+    return -1;
+  }
+  if((ufd = fd_ualloc()) < 0){
+    iput(ip);
+    fd_close(fd);
+    return -1;
+  }
+
+  iunlock(ip);
+  fd->type = FD_FILE;
+  if(arg1 & O_RDWR) {
+    fd->readable = 1;
+    fd->writable = 1;
+  } else if(arg1 & O_WRONLY) {
+    fd->readable = 0;
+    fd->writable = 1;
+  } else {
+    fd->readable = 1;
+    fd->writable = 0;
+  }
+  fd->ip = ip;
+  fd->off = 0;
+  cp->fds[ufd] = fd;
+
+  return ufd;
+}
+
+int
+sys_mknod(void)
+{
+  struct proc *cp = curproc[cpu()];
+  struct inode *nip;
+  uint arg0, arg1, arg2, arg3;
+  int l;
+
+  if(fetcharg(0, &arg0) < 0 || fetcharg(1, &arg1) < 0 ||
+     fetcharg(2, &arg2) < 0 || fetcharg(3, &arg3) < 0)
+    return -1;
+
+  if((l = checkstring(arg0)) < 0)
+    return -1;
+
+  if(l >= DIRSIZ)
+    return -1;
+
+  nip = mknod(cp->mem + arg0, (short) arg1, (short) arg2, (short) arg3);
+  if(nip)
+    iput(nip);
+  return (nip == 0) ? -1 : 0;
+}
+
+int
+sys_mkdir(void)
+{
+  struct proc *cp = curproc[cpu()];
+  struct inode *nip;
+  struct inode *dp;
+  uint arg0;
+  int l;
+  struct dirent de;
+  char *last;
+
+  if(fetcharg(0, &arg0) < 0)
+    return -1;
+
+  if((l = checkstring(arg0)) < 0)
+    return -1;
+
+  dp = namei(cp->mem + arg0, NAMEI_CREATE, 0, &last, 0);
+  if(dp == 0)
+    return -1;
+
+  nip = mknod1(dp, last, T_DIR, 0, 0);
+  if(nip == 0){
+    iput(dp);
+    return -1;
+  }
+
+  dp->nlink += 1;
+  iupdate(dp);
+
+  memset(de.name, '\0', DIRSIZ);
+  de.name[0] = '.';
+  de.inum = nip->inum;
+  writei(nip, (char*) &de, 0, sizeof(de));
+
+  de.inum = dp->inum;
+  de.name[1] = '.';
+  writei(nip, (char*) &de, sizeof(de), sizeof(de));
+
+  iput(dp);
+  iput(nip);
+
+  return 0;
+}
+
+
+int
+sys_chdir(void)
+{
+  struct proc *cp = curproc[cpu()];
+  struct inode *ip;
+    uint arg0;
+  int l;
+
+  if(fetcharg(0, &arg0) < 0)
+    return -1;
+
+  if((l = checkstring(arg0)) < 0)
+    return -1;
+
+  if((ip = namei(cp->mem + arg0, NAMEI_LOOKUP, 0, 0, 0)) == 0)
+    return -1;
+
+  if(ip == cp->cwd) {
+    iput(ip);
+    return 0;
+  }
+
+  if(ip->type != T_DIR) {
+    iput(ip);
+    return -1;
+  }
+
+  idecref(cp->cwd);
+  cp->cwd = ip;
+  iunlock(cp->cwd);
+  return 0;
+}
+
+int
+sys_unlink(void)
+{
+  struct proc *cp = curproc[cpu()];
+  uint arg0;
+  int r;
+
+  if(fetcharg(0, &arg0) < 0)
+    return -1;
+  if(checkstring(arg0) < 0)
+    return -1;
+  r = unlink(cp->mem + arg0);
+  return r;
+}
+
+int
+sys_fstat(void)
+{
+  struct proc *cp = curproc[cpu()];
+  uint fd, addr;
+  int r;
+
+  if(fetcharg(0, &fd) < 0)
+    return -1;
+  if(fetcharg(1, &addr) < 0)
+    return -1;
+  if(fd < 0 || fd >= NOFILE)
+    return -1;
+  if(cp->fds[fd] == 0)
+    return -1;
+  if(addr + sizeof(struct stat) > cp->sz)
+    return -1;
+  r = fd_stat(cp->fds[fd], (struct stat*)(cp->mem + addr));
+  return r;
+}
+
+int
+sys_dup(void)
+{
+  struct proc *cp = curproc[cpu()];
+  uint fd, ufd1;
+
+  if(fetcharg(0, &fd) < 0)
+    return -1;
+  if(fd < 0 || fd >= NOFILE)
+    return -1;
+  if(cp->fds[fd] == 0)
+    return -1;
+  if((ufd1 = fd_ualloc()) < 0)
+    return -1;
+  cp->fds[ufd1] = cp->fds[fd];
+  fd_incref(cp->fds[ufd1]);
+  return ufd1;
+}
+
+int
+sys_link(void)
+{
+  struct proc *cp = curproc[cpu()];
+  uint name1, name2;
+  int r;
+
+  if(fetcharg(0, &name1) < 0 || checkstring(name1) < 0)
+    return -1;
+  if(fetcharg(1, &name2) < 0 || checkstring(name2) < 0)
+    return -1;
+  r = link(cp->mem + name1, cp->mem + name2);
+  return r;
+}
+
+int
+sys_exec(void)
+{
+  struct proc *cp = curproc[cpu()];
+  uint arg0, arg1, sz=0, ap, sp, p1, p2;
+  int i, nargs, argbytes, len;
+  struct inode *ip;
+  struct elfhdr elf;
+  struct proghdr ph;
+  char *mem = 0;
+
+  if(fetcharg(0, &arg0) < 0)
+    return -1;
+  if(fetcharg(1, &arg1) < 0)
+    return -1;
+  if(checkstring(arg0) < 0)
+    return -1;
+  ip = namei(cp->mem + arg0, NAMEI_LOOKUP, 0, 0, 0);
+  if(ip == 0)
+    return -1;
+
+  if(readi(ip, (char*)&elf, 0, sizeof(elf)) < sizeof(elf))
+    goto bad;
+
+  if(elf.magic != ELF_MAGIC)
+    goto bad;
+
+  sz = 0;
+  for(i = 0; i < elf.phnum; i++){
+    if(readi(ip, (char*)&ph, elf.phoff + i * sizeof(ph),
+             sizeof(ph)) != sizeof(ph))
+      goto bad;
+    if(ph.type != ELF_PROG_LOAD)
+      continue;
+    if(ph.memsz < ph.filesz)
+      goto bad;
+    sz += ph.memsz;
+  }
+
+  sz += 4096 - (sz % 4096);
+  sz += 4096;
+
+  mem = kalloc(sz);
+  if(mem == 0)
+    goto bad;
+  memset(mem, 0, sz);
+
+  // arg1 is a pointer to an array of pointers to string.
+  nargs = 0;
+  argbytes = 0;
+  for(i = 0; ; i++){
+    if(fetchint(cp, arg1 + 4*i, &ap) < 0)
+      goto bad;
+    if(ap == 0)
+      break;
+    len = checkstring(ap);
+    if(len < 0)
+      goto bad;
+    nargs++;
+    argbytes += len + 1;
+  }
+
+  // argn\0
+  // ...
+  // arg0\0
+  // 0
+  // ptr to argn
+  // ...
+  // 12: ptr to arg0
+  //  8: argv (points to ptr to arg0)
+  //  4: argc
+  //  0: fake return pc
+  sp = sz - argbytes - (nargs+1)*4 - 4 - 4 - 4;
+  *(uint*)(mem + sp) = 0xffffffff;
+  *(uint*)(mem + sp + 4) = nargs;
+  *(uint*)(mem + sp + 8) = (uint)(sp + 12);
+
+  p1 = sp + 12;
+  p2 = sp + 12 + (nargs + 1) * 4;
+  for(i = 0; i < nargs; i++){
+    fetchint(cp, arg1 + 4*i, &ap);
+    len = checkstring(ap);
+    memmove(mem + p2, cp->mem + ap, len + 1);
+    *(uint*)(mem + p1) = p2;
+    p1 += 4;
+    p2 += len + 1;
+  }
+  *(uint*)(mem + p1) = 0;
+
+  // commit to the new image.
+  kfree(cp->mem, cp->sz);
+  cp->sz = sz;
+  cp->mem = mem;
+  mem = 0;
+
+  for(i = 0; i < elf.phnum; i++){
+    if(readi(ip, (char*)&ph, elf.phoff + i * sizeof(ph),
+             sizeof(ph)) != sizeof(ph))
+      goto bad2;
+    if(ph.type != ELF_PROG_LOAD)
+      continue;
+    if(ph.va + ph.memsz > sz)
+      goto bad2;
+    if(readi(ip, cp->mem + ph.va, ph.offset, ph.filesz) != ph.filesz)
+      goto bad2;
+    memset(cp->mem + ph.va + ph.filesz, 0, ph.memsz - ph.filesz);
+  }
+
+  iput(ip);
+
+  cp->tf->eip = elf.entry;
+  cp->tf->esp = sp;
+  setupsegs(cp);
+
+  return 0;
+
+ bad:
+  if(mem)
+    kfree(mem, sz);
+  iput(ip);
+  return -1;
+
+ bad2:
+  iput(ip);
+  proc_exit();
+  return 0;
+}
diff --git a/sysproc.c b/sysproc.c
new file mode 100644
index 0000000000000000000000000000000000000000..f648c0eaaa966ceab7cc620cf9c5937a88b78b2d
--- /dev/null
+++ b/sysproc.c
@@ -0,0 +1,72 @@
+#include "types.h"
+#include "stat.h"
+#include "param.h"
+#include "mmu.h"
+#include "proc.h"
+#include "defs.h"
+#include "x86.h"
+#include "traps.h"
+#include "syscall.h"
+#include "spinlock.h"
+#include "buf.h"
+#include "fs.h"
+#include "fsvar.h"
+#include "elf.h"
+#include "fd.h"
+#include "fcntl.h"
+
+int
+sys_fork(void)
+{
+  struct proc *np;
+
+  if((np = copyproc(curproc[cpu()])) == 0)
+    return -1;
+  np->state = RUNNABLE;
+  return np->pid;
+}
+
+int
+sys_exit(void)
+{
+  proc_exit();
+  return 0;  // not reached
+}
+
+int
+sys_wait(void)
+{
+  return proc_wait();
+}
+
+int
+sys_kill(void)
+{
+  int pid;
+
+  if(fetcharg(0, &pid) < 0)
+    return -1;
+  return proc_kill(pid);
+}
+
+int
+sys_getpid(void)
+{
+  struct proc *cp = curproc[cpu()];
+  return cp->pid;
+}
+
+int
+sys_sbrk(void)
+{
+  uint addr;
+  int n;
+  struct proc *cp = curproc[cpu()];
+
+  if(fetcharg(0, &n) < 0)
+    return -1;
+  if((addr = growproc(n)) == 0xffffffff)
+    return -1;
+  setupsegs(cp);
+  return addr;
+}