Update.
authorBen Pfaff <blp@cs.stanford.edu>
Mon, 27 Sep 2004 23:49:29 +0000 (23:49 +0000)
committerBen Pfaff <blp@cs.stanford.edu>
Mon, 27 Sep 2004 23:49:29 +0000 (23:49 +0000)
solutions/README [new file with mode: 0644]
solutions/p1-2.patch
solutions/p2.patch
solutions/p3.patch [new file with mode: 0644]

diff --git a/solutions/README b/solutions/README
new file mode 100644 (file)
index 0000000..8a83af0
--- /dev/null
@@ -0,0 +1,7 @@
+Sample solutions.
+
+* The solutions for p1-2 and p2 are okay.
+
+* The solution for p3 is terrible.  For example, there's no locking at
+  all.  I just wrote it to make sure that the project was possible
+  given the tools that we gave the students.
index dbe443436455b3e284f91eb5a03d33574feaac40..a5e743f0e61aaf5cf45c907e56ccb3c86bae8218 100644 (file)
@@ -1,9 +1,6 @@
-Only in pintos/src/threads: .#init.c
-Only in pintos/src/threads: build
-Only in pintos/src/threads: init.c~
-diff -urp pintos.orig/src/threads/synch.c pintos/src/threads/synch.c
+diff -X pat -urpN pintos.orig/src/threads/synch.c pintos/src/threads/synch.c
 --- pintos.orig/src/threads/synch.c    2004-09-19 21:29:53.000000000 -0700
-+++ pintos/src/threads/synch.c 2004-09-20 22:38:56.000000000 -0700
++++ pintos/src/threads/synch.c 2004-09-27 16:50:14.000000000 -0700
 @@ -330,3 +330,35 @@ cond_name (const struct condition *cond)
  
    return cond->name;
@@ -40,10 +37,9 @@ diff -urp pintos.orig/src/threads/synch.c pintos/src/threads/synch.c
 +    }
 +  lock_release (&latch->monitor_lock);
 +}
-Only in pintos/src/threads: synch.c.orig
-diff -urp pintos.orig/src/threads/synch.h pintos/src/threads/synch.h
+diff -X pat -urpN pintos.orig/src/threads/synch.h pintos/src/threads/synch.h
 --- pintos.orig/src/threads/synch.h    2004-09-19 21:29:53.000000000 -0700
-+++ pintos/src/threads/synch.h 2004-09-20 22:38:56.000000000 -0700
++++ pintos/src/threads/synch.h 2004-09-27 16:50:14.000000000 -0700
 @@ -44,4 +44,16 @@ void cond_signal (struct condition *, st
  void cond_broadcast (struct condition *, struct lock *);
  const char *cond_name (const struct condition *);
@@ -61,11 +57,10 @@ diff -urp pintos.orig/src/threads/synch.h pintos/src/threads/synch.h
 +void latch_release (struct latch *);
 +
  #endif /* threads/synch.h */
-Only in pintos/src/threads: synch.h.orig
-diff -urp pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
---- pintos.orig/src/threads/thread.c   2004-09-20 19:32:31.000000000 -0700
-+++ pintos/src/threads/thread.c        2004-09-20 22:52:43.000000000 -0700
-@@ -76,6 +76,7 @@ thread_init (void) 
+diff -X pat -urpN pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
+--- pintos.orig/src/threads/thread.c   2004-09-26 14:15:17.000000000 -0700
++++ pintos/src/threads/thread.c        2004-09-27 16:51:03.000000000 -0700
+@@ -80,6 +80,7 @@ thread_init (void) 
    init_thread (initial_thread, "main", PRI_DEFAULT);
    initial_thread->status = THREAD_RUNNING;
    initial_thread->tid = allocate_tid ();
@@ -73,7 +68,7 @@ diff -urp pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
  }
  
  /* Starts preemptive thread scheduling by enabling interrupts.
-@@ -120,6 +121,7 @@ thread_create (const char *name, int pri
+@@ -148,6 +149,7 @@ thread_create (const char *name, int pri
    /* Initialize thread. */
    init_thread (t, name, priority);
    tid = t->tid = allocate_tid ();
@@ -81,7 +76,7 @@ diff -urp pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
  
    /* Stack frame for kernel_thread(). */
    kf = alloc_frame (t, sizeof *kf);
-@@ -196,12 +198,30 @@ thread_tid (void) 
+@@ -224,16 +226,34 @@ thread_tid (void) 
  void
  thread_exit (void) 
  {
@@ -90,6 +85,10 @@ diff -urp pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
 +
    ASSERT (!intr_context ());
  
+ #ifdef USERPROG
+   process_exit ();
+ #endif
 +  /* Notify our parent that we're dying. */
 +  latch_release (&t->ready_to_die);
 +
@@ -113,7 +112,7 @@ diff -urp pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
    schedule ();
    NOT_REACHED ();
  }
-@@ -238,6 +258,22 @@ thread_block (void) 
+@@ -270,6 +290,22 @@ thread_block (void) 
    thread_current ()->status = THREAD_BLOCKED;
    schedule ();
  }
@@ -136,7 +135,7 @@ diff -urp pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
  \f
  /* Idle thread.  Executes when no other thread is ready to run. */
  static void
-@@ -303,6 +339,9 @@ init_thread (struct thread *t, const cha
+@@ -335,6 +371,9 @@ init_thread (struct thread *t, const cha
    strlcpy (t->name, name, sizeof t->name);
    t->stack = (uint8_t *) t + PGSIZE;
    t->priority = priority;
@@ -146,13 +145,9 @@ diff -urp pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
    t->magic = THREAD_MAGIC;
  }
  
-Only in pintos/src/threads: thread.c.orig
-Only in pintos/src/threads: thread.c.rej
-Only in pintos/src/threads: thread.c.rej~
-Only in pintos/src/threads: thread.c~
-diff -urp pintos.orig/src/threads/thread.h pintos/src/threads/thread.h
---- pintos.orig/src/threads/thread.h   2004-09-20 15:29:18.000000000 -0700
-+++ pintos/src/threads/thread.h        2004-09-20 22:36:55.000000000 -0700
+diff -X pat -urpN pintos.orig/src/threads/thread.h pintos/src/threads/thread.h
+--- pintos.orig/src/threads/thread.h   2004-09-26 14:15:17.000000000 -0700
++++ pintos/src/threads/thread.h        2004-09-27 16:50:14.000000000 -0700
 @@ -4,6 +4,7 @@
  #include <debug.h>
  #include <list.h>
@@ -174,5 +169,3 @@ diff -urp pintos.orig/src/threads/thread.h pintos/src/threads/thread.h
      /* Shared between thread.c and synch.c. */
      list_elem elem;                     /* List element. */
  
-Only in pintos/src/threads: thread.h.orig
-Only in pintos/src/threads: thread.h~
index 8ff1be76ce0757f2562dbb3ac8a07058c672e366..68331bd87b80895da485cac29b216f8c922e481f 100644 (file)
@@ -1,16 +1,15 @@
-diff -urp pintos.orig/src/constants.h pintos/src/constants.h
+diff -urpN pintos.orig/src/constants.h pintos/src/constants.h
 --- pintos.orig/src/constants.h        2004-09-21 17:26:39.000000000 -0700
-+++ pintos/src/constants.h     2004-09-22 00:34:01.000000000 -0700
++++ pintos/src/constants.h     2004-09-27 16:41:17.000000000 -0700
 @@ -8,4 +8,4 @@
  /*#define MACRONAME 1 */
  
  /* Uncomment if if you've implemented thread_join(). */
 -/*#define THREAD_JOIN_IMPLEMENTED 1*/
 +#define THREAD_JOIN_IMPLEMENTED 1
-Only in pintos/src: constants.h~
-diff -urp pintos.orig/src/threads/synch.c pintos/src/threads/synch.c
+diff -urpN pintos.orig/src/threads/synch.c pintos/src/threads/synch.c
 --- pintos.orig/src/threads/synch.c    2004-09-19 21:29:53.000000000 -0700
-+++ pintos/src/threads/synch.c 2004-09-22 00:30:05.000000000 -0700
++++ pintos/src/threads/synch.c 2004-09-27 16:41:17.000000000 -0700
 @@ -330,3 +330,35 @@ cond_name (const struct condition *cond)
  
    return cond->name;
@@ -47,9 +46,9 @@ diff -urp pintos.orig/src/threads/synch.c pintos/src/threads/synch.c
 +    }
 +  lock_release (&latch->monitor_lock);
 +}
-diff -urp pintos.orig/src/threads/synch.h pintos/src/threads/synch.h
+diff -urpN pintos.orig/src/threads/synch.h pintos/src/threads/synch.h
 --- pintos.orig/src/threads/synch.h    2004-09-19 21:29:53.000000000 -0700
-+++ pintos/src/threads/synch.h 2004-09-22 00:30:05.000000000 -0700
++++ pintos/src/threads/synch.h 2004-09-27 16:41:17.000000000 -0700
 @@ -44,4 +44,16 @@ void cond_signal (struct condition *, st
  void cond_broadcast (struct condition *, struct lock *);
  const char *cond_name (const struct condition *);
@@ -67,9 +66,9 @@ diff -urp pintos.orig/src/threads/synch.h pintos/src/threads/synch.h
 +void latch_release (struct latch *);
 +
  #endif /* threads/synch.h */
-diff -urp pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
---- pintos.orig/src/threads/thread.c   2004-09-21 22:42:17.000000000 -0700
-+++ pintos/src/threads/thread.c        2004-09-22 00:32:39.000000000 -0700
+diff -urpN pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
+--- pintos.orig/src/threads/thread.c   2004-09-26 14:15:17.000000000 -0700
++++ pintos/src/threads/thread.c        2004-09-27 16:41:17.000000000 -0700
 @@ -13,6 +13,7 @@
  #include "threads/synch.h"
  #ifdef USERPROG
@@ -78,7 +77,7 @@ diff -urp pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
  #endif
  
  /* Random value for struct thread's `magic' member.
-@@ -75,6 +76,7 @@ thread_init (void) 
+@@ -80,6 +81,7 @@ thread_init (void) 
    init_thread (initial_thread, "main", PRI_DEFAULT);
    initial_thread->status = THREAD_RUNNING;
    initial_thread->tid = allocate_tid ();
@@ -86,7 +85,7 @@ diff -urp pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
  }
  
  /* Starts preemptive thread scheduling by enabling interrupts.
-@@ -119,6 +121,7 @@ thread_create (const char *name, int pri
+@@ -148,6 +150,7 @@ thread_create (const char *name, int pri
    /* Initialize thread. */
    init_thread (t, name, priority);
    tid = t->tid = allocate_tid ();
@@ -94,7 +93,7 @@ diff -urp pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
  
    /* Stack frame for kernel_thread(). */
    kf = alloc_frame (t, sizeof *kf);
-@@ -195,16 +198,36 @@ thread_tid (void) 
+@@ -224,16 +227,36 @@ thread_tid (void) 
  void
  thread_exit (void) 
  {
@@ -132,7 +131,7 @@ diff -urp pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
    schedule ();
    NOT_REACHED ();
  }
-@@ -241,6 +264,26 @@ thread_block (void) 
+@@ -270,6 +293,26 @@ thread_block (void) 
    thread_current ()->status = THREAD_BLOCKED;
    schedule ();
  }
@@ -159,7 +158,7 @@ diff -urp pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
  \f
  /* Idle thread.  Executes when no other thread is ready to run. */
  static void
-@@ -306,6 +349,12 @@ init_thread (struct thread *t, const cha
+@@ -335,6 +378,12 @@ init_thread (struct thread *t, const cha
    strlcpy (t->name, name, sizeof t->name);
    t->stack = (uint8_t *) t + PGSIZE;
    t->priority = priority;
@@ -172,12 +171,9 @@ diff -urp pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
    t->magic = THREAD_MAGIC;
  }
  
-Only in pintos/src/threads: thread.c.orig
-Only in pintos/src/threads: thread.c.rej
-Only in pintos/src/threads: thread.c~
-diff -urp pintos.orig/src/threads/thread.h pintos/src/threads/thread.h
---- pintos.orig/src/threads/thread.h   2004-09-20 15:29:18.000000000 -0700
-+++ pintos/src/threads/thread.h        2004-09-22 00:30:05.000000000 -0700
+diff -urpN pintos.orig/src/threads/thread.h pintos/src/threads/thread.h
+--- pintos.orig/src/threads/thread.h   2004-09-26 14:15:17.000000000 -0700
++++ pintos/src/threads/thread.h        2004-09-27 16:41:17.000000000 -0700
 @@ -4,6 +4,7 @@
  #include <debug.h>
  #include <list.h>
@@ -210,7 +206,7 @@ diff -urp pintos.orig/src/threads/thread.h pintos/src/threads/thread.h
  #endif
  
      /* Owned by thread.c */
-@@ -117,7 +129,7 @@ void thread_yield (void);
+@@ -119,7 +131,7 @@ void thread_yield (void);
  void thread_block (void);
  
  /* This function will be implemented in problem 1-2. */
@@ -219,11 +215,10 @@ diff -urp pintos.orig/src/threads/thread.h pintos/src/threads/thread.h
  
  /* These functions will be implemented in problem 1-3. */
  void thread_set_priority (int);
-Only in pintos/src/userprog: build
-diff -urp pintos.orig/src/userprog/exception.c pintos/src/userprog/exception.c
---- pintos.orig/src/userprog/exception.c       2004-09-20 12:06:58.000000000 -0700
-+++ pintos/src/userprog/exception.c    2004-09-22 00:30:05.000000000 -0700
-@@ -134,6 +134,13 @@ page_fault (struct intr_frame *f) 
+diff -urpN pintos.orig/src/userprog/exception.c pintos/src/userprog/exception.c
+--- pintos.orig/src/userprog/exception.c       2004-09-26 14:15:17.000000000 -0700
++++ pintos/src/userprog/exception.c    2004-09-27 16:41:17.000000000 -0700
+@@ -147,6 +147,13 @@ page_fault (struct intr_frame *f) 
    write = (f->error_code & PF_W) != 0;
    user = (f->error_code & PF_U) != 0;
  
@@ -237,25 +232,9 @@ diff -urp pintos.orig/src/userprog/exception.c pintos/src/userprog/exception.c
    /* To implement virtual memory, delete the rest of the function
       body, and replace it with code that brings in the page to
       which fault_addr refers. */
-diff -urp pintos.orig/src/userprog/pagedir.c pintos/src/userprog/pagedir.c
---- pintos.orig/src/userprog/pagedir.c 2004-09-21 22:42:17.000000000 -0700
-+++ pintos/src/userprog/pagedir.c      2004-09-22 00:32:23.000000000 -0700
-@@ -99,7 +99,7 @@ pagedir_set_page (uint32_t *pd, void *up
-   ASSERT (pg_ofs (upage) == 0);
-   ASSERT (pg_ofs (kpage) == 0);
-   ASSERT (upage < PHYS_BASE);
--  ASSERT (lookup_page (pd, upage, false) == NULL);
-+  ASSERT (pagedir_get_page (pd, upage) == NULL);
-   pte = lookup_page (pd, upage, true);
-   if (pte != NULL) 
-Only in pintos/src/userprog: pagedir.c.orig
-Only in pintos/src/userprog: pagedir.c.rej
-Only in pintos/src/userprog: pagedir.c.rej~
-Only in pintos/src/userprog: pagedir.c~
-diff -urp pintos.orig/src/userprog/process.c pintos/src/userprog/process.c
---- pintos.orig/src/userprog/process.c 2004-09-21 22:42:17.000000000 -0700
-+++ pintos/src/userprog/process.c      2004-09-22 00:30:05.000000000 -0700
+diff -urpN pintos.orig/src/userprog/process.c pintos/src/userprog/process.c
+--- pintos.orig/src/userprog/process.c 2004-09-22 17:58:29.000000000 -0700
++++ pintos/src/userprog/process.c      2004-09-27 16:41:17.000000000 -0700
 @@ -182,7 +182,7 @@ struct Elf32_Phdr
  #define PF_R 4          /* Readable. */
  
@@ -391,7 +370,7 @@ diff -urp pintos.orig/src/userprog/process.c pintos/src/userprog/process.c
    uint8_t *kpage;
    bool success = false;
 @@ -382,9 +462,9 @@ setup_stack (void **esp) 
-   kpage = palloc_get (PAL_USER | PAL_ZERO);
+   kpage = palloc_get_page (PAL_USER | PAL_ZERO);
    if (kpage != NULL) 
      {
 -      success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage);
@@ -401,12 +380,11 @@ diff -urp pintos.orig/src/userprog/process.c pintos/src/userprog/process.c
 +      if (install_page (upage, kpage))
 +        success = init_cmdline (kpage, upage, cmdline, esp);
        else
-         palloc_free (kpage);
+         palloc_free_page (kpage);
      }
-Only in pintos/src/userprog: process.c.orig
-diff -urp pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
---- pintos.orig/src/userprog/syscall.c 2004-09-05 22:19:19.000000000 -0700
-+++ pintos/src/userprog/syscall.c      2004-09-22 00:30:05.000000000 -0700
+diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
+--- pintos.orig/src/userprog/syscall.c 2004-09-26 14:15:17.000000000 -0700
++++ pintos/src/userprog/syscall.c      2004-09-27 16:43:00.000000000 -0700
 @@ -1,20 +1,429 @@
  #include "userprog/syscall.h"
  #include <stdio.h>
@@ -423,9 +401,10 @@ diff -urp pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +#include "threads/mmu.h"
 +#include "threads/palloc.h"
  #include "threads/thread.h"
+-
++ 
 +typedef int syscall_function (int, int, int);
-+
++ 
 +static int sys_halt (void);
 +static int sys_exit (int status);
 +static int sys_exec (const char *ufile);
@@ -439,13 +418,13 @@ diff -urp pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +static int sys_seek (int handle, unsigned position);
 +static int sys_tell (int handle);
 +static int sys_close (int handle);
-+
++ 
 +struct syscall 
 +  {
 +    size_t arg_cnt;
 +    syscall_function *func;
 +  };
-+
++ 
 +struct syscall syscall_table[] = 
 +  {
 +    {0, (syscall_function *) sys_halt},
@@ -463,85 +442,88 @@ diff -urp pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +    {1, (syscall_function *) sys_close},
 +  };
 +static const int syscall_cnt = sizeof syscall_table / sizeof *syscall_table;
-+
++ 
  static void syscall_handler (struct intr_frame *);
+-
 +static void copy_in (void *, const void *, size_t);
-+
++ 
 +static struct lock fs_lock;
++ 
  void
  syscall_init (void) 
  {
    intr_register (0x30, 3, INTR_ON, syscall_handler, "syscall");
 +  lock_init (&fs_lock, "fs");
  }
+-
++ 
  static void
- syscall_handler (struct intr_frame *f) 
+-syscall_handler (struct intr_frame *f UNUSED) 
++syscall_handler (struct intr_frame *f) 
  {
 -  printf ("system call!\n");
 +  struct syscall *s;
 +  int call_nr;
 +  int args[3];
-+
++ 
 +  copy_in (&call_nr, f->esp, sizeof call_nr);
 +  if (call_nr < 0 || call_nr >= syscall_cnt)
 +    {
 +      printf ("bad syscall number %d\n", call_nr);
 +      thread_exit ();
 +    }
-+
++ 
 +  s = syscall_table + call_nr;
 +  ASSERT (s->arg_cnt <= sizeof args / sizeof *args);
 +  memset (args, 0, sizeof args);
 +  copy_in (args, (uint32_t *) f->esp + 1, sizeof *args * s->arg_cnt);
 +  f->eax = s->func (args[0], args[1], args[2]);
 +}
-+
++ 
 +static bool
 +verify_user (const void *uaddr) 
 +{
 +  return pagedir_get_page (thread_current ()->pagedir, uaddr) != NULL;
 +}
-+
++ 
 +static inline bool get_user (uint8_t *dst, const uint8_t *usrc) {
 +  int eax;
 +  asm ("movl $1f, %%eax; movb %2, %%al; movb %%al, %0; 1:"
 +       : "=m" (*dst), "=&a" (eax) : "m" (*usrc));
 +  return eax != 0;
 +}
-+
++ 
 +static inline bool put_user (uint8_t *udst, uint8_t byte) {
 +  int eax;
 +  asm ("movl $1f, %%eax; movb %b2, %0; 1:"
 +       : "=m" (*udst), "=&a" (eax) : "r" (byte));
 +  return eax != 0;
 +}
-+
++ 
 +static void
 +copy_in (void *dst_, const void *usrc_, size_t size) 
 +{
 +  uint8_t *dst = dst_;
 +  const uint8_t *usrc = usrc_;
-+
++ 
 +  for (; size > 0; size--, dst++, usrc++) 
 +    if (usrc >= (uint8_t *) PHYS_BASE || !get_user (dst, usrc)) 
 +      thread_exit ();
 +}
-+
++ 
 +static char *
 +copy_in_string (const char *us) 
 +{
 +  char *ks;
 +  size_t length;
-+
-+  ks = palloc_get (0);
++ 
++  ks = palloc_get_page (0);
 +  if (ks == NULL) 
 +    {
 +      printf ("copy_in_string: out of memory\n");
 +      thread_exit ();
 +    }
-+
++ 
 +  for (length = 0; length < PGSIZE; length++)
 +    {
 +      if (us >= (char *) PHYS_BASE || !get_user (ks + length, us++)) 
@@ -549,22 +531,22 @@ diff -urp pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +          printf ("bad user reference (%p)\n", us + length);
 +          thread_exit (); 
 +        }
-+      
++       
 +      if (ks[length] == '\0')
 +        return ks;
 +    }
-+
++ 
 +  printf ("copy_in_string: string too long\n");
-+  palloc_free (ks);
++  palloc_free_page (ks);
 +  thread_exit ();
 +}
-+
++ 
 +static int
 +sys_halt (void)
 +{
 +  power_off ();
 +}
-+
++ 
 +static int
 +sys_exit (int ret_code) 
 +{
@@ -572,76 +554,76 @@ diff -urp pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +  thread_exit ();
 +  NOT_REACHED ();
 +}
-+
++ 
 +static int
 +sys_exec (const char *ufile) 
 +{
 +  tid_t tid;
 +  char *kfile = copy_in_string (ufile);
-+
++ 
 +  lock_acquire (&fs_lock);
 +  tid = process_execute (kfile);
 +  lock_release (&fs_lock);
-+
-+  palloc_free (kfile);
-+
++ 
++  palloc_free_page (kfile);
++ 
 +  return tid;
 +}
-+
++ 
 +static int
 +sys_join (tid_t child) 
 +{
 +  return thread_join (child);
 +}
-+
++ 
 +static int
 +sys_create (const char *ufile, unsigned initial_size) 
 +{
 +  char *kfile = copy_in_string (ufile);
 +  bool ok;
-+  
++   
 +  lock_acquire (&fs_lock);
 +  ok = filesys_create (kfile, initial_size);
 +  lock_release (&fs_lock);
-+
-+  palloc_free (kfile);
-+
++ 
++  palloc_free_page (kfile);
++ 
 +  return ok;
 +}
-+
++ 
 +static int
 +sys_remove (const char *ufile) 
 +{
 +  char *kfile = copy_in_string (ufile);
 +  bool ok;
-+  
++   
 +  lock_acquire (&fs_lock);
 +  ok = filesys_remove (kfile);
 +  lock_release (&fs_lock);
-+
-+  palloc_free (kfile);
-+
++ 
++  palloc_free_page (kfile);
++ 
 +  return ok;
 +}
-+
++ 
 +struct fildes
 +  {
 +    list_elem elem;
 +    struct file *file;
 +    int handle;
 +  };
-+
++ 
 +static int
 +sys_open (const char *ufile) 
 +{
 +  char *kfile = copy_in_string (ufile);
 +  struct fildes *fd;
 +  int handle = -1;
-+
++ 
 +  fd = malloc (sizeof *fd);
 +  if (fd == NULL)
 +    goto exit;
-+
++ 
 +  lock_acquire (&fs_lock);
 +  fd->file = filesys_open (kfile);
 +  if (fd->file != NULL)
@@ -653,18 +635,18 @@ diff -urp pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +  else 
 +    free (fd);
 +  lock_release (&fs_lock);
-+
++ 
 + exit:
-+  palloc_free (kfile);
++  palloc_free_page (kfile);
 +  return handle;
 +}
-+
++ 
 +static struct fildes *
 +lookup_fd (int handle) 
 +{
 +  struct thread *cur = thread_current ();
 +  list_elem *e;
-+  
++   
 +  for (e = list_begin (&cur->fds); e != list_end (&cur->fds);
 +       e = list_next (e))
 +    {
@@ -672,31 +654,31 @@ diff -urp pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +      if (fd->handle == handle)
 +        return fd;
 +    }
-+
++ 
 +  printf ("no handle %d\n", handle);
    thread_exit ();
  }
-+
++ 
 +static int
 +sys_filesize (int handle) 
 +{
 +  struct fildes *fd = lookup_fd (handle);
 +  int size;
-+
++ 
 +  lock_acquire (&fs_lock);
 +  size = file_length (fd->file);
 +  lock_release (&fs_lock);
-+
++ 
 +  return size;
 +}
-+
++ 
 +static int
 +sys_read (int handle, void *udst_, unsigned size) 
 +{
 +  uint8_t *udst = udst_;
 +  struct fildes *fd;
 +  int bytes_read = 0;
-+
++ 
 +  if (handle == STDIN_FILENO) 
 +    {
 +      for (bytes_read = 0; (size_t) bytes_read < size; bytes_read++)
@@ -704,7 +686,7 @@ diff -urp pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +          thread_exit ();
 +      return bytes_read;
 +    }
-+
++ 
 +  lock_acquire (&fs_lock);
 +  fd = lookup_fd (handle);
 +  while (size > 0) 
@@ -712,13 +694,13 @@ diff -urp pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +      size_t page_left = PGSIZE - pg_ofs (udst);
 +      size_t read_amt = size < page_left ? size : page_left;
 +      off_t retval;
-+
++ 
 +      if (!verify_user (udst)) 
 +        {
 +          lock_release (&fs_lock);
 +          thread_exit ();
 +        }
-+      
++       
 +      retval = file_read (fd->file, udst, read_amt);
 +      if (retval < 0)
 +        {
@@ -726,26 +708,26 @@ diff -urp pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +            bytes_read = -1; 
 +          break;
 +        }
-+
++ 
 +      bytes_read += retval;
 +      if (retval != (off_t) read_amt)
 +        break;
-+
++ 
 +      udst += retval;
 +      size -= retval;
 +    }
 +  lock_release (&fs_lock);
-+  
++   
 +  return bytes_read;
 +}
-+
++ 
 +static int
 +sys_write (int handle, void *usrc_, unsigned size) 
 +{
 +  uint8_t *usrc = usrc_;
 +  struct fildes *fd = NULL;
 +  int bytes_written = 0;
-+
++ 
 +  lock_acquire (&fs_lock);
 +  if (handle != STDOUT_FILENO)
 +    fd = lookup_fd (handle);
@@ -754,13 +736,13 @@ diff -urp pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +      size_t page_left = PGSIZE - pg_ofs (usrc);
 +      size_t write_amt = size < page_left ? size : page_left;
 +      off_t retval;
-+
++ 
 +      if (!verify_user (usrc)) 
 +        {
 +          lock_release (&fs_lock);
 +          thread_exit ();
 +        }
-+
++ 
 +      if (handle == STDOUT_FILENO)
 +        {
 +          putbuf (usrc, write_amt);
@@ -774,44 +756,44 @@ diff -urp pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +            bytes_written = -1;
 +          break;
 +        }
-+
++ 
 +      bytes_written += retval;
 +      if (retval != (off_t) write_amt)
 +        break;
-+
++ 
 +      usrc += retval;
 +      size -= retval;
 +    }
 +  lock_release (&fs_lock);
-+
++ 
 +  return bytes_written;
 +}
-+
++ 
 +static int
 +sys_seek (int handle, unsigned position) 
 +{
 +  struct fildes *fd = lookup_fd (handle);
-+  
++   
 +  lock_acquire (&fs_lock);
 +  file_seek (fd->file, position);
 +  lock_release (&fs_lock);
-+
++ 
 +  return 0;
 +}
-+
++ 
 +static int
 +sys_tell (int handle) 
 +{
 +  struct fildes *fd = lookup_fd (handle);
 +  unsigned position;
-+  
++   
 +  lock_acquire (&fs_lock);
 +  position = file_tell (fd->file);
 +  lock_release (&fs_lock);
-+
++ 
 +  return position;
 +}
-+
++ 
 +static int
 +sys_close (int handle) 
 +{
@@ -823,13 +805,13 @@ diff -urp pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +  free (fd);
 +  return 0;
 +}
-+
++ 
 +void
 +syscall_exit (void) 
 +{
 +  struct thread *cur = thread_current ();
 +  list_elem *e, *next;
-+  
++   
 +  for (e = list_begin (&cur->fds); e != list_end (&cur->fds); e = next)
 +    {
 +      struct fildes *fd = list_entry (e, struct fildes, elem);
@@ -838,9 +820,9 @@ diff -urp pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +      free (fd);
 +    }
 +}
-diff -urp pintos.orig/src/userprog/syscall.h pintos/src/userprog/syscall.h
+diff -urpN pintos.orig/src/userprog/syscall.h pintos/src/userprog/syscall.h
 --- pintos.orig/src/userprog/syscall.h 2004-09-05 22:38:45.000000000 -0700
-+++ pintos/src/userprog/syscall.h      2004-09-22 00:30:05.000000000 -0700
++++ pintos/src/userprog/syscall.h      2004-09-27 16:41:17.000000000 -0700
 @@ -2,5 +2,6 @@
  #define USERPROG_SYSCALL_H
  
diff --git a/solutions/p3.patch b/solutions/p3.patch
new file mode 100644 (file)
index 0000000..078d12a
--- /dev/null
@@ -0,0 +1,1424 @@
+diff -urpN pintos.orig/src/Makefile.build pintos/src/Makefile.build
+--- pintos.orig/src/Makefile.build     2004-09-20 20:26:41.000000000 -0700
++++ pintos/src/Makefile.build  2004-09-27 13:29:43.000000000 -0700
+@@ -51,8 +51,9 @@ userprog_SRC += userprog/syscall.c   # Sys
+ userprog_SRC += userprog/gdt.c                # GDT initialization.
+ userprog_SRC += userprog/tss.c                # TSS management.
+-# No virtual memory code yet.
+-#vm_SRC = vm/filename.c                       # Some file.
++# Virtual memory code.
++vm_SRC = vm/pageframe.c                       # Page frame management.
++vm_SRC += vm/swap.c                   # Swap file management.
+ # Filesystem code.
+ filesys_SRC  = filesys/filesys.c      # Filesystem core.
+diff -urpN pintos.orig/src/constants.h pintos/src/constants.h
+--- pintos.orig/src/constants.h        2004-09-21 17:26:39.000000000 -0700
++++ pintos/src/constants.h     2004-09-27 13:29:43.000000000 -0700
+@@ -8,4 +8,4 @@
+ /*#define MACRONAME 1 */
+ /* Uncomment if if you've implemented thread_join(). */
+-/*#define THREAD_JOIN_IMPLEMENTED 1*/
++#define THREAD_JOIN_IMPLEMENTED 1
+diff -urpN pintos.orig/src/threads/init.c pintos/src/threads/init.c
+--- pintos.orig/src/threads/init.c     2004-09-26 14:15:17.000000000 -0700
++++ pintos/src/threads/init.c  2004-09-27 16:08:03.000000000 -0700
+@@ -21,12 +21,15 @@
+ #include "threads/test.h"
+ #include "threads/thread.h"
+ #ifdef USERPROG
++#include "userprog/pagedir.h"
+ #include "userprog/process.h"
+ #include "userprog/exception.h"
+ #include "userprog/gdt.h"
+ #include "userprog/syscall.h"
+ #include "userprog/tss.h"
+ #endif
++#include "vm/pageframe.h"
++#include "vm/swap.h"
+ #ifdef FILESYS
+ #include "devices/disk.h"
+ #include "filesys/filesys.h"
+@@ -78,6 +81,7 @@ main (void)
+   /* Initialize memory system, segments, paging. */
+   palloc_init ();
+   paging_init ();
++  pageframe_init ();
+ #ifdef USERPROG
+   tss_init ();
+   gdt_init ();
+@@ -105,6 +109,7 @@ main (void)
+   disk_init ();
+   filesys_init (format_filesys);
+   fsutil_run ();
++  swap_init ();
+ #endif
+   printf ("Boot complete.\n");
+diff -urpN pintos.orig/src/threads/palloc.c pintos/src/threads/palloc.c
+diff -urpN pintos.orig/src/threads/palloc.h pintos/src/threads/palloc.h
+diff -urpN pintos.orig/src/threads/synch.c pintos/src/threads/synch.c
+--- pintos.orig/src/threads/synch.c    2004-09-19 21:29:53.000000000 -0700
++++ pintos/src/threads/synch.c 2004-09-27 13:29:43.000000000 -0700
+@@ -330,3 +330,35 @@ cond_name (const struct condition *cond)
+   return cond->name;
+ }
++\f
++void
++latch_init (struct latch *latch, const char *name) 
++{
++  latch->released = false;
++  lock_init (&latch->monitor_lock, name);
++  cond_init (&latch->rel_cond, name);
++}
++
++void
++latch_acquire (struct latch *latch) 
++{
++  lock_acquire (&latch->monitor_lock);
++  if (!latch->released) 
++    {
++      cond_wait (&latch->rel_cond, &latch->monitor_lock);
++      ASSERT (latch->released); 
++    }
++  lock_release (&latch->monitor_lock);
++}
++
++void
++latch_release (struct latch *latch) 
++{
++  lock_acquire (&latch->monitor_lock);
++  if (!latch->released)
++    {
++      latch->released = true;
++      cond_signal (&latch->rel_cond, &latch->monitor_lock);
++    }
++  lock_release (&latch->monitor_lock);
++}
+diff -urpN pintos.orig/src/threads/synch.h pintos/src/threads/synch.h
+--- pintos.orig/src/threads/synch.h    2004-09-19 21:29:53.000000000 -0700
++++ pintos/src/threads/synch.h 2004-09-27 13:29:43.000000000 -0700
+@@ -44,4 +44,16 @@ void cond_signal (struct condition *, st
+ void cond_broadcast (struct condition *, struct lock *);
+ const char *cond_name (const struct condition *);
++/* Latch. */
++struct latch 
++  {
++    bool released;              /* Released yet? */
++    struct lock monitor_lock;   /* Monitor lock. */
++    struct condition rel_cond;  /* Signaled when released. */
++  };
++
++void latch_init (struct latch *, const char *);
++void latch_acquire (struct latch *);
++void latch_release (struct latch *);
++
+ #endif /* threads/synch.h */
+diff -urpN pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
+--- pintos.orig/src/threads/thread.c   2004-09-26 14:15:17.000000000 -0700
++++ pintos/src/threads/thread.c        2004-09-27 13:29:43.000000000 -0700
+@@ -13,6 +13,7 @@
+ #include "threads/synch.h"
+ #ifdef USERPROG
+ #include "userprog/process.h"
++#include "userprog/syscall.h"
+ #endif
+ /* Random value for struct thread's `magic' member.
+@@ -80,6 +81,7 @@ thread_init (void) 
+   init_thread (initial_thread, "main", PRI_DEFAULT);
+   initial_thread->status = THREAD_RUNNING;
+   initial_thread->tid = allocate_tid ();
++  sema_up (&initial_thread->can_die);
+ }
+ /* Starts preemptive thread scheduling by enabling interrupts.
+@@ -148,6 +150,7 @@ thread_create (const char *name, int pri
+   /* Initialize thread. */
+   init_thread (t, name, priority);
+   tid = t->tid = allocate_tid ();
++  list_push_back (&thread_current ()->children, &t->children_elem);
+   /* Stack frame for kernel_thread(). */
+   kf = alloc_frame (t, sizeof *kf);
+@@ -224,16 +227,36 @@ thread_tid (void) 
+ void
+ thread_exit (void) 
+ {
++  struct thread *t = thread_current ();
++  list_elem *e, *next;
++
+   ASSERT (!intr_context ());
+ #ifdef USERPROG
+   process_exit ();
+ #endif
++  syscall_exit ();
++  
++  /* Notify our parent that we're dying. */
++  latch_release (&t->ready_to_die);
++
++  /* Notify our children that they can die. */
++  for (e = list_begin (&t->children); e != list_end (&t->children);
++       e = next) 
++    {
++      struct thread *child = list_entry (e, struct thread, children_elem);
++      next = list_next (e);
++      list_remove (e);
++      sema_up (&child->can_die); 
++    }
++
++  /* Wait until our parent is ready for us to die. */
++  sema_down (&t->can_die);
+   /* Just set our status to dying and schedule another process.
+      We will be destroyed during the call to schedule_tail(). */
+   intr_disable ();
+-  thread_current ()->status = THREAD_DYING;
++  t->status = THREAD_DYING;
+   schedule ();
+   NOT_REACHED ();
+ }
+@@ -270,6 +293,26 @@ thread_block (void) 
+   thread_current ()->status = THREAD_BLOCKED;
+   schedule ();
+ }
++
++/* Waits for thread with tid CHILD_TID to die. */
++int
++thread_join (tid_t child_tid) 
++{
++  struct thread *cur = thread_current ();
++  list_elem *e;
++
++  for (e = list_begin (&cur->children); e != list_end (&cur->children); ) 
++    {
++      struct thread *child = list_entry (e, struct thread, children_elem);
++      e = list_next (e);
++      if (child->tid == child_tid) 
++        {
++          latch_acquire (&child->ready_to_die);
++          return child->ret_code; 
++        }
++    }
++  return -1;
++}
\f
+ /* Idle thread.  Executes when no other thread is ready to run. */
+ static void
+@@ -335,6 +378,12 @@ init_thread (struct thread *t, const cha
+   strlcpy (t->name, name, sizeof t->name);
+   t->stack = (uint8_t *) t + PGSIZE;
+   t->priority = priority;
++  latch_init (&t->ready_to_die, "ready-to-die");
++  sema_init (&t->can_die, 0, "can-die");
++  list_init (&t->children);
++  t->ret_code = -1;
++  list_init (&t->fds);
++  t->next_handle = 2;
+   t->magic = THREAD_MAGIC;
+ }
+diff -urpN pintos.orig/src/threads/thread.h pintos/src/threads/thread.h
+--- pintos.orig/src/threads/thread.h   2004-09-26 14:15:17.000000000 -0700
++++ pintos/src/threads/thread.h        2004-09-27 13:29:43.000000000 -0700
+@@ -2,8 +2,10 @@
+ #define THREADS_THREAD_H
+ #include <debug.h>
++#include <hash.h>
+ #include <list.h>
+ #include <stdint.h>
++#include "threads/synch.h"
+ /* States in a thread's life cycle. */
+ enum thread_status
+@@ -89,12 +91,24 @@ struct thread
+     uint8_t *stack;                     /* Saved stack pointer. */
+     int priority;                       /* Priority. */
++    /* Members for implementing thread_join(). */
++    struct latch ready_to_die;          /* Release when thread about to die. */
++    struct semaphore can_die;           /* Up when thread allowed to die. */
++    struct list children;               /* List of child threads. */
++    list_elem children_elem;            /* Element of `children' list. */
++    int ret_code;                       /* Return status. */
++
+     /* Shared between thread.c and synch.c. */
+     list_elem elem;                     /* List element. */
+ #ifdef USERPROG
+     /* Owned by userprog/process.c. */
+     uint32_t *pagedir;                  /* Page directory. */
++    struct hash pages;                  /* Hash of `struct user_page's. */
++
++    /* Owned by syscall.c. */
++    struct list fds;                    /* List of file descriptors. */
++    int next_handle;                    /* Next handle value. */
+ #endif
+     /* Owned by thread.c */
+@@ -119,7 +133,7 @@ void thread_yield (void);
+ void thread_block (void);
+ /* This function will be implemented in problem 1-2. */
+-void thread_join (tid_t);
++int thread_join (tid_t);
+ /* These functions will be implemented in problem 1-3. */
+ void thread_set_priority (int);
+diff -urpN pintos.orig/src/userprog/exception.c pintos/src/userprog/exception.c
+--- pintos.orig/src/userprog/exception.c       2004-09-26 14:15:17.000000000 -0700
++++ pintos/src/userprog/exception.c    2004-09-27 13:29:44.000000000 -0700
+@@ -1,9 +1,16 @@
+ #include "userprog/exception.h"
+ #include <inttypes.h>
+ #include <stdio.h>
++#include <string.h>
+ #include "userprog/gdt.h"
++#include "userprog/pagedir.h"
++#include "userprog/process.h"
++#include "filesys/file.h"
+ #include "threads/interrupt.h"
++#include "threads/mmu.h"
+ #include "threads/thread.h"
++#include "vm/pageframe.h"
++#include "vm/swap.h"
+ /* Number of page faults processed. */
+ static long long page_fault_cnt;
+@@ -124,10 +131,13 @@ kill (struct intr_frame *f) 
+ static void
+ page_fault (struct intr_frame *f) 
+ {
++  struct thread *t;
+   bool not_present;  /* True: not-present page, false: writing r/o page. */
+   bool write;        /* True: access was write, false: access was read. */
+   bool user;         /* True: access by user, false: access by kernel. */
+   void *fault_addr;  /* Fault address. */
++  struct user_page tmp_up, *up;
++  hash_elem *e;
+   /* Obtain faulting address, the virtual address that was
+      accessed to cause the fault.  It may point to code or to
+@@ -147,14 +157,62 @@ page_fault (struct intr_frame *f) 
+   write = (f->error_code & PF_W) != 0;
+   user = (f->error_code & PF_U) != 0;
+-  /* To implement virtual memory, delete the rest of the function
+-     body, and replace it with code that brings in the page to
+-     which fault_addr refers. */
+-  printf ("Page fault at %p: %s error %s page in %s context.\n",
+-          fault_addr,
+-          not_present ? "not present" : "rights violation",
+-          write ? "writing" : "reading",
+-          user ? "user" : "kernel");
+-  kill (f);
++  if (!not_present) 
++    goto bad_access;
++
++  t = thread_current ();
++  if (t->pagedir == NULL)
++    goto bad_access;
++
++  //printf ("fault %p (page=%p)\n", fault_addr, pg_round_down (fault_addr));
++  tmp_up.upage = pg_round_down (fault_addr);
++  e = hash_find (&t->pages, &tmp_up.elem);
++  if (e == NULL) 
++    {
++      printf ("no user_page for %p\n", fault_addr);
++      goto bad_access; 
++    }
++  up = hash_entry (e, struct user_page, elem);
++
++  if (up->frame == NULL) 
++    {
++      if (!pageframe_allocate (up))
++        {
++          printf ("virtual memory exhausted, killing process\n");
++          if (!user)
++            goto bad_access;
++          thread_exit ();
++        }
++      if (up->file != NULL) 
++        {
++          off_t amt = file_read_at (up->file,
++                                    up->frame->kpage, up->file_size,
++                                    up->file_ofs);
++          ASSERT (amt == (off_t) up->file_size);
++          memset (up->frame->kpage + up->file_size, 0, PGSIZE - up->file_size);
++        }
++      else if (up->swap_page != SIZE_MAX)
++        swap_read (up);
++      else
++        memset (up->frame->kpage, 0, PGSIZE);
++    }
++  pagedir_set_page (t->pagedir, up->upage, up->frame->kpage, true);
++  return;
++
++ bad_access:
++  if (user || fault_addr > PHYS_BASE) 
++    {
++      printf ("Page fault at %p: %s error %s page in %s context.\n",
++              fault_addr,
++              not_present ? "not present" : "rights violation",
++              write ? "writing" : "reading",
++              user ? "user" : "kernel");
++      kill (f);
++    }
++  else
++    {
++      f->eip = (void (*) (void)) f->eax;
++      f->eax = 0;
++    }
+ }
+diff -urpN pintos.orig/src/userprog/process.c pintos/src/userprog/process.c
+--- pintos.orig/src/userprog/process.c 2004-09-22 17:58:29.000000000 -0700
++++ pintos/src/userprog/process.c      2004-09-27 14:43:09.000000000 -0700
+@@ -7,15 +7,18 @@
+ #include "userprog/gdt.h"
+ #include "userprog/pagedir.h"
+ #include "userprog/tss.h"
++#include "vm/pageframe.h"
+ #include "filesys/directory.h"
+ #include "filesys/file.h"
+ #include "filesys/filesys.h"
+ #include "threads/flags.h"
+ #include "threads/init.h"
+ #include "threads/interrupt.h"
++#include "threads/malloc.h"
+ #include "threads/mmu.h"
+ #include "threads/palloc.h"
+ #include "threads/thread.h"
++#include "vm/swap.h"
+ static thread_func execute_thread NO_RETURN;
+ static bool load (const char *cmdline, void (**eip) (void), void **esp);
+@@ -100,6 +103,10 @@ process_exit (void)
+       cur->pagedir = NULL;
+       pagedir_activate (NULL);
+       pagedir_destroy (pd);
++
++      /* We maintain the invariant that `hash' is initialized iff
++         `pd != NULL'. */
++      hash_destroy (&cur->pages);
+     }
+ }
+@@ -182,7 +189,10 @@ struct Elf32_Phdr
+ #define PF_R 4          /* Readable. */
+ static bool load_segment (struct file *, const struct Elf32_Phdr *);
+-static bool setup_stack (void **esp);
++static bool setup_stack (const char *cmdline, void **esp);
++static unsigned user_page_hash (const hash_elem *, void *);
++static bool user_page_less (const hash_elem *, const hash_elem *, void *);
++static struct user_page *make_user_page (void *upage);
+ /* Aborts loading an executable, with an error message. */
+ #define LOAD_ERROR(MSG)                                         \
+@@ -198,19 +208,35 @@ static bool setup_stack (void **esp);
+    and its initial stack pointer into *ESP.
+    Returns true if successful, false otherwise. */
+ bool
+-load (const char *filename, void (**eip) (void), void **esp) 
++load (const char *cmdline, void (**eip) (void), void **esp) 
+ {
+   struct thread *t = thread_current ();
++  char filename[NAME_MAX + 2];
+   struct Elf32_Ehdr ehdr;
+   struct file *file = NULL;
+   off_t file_ofs;
+   bool success = false;
++  char *cp;
+   int i;
++  /* Create hash of user pages. */
++  hash_init (&t->pages, user_page_hash, user_page_less, NULL);
++
+   /* Allocate page directory. */
+   t->pagedir = pagedir_create ();
+-  if (t->pagedir == NULL)
+-    LOAD_ERROR (("page directory allocation failed"));
++  if (t->pagedir == NULL) 
++    {
++      hash_destroy (&t->pages);
++      LOAD_ERROR (("page directory allocation failed")); 
++    }
++
++  /* Extract filename from command line. */
++  while (*cmdline == ' ')
++    cmdline++;
++  strlcpy (filename, cmdline, sizeof filename);
++  cp = strchr (filename, ' ');
++  if (cp != NULL)
++    *cp = '\0';
+   /* Open executable file. */
+   file = filesys_open (filename);
+@@ -269,8 +295,23 @@ load (const char *filename, void (**eip)
+     }
+   /* Set up stack. */
+-  if (!setup_stack (esp))
++  if (!setup_stack (cmdline, esp))
+     goto done;
++  
++#if 0
++  {
++    struct hash_iterator i;
++
++    hash_first (&i, &thread_current ()->pages);
++    while (hash_next (&i))
++      {
++        struct user_page *up = hash_entry (hash_cur (&i),
++                                           struct user_page, elem);
++        printf ("%08x ", up->upage);
++      }
++    printf ("\n");
++  }
++#endif
+   /* Start address. */
+   *eip = (void (*) (void)) ehdr.e_entry;
+@@ -279,14 +320,12 @@ load (const char *filename, void (**eip)
+  done:
+   /* We arrive here whether the load is successful or not. */
+-  file_close (file);
++  //file_close (file);                  // FIXME
+   return success;
+ }
\f
+ /* load() helpers. */
+-static bool install_page (void *upage, void *kpage);
+-
+ /* Loads the segment described by PHDR from FILE into user
+    address space.  Return true if successful, false otherwise. */
+ static bool
+@@ -296,6 +335,7 @@ load_segment (struct file *file, const s
+   uint8_t *upage;     /* Iterator from start to end. */
+   off_t filesz_left;  /* Bytes left of file data (as opposed to
+                          zero-initialized bytes). */
++  off_t file_ofs;
+   /* Is this a read-only segment?  Not currently used, so it's
+      commented out.  You'll want to use it when implementing VM
+@@ -340,70 +380,206 @@ load_segment (struct file *file, const s
+   /* Load the segment page-by-page into memory. */
+   filesz_left = phdr->p_filesz + (phdr->p_vaddr & PGMASK);
+-  file_seek (file, ROUND_DOWN (phdr->p_offset, PGSIZE));
++  file_ofs = ROUND_DOWN (phdr->p_offset, PGSIZE);
+   for (upage = start; upage < (uint8_t *) end; upage += PGSIZE) 
+     {
+       /* We want to read min(PGSIZE, filesz_left) bytes from the
+          file into the page and zero the rest. */
+       size_t read_bytes = filesz_left >= PGSIZE ? PGSIZE : filesz_left;
+-      size_t zero_bytes = PGSIZE - read_bytes;
+-      uint8_t *kpage = palloc_get_page (PAL_USER);
+-      if (kpage == NULL)
++      struct user_page *up = make_user_page (upage);
++      if (up == NULL)
+         return false;
+-      /* Do the reading and zeroing. */
+-      if (file_read (file, kpage, read_bytes) != (int) read_bytes) 
++      if (read_bytes > 0) 
+         {
+-          palloc_free_page (kpage);
+-          return false; 
++          /* Map page. */
++          up->file = file;
++          up->file_ofs = file_ofs;
++          up->file_size = read_bytes;
++          file_ofs += read_bytes;
+         }
+-      memset (kpage + read_bytes, 0, zero_bytes);
+-      filesz_left -= read_bytes;
+-
+-      /* Add the page to the process's address space. */
+-      if (!install_page (upage, kpage)) 
++      else 
+         {
+-          palloc_free_page (kpage);
+-          return false; 
++          /* Page is all zeros.  Nothing to do. */
+         }
++      filesz_left -= read_bytes;
+     }
++  
++  return true;
++}
++
++static void
++reverse (int argc, char **argv) 
++{
++  for (; argc > 1; argc -= 2, argv++) 
++    {
++      char *tmp = argv[0];
++      argv[0] = argv[argc - 1];
++      argv[argc - 1] = tmp;
++    }
++}
++static void *
++push (uint8_t *kpage, size_t *ofs, const void *buf, size_t size) 
++{
++  size_t padsize = ROUND_UP (size, sizeof (uint32_t));
++  if (*ofs < padsize)
++    return NULL;
++
++  *ofs -= padsize;
++  memcpy (kpage + *ofs + (padsize - size), buf, size);
++  return kpage + *ofs + (padsize - size);
++}
++
++static bool
++init_cmdline (uint8_t *kpage, uint8_t *upage, const char *cmdline,
++              void **esp) 
++{
++  size_t ofs = PGSIZE;
++  char *const null = NULL;
++  char *cmdline_copy;
++  char *karg, *saveptr;
++  int argc;
++  char **argv;
++
++  /* Push command line string. */
++  cmdline_copy = push (kpage, &ofs, cmdline, strlen (cmdline) + 1);
++  if (cmdline_copy == NULL)
++    return false;
++
++  if (push (kpage, &ofs, &null, sizeof null) == NULL)
++    return false;
++
++  /* Parse command line into arguments
++     and push them in reverse order. */
++  argc = 0;
++  for (karg = strtok_r (cmdline_copy, " ", &saveptr); karg != NULL;
++       karg = strtok_r (NULL, " ", &saveptr))
++    {
++      char *uarg = upage + (karg - (char *) kpage);
++      if (push (kpage, &ofs, &uarg, sizeof uarg) == NULL)
++        return false;
++      argc++;
++    }
++
++  /* Reverse the order of the command line arguments. */
++  argv = (char **) (upage + ofs);
++  reverse (argc, (char **) (kpage + ofs));
++
++  /* Push argv, argc, "return address". */
++  if (push (kpage, &ofs, &argv, sizeof argv) == NULL
++      || push (kpage, &ofs, &argc, sizeof argc) == NULL
++      || push (kpage, &ofs, &null, sizeof null) == NULL)
++    return false;
++
++  /* Set initial stack pointer. */
++  *esp = upage + ofs;
+   return true;
+ }
+-/* Create a minimal stack by mapping a zeroed page at the top of
+-   user virtual memory. */
++/* Create a minimal stack for T by mapping a page at the
++   top of user virtual memory.  Fills in the page using CMDLINE
++   and sets *ESP to the stack pointer. */
+ static bool
+-setup_stack (void **esp) 
++setup_stack (const char *cmdline, void **esp) 
+ {
+-  uint8_t *kpage;
+-  bool success = false;
++  struct user_page *up = make_user_page ((uint8_t *) PHYS_BASE - PGSIZE);
++  return (up != NULL
++          && pageframe_allocate (up)
++          && init_cmdline (up->frame->kpage, up->upage, cmdline, esp));
++}
++
++static unsigned
++user_page_hash (const hash_elem *e, void *aux UNUSED) 
++{
++  struct user_page *up = hash_entry (e, struct user_page, elem);
++  return hash_bytes (&up->upage, sizeof up->upage);
++}
+-  kpage = palloc_get_page (PAL_USER | PAL_ZERO);
+-  if (kpage != NULL) 
++static bool
++user_page_less (const hash_elem *a_, const hash_elem *b_, void *aux UNUSED) 
++{
++  struct user_page *a = hash_entry (a_, struct user_page, elem);
++  struct user_page *b = hash_entry (b_, struct user_page, elem);
++
++  return a->upage < b->upage;
++}
++
++static struct user_page *
++make_user_page (void *upage) 
++{
++  struct user_page *up;
++
++  up = malloc (sizeof *up);
++  if (up != NULL) 
+     {
+-      success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage);
+-      if (success)
+-        *esp = PHYS_BASE;
++      memset (up, 0, sizeof *up);
++      up->swap_page = SIZE_MAX;
++
++      up->upage = upage;
++      if (hash_insert (&thread_current ()->pages, &up->elem) != NULL) 
++        {
++          free (up);
++          up = NULL;
++        }
++#if 0
+       else
+-        palloc_free_page (kpage);
++        printf ("make_user_page(%p) okay\n", upage);
++#endif
+     }
+-  else
+-    printf ("failed to allocate process stack\n");
+-  return success;
++  return up;
+ }
+-/* Adds a mapping from user virtual address UPAGE to kernel
+-   virtual address KPAGE to the page table.  Fails if UPAGE is
+-   already mapped or if memory allocation fails. */
+-static bool
+-install_page (void *upage, void *kpage)
++static void
++dump_page (struct user_page *up) 
+ {
+-  struct thread *t = thread_current ();
++  off_t amt;
+-  /* Verify that there's not already a page at that virtual
+-     address, then map our page there. */
+-  return (pagedir_get_page (t->pagedir, upage) == NULL
+-          && pagedir_set_page (t->pagedir, upage, kpage, true));
++  ASSERT (up->file != NULL);
++  up->file_size = PGSIZE;
++  amt = file_write_at (up->file, up->frame->kpage,
++                       up->file_size, up->file_ofs);
++  ASSERT (amt == (off_t) up->file_size);
+ }
++
++bool
++process_evict_page (struct thread *t, struct user_page *up) 
++{
++  ASSERT (up->frame != NULL);
++
++  if (pagedir_test_accessed (t->pagedir, up->upage)) 
++    {
++      pagedir_clear_accessed (t->pagedir, up->upage);
++      return false;
++    }
++
++  if (up->file == NULL) 
++    {
++      if (!swap_write (up))
++        return false;
++    }
++  else if (pagedir_test_dirty (t->pagedir, up->upage)) 
++    {
++      /* Need to write out. */
++      if (up->private) 
++        {
++          up->file = NULL; // FIXME
++          up->private = false;
++          if (!swap_write (up))
++            return false;
++        }
++
++      dump_page (up);
++    }
++  else 
++    {
++      /* Already on disk, not dirty.
++         Nothing to do. */
++    }
++
++  pagedir_clear_page (t->pagedir, up->upage);
++  pageframe_free (up->frame);
++  return true;
++}
++
+diff -urpN pintos.orig/src/userprog/process.h pintos/src/userprog/process.h
+--- pintos.orig/src/userprog/process.h 2004-09-21 22:42:17.000000000 -0700
++++ pintos/src/userprog/process.h      2004-09-27 14:43:13.000000000 -0700
+@@ -2,9 +2,32 @@
+ #define USERPROG_PROCESS_H
+ #include "threads/thread.h"
++#include "filesys/off_t.h"
++
++struct user_page 
++  {
++    hash_elem elem;
++    void *upage;                /* Virtual address of mapping. */
++
++    /* If FRAME is nonnull, the page is in memory.
++       If FILE is nonnull, the page is on disk.
++       If both are null, the page is all zeroes.
++       If both are nonnull, the page is in memory and backed by a
++       file mapping (not the swap file). */
++    struct page_frame *frame;
++    size_t swap_page;
++    struct file *file;
++    off_t file_ofs;
++    size_t file_size;           /* Number of bytes on disk, <= PGSIZE. */
++
++    bool dirty : 1;
++    bool accessed : 1;
++    bool private : 1;           /* Write dirty pages to swap or to FILE? */
++  };
+ tid_t process_execute (const char *filename);
+ void process_exit (void);
+ void process_activate (void);
++bool process_evict_page (struct thread *, struct user_page *);
+ #endif /* userprog/process.h */
+diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
+--- pintos.orig/src/userprog/syscall.c 2004-09-26 14:15:17.000000000 -0700
++++ pintos/src/userprog/syscall.c      2004-09-27 14:42:01.000000000 -0700
+@@ -1,20 +1,429 @@
+ #include "userprog/syscall.h"
+ #include <stdio.h>
++#include <string.h>
+ #include <syscall-nr.h>
++#include "threads/init.h"
+ #include "threads/interrupt.h"
++#include "threads/malloc.h"
++#include "threads/mmu.h"
++#include "threads/palloc.h"
+ #include "threads/thread.h"
++#include "userprog/pagedir.h"
++#include "userprog/process.h"
++#include "filesys/filesys.h"
++#include "filesys/file.h"
++#include "devices/kbd.h"
++
++typedef int syscall_function (int, int, int);
++
++static int sys_halt (void);
++static int sys_exit (int status);
++static int sys_exec (const char *ufile);
++static int sys_join (tid_t);
++static int sys_create (const char *ufile, unsigned initial_size);
++static int sys_remove (const char *ufile);
++static int sys_open (const char *ufile);
++static int sys_filesize (int handle);
++static int sys_read (int handle, void *udst_, unsigned size);
++static int sys_write (int handle, void *usrc_, unsigned size);
++static int sys_seek (int handle, unsigned position);
++static int sys_tell (int handle);
++static int sys_close (int handle);
++
++struct syscall 
++  {
++    size_t arg_cnt;
++    syscall_function *func;
++  };
++
++struct syscall syscall_table[] = 
++  {
++    {0, (syscall_function *) sys_halt},
++    {1, (syscall_function *) sys_exit},
++    {1, (syscall_function *) sys_exec},
++    {1, (syscall_function *) sys_join},
++    {2, (syscall_function *) sys_create},
++    {1, (syscall_function *) sys_remove},
++    {1, (syscall_function *) sys_open},
++    {1, (syscall_function *) sys_filesize},
++    {3, (syscall_function *) sys_read},
++    {3, (syscall_function *) sys_write},
++    {2, (syscall_function *) sys_seek},
++    {1, (syscall_function *) sys_tell},
++    {1, (syscall_function *) sys_close},
++  };
++static const int syscall_cnt = sizeof syscall_table / sizeof *syscall_table;
+ static void syscall_handler (struct intr_frame *);
++static void copy_in (void *, const void *, size_t);
++
++static struct lock fs_lock;
+ void
+ syscall_init (void) 
+ {
+   intr_register (0x30, 3, INTR_ON, syscall_handler, "syscall");
++  lock_init (&fs_lock, "fs");
+ }
+ static void
+-syscall_handler (struct intr_frame *f UNUSED) 
++syscall_handler (struct intr_frame *f) 
++{
++  struct syscall *s;
++  int call_nr;
++  int args[3];
++
++  copy_in (&call_nr, f->esp, sizeof call_nr);
++  if (call_nr < 0 || call_nr >= syscall_cnt)
++    {
++      printf ("bad syscall number %d\n", call_nr);
++      thread_exit ();
++    }
++
++  s = syscall_table + call_nr;
++  ASSERT (s->arg_cnt <= sizeof args / sizeof *args);
++  memset (args, 0, sizeof args);
++  copy_in (args, (uint32_t *) f->esp + 1, sizeof *args * s->arg_cnt);
++  f->eax = s->func (args[0], args[1], args[2]);
++}
++
++static bool
++verify_user (const void *uaddr) 
++{
++  return pagedir_get_page (thread_current ()->pagedir, uaddr) != NULL;
++}
++
++static inline bool get_user (uint8_t *dst, const uint8_t *usrc) {
++  int eax;
++  asm ("movl $1f, %%eax; movb %2, %%al; movb %%al, %0; 1:"
++       : "=m" (*dst), "=&a" (eax) : "m" (*usrc));
++  return eax != 0;
++}
++
++static inline bool put_user (uint8_t *udst, uint8_t byte) {
++  int eax;
++  asm ("movl $1f, %%eax; movb %b2, %0; 1:"
++       : "=m" (*udst), "=&a" (eax) : "r" (byte));
++  return eax != 0;
++}
++
++static void
++copy_in (void *dst_, const void *usrc_, size_t size) 
++{
++  uint8_t *dst = dst_;
++  const uint8_t *usrc = usrc_;
++
++  for (; size > 0; size--, dst++, usrc++) 
++    if (usrc >= (uint8_t *) PHYS_BASE || !get_user (dst, usrc)) 
++      thread_exit ();
++}
++
++static char *
++copy_in_string (const char *us) 
++{
++  char *ks;
++  size_t length;
++
++  ks = palloc_get_page (0);
++  if (ks == NULL) 
++    {
++      printf ("copy_in_string: out of memory\n");
++      thread_exit ();
++    }
++
++  for (length = 0; length < PGSIZE; length++)
++    {
++      if (us >= (char *) PHYS_BASE || !get_user (ks + length, us++)) 
++        {
++          printf ("bad user reference (%p)\n", us + length);
++          thread_exit (); 
++        }
++      
++      if (ks[length] == '\0')
++        return ks;
++    }
++
++  printf ("copy_in_string: string too long\n");
++  palloc_free_page (ks);
++  thread_exit ();
++}
++
++static int
++sys_halt (void)
++{
++  power_off ();
++}
++
++static int
++sys_exit (int ret_code) 
+ {
+-  printf ("system call!\n");
++  thread_current ()->ret_code = ret_code;
+   thread_exit ();
++  NOT_REACHED ();
++}
++
++static int
++sys_exec (const char *ufile) 
++{
++  tid_t tid;
++  char *kfile = copy_in_string (ufile);
++
++  lock_acquire (&fs_lock);
++  tid = process_execute (kfile);
++  lock_release (&fs_lock);
++
++  palloc_free_page (kfile);
++
++  return tid;
++}
++
++static int
++sys_join (tid_t child) 
++{
++  return thread_join (child);
++}
++
++static int
++sys_create (const char *ufile, unsigned initial_size) 
++{
++  char *kfile = copy_in_string (ufile);
++  bool ok;
++  
++  lock_acquire (&fs_lock);
++  ok = filesys_create (kfile, initial_size);
++  lock_release (&fs_lock);
++
++  palloc_free_page (kfile);
++
++  return ok;
++}
++
++static int
++sys_remove (const char *ufile) 
++{
++  char *kfile = copy_in_string (ufile);
++  bool ok;
++  
++  lock_acquire (&fs_lock);
++  ok = filesys_remove (kfile);
++  lock_release (&fs_lock);
++
++  palloc_free_page (kfile);
++
++  return ok;
++}
++
++struct fildes
++  {
++    list_elem elem;
++    struct file *file;
++    int handle;
++  };
++
++static int
++sys_open (const char *ufile) 
++{
++  char *kfile = copy_in_string (ufile);
++  struct fildes *fd;
++  int handle = -1;
++
++  fd = malloc (sizeof *fd);
++  if (fd == NULL)
++    goto exit;
++
++  lock_acquire (&fs_lock);
++  fd->file = filesys_open (kfile);
++  if (fd->file != NULL)
++    {
++      struct thread *cur = thread_current ();
++      handle = fd->handle = cur->next_handle++;
++      list_push_front (&cur->fds, &fd->elem);
++    }
++  else 
++    free (fd);
++  lock_release (&fs_lock);
++
++ exit:
++  palloc_free_page (kfile);
++  return handle;
++}
++
++static struct fildes *
++lookup_fd (int handle) 
++{
++  struct thread *cur = thread_current ();
++  list_elem *e;
++  
++  for (e = list_begin (&cur->fds); e != list_end (&cur->fds);
++       e = list_next (e))
++    {
++      struct fildes *fd = list_entry (e, struct fildes, elem);
++      if (fd->handle == handle)
++        return fd;
++    }
++
++  printf ("no handle %d\n", handle);
++thread_exit ();
++}
++
++static int
++sys_filesize (int handle) 
++{
++  struct fildes *fd = lookup_fd (handle);
++  int size;
++
++  lock_acquire (&fs_lock);
++  size = file_length (fd->file);
++  lock_release (&fs_lock);
++
++  return size;
++}
++
++static int
++sys_read (int handle, void *udst_, unsigned size) 
++{
++  uint8_t *udst = udst_;
++  struct fildes *fd;
++  int bytes_read = 0;
++
++  if (handle == STDIN_FILENO) 
++    {
++      for (bytes_read = 0; (size_t) bytes_read < size; bytes_read++)
++        if (udst >= (uint8_t *) PHYS_BASE || !put_user (udst++, kbd_getc ()))
++          thread_exit ();
++      return bytes_read;
++    }
++
++  lock_acquire (&fs_lock);
++  fd = lookup_fd (handle);
++  while (size > 0) 
++    {
++      size_t page_left = PGSIZE - pg_ofs (udst);
++      size_t read_amt = size < page_left ? size : page_left;
++      off_t retval;
++
++      if (!verify_user (udst)) 
++        {
++          lock_release (&fs_lock);
++          thread_exit ();
++        }
++      
++      retval = file_read (fd->file, udst, read_amt);
++      if (retval < 0)
++        {
++          if (bytes_read == 0)
++            bytes_read = -1; 
++          break;
++        }
++
++      bytes_read += retval;
++      if (retval != (off_t) read_amt)
++        break;
++
++      udst += retval;
++      size -= retval;
++    }
++  lock_release (&fs_lock);
++  
++  return bytes_read;
++}
++
++static int
++sys_write (int handle, void *usrc_, unsigned size) 
++{
++  uint8_t *usrc = usrc_;
++  struct fildes *fd = NULL;
++  int bytes_written = 0;
++
++  lock_acquire (&fs_lock);
++  if (handle != STDOUT_FILENO)
++    fd = lookup_fd (handle);
++  while (size > 0) 
++    {
++      size_t page_left = PGSIZE - pg_ofs (usrc);
++      size_t write_amt = size < page_left ? size : page_left;
++      off_t retval;
++
++      if (!verify_user (usrc)) 
++        {
++          lock_release (&fs_lock);
++          thread_exit ();
++        }
++
++      if (handle == STDOUT_FILENO)
++        {
++          putbuf (usrc, write_amt);
++          retval = write_amt;
++        }
++      else
++        retval = file_write (fd->file, usrc, write_amt);
++      if (retval < 0) 
++        {
++          if (bytes_written == 0)
++            bytes_written = -1;
++          break;
++        }
++
++      bytes_written += retval;
++      if (retval != (off_t) write_amt)
++        break;
++
++      usrc += retval;
++      size -= retval;
++    }
++  lock_release (&fs_lock);
++
++  return bytes_written;
++}
++
++static int
++sys_seek (int handle, unsigned position) 
++{
++  struct fildes *fd = lookup_fd (handle);
++  
++  lock_acquire (&fs_lock);
++  file_seek (fd->file, position);
++  lock_release (&fs_lock);
++
++  return 0;
++}
++
++static int
++sys_tell (int handle) 
++{
++  struct fildes *fd = lookup_fd (handle);
++  unsigned position;
++  
++  lock_acquire (&fs_lock);
++  position = file_tell (fd->file);
++  lock_release (&fs_lock);
++
++  return position;
++}
++
++static int
++sys_close (int handle) 
++{
++  struct fildes *fd = lookup_fd (handle);
++  lock_acquire (&fs_lock);
++  file_close (fd->file);
++  lock_release (&fs_lock);
++  list_remove (&fd->elem);
++  free (fd);
++  return 0;
++}
++
++void
++syscall_exit (void) 
++{
++  struct thread *cur = thread_current ();
++  list_elem *e, *next;
++  
++  for (e = list_begin (&cur->fds); e != list_end (&cur->fds); e = next)
++    {
++      struct fildes *fd = list_entry (e, struct fildes, elem);
++      next = list_next (e);
++      file_close (fd->file);
++      free (fd);
++    }
+ }
+diff -urpN pintos.orig/src/userprog/syscall.h pintos/src/userprog/syscall.h
+--- pintos.orig/src/userprog/syscall.h 2004-09-05 22:38:45.000000000 -0700
++++ pintos/src/userprog/syscall.h      2004-09-27 13:29:44.000000000 -0700
+@@ -2,5 +2,6 @@
+ #define USERPROG_SYSCALL_H
+ void syscall_init (void);
++void syscall_exit (void);
+ #endif /* userprog/syscall.h */
+diff -urpN pintos.orig/src/vm/pageframe.c pintos/src/vm/pageframe.c
+--- pintos.orig/src/vm/pageframe.c     1969-12-31 16:00:00.000000000 -0800
++++ pintos/src/vm/pageframe.c  2004-09-27 13:29:44.000000000 -0700
+@@ -0,0 +1,75 @@
++#include "vm/pageframe.h"
++#include <stdint.h>
++#include "threads/init.h"
++#include "threads/malloc.h"
++#include "threads/mmu.h"
++#include "threads/palloc.h"
++#include "userprog/process.h"
++
++static struct page_frame *frames;
++static size_t frame_cnt;
++
++static struct page_frame *next_frame;
++
++static inline bool
++in_use (const struct page_frame *pf) 
++{
++  ASSERT ((pf->owner != NULL) == (pf->user_page != NULL));
++  return pf->owner != NULL;
++}
++
++void
++pageframe_init (void) 
++{
++  uint8_t *kpage;
++
++  frame_cnt = ram_pages;
++  frames = calloc (sizeof *frames, frame_cnt);
++  if (frames == NULL)
++    PANIC ("can't allocate page frames");
++
++  while ((kpage = palloc_get_page (PAL_USER)) != NULL)
++    {
++      struct page_frame *pf = frames + (vtop (kpage) >> PGBITS);
++      pf->kpage = kpage;
++    }
++
++  next_frame = frames;
++}
++
++bool
++pageframe_allocate (struct user_page *up) 
++{
++  struct page_frame *pf;
++  size_t loops;
++
++  ASSERT (up->frame == NULL);
++
++  loops = 0;
++  do 
++    {
++      pf = next_frame++;
++      if (next_frame >= frames + frame_cnt)
++        next_frame = frames;
++      if (loops++ > 2 * frame_cnt)
++        return false;
++    }
++  while (pf->kpage == NULL
++         || (in_use (pf) && !process_evict_page (pf->owner, pf->user_page)));
++
++  ASSERT (!in_use (pf));
++  pf->owner = thread_current ();
++  pf->user_page = up;
++  up->frame = pf;
++  return true; 
++}
++
++void
++pageframe_free (struct page_frame *pf) 
++{
++  ASSERT (in_use (pf));
++  
++  pf->owner = NULL;
++  pf->user_page->frame = NULL;
++  pf->user_page = NULL;
++}
+diff -urpN pintos.orig/src/vm/pageframe.h pintos/src/vm/pageframe.h
+--- pintos.orig/src/vm/pageframe.h     1969-12-31 16:00:00.000000000 -0800
++++ pintos/src/vm/pageframe.h  2004-09-27 13:29:44.000000000 -0700
+@@ -0,0 +1,17 @@
++#ifndef VM_PAGEFRAME_H
++#define VM_PAGEFRAME_H 1
++
++#include <stdbool.h>
++
++struct page_frame 
++  {
++    void *kpage;
++    struct thread *owner;
++    struct user_page *user_page;
++  };
++
++void pageframe_init (void);
++bool pageframe_allocate (struct user_page *);
++void pageframe_free (struct page_frame *);
++
++#endif /* vm/pageframe.h */
+diff -urpN pintos.orig/src/vm/swap.c pintos/src/vm/swap.c
+--- pintos.orig/src/vm/swap.c  1969-12-31 16:00:00.000000000 -0800
++++ pintos/src/vm/swap.c       2004-09-27 13:29:44.000000000 -0700
+@@ -0,0 +1,66 @@
++#include "vm/swap.h"
++#include <bitmap.h>
++#include <stdio.h>
++#include "vm/pageframe.h"
++#include "threads/mmu.h"
++#include "filesys/file.h"
++#include "filesys/filesys.h"
++#include "userprog/process.h"
++
++static size_t swap_pages;
++static struct disk *swap_disk;
++static struct bitmap *used_pages;
++
++void
++swap_init (void) 
++{
++  swap_disk = disk_get (1, 1);
++  if (swap_disk == NULL)
++    PANIC ("no swap disk");
++  swap_pages = disk_size (swap_disk) / (PGSIZE / DISK_SECTOR_SIZE);
++  printf ("swap disk has room for %zu pages\n", swap_pages);
++
++  used_pages = bitmap_create (swap_pages);
++  if (used_pages == NULL)
++    PANIC ("couldn't create swap bitmap");
++}
++
++bool
++swap_write (struct user_page *up) 
++{
++  size_t page;
++  disk_sector_t sector;
++  int i;
++
++  ASSERT (up->frame != NULL);
++  ASSERT (up->file == NULL);
++
++  page = bitmap_scan_and_flip (used_pages, 0, 1, false);
++  if (page == BITMAP_ERROR)
++    return false;
++
++  up->swap_page = page;
++  sector = (disk_sector_t) page * (PGSIZE / DISK_SECTOR_SIZE);
++  for (i = 0; i < PGSIZE / DISK_SECTOR_SIZE; i++)
++    disk_write (swap_disk, sector++, up->frame->kpage + i * DISK_SECTOR_SIZE);
++
++  return true;
++}
++
++void
++swap_read (struct user_page *up) 
++{
++  disk_sector_t sector;
++  int i;
++
++  ASSERT (up->frame != NULL);
++
++  ASSERT (bitmap_test (used_pages, up->swap_page));
++  bitmap_reset (used_pages, up->swap_page);
++
++  sector = (disk_sector_t) up->swap_page * (PGSIZE / DISK_SECTOR_SIZE);
++  for (i = 0; i < PGSIZE / DISK_SECTOR_SIZE; i++)
++    disk_read (swap_disk, sector++, up->frame->kpage + i * DISK_SECTOR_SIZE);
++
++  up->swap_page = SIZE_MAX;
++}
+diff -urpN pintos.orig/src/vm/swap.h pintos/src/vm/swap.h
+--- pintos.orig/src/vm/swap.h  1969-12-31 16:00:00.000000000 -0800
++++ pintos/src/vm/swap.h       2004-09-27 13:29:44.000000000 -0700
+@@ -0,0 +1,11 @@
++#ifndef VM_SWAP_H
++#define VM_SWAP_H 1
++
++#include <stdbool.h>
++
++struct user_page;
++void swap_init (void);
++bool swap_write (struct user_page *);
++void swap_read (struct user_page *);
++
++#endif /* vm/swap.h */