Fix warning.
[pintos-anon] / solutions / p3.patch
1 diff -u src/Makefile.build~ src/Makefile.build
2 --- src/Makefile.build~ 2005-06-02 17:24:02.000000000 -0700
3 +++ src/Makefile.build 2005-06-08 14:10:54.000000000 -0700
4 @@ -53,7 +53,9 @@ userprog_SRC += userprog/gdt.c                # GDT in
5  userprog_SRC += userprog/tss.c         # TSS management.
6  
7  # No virtual memory code yet.
8 -#vm_SRC = vm/filename.c                        # Some file.
9 +vm_SRC = vm/page.c
10 +vm_SRC += vm/frame.c
11 +vm_SRC += vm/swap.c
12  
13  # Filesystem code.
14  filesys_SRC  = filesys/filesys.c       # Filesystem core.
15 diff -u src/devices/timer.c~ src/devices/timer.c
16 --- src/devices/timer.c~ 2005-05-24 15:52:43.000000000 -0700
17 +++ src/devices/timer.c 2005-06-08 14:10:54.000000000 -0700
18 @@ -23,6 +23,9 @@ static volatile int64_t ticks;
19     Initialized by timer_calibrate(). */
20  static unsigned loops_per_tick;
21  
22 +/* Threads waiting in timer_sleep(). */
23 +static struct list wait_list;
24 +
25  static intr_handler_func timer_interrupt;
26  static bool too_many_loops (unsigned loops);
27  static void busy_wait (int64_t loops);
28 @@ -43,6 +46,8 @@ timer_init (void) 
29    outb (0x40, count >> 8);
30  
31    intr_register_ext (0x20, timer_interrupt, "8254 Timer");
32 +
33 +  list_init (&wait_list);
34  }
35  
36  /* Calibrates loops_per_tick, used to implement brief delays. */
37 @@ -87,15 +92,36 @@ timer_elapsed (int64_t then) 
38    return timer_ticks () - then;
39  }
40  
41 +/* Compares two threads based on their wake-up times. */
42 +static bool
43 +compare_threads_by_wakeup_time (const struct list_elem *a_,
44 +                                const struct list_elem *b_,
45 +                                void *aux UNUSED) 
46 +{
47 +  const struct thread *a = list_entry (a_, struct thread, timer_elem);
48 +  const struct thread *b = list_entry (b_, struct thread, timer_elem);
49 +
50 +  return a->wakeup_time < b->wakeup_time;
51 +}
52 +
53  /* Suspends execution for approximately TICKS timer ticks. */
54  void
55  timer_sleep (int64_t ticks) 
56  {
57 -  int64_t start = timer_ticks ();
58 +  struct thread *t = thread_current ();
59 +
60 +  /* Schedule our wake-up time. */
61 +  t->wakeup_time = timer_ticks () + ticks;
62  
63 +  /* Atomically insert the current thread into the wait list. */
64    ASSERT (intr_get_level () == INTR_ON);
65 -  while (timer_elapsed (start) < ticks) 
66 -    thread_yield ();
67 +  intr_disable ();
68 +  list_insert_ordered (&wait_list, &t->timer_elem,
69 +                       compare_threads_by_wakeup_time, NULL);
70 +  intr_enable ();
71 +
72 +  /* Wait. */
73 +  sema_down (&t->timer_sema);
74  }
75  
76  /* Suspends execution for approximately MS milliseconds. */
77 @@ -132,6 +158,16 @@ timer_interrupt (struct intr_frame *args
78  {
79    ticks++;
80    thread_tick ();
81 +
82 +  while (!list_empty (&wait_list))
83 +    {
84 +      struct thread *t = list_entry (list_front (&wait_list),
85 +                                     struct thread, timer_elem);
86 +      if (ticks < t->wakeup_time) 
87 +        break;
88 +      sema_up (&t->timer_sema);
89 +      list_pop_front (&wait_list);
90 +    }
91  }
92  
93  /* Returns true if LOOPS iterations waits for more than one timer
94 diff -u src/threads/init.c~ src/threads/init.c
95 --- src/threads/init.c~ 2005-06-02 15:43:44.000000000 -0700
96 +++ src/threads/init.c 2005-06-08 14:10:54.000000000 -0700
97 @@ -33,6 +33,8 @@
98  #include "filesys/filesys.h"
99  #include "filesys/fsutil.h"
100  #endif
101 +#include "vm/frame.h"
102 +#include "vm/swap.h"
103  
104  /* Amount of physical memory, in 4 kB pages. */
105  size_t ram_pages;
106 @@ -131,6 +133,9 @@ main (void)
107    filesys_init (format_filesys);
108  #endif
109  
110 +  frame_init ();
111 +  swap_init ();
112 +
113    printf ("Boot complete.\n");
114    
115    /* Run actions specified on kernel command line. */
116 diff -u src/threads/interrupt.c~ src/threads/interrupt.c
117 --- src/threads/interrupt.c~ 2005-01-21 13:43:16.000000000 -0800
118 +++ src/threads/interrupt.c 2005-06-08 14:10:54.000000000 -0700
119 @@ -331,6 +331,8 @@ intr_handler (struct intr_frame *frame) 
120        in_external_intr = true;
121        yield_on_return = false;
122      }
123 +  else 
124 +    thread_current ()->user_esp = frame->esp;
125  
126    /* Invoke the interrupt's handler.
127       If there is no handler, invoke the unexpected interrupt
128 diff -u src/threads/thread.c~ src/threads/thread.c
129 --- src/threads/thread.c~ 2005-06-02 14:35:12.000000000 -0700
130 +++ src/threads/thread.c 2005-06-08 14:10:54.000000000 -0700
131 @@ -13,6 +13,7 @@
132  #include "threads/synch.h"
133  #ifdef USERPROG
134  #include "userprog/process.h"
135 +#include "userprog/syscall.h"
136  #endif
137  
138  /* Random value for struct thread's `magic' member.
139 @@ -55,7 +56,8 @@ static void kernel_thread (thread_func *
140  static void idle (void *aux UNUSED);
141  static struct thread *running_thread (void);
142  static struct thread *next_thread_to_run (void);
143 -static void init_thread (struct thread *, const char *name, int priority);
144 +static void init_thread (struct thread *, const char *name, int priority,
145 +                         tid_t);
146  static bool is_thread (struct thread *) UNUSED;
147  static void *alloc_frame (struct thread *, size_t size);
148  static void schedule (void);
149 @@ -82,9 +84,8 @@ thread_init (void) 
150  
151    /* Set up a thread structure for the running thread. */
152    initial_thread = running_thread ();
153 -  init_thread (initial_thread, "main", PRI_DEFAULT);
154 +  init_thread (initial_thread, "main", PRI_DEFAULT, 0);
155    initial_thread->status = THREAD_RUNNING;
156 -  initial_thread->tid = allocate_tid ();
157  }
158  
159  /* Starts preemptive thread scheduling by enabling interrupts.
160 @@ -157,8 +158,8 @@ thread_create (const char *name, int pri
161      return TID_ERROR;
162  
163    /* Initialize thread. */
164 -  init_thread (t, name, priority);
165 -  tid = t->tid = allocate_tid ();
166 +  init_thread (t, name, priority, allocate_tid ());
167 +  tid = t->tid;
168  
169    /* Stack frame for kernel_thread(). */
170    kf = alloc_frame (t, sizeof *kf);
171 @@ -251,16 +252,19 @@ thread_tid (void) 
172  void
173  thread_exit (void) 
174  {
175 +  struct thread *t = thread_current ();
176 +
177    ASSERT (!intr_context ());
178  
179 +  syscall_exit ();
180  #ifdef USERPROG
181    process_exit ();
182  #endif
183 -
184 +  
185    /* Just set our status to dying and schedule another process.
186       We will be destroyed during the call to schedule_tail(). */
187    intr_disable ();
188 -  thread_current ()->status = THREAD_DYING;
189 +  t->status = THREAD_DYING;
190    schedule ();
191    NOT_REACHED ();
192  }
193 @@ -389,17 +393,28 @@ is_thread (struct thread *t)
194  /* Does basic initialization of T as a blocked thread named
195     NAME. */
196  static void
197 -init_thread (struct thread *t, const char *name, int priority)
198 +init_thread (struct thread *t, const char *name, int priority, tid_t tid)
199  {
200    ASSERT (t != NULL);
201    ASSERT (PRI_MIN <= priority && priority <= PRI_MAX);
202    ASSERT (name != NULL);
203  
204    memset (t, 0, sizeof *t);
205 +  t->tid = tid;
206    t->status = THREAD_BLOCKED;
207    strlcpy (t->name, name, sizeof t->name);
208    t->stack = (uint8_t *) t + PGSIZE;
209    t->priority = priority;
210 +  t->exit_code = -1;
211 +  t->wait_status = NULL;
212 +  list_init (&t->children);
213 +  sema_init (&t->timer_sema, 0);
214 +  t->pagedir = NULL;
215 +  t->pages = NULL;
216 +  t->bin_file = NULL;
217 +  list_init (&t->fds);
218 +  list_init (&t->mappings);
219 +  t->next_handle = 2;
220    t->magic = THREAD_MAGIC;
221  }
222  
223 diff -u src/threads/thread.h~ src/threads/thread.h
224 --- src/threads/thread.h~ 2005-06-02 14:32:36.000000000 -0700
225 +++ src/threads/thread.h 2005-06-08 14:10:54.000000000 -0700
226 @@ -2,8 +2,10 @@
227  #define THREADS_THREAD_H
228  
229  #include <debug.h>
230 +#include <hash.h>
231  #include <list.h>
232  #include <stdint.h>
233 +#include "threads/synch.h"
234  
235  /* States in a thread's life cycle. */
236  enum thread_status
237 @@ -89,18 +91,49 @@ struct thread
238      uint8_t *stack;                     /* Saved stack pointer. */
239      int priority;                       /* Priority. */
240  
241 +    /* Owned by process.c. */
242 +    int exit_code;                      /* Exit code. */
243 +    struct wait_status *wait_status;    /* This process's completion status. */
244 +    struct list children;               /* Completion status of children. */
245 +
246      /* Shared between thread.c and synch.c. */
247      struct list_elem elem;              /* List element. */
248  
249 -#ifdef USERPROG
250 +    /* Alarm clock. */
251 +    int64_t wakeup_time;                /* Time to wake this thread up. */
252 +    struct list_elem timer_elem;        /* Element in timer_wait_list. */
253 +    struct semaphore timer_sema;        /* Semaphore. */
254 +
255      /* Owned by userprog/process.c. */
256      uint32_t *pagedir;                  /* Page directory. */
257 -#endif
258 +    struct hash *pages;                 /* Page table. */
259 +    struct file *bin_file;              /* The binary executable. */
260 +
261 +    /* Owned by syscall.c. */
262 +    struct list fds;                    /* List of file descriptors. */
263 +    struct list mappings;               /* Memory-mapped files. */
264 +    int next_handle;                    /* Next handle value. */
265 +    void *user_esp;                     /* User's stack pointer. */
266  
267      /* Owned by thread.c. */
268      unsigned magic;                     /* Detects stack overflow. */
269    };
270  
271 +/* Tracks the completion of a process.
272 +   Reference held by both the parent, in its `children' list,
273 +   and by the child, in its `wait_status' pointer. */
274 +struct wait_status
275 +  {
276 +    struct list_elem elem;              /* `children' list element. */
277 +    struct lock lock;                   /* Protects ref_cnt. */
278 +    int ref_cnt;                        /* 2=child and parent both alive,
279 +                                           1=either child or parent alive,
280 +                                           0=child and parent both dead. */
281 +    tid_t tid;                          /* Child thread id. */
282 +    int exit_code;                      /* Child exit code, if dead. */
283 +    struct semaphore dead;              /* 1=child alive, 0=child dead. */
284 +  };
285 +
286  void thread_init (void);
287  void thread_start (void);
288  void thread_tick (void);
289 diff -u src/userprog/exception.c~ src/userprog/exception.c
290 --- src/userprog/exception.c~ 2005-01-01 18:09:59.000000000 -0800
291 +++ src/userprog/exception.c 2005-06-08 14:10:54.000000000 -0700
292 @@ -4,6 +4,7 @@
293  #include "userprog/gdt.h"
294  #include "threads/interrupt.h"
295  #include "threads/thread.h"
296 +#include "vm/page.h"
297  
298  /* Number of page faults processed. */
299  static long long page_fault_cnt;
300 @@ -150,9 +151,14 @@ page_fault (struct intr_frame *f) 
301    write = (f->error_code & PF_W) != 0;
302    user = (f->error_code & PF_U) != 0;
303  
304 -  /* To implement virtual memory, delete the rest of the function
305 -     body, and replace it with code that brings in the page to
306 -     which fault_addr refers. */
307 +  /* Allow the pager to try to handle it. */
308 +  if (user && not_present)
309 +    {
310 +      if (!page_in (fault_addr))
311 +        thread_exit ();
312 +      return;
313 +    }
314 +
315    printf ("Page fault at %p: %s error %s page in %s context.\n",
316            fault_addr,
317            not_present ? "not present" : "rights violation",
318 diff -u src/userprog/pagedir.c~ src/userprog/pagedir.c
319 --- src/userprog/pagedir.c~ 2005-05-20 15:44:13.000000000 -0700
320 +++ src/userprog/pagedir.c 2005-06-08 14:10:54.000000000 -0700
321 @@ -34,15 +34,7 @@ pagedir_destroy (uint32_t *pd) 
322    ASSERT (pd != base_page_dir);
323    for (pde = pd; pde < pd + pd_no (PHYS_BASE); pde++)
324      if (*pde & PG_P) 
325 -      {
326 -        uint32_t *pt = pde_get_pt (*pde);
327 -        uint32_t *pte;
328 -        
329 -        for (pte = pt; pte < pt + PGSIZE / sizeof *pte; pte++)
330 -          if (*pte & PG_P) 
331 -            palloc_free_page (pte_get_page (*pte));
332 -        palloc_free_page (pt);
333 -      }
334 +      palloc_free_page (pde_get_pt (*pde));
335    palloc_free_page (pd);
336  }
337  
338 diff -u src/userprog/process.c~ src/userprog/process.c
339 --- src/userprog/process.c~ 2005-05-26 13:19:48.000000000 -0700
340 +++ src/userprog/process.c 2005-06-08 14:13:25.000000000 -0700
341 @@ -14,11 +14,25 @@
342  #include "threads/init.h"
343  #include "threads/interrupt.h"
344  #include "threads/mmu.h"
345 +#include "threads/malloc.h"
346  #include "threads/palloc.h"
347  #include "threads/thread.h"
348 +#include "vm/page.h"
349 +#include "vm/frame.h"
350  
351  static thread_func execute_thread NO_RETURN;
352 -static bool load (const char *cmdline, void (**eip) (void), void **esp);
353 +static bool load (const char *cmd_line, void (**eip) (void), void **esp);
354 +
355 +/* Data structure shared between process_execute() in the
356 +   invoking thread and execute_thread() in the newly invoked
357 +   thread. */
358 +struct exec_info 
359 +  {
360 +    const char *filename;               /* Program to load. */
361 +    struct semaphore load_done;         /* "Up"ed when loading complete. */
362 +    struct wait_status *wait_status;    /* Child process. */
363 +    bool success;                       /* Program successfully loaded? */
364 +  };
365  
366  /* Starts a new thread running a user program loaded from
367     FILENAME.  The new thread may be scheduled (and may even exit)
368 @@ -27,29 +41,37 @@ static bool load (const char *cmdline, v
369  tid_t
370  process_execute (const char *filename) 
371  {
372 -  char *fn_copy;
373 +  struct exec_info exec;
374 +  char thread_name[16];
375 +  char *save_ptr;
376    tid_t tid;
377  
378 -  /* Make a copy of FILENAME.
379 -     Otherwise there's a race between the caller and load(). */
380 -  fn_copy = palloc_get_page (0);
381 -  if (fn_copy == NULL)
382 -    return TID_ERROR;
383 -  strlcpy (fn_copy, filename, PGSIZE);
384 +  /* Initialize exec_info. */
385 +  exec.filename = filename;
386 +  sema_init (&exec.load_done, 0);
387  
388    /* Create a new thread to execute FILENAME. */
389 -  tid = thread_create (filename, PRI_DEFAULT, execute_thread, fn_copy);
390 -  if (tid == TID_ERROR)
391 -    palloc_free_page (fn_copy); 
392 +  strlcpy (thread_name, filename, sizeof thread_name);
393 +  strtok_r (thread_name, " ", &save_ptr);
394 +  tid = thread_create (thread_name, PRI_DEFAULT, execute_thread, &exec);
395 +  if (tid != TID_ERROR)
396 +    {
397 +      sema_down (&exec.load_done);
398 +      if (exec.success)
399 +        list_push_back (&thread_current ()->children, &exec.wait_status->elem);
400 +      else 
401 +        tid = TID_ERROR;
402 +    }
403 +
404    return tid;
405  }
406  
407  /* A thread function that loads a user process and starts it
408     running. */
409  static void
410 -execute_thread (void *filename_)
411 +execute_thread (void *exec_)
412  {
413 -  char *filename = filename_;
414 +  struct exec_info *exec = exec_;
415    struct intr_frame if_;
416    bool success;
417  
418 @@ -58,10 +80,28 @@ execute_thread (void *filename_)
419    if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG;
420    if_.cs = SEL_UCSEG;
421    if_.eflags = FLAG_IF | FLAG_MBS;
422 -  success = load (filename, &if_.eip, &if_.esp);
423 +  success = load (exec->filename, &if_.eip, &if_.esp);
424  
425 -  /* If load failed, quit. */
426 -  palloc_free_page (filename);
427 +  /* Allocate wait_status. */
428 +  if (success)
429 +    {
430 +      exec->wait_status = thread_current ()->wait_status
431 +        = malloc (sizeof *exec->wait_status);
432 +      success = exec->wait_status != NULL; 
433 +    }
434 +
435 +  /* Initialize wait_status. */
436 +  if (success) 
437 +    {
438 +      lock_init (&exec->wait_status->lock);
439 +      exec->wait_status->ref_cnt = 2;
440 +      exec->wait_status->tid = thread_current ()->tid;
441 +      sema_init (&exec->wait_status->dead, 0);
442 +    }
443 +  
444 +  /* Notify parent thread and clean up. */
445 +  exec->success = success;
446 +  sema_up (&exec->load_done);
447    if (!success) 
448      thread_exit ();
449  
450 @@ -75,18 +115,47 @@ execute_thread (void *filename_)
451    NOT_REACHED ();
452  }
453  
454 +/* Releases one reference to CS and, if it is now unreferenced,
455 +   frees it. */
456 +static void
457 +release_child (struct wait_status *cs) 
458 +{
459 +  int new_ref_cnt;
460 +  
461 +  lock_acquire (&cs->lock);
462 +  new_ref_cnt = --cs->ref_cnt;
463 +  lock_release (&cs->lock);
464 +
465 +  if (new_ref_cnt == 0)
466 +    free (cs);
467 +}
468 +
469  /* Waits for thread TID to die and returns its exit status.  If
470     it was terminated by the kernel (i.e. killed due to an
471     exception), returns -1.  If TID is invalid or if it was not a
472     child of the calling process, or if process_wait() has already
473     been successfully called for the given TID, returns -1
474 -   immediately, without waiting.
475 -
476 -   This function will be implemented in problem 2-2.  For now, it
477 -   does nothing. */
478 +   immediately, without waiting. */
479  int
480 -process_wait (tid_t child_tid UNUSED) 
481 +process_wait (tid_t child_tid) 
482  {
483 +  struct thread *cur = thread_current ();
484 +  struct list_elem *e;
485 +
486 +  for (e = list_begin (&cur->children); e != list_end (&cur->children);
487 +       e = list_next (e)) 
488 +    {
489 +      struct wait_status *cs = list_entry (e, struct wait_status, elem);
490 +      if (cs->tid == child_tid) 
491 +        {
492 +          int exit_code;
493 +          list_remove (e);
494 +          sema_down (&cs->dead);
495 +          exit_code = cs->exit_code;
496 +          release_child (cs);
497 +          return exit_code;
498 +        }
499 +    }
500    return -1;
501  }
502  
503 @@ -95,8 +164,35 @@ void
504  process_exit (void)
505  {
506    struct thread *cur = thread_current ();
507 +  struct list_elem *e, *next;
508    uint32_t *pd;
509  
510 +  printf ("%s: exit(%d)\n", cur->name, cur->exit_code);
511 +
512 +  /* Notify parent that we're dead. */
513 +  if (cur->wait_status != NULL) 
514 +    {
515 +      struct wait_status *cs = cur->wait_status;
516 +      cs->exit_code = cur->exit_code;
517 +      sema_up (&cs->dead);
518 +      release_child (cs);
519 +    }
520 +
521 +  /* Free entries of children list. */
522 +  for (e = list_begin (&cur->children); e != list_end (&cur->children);
523 +       e = next) 
524 +    {
525 +      struct wait_status *cs = list_entry (e, struct wait_status, elem);
526 +      next = list_remove (e);
527 +      release_child (cs);
528 +    }
529 +
530 +  /* Destroy the page hash table. */
531 +  page_exit ();
532 +  
533 +  /* Close executable (and allow writes). */
534 +  file_close (cur->bin_file);
535 +
536    /* Destroy the current process's page directory and switch back
537       to the kernel-only page directory. */
538    pd = cur->pagedir;
539 @@ -193,7 +289,7 @@ struct Elf32_Phdr
540  #define PF_R 4          /* Readable. */
541  
542  static bool load_segment (struct file *, const struct Elf32_Phdr *);
543 -static bool setup_stack (void **esp);
544 +static bool setup_stack (const char *cmd_line, void **esp);
545  
546  /* Loads an ELF executable from FILENAME into the current thread.
547     Stores the executable's entry point into *EIP
548 @@ -209,13 +305,15 @@ static bool setup_stack (void **esp);
549     and its initial stack pointer into *ESP.
550     Returns true if successful, false otherwise. */
551  bool
552 -load (const char *filename, void (**eip) (void), void **esp) 
553 +load (const char *cmd_line, void (**eip) (void), void **esp) 
554  {
555    struct thread *t = thread_current ();
556 +  char filename[NAME_MAX + 2];
557    struct Elf32_Ehdr ehdr;
558    struct file *file = NULL;
559    off_t file_ofs;
560    bool success = false;
561 +  char *cp;
562    int i;
563  
564    /* Allocate and activate page directory. */
565 @@ -224,13 +322,28 @@ load (const char *filename, void (**eip)
566      goto done;
567    process_activate ();
568  
569 +  /* Create page hash table. */
570 +  t->pages = malloc (sizeof *t->pages);
571 +  if (t->pages == NULL)
572 +    goto done;
573 +  hash_init (t->pages, page_hash, page_less, NULL);
574 +
575 +  /* Extract filename from command line. */
576 +  while (*cmd_line == ' ')
577 +    cmd_line++;
578 +  strlcpy (filename, cmd_line, sizeof filename);
579 +  cp = strchr (filename, ' ');
580 +  if (cp != NULL)
581 +    *cp = '\0';
582 +
583    /* Open executable file. */
584 -  file = filesys_open (filename);
585 +  t->bin_file = file = filesys_open (filename);
586    if (file == NULL) 
587      {
588        printf ("load: %s: open failed\n", filename);
589        goto done; 
590      }
591 +  file_deny_write (t->bin_file);
592  
593    /* Read and verify executable header. */
594    if (file_read (file, &ehdr, sizeof ehdr) != sizeof ehdr
595 @@ -284,7 +397,7 @@ load (const char *filename, void (**eip)
596      }
597  
598    /* Set up stack. */
599 -  if (!setup_stack (esp))
600 +  if (!setup_stack (cmd_line, esp))
601      goto done;
602  
603    /* Start address. */
604 @@ -294,14 +407,11 @@ load (const char *filename, void (**eip)
605  
606   done:
607    /* We arrive here whether the load is successful or not. */
608 -  file_close (file);
609    return success;
610  }
611  \f
612  /* load() helpers. */
613  
614 -static bool install_page (void *upage, void *kpage);
615 -
616  /* Loads the segment described by PHDR from FILE into user
617     address space.  Return true if successful, false otherwise. */
618  static bool
619 @@ -309,6 +419,7 @@ load_segment (struct file *file, const s
620  {
621    void *start, *end;  /* Page-rounded segment start and end. */
622    uint8_t *upage;     /* Iterator from start to end. */
623 +  off_t file_offset;  /* Offset into file. */
624    off_t filesz_left;  /* Bytes left of file data (as opposed to
625                           zero-initialized bytes). */
626  
627 @@ -316,7 +427,7 @@ load_segment (struct file *file, const s
628       commented out.  You'll want to use it when implementing VM
629       to decide whether to page the segment from its executable or
630       from swap. */
631 -  //bool read_only = (phdr->p_flags & PF_W) == 0;
632 +  bool read_only = (phdr->p_flags & PF_W) == 0;
633  
634    ASSERT (file != NULL);
635    ASSERT (phdr != NULL);
636 @@ -360,73 +471,129 @@ load_segment (struct file *file, const s
637        return false; 
638      }
639  
640 -  /* Load the segment page-by-page into memory. */
641 +  /* Add the segment page-by-page to the hash table. */
642    filesz_left = phdr->p_filesz + (phdr->p_vaddr & PGMASK);
643 -  file_seek (file, ROUND_DOWN (phdr->p_offset, PGSIZE));
644 +  file_offset = ROUND_DOWN (phdr->p_offset, PGSIZE);
645    for (upage = start; upage < (uint8_t *) end; upage += PGSIZE) 
646      {
647 -      /* We want to read min(PGSIZE, filesz_left) bytes from the
648 -         file into the page and zero the rest. */
649 -      size_t read_bytes = filesz_left >= PGSIZE ? PGSIZE : filesz_left;
650 -      size_t zero_bytes = PGSIZE - read_bytes;
651 -      uint8_t *kpage = palloc_get_page (PAL_USER);
652 -      if (kpage == NULL)
653 +      struct page *p = page_allocate (upage, read_only);
654 +      if (p == NULL)
655          return false;
656  
657 -      /* Do the reading and zeroing. */
658 -      if (file_read (file, kpage, read_bytes) != (int) read_bytes) 
659 -        {
660 -          palloc_free_page (kpage);
661 -          return false; 
662 -        }
663 -      memset (kpage + read_bytes, 0, zero_bytes);
664 -      filesz_left -= read_bytes;
665 -
666 -      /* Add the page to the process's address space. */
667 -      if (!install_page (upage, kpage)) 
668 +      if (filesz_left > 0) 
669          {
670 -          palloc_free_page (kpage);
671 -          return false; 
672 +          size_t file_bytes = filesz_left >= PGSIZE ? PGSIZE : filesz_left;
673 +          p->file = file;
674 +          p->file_offset = file_offset;
675 +          p->file_bytes = file_bytes;
676 +          filesz_left -= file_bytes;
677 +          file_offset += file_bytes;
678          }
679      }
680  
681    return true;
682  }
683  
684 -/* Create a minimal stack by mapping a zeroed page at the top of
685 -   user virtual memory. */
686 -static bool
687 -setup_stack (void **esp) 
688 +/* Reverse the order of the ARGC pointers to char in ARGV. */
689 +static void
690 +reverse (int argc, char **argv) 
691  {
692 -  uint8_t *kpage;
693 -  bool success = false;
694 -
695 -  kpage = palloc_get_page (PAL_USER | PAL_ZERO);
696 -  if (kpage != NULL) 
697 +  for (; argc > 1; argc -= 2, argv++) 
698      {
699 -      success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage);
700 -      if (success)
701 -        *esp = PHYS_BASE;
702 -      else
703 -        palloc_free_page (kpage);
704 +      char *tmp = argv[0];
705 +      argv[0] = argv[argc - 1];
706 +      argv[argc - 1] = tmp;
707      }
708 +}
709
710 -  return success;
711 +/* Pushes the SIZE bytes in BUF onto the stack in KPAGE, whose
712 +   page-relative stack pointer is *OFS, and then adjusts *OFS
713 +   appropriately.  The bytes pushed are rounded to a 32-bit
714 +   boundary.
715 +
716 +   If successful, returns a pointer to the newly pushed object.
717 +   On failure, returns a null pointer. */
718 +static void *
719 +push (uint8_t *kpage, size_t *ofs, const void *buf, size_t size) 
720 +{
721 +  size_t padsize = ROUND_UP (size, sizeof (uint32_t));
722 +  if (*ofs < padsize)
723 +    return NULL;
724 +
725 +  *ofs -= padsize;
726 +  memcpy (kpage + *ofs + (padsize - size), buf, size);
727 +  return kpage + *ofs + (padsize - size);
728  }
729  
730 -/* Adds a mapping from user virtual address UPAGE to kernel
731 -   virtual address KPAGE to the page table.
732 -   UPAGE must not already be mapped.
733 -   KPAGE should probably be a page obtained from the user pool
734 -   with palloc_get_page().
735 -   Returns true on success, false if UPAGE is already mapped or
736 -   if memory allocation fails. */
737 +/* Sets up command line arguments in KPAGE, which will be mapped
738 +   to UPAGE in user space.  The command line arguments are taken
739 +   from CMD_LINE, separated by spaces.  Sets *ESP to the initial
740 +   stack pointer for the process. */
741  static bool
742 -install_page (void *upage, void *kpage)
743 +init_cmd_line (uint8_t *kpage, uint8_t *upage, const char *cmd_line,
744 +               void **esp) 
745  {
746 -  struct thread *t = thread_current ();
747 +  size_t ofs = PGSIZE;
748 +  char *const null = NULL;
749 +  char *cmd_line_copy;
750 +  char *karg, *saveptr;
751 +  int argc;
752 +  char **argv;
753 +
754 +  /* Push command line string. */
755 +  cmd_line_copy = push (kpage, &ofs, cmd_line, strlen (cmd_line) + 1);
756 +  if (cmd_line_copy == NULL)
757 +    return false;
758 +
759 +  if (push (kpage, &ofs, &null, sizeof null) == NULL)
760 +    return false;
761 +
762 +  /* Parse command line into arguments
763 +     and push them in reverse order. */
764 +  argc = 0;
765 +  for (karg = strtok_r (cmd_line_copy, " ", &saveptr); karg != NULL;
766 +       karg = strtok_r (NULL, " ", &saveptr))
767 +    {
768 +      void *uarg = upage + (karg - (char *) kpage);
769 +      if (push (kpage, &ofs, &uarg, sizeof uarg) == NULL)
770 +        return false;
771 +      argc++;
772 +    }
773 +
774 +  /* Reverse the order of the command line arguments. */
775 +  argv = (char **) (upage + ofs);
776 +  reverse (argc, (char **) (kpage + ofs));
777 +
778 +  /* Push argv, argc, "return address". */
779 +  if (push (kpage, &ofs, &argv, sizeof argv) == NULL
780 +      || push (kpage, &ofs, &argc, sizeof argc) == NULL
781 +      || push (kpage, &ofs, &null, sizeof null) == NULL)
782 +    return false;
783 +
784 +  /* Set initial stack pointer. */
785 +  *esp = upage + ofs;
786 +  return true;
787 +}
788  
789 -  /* Verify that there's not already a page at that virtual
790 -     address, then map our page there. */
791 -  return (pagedir_get_page (t->pagedir, upage) == NULL
792 -          && pagedir_set_page (t->pagedir, upage, kpage, true));
793 +/* Create a minimal stack for T by mapping a page at the
794 +   top of user virtual memory.  Fills in the page using CMD_LINE
795 +   and sets *ESP to the stack pointer. */
796 +static bool
797 +setup_stack (const char *cmd_line, void **esp) 
798 +{
799 +  struct page *page = page_allocate (((uint8_t *) PHYS_BASE) - PGSIZE, false);
800 +  if (page != NULL) 
801 +    {
802 +      page->frame = frame_alloc_and_lock (page);
803 +      if (page->frame != NULL)
804 +        {
805 +          bool ok;
806 +          page->read_only = false;
807 +          page->private = false;
808 +          ok = init_cmd_line (page->frame->base, page->addr, cmd_line, esp);
809 +          frame_unlock (page->frame);
810 +          return ok;
811 +        }
812 +    }
813 +  return false;
814  }
815 diff -u src/userprog/syscall.c~ src/userprog/syscall.c
816 --- src/userprog/syscall.c~ 2004-09-26 14:15:17.000000000 -0700
817 +++ src/userprog/syscall.c 2005-06-08 14:10:54.000000000 -0700
818 @@ -1,20 +1,557 @@
819  #include "userprog/syscall.h"
820  #include <stdio.h>
821 +#include <string.h>
822  #include <syscall-nr.h>
823 +#include "userprog/process.h"
824 +#include "userprog/pagedir.h"
825 +#include "devices/kbd.h"
826 +#include "filesys/directory.h"
827 +#include "filesys/filesys.h"
828 +#include "filesys/file.h"
829 +#include "threads/init.h"
830  #include "threads/interrupt.h"
831 +#include "threads/malloc.h"
832 +#include "threads/mmu.h"
833 +#include "threads/palloc.h"
834  #include "threads/thread.h"
835 -
836 +#include "vm/page.h"
837
838
839 +static int sys_halt (void);
840 +static int sys_exit (int status);
841 +static int sys_exec (const char *ufile);
842 +static int sys_wait (tid_t);
843 +static int sys_create (const char *ufile, unsigned initial_size);
844 +static int sys_remove (const char *ufile);
845 +static int sys_open (const char *ufile);
846 +static int sys_filesize (int handle);
847 +static int sys_read (int handle, void *udst_, unsigned size);
848 +static int sys_write (int handle, void *usrc_, unsigned size);
849 +static int sys_seek (int handle, unsigned position);
850 +static int sys_tell (int handle);
851 +static int sys_close (int handle);
852 +static int sys_mmap (int handle, void *addr);
853 +static int sys_munmap (int mapping);
854
855  static void syscall_handler (struct intr_frame *);
856 -
857 +static void copy_in (void *, const void *, size_t);
858
859  void
860  syscall_init (void) 
861  {
862    intr_register_int (0x30, 3, INTR_ON, syscall_handler, "syscall");
863  }
864
865 +/* System call handler. */
866 +static void
867 +syscall_handler (struct intr_frame *f) 
868 +{
869 +  typedef int syscall_function (int, int, int);
870 +
871 +  /* A system call. */
872 +  struct syscall 
873 +    {
874 +      size_t arg_cnt;           /* Number of arguments. */
875 +      syscall_function *func;   /* Implementation. */
876 +    };
877 +
878 +  /* Table of system calls. */
879 +  static const struct syscall syscall_table[] =
880 +    {
881 +      {0, (syscall_function *) sys_halt},
882 +      {1, (syscall_function *) sys_exit},
883 +      {1, (syscall_function *) sys_exec},
884 +      {1, (syscall_function *) sys_wait},
885 +      {2, (syscall_function *) sys_create},
886 +      {1, (syscall_function *) sys_remove},
887 +      {1, (syscall_function *) sys_open},
888 +      {1, (syscall_function *) sys_filesize},
889 +      {3, (syscall_function *) sys_read},
890 +      {3, (syscall_function *) sys_write},
891 +      {2, (syscall_function *) sys_seek},
892 +      {1, (syscall_function *) sys_tell},
893 +      {1, (syscall_function *) sys_close},
894 +      {2, (syscall_function *) sys_mmap},
895 +      {1, (syscall_function *) sys_munmap},
896 +    };
897  
898 +  const struct syscall *sc;
899 +  unsigned call_nr;
900 +  int args[3];
901 +
902 +  /* Get the system call. */
903 +  copy_in (&call_nr, f->esp, sizeof call_nr);
904 +  if (call_nr >= sizeof syscall_table / sizeof *syscall_table)
905 +    thread_exit ();
906 +  sc = syscall_table + call_nr;
907 +
908 +  /* Get the system call arguments. */
909 +  ASSERT (sc->arg_cnt <= sizeof args / sizeof *args);
910 +  memset (args, 0, sizeof args);
911 +  copy_in (args, (uint32_t *) f->esp + 1, sizeof *args * sc->arg_cnt);
912 +
913 +  /* Execute the system call,
914 +     and set the return value. */
915 +  f->eax = sc->func (args[0], args[1], args[2]);
916 +}
917
918 +/* Copies SIZE bytes from user address USRC to kernel address
919 +   DST.
920 +   Call thread_exit() if any of the user accesses are invalid. */
921  static void
922 -syscall_handler (struct intr_frame *f UNUSED) 
923 +copy_in (void *dst_, const void *usrc_, size_t size) 
924 +{
925 +  uint8_t *dst = dst_;
926 +  const uint8_t *usrc = usrc_;
927 +
928 +  while (size > 0) 
929 +    {
930 +      size_t chunk_size = PGSIZE - pg_ofs (usrc);
931 +      if (chunk_size > size)
932 +        chunk_size = size;
933 +      
934 +      if (!page_lock (usrc, false))
935 +        thread_exit ();
936 +      memcpy (dst, usrc, chunk_size);
937 +      page_unlock (usrc);
938 +
939 +      dst += chunk_size;
940 +      usrc += chunk_size;
941 +      size -= chunk_size;
942 +    }
943 +}
944
945 +/* Creates a copy of user string US in kernel memory
946 +   and returns it as a page that must be freed with
947 +   palloc_free_page().
948 +   Truncates the string at PGSIZE bytes in size.
949 +   Call thread_exit() if any of the user accesses are invalid. */
950 +static char *
951 +copy_in_string (const char *us) 
952 +{
953 +  char *ks;
954 +  char *upage;
955 +  size_t length;
956
957 +  ks = palloc_get_page (0);
958 +  if (ks == NULL) 
959 +    thread_exit ();
960 +
961 +  length = 0;
962 +  for (;;) 
963 +    {
964 +      upage = pg_round_down (us);
965 +      if (!page_lock (upage, false))
966 +        goto lock_error;
967 +
968 +      for (; us < upage + PGSIZE; us++) 
969 +        {
970 +          ks[length++] = *us;
971 +          if (*us == '\0') 
972 +            {
973 +              page_unlock (upage);
974 +              return ks; 
975 +            }
976 +          else if (length >= PGSIZE) 
977 +            goto too_long_error;
978 +        }
979 +
980 +      page_unlock (upage);
981 +    }
982 +
983 + too_long_error:
984 +  page_unlock (upage);
985 + lock_error:
986 +  palloc_free_page (ks);
987 +  thread_exit ();
988 +}
989
990 +/* Halt system call. */
991 +static int
992 +sys_halt (void)
993  {
994 -  printf ("system call!\n");
995 +  power_off ();
996 +}
997
998 +/* Exit system call. */
999 +static int
1000 +sys_exit (int exit_code) 
1001 +{
1002 +  thread_current ()->exit_code = exit_code;
1003    thread_exit ();
1004 +  NOT_REACHED ();
1005 +}
1006
1007 +/* Exec system call. */
1008 +static int
1009 +sys_exec (const char *ufile) 
1010 +{
1011 +  tid_t tid;
1012 +  char *kfile = copy_in_string (ufile);
1013
1014 +  tid = process_execute (kfile);
1015
1016 +  palloc_free_page (kfile);
1017
1018 +  return tid;
1019 +}
1020
1021 +/* Wait system call. */
1022 +static int
1023 +sys_wait (tid_t child) 
1024 +{
1025 +  return process_wait (child);
1026 +}
1027
1028 +/* Create system call. */
1029 +static int
1030 +sys_create (const char *ufile, unsigned initial_size) 
1031 +{
1032 +  char *kfile = copy_in_string (ufile);
1033 +  bool ok = filesys_create (kfile, initial_size);
1034 +  palloc_free_page (kfile);
1035
1036 +  return ok;
1037 +}
1038
1039 +/* Remove system call. */
1040 +static int
1041 +sys_remove (const char *ufile) 
1042 +{
1043 +  char *kfile = copy_in_string (ufile);
1044 +  bool ok = filesys_remove (kfile);
1045 +  palloc_free_page (kfile);
1046
1047 +  return ok;
1048 +}
1049 +\f
1050 +/* A file descriptor, for binding a file handle to a file. */
1051 +struct file_descriptor
1052 +  {
1053 +    struct list_elem elem;      /* List element. */
1054 +    struct file *file;          /* File. */
1055 +    int handle;                 /* File handle. */
1056 +  };
1057
1058 +/* Open system call. */
1059 +static int
1060 +sys_open (const char *ufile) 
1061 +{
1062 +  char *kfile = copy_in_string (ufile);
1063 +  struct file_descriptor *fd;
1064 +  int handle = -1;
1065
1066 +  fd = malloc (sizeof *fd);
1067 +  if (fd != NULL)
1068 +    {
1069 +      fd->file = filesys_open (kfile);
1070 +      if (fd->file != NULL)
1071 +        {
1072 +          struct thread *cur = thread_current ();
1073 +          handle = fd->handle = cur->next_handle++;
1074 +          list_push_front (&cur->fds, &fd->elem);
1075 +        }
1076 +      else 
1077 +        free (fd);
1078 +    }
1079 +  
1080 +  palloc_free_page (kfile);
1081 +  return handle;
1082 +}
1083
1084 +/* Returns the file descriptor associated with the given handle.
1085 +   Terminates the process if HANDLE is not associated with an
1086 +   open file. */
1087 +static struct file_descriptor *
1088 +lookup_fd (int handle) 
1089 +{
1090 +  struct thread *cur = thread_current ();
1091 +  struct list_elem *e;
1092 +   
1093 +  for (e = list_begin (&cur->fds); e != list_end (&cur->fds);
1094 +       e = list_next (e))
1095 +    {
1096 +      struct file_descriptor *fd;
1097 +      fd = list_entry (e, struct file_descriptor, elem);
1098 +      if (fd->handle == handle)
1099 +        return fd;
1100 +    }
1101
1102 +  thread_exit ();
1103 +}
1104
1105 +/* Filesize system call. */
1106 +static int
1107 +sys_filesize (int handle) 
1108 +{
1109 +  struct file_descriptor *fd = lookup_fd (handle);
1110 +  int size;
1111
1112 +  size = file_length (fd->file);
1113
1114 +  return size;
1115 +}
1116
1117 +/* Read system call. */
1118 +static int
1119 +sys_read (int handle, void *udst_, unsigned size) 
1120 +{
1121 +  uint8_t *udst = udst_;
1122 +  struct file_descriptor *fd;
1123 +  int bytes_read = 0;
1124 +
1125 +  /* Look up file descriptor. */
1126 +  if (handle != STDIN_FILENO)
1127 +    fd = lookup_fd (handle);
1128 +
1129 +  while (size > 0) 
1130 +    {
1131 +      /* How much to read into this page? */
1132 +      size_t page_left = PGSIZE - pg_ofs (udst);
1133 +      size_t read_amt = size < page_left ? size : page_left;
1134 +      off_t retval;
1135 +
1136 +      /* Check that touching this page is okay. */
1137 +      if (!page_lock (udst, true)) 
1138 +        thread_exit ();
1139 +
1140 +      /* Read from file into page. */
1141 +      if (handle != STDIN_FILENO) 
1142 +        {
1143 +          retval = file_read (fd->file, udst, read_amt);
1144 +          if (retval < 0)
1145 +            {
1146 +              if (bytes_read == 0)
1147 +                bytes_read = -1; 
1148 +              break;
1149 +            }
1150 +          bytes_read += retval; 
1151 +        }
1152 +      else 
1153 +        {
1154 +          size_t i;
1155 +          
1156 +          for (i = 0; i < read_amt; i++) 
1157 +            udst[i] = kbd_getc ();
1158 +          bytes_read = read_amt;
1159 +        }
1160 +
1161 +      /* Release page. */
1162 +      page_unlock (udst);
1163 +
1164 +      /* If it was a short read we're done. */
1165 +      if (retval != (off_t) read_amt)
1166 +        break;
1167 +
1168 +      /* Advance. */
1169 +      udst += retval;
1170 +      size -= retval;
1171 +    }
1172 +   
1173 +  return bytes_read;
1174 +}
1175
1176 +/* Write system call. */
1177 +static int
1178 +sys_write (int handle, void *usrc_, unsigned size) 
1179 +{
1180 +  uint8_t *usrc = usrc_;
1181 +  struct file_descriptor *fd = NULL;
1182 +  int bytes_written = 0;
1183 +
1184 +  /* Lookup up file descriptor. */
1185 +  if (handle != STDOUT_FILENO)
1186 +    fd = lookup_fd (handle);
1187 +
1188 +  while (size > 0) 
1189 +    {
1190 +      /* How much bytes to write to this page? */
1191 +      size_t page_left = PGSIZE - pg_ofs (usrc);
1192 +      size_t write_amt = size < page_left ? size : page_left;
1193 +      off_t retval;
1194 +
1195 +      /* Check that we can touch this user page. */
1196 +      if (!page_lock (usrc, false)) 
1197 +        thread_exit ();
1198 +
1199 +      /* Do the write. */
1200 +      if (handle == STDOUT_FILENO)
1201 +        {
1202 +          putbuf (usrc, write_amt);
1203 +          retval = write_amt;
1204 +        }
1205 +      else
1206 +        retval = file_write (fd->file, usrc, write_amt);
1207 +
1208 +      /* Release user page. */
1209 +      page_unlock (usrc);
1210 +
1211 +      /* Handle return value. */
1212 +      if (retval < 0) 
1213 +        {
1214 +          if (bytes_written == 0)
1215 +            bytes_written = -1;
1216 +          break;
1217 +        }
1218 +      bytes_written += retval;
1219 +
1220 +      /* If it was a short write we're done. */
1221 +      if (retval != (off_t) write_amt)
1222 +        break;
1223 +
1224 +      /* Advance. */
1225 +      usrc += retval;
1226 +      size -= retval;
1227 +    }
1228
1229 +  return bytes_written;
1230 +}
1231
1232 +/* Seek system call. */
1233 +static int
1234 +sys_seek (int handle, unsigned position) 
1235 +{
1236 +  if ((off_t) position >= 0)
1237 +    file_seek (lookup_fd (handle)->file, position);
1238 +  return 0;
1239 +}
1240
1241 +/* Tell system call. */
1242 +static int
1243 +sys_tell (int handle) 
1244 +{
1245 +  return file_tell (lookup_fd (handle)->file);
1246 +}
1247
1248 +/* Close system call. */
1249 +static int
1250 +sys_close (int handle) 
1251 +{
1252 +  struct file_descriptor *fd = lookup_fd (handle);
1253 +  file_close (fd->file);
1254 +  list_remove (&fd->elem);
1255 +  free (fd);
1256 +  return 0;
1257 +}
1258 +\f
1259 +/* Binds a mapping id to a region of memory and a file. */
1260 +struct mapping
1261 +  {
1262 +    struct list_elem elem;      /* List element. */
1263 +    int handle;                 /* Mapping id. */
1264 +    struct file *file;          /* File. */
1265 +    uint8_t *base;              /* Start of memory mapping. */
1266 +    size_t page_cnt;            /* Number of pages mapped. */
1267 +  };
1268 +
1269 +/* Returns the file descriptor associated with the given handle.
1270 +   Terminates the process if HANDLE is not associated with a
1271 +   memory mapping. */
1272 +static struct mapping *
1273 +lookup_mapping (int handle) 
1274 +{
1275 +  struct thread *cur = thread_current ();
1276 +  struct list_elem *e;
1277 +   
1278 +  for (e = list_begin (&cur->mappings); e != list_end (&cur->mappings);
1279 +       e = list_next (e))
1280 +    {
1281 +      struct mapping *m = list_entry (e, struct mapping, elem);
1282 +      if (m->handle == handle)
1283 +        return m;
1284 +    }
1285
1286 +  thread_exit ();
1287 +}
1288 +
1289 +/* Remove mapping M from the virtual address space,
1290 +   writing back any pages that have changed. */
1291 +static void
1292 +unmap (struct mapping *m) 
1293 +{
1294 +  list_remove (&m->elem);
1295 +  while (m->page_cnt-- > 0) 
1296 +    {
1297 +      page_deallocate (m->base);
1298 +      m->base += PGSIZE;
1299 +    }
1300 +  file_close (m->file);
1301 +  free (m);
1302 +}
1303
1304 +/* Mmap system call. */
1305 +static int
1306 +sys_mmap (int handle, void *addr)
1307 +{
1308 +  struct file_descriptor *fd = lookup_fd (handle);
1309 +  struct mapping *m = malloc (sizeof *m);
1310 +  size_t offset;
1311 +  off_t length;
1312 +
1313 +  if (m == NULL || addr == NULL || pg_ofs (addr) != 0)
1314 +    return -1;
1315 +
1316 +  m->handle = thread_current ()->next_handle++;
1317 +  m->file = file_reopen (fd->file);
1318 +  if (m->file == NULL) 
1319 +    {
1320 +      free (m);
1321 +      return -1;
1322 +    }
1323 +  m->base = addr;
1324 +  m->page_cnt = 0;
1325 +  list_push_front (&thread_current ()->mappings, &m->elem);
1326 +
1327 +  offset = 0;
1328 +  length = file_length (m->file);
1329 +  while (length > 0)
1330 +    {
1331 +      struct page *p = page_allocate ((uint8_t *) addr + offset, false);
1332 +      if (p == NULL)
1333 +        {
1334 +          unmap (m);
1335 +          return -1;
1336 +        }
1337 +      p->private = false;
1338 +      p->file = m->file;
1339 +      p->file_offset = offset;
1340 +      p->file_bytes = length >= PGSIZE ? PGSIZE : length;
1341 +      offset += p->file_bytes;
1342 +      length -= p->file_bytes;
1343 +      m->page_cnt++;
1344 +    }
1345 +  
1346 +  return m->handle;
1347 +}
1348 +
1349 +/* Munmap system call. */
1350 +static int
1351 +sys_munmap (int mapping) 
1352 +{
1353 +  unmap (lookup_mapping (mapping));
1354 +  return 0;
1355 +}
1356 +\f 
1357 +/* On thread exit, close all open files and unmap all mappings. */
1358 +void
1359 +syscall_exit (void) 
1360 +{
1361 +  struct thread *cur = thread_current ();
1362 +  struct list_elem *e, *next;
1363 +   
1364 +  for (e = list_begin (&cur->fds); e != list_end (&cur->fds); e = next)
1365 +    {
1366 +      struct file_descriptor *fd = list_entry (e, struct file_descriptor, elem);
1367 +      next = list_next (e);
1368 +      file_close (fd->file);
1369 +      free (fd);
1370 +    }
1371 +   
1372 +  for (e = list_begin (&cur->mappings); e != list_end (&cur->mappings);
1373 +       e = next)
1374 +    {
1375 +      struct mapping *m = list_entry (e, struct mapping, elem);
1376 +      next = list_next (e);
1377 +      unmap (m);
1378 +    }
1379  }
1380 diff -u src/userprog/syscall.h~ src/userprog/syscall.h
1381 --- src/userprog/syscall.h~ 2004-09-05 22:38:45.000000000 -0700
1382 +++ src/userprog/syscall.h 2005-06-08 14:10:54.000000000 -0700
1383 @@ -2,5 +2,6 @@
1384  #define USERPROG_SYSCALL_H
1385  
1386  void syscall_init (void);
1387 +void syscall_exit (void);
1388  
1389  #endif /* userprog/syscall.h */
1390 diff -u src/vm/frame.c~ src/vm/frame.c
1391 --- src/vm/frame.c~ 1969-12-31 16:00:00.000000000 -0800
1392 +++ src/vm/frame.c 2005-06-08 14:10:54.000000000 -0700
1393 @@ -0,0 +1,162 @@
1394 +#include "vm/frame.h"
1395 +#include <stdio.h>
1396 +#include "vm/page.h"
1397 +#include "devices/timer.h"
1398 +#include "threads/init.h"
1399 +#include "threads/malloc.h"
1400 +#include "threads/mmu.h"
1401 +#include "threads/palloc.h"
1402 +#include "threads/synch.h"
1403 +
1404 +static struct frame *frames;
1405 +static size_t frame_cnt;
1406 +
1407 +static struct lock scan_lock;
1408 +static size_t hand;
1409 +
1410 +/* Initialize the frame manager. */
1411 +void
1412 +frame_init (void) 
1413 +{
1414 +  void *base;
1415 +
1416 +  lock_init (&scan_lock);
1417 +  
1418 +  frames = malloc (sizeof *frames * ram_pages);
1419 +  if (frames == NULL)
1420 +    PANIC ("out of memory allocating page frames");
1421 +
1422 +  while ((base = palloc_get_page (PAL_USER)) != NULL) 
1423 +    {
1424 +      struct frame *f = &frames[frame_cnt++];
1425 +      lock_init (&f->lock);
1426 +      f->base = base;
1427 +      f->page = NULL;
1428 +    }
1429 +}
1430 +
1431 +/* Tries to allocate and lock a frame for PAGE.
1432 +   Returns the frame if successful, false on failure. */
1433 +static struct frame *
1434 +try_frame_alloc_and_lock (struct page *page) 
1435 +{
1436 +  size_t i;
1437 +
1438 +  lock_acquire (&scan_lock);
1439 +
1440 +  /* Find a free frame. */
1441 +  for (i = 0; i < frame_cnt; i++)
1442 +    {
1443 +      struct frame *f = &frames[i];
1444 +      if (!lock_try_acquire (&f->lock))
1445 +        continue;
1446 +      if (f->page == NULL) 
1447 +        {
1448 +          f->page = page;
1449 +          lock_release (&scan_lock);
1450 +          return f;
1451 +        } 
1452 +      lock_release (&f->lock);
1453 +    }
1454 +
1455 +  /* No free frame.  Find a frame to evict. */
1456 +  for (i = 0; i < frame_cnt * 2; i++) 
1457 +    {
1458 +      /* Get a frame. */
1459 +      struct frame *f = &frames[hand];
1460 +      if (++hand >= frame_cnt)
1461 +        hand = 0;
1462 +
1463 +      if (!lock_try_acquire (&f->lock))
1464 +        continue;
1465 +
1466 +      if (f->page == NULL) 
1467 +        {
1468 +          f->page = page;
1469 +          lock_release (&scan_lock);
1470 +          return f;
1471 +        } 
1472 +
1473 +      if (page_accessed_recently (f->page)) 
1474 +        {
1475 +          lock_release (&f->lock);
1476 +          continue;
1477 +        }
1478 +          
1479 +      lock_release (&scan_lock);
1480 +      
1481 +      /* Evict this frame. */
1482 +      if (!page_out (f->page))
1483 +        {
1484 +          lock_release (&f->lock);
1485 +          return NULL;
1486 +        }
1487 +
1488 +      f->page = page;
1489 +      return f;
1490 +    }
1491 +
1492 +  lock_release (&scan_lock);
1493 +  return NULL;
1494 +}
1495 +
1496 +
1497 +/* Tries really hard to allocate and lock a frame for PAGE.
1498 +   Returns the frame if successful, false on failure. */
1499 +struct frame *
1500 +frame_alloc_and_lock (struct page *page) 
1501 +{
1502 +  size_t try;
1503 +
1504 +  for (try = 0; try < 3; try++) 
1505 +    {
1506 +      struct frame *f = try_frame_alloc_and_lock (page);
1507 +      if (f != NULL) 
1508 +        {
1509 +          ASSERT (lock_held_by_current_thread (&f->lock));
1510 +          return f; 
1511 +        }
1512 +      timer_msleep (1000);
1513 +    }
1514 +
1515 +  return NULL;
1516 +}
1517 +
1518 +/* Locks P's frame into memory, if it has one.
1519 +   Upon return, p->frame will not change until P is unlocked. */
1520 +void
1521 +frame_lock (struct page *p) 
1522 +{
1523 +  /* A frame can be asynchronously removed, but never inserted. */
1524 +  struct frame *f = p->frame;
1525 +  if (f != NULL) 
1526 +    {
1527 +      lock_acquire (&f->lock);
1528 +      if (f != p->frame)
1529 +        {
1530 +          lock_release (&f->lock);
1531 +          ASSERT (p->frame == NULL); 
1532 +        } 
1533 +    }
1534 +}
1535 +
1536 +/* Releases frame F for use by another page.
1537 +   F must be locked for use by the current process.
1538 +   Any data in F is lost. */
1539 +void
1540 +frame_free (struct frame *f)
1541 +{
1542 +  ASSERT (lock_held_by_current_thread (&f->lock));
1543 +          
1544 +  f->page = NULL;
1545 +  lock_release (&f->lock);
1546 +}
1547 +
1548 +/* Unlocks frame F, allowing it to be evicted.
1549 +   F must be locked for use by the current process. */
1550 +void
1551 +frame_unlock (struct frame *f) 
1552 +{
1553 +  ASSERT (lock_held_by_current_thread (&f->lock));
1554 +  lock_release (&f->lock);
1555 +}
1556 diff -u src/vm/frame.h~ src/vm/frame.h
1557 --- src/vm/frame.h~ 1969-12-31 16:00:00.000000000 -0800
1558 +++ src/vm/frame.h 2005-06-08 14:10:54.000000000 -0700
1559 @@ -0,0 +1,23 @@
1560 +#ifndef VM_FRAME_H
1561 +#define VM_FRAME_H
1562 +
1563 +#include <stdbool.h>
1564 +#include "threads/synch.h"
1565 +
1566 +/* A physical frame. */
1567 +struct frame 
1568 +  {
1569 +    struct lock lock;           /* Prevent simultaneous access. */
1570 +    void *base;                 /* Kernel virtual base address. */
1571 +    struct page *page;          /* Mapped process page, if any. */
1572 +  };
1573 +
1574 +void frame_init (void);
1575 +
1576 +struct frame *frame_alloc_and_lock (struct page *);
1577 +void frame_lock (struct page *);
1578 +
1579 +void frame_free (struct frame *);
1580 +void frame_unlock (struct frame *);
1581 +
1582 +#endif /* vm/frame.h */
1583 diff -u src/vm/page.c~ src/vm/page.c
1584 --- src/vm/page.c~ 1969-12-31 16:00:00.000000000 -0800
1585 +++ src/vm/page.c 2005-06-08 14:10:54.000000000 -0700
1586 @@ -0,0 +1,293 @@
1587 +#include "vm/page.h"
1588 +#include <stdio.h>
1589 +#include <string.h>
1590 +#include "vm/frame.h"
1591 +#include "vm/swap.h"
1592 +#include "filesys/file.h"
1593 +#include "threads/malloc.h"
1594 +#include "threads/mmu.h"
1595 +#include "threads/thread.h"
1596 +#include "userprog/pagedir.h"
1597 +
1598 +/* Maximum size of process stack, in bytes. */
1599 +#define STACK_MAX (1024 * 1024)
1600 +
1601 +/* Destroys a page, which must be in the current process's
1602 +   page table.  Used as a callback for hash_destroy(). */
1603 +static void
1604 +destroy_page (struct hash_elem *p_, void *aux UNUSED)
1605 +{
1606 +  struct page *p = hash_entry (p_, struct page, hash_elem);
1607 +  frame_lock (p);
1608 +  if (p->frame)
1609 +    frame_free (p->frame);
1610 +  free (p);
1611 +}
1612 +
1613 +/* Destroys the current process's page table. */
1614 +void
1615 +page_exit (void) 
1616 +{
1617 +  struct hash *h = thread_current ()->pages;
1618 +  if (h != NULL)
1619 +    hash_destroy (h, destroy_page);
1620 +}
1621 +
1622 +/* Returns the page containing the given virtual ADDRESS,
1623 +   or a null pointer if no such page exists.
1624 +   Allocates stack pages as necessary. */
1625 +static struct page *
1626 +page_for_addr (const void *address) 
1627 +{
1628 +  if (address < PHYS_BASE) 
1629 +    {
1630 +      struct page p;
1631 +      struct hash_elem *e;
1632 +
1633 +      /* Find existing page. */
1634 +      p.addr = (void *) pg_round_down (address);
1635 +      e = hash_find (thread_current ()->pages, &p.hash_elem);
1636 +      if (e != NULL)
1637 +        return hash_entry (e, struct page, hash_elem);
1638 +
1639 +      /* No page.  Expand stack? */
1640 +      if (address >= PHYS_BASE - STACK_MAX
1641 +          && address >= thread_current ()->user_esp - 32)
1642 +        return page_allocate ((void *) address, false);
1643 +    }
1644 +  return NULL;
1645 +}
1646 +
1647 +/* Locks a frame for page P and pages it in.
1648 +   Returns true if successful, false on failure. */
1649 +static bool
1650 +do_page_in (struct page *p)
1651 +{
1652 +  /* Get a frame for the page. */
1653 +  p->frame = frame_alloc_and_lock (p);
1654 +  if (p->frame == NULL)
1655 +    return false;
1656 +
1657 +  /* Copy data into the frame. */
1658 +  if (p->sector != (disk_sector_t) -1) 
1659 +    {
1660 +      /* Get data from swap. */
1661 +      swap_in (p); 
1662 +    }
1663 +  else if (p->file != NULL) 
1664 +    {
1665 +      /* Get data from file. */
1666 +      off_t read_bytes = file_read_at (p->file, p->frame->base,
1667 +                                        p->file_bytes, p->file_offset);
1668 +      off_t zero_bytes = PGSIZE - read_bytes;
1669 +      memset (p->frame->base + read_bytes, 0, zero_bytes);
1670 +      if (read_bytes != p->file_bytes)
1671 +        printf ("bytes read (%"PROTd") != bytes requested (%"PROTd")\n",
1672 +                read_bytes, p->file_bytes);
1673 +    }
1674 +  else 
1675 +    {
1676 +      /* Provide all-zero page. */
1677 +      memset (p->frame->base, 0, PGSIZE);
1678 +    }
1679 +
1680 +  return true;
1681 +}
1682 +
1683 +/* Faults in the page containing FAULT_ADDR.
1684 +   Returns true if successful, false on failure. */
1685 +bool
1686 +page_in (void *fault_addr) 
1687 +{
1688 +  struct page *p;
1689 +  bool success;
1690 +
1691 +  /* Can't handle page faults without a hash table. */
1692 +  if (thread_current ()->pages == NULL) 
1693 +    return false;
1694 +
1695 +  p = page_for_addr (fault_addr);
1696 +  if (p == NULL) 
1697 +    return false; 
1698 +
1699 +  frame_lock (p);
1700 +  if (p->frame == NULL)
1701 +    {
1702 +      if (!do_page_in (p))
1703 +        return false;
1704 +    }
1705 +  ASSERT (lock_held_by_current_thread (&p->frame->lock));
1706 +    
1707 +  /* Install frame into page table. */
1708 +  success = pagedir_set_page (thread_current ()->pagedir, p->addr,
1709 +                              p->frame->base, !p->read_only);
1710 +
1711 +  /* Release frame. */
1712 +  frame_unlock (p->frame);
1713 +
1714 +  return success;
1715 +}
1716 +
1717 +/* Evicts page P.
1718 +   P must have a locked frame.
1719 +   Return true if successful, false on failure. */
1720 +bool
1721 +page_out (struct page *p) 
1722 +{
1723 +  bool dirty;
1724 +  bool ok;
1725 +
1726 +  ASSERT (p->frame != NULL);
1727 +  ASSERT (lock_held_by_current_thread (&p->frame->lock));
1728 +
1729 +  /* Mark page not present in page table, forcing accesses by the
1730 +     process to fault.  This must happen before checking the
1731 +     dirty bit, to prevent a race with the process dirtying the
1732 +     page. */
1733 +  pagedir_clear_page (p->thread->pagedir, p->addr);
1734 +
1735 +  /* Has the frame been modified? */
1736 +  dirty = pagedir_is_dirty (p->thread->pagedir, p->addr);
1737 +
1738 +  /* Write frame contents to disk if necessary. */
1739 +  if (p->file != NULL) 
1740 +    {
1741 +      if (dirty) 
1742 +        {
1743 +          if (p->private)
1744 +            ok = swap_out (p);
1745 +          else 
1746 +            ok = file_write_at (p->file, p->frame->base, p->file_bytes,
1747 +                                p->file_offset) == p->file_bytes;
1748 +        }
1749 +      else
1750 +        ok = true;
1751 +    }
1752 +  else
1753 +    ok = swap_out (p);
1754 +  if (ok) 
1755 +    {
1756 +      //memset (p->frame->base, 0xcc, PGSIZE);
1757 +      p->frame = NULL; 
1758 +    }
1759 +  return ok;
1760 +}
1761 +
1762 +/* Returns true if page P's data has been accessed recently,
1763 +   false otherwise.
1764 +   P must have a frame locked into memory. */
1765 +bool
1766 +page_accessed_recently (struct page *p) 
1767 +{
1768 +  bool was_accessed;
1769 +
1770 +  ASSERT (p->frame != NULL);
1771 +  ASSERT (lock_held_by_current_thread (&p->frame->lock));
1772 +
1773 +  was_accessed = pagedir_is_accessed (p->thread->pagedir, p->addr);
1774 +  if (was_accessed)
1775 +    pagedir_set_accessed (p->thread->pagedir, p->addr, false);
1776 +  return was_accessed;
1777 +}
1778 +
1779 +/* Adds a mapping for user virtual address VADDR to the page hash
1780 +   table.  Fails if VADDR is already mapped or if memory
1781 +   allocation fails. */
1782 +struct page *
1783 +page_allocate (void *vaddr, bool read_only)
1784 +{
1785 +  struct thread *t = thread_current ();
1786 +  struct page *p = malloc (sizeof *p);
1787 +  if (p != NULL) 
1788 +    {
1789 +      p->addr = pg_round_down (vaddr);
1790 +
1791 +      p->read_only = read_only;
1792 +      p->private = !read_only;
1793 +
1794 +      p->frame = NULL;
1795 +
1796 +      p->sector = (disk_sector_t) -1;
1797 +
1798 +      p->file = NULL;
1799 +      p->file_offset = 0;
1800 +      p->file_bytes = 0;
1801 +
1802 +      p->thread = thread_current ();
1803 +
1804 +      if (hash_insert (t->pages, &p->hash_elem) != NULL) 
1805 +        {
1806 +          /* Already mapped. */
1807 +          free (p);
1808 +          p = NULL;
1809 +        }
1810 +    }
1811 +  return p;
1812 +}
1813 +
1814 +/* Evicts the page containing address VADDR
1815 +   and removes it from the page table. */
1816 +void
1817 +page_deallocate (void *vaddr) 
1818 +{
1819 +  struct page *p = page_for_addr (vaddr);
1820 +  ASSERT (p != NULL);
1821 +  frame_lock (p);
1822 +  if (p->frame)
1823 +    {
1824 +      struct frame *f = p->frame;
1825 +      if (p->file && !p->private) 
1826 +        page_out (p); 
1827 +      frame_free (f);
1828 +    }
1829 +  hash_delete (thread_current ()->pages, &p->hash_elem);
1830 +  free (p);
1831 +}
1832 +
1833 +/* Returns a hash value for the page that E refers to. */
1834 +unsigned
1835 +page_hash (const struct hash_elem *e, void *aux UNUSED) 
1836 +{
1837 +  const struct page *p = hash_entry (e, struct page, hash_elem);
1838 +  return ((uintptr_t) p->addr) >> PGBITS;
1839 +}
1840 +
1841 +/* Returns true if page A precedes page B. */
1842 +bool
1843 +page_less (const struct hash_elem *a_, const struct hash_elem *b_,
1844 +           void *aux UNUSED) 
1845 +{
1846 +  const struct page *a = hash_entry (a_, struct page, hash_elem);
1847 +  const struct page *b = hash_entry (b_, struct page, hash_elem);
1848 +  
1849 +  return a->addr < b->addr;
1850 +}
1851 +
1852 +/* Tries to lock the page containing ADDR into physical memory.
1853 +   If WILL_WRITE is true, the page must be writeable;
1854 +   otherwise it may be read-only.
1855 +   Returns true if successful, false on failure. */
1856 +bool
1857 +page_lock (const void *addr, bool will_write) 
1858 +{
1859 +  struct page *p = page_for_addr (addr);
1860 +  if (p == NULL || (p->read_only && will_write))
1861 +    return false;
1862 +  
1863 +  frame_lock (p);
1864 +  if (p->frame == NULL)
1865 +    return (do_page_in (p)
1866 +            && pagedir_set_page (thread_current ()->pagedir, p->addr,
1867 +                                 p->frame->base, !p->read_only)); 
1868 +  else
1869 +    return true;
1870 +}
1871 +
1872 +/* Unlocks a page locked with page_lock(). */
1873 +void
1874 +page_unlock (const void *addr) 
1875 +{
1876 +  struct page *p = page_for_addr (addr);
1877 +  ASSERT (p != NULL);
1878 +  frame_unlock (p->frame);
1879 +}
1880 diff -u src/vm/page.h~ src/vm/page.h
1881 --- src/vm/page.h~ 1969-12-31 16:00:00.000000000 -0800
1882 +++ src/vm/page.h 2005-06-08 14:10:54.000000000 -0700
1883 @@ -0,0 +1,50 @@
1884 +#ifndef VM_PAGE_H
1885 +#define VM_PAGE_H
1886 +
1887 +#include <hash.h>
1888 +#include "devices/disk.h"
1889 +#include "filesys/off_t.h"
1890 +#include "threads/synch.h"
1891 +
1892 +/* Virtual page. */
1893 +struct page 
1894 +  {
1895 +    /* Immutable members. */
1896 +    void *addr;                 /* User virtual address. */
1897 +    bool read_only;             /* Read-only page? */
1898 +    struct thread *thread;      /* Owning thread. */
1899 +
1900 +    /* Accessed only in owning process context. */
1901 +    struct hash_elem hash_elem; /* struct thread `pages' hash element. */
1902 +
1903 +    /* Set only in owning process context with frame->frame_lock held.
1904 +       Cleared only with scan_lock and frame->frame_lock held. */
1905 +    struct frame *frame;        /* Page frame. */
1906 +
1907 +    /* Swap information, protected by frame->frame_lock. */
1908 +    disk_sector_t sector;       /* Starting sector of swap area, or -1. */
1909 +    
1910 +    /* Memory-mapped file information, protected by frame->frame_lock. */
1911 +    bool private;               /* False to write back to file,
1912 +                                   true to write back to swap. */
1913 +    struct file *file;          /* File. */
1914 +    off_t file_offset;          /* Offset in file. */
1915 +    off_t file_bytes;           /* Bytes to read/write, 1...PGSIZE. */
1916 +  };
1917 +
1918 +void page_exit (void);
1919 +
1920 +struct page *page_allocate (void *, bool read_only);
1921 +void page_deallocate (void *vaddr);
1922 +
1923 +bool page_in (void *fault_addr);
1924 +bool page_out (struct page *);
1925 +bool page_accessed_recently (struct page *);
1926 +
1927 +bool page_lock (const void *, bool will_write);
1928 +void page_unlock (const void *);
1929 +
1930 +hash_hash_func page_hash;
1931 +hash_less_func page_less;
1932 +
1933 +#endif /* vm/page.h */
1934 diff -u src/vm/swap.c~ src/vm/swap.c
1935 --- src/vm/swap.c~ 1969-12-31 16:00:00.000000000 -0800
1936 +++ src/vm/swap.c 2005-06-08 14:10:54.000000000 -0700
1937 @@ -0,0 +1,85 @@
1938 +#include "vm/swap.h"
1939 +#include <bitmap.h>
1940 +#include <debug.h>
1941 +#include <stdio.h>
1942 +#include "vm/frame.h"
1943 +#include "vm/page.h"
1944 +#include "devices/disk.h"
1945 +#include "threads/mmu.h"
1946 +#include "threads/synch.h"
1947 +
1948 +/* The swap disk. */
1949 +static struct disk *swap_disk;
1950 +
1951 +/* Used swap pages. */
1952 +static struct bitmap *swap_bitmap;
1953 +
1954 +/* Protects swap_bitmap. */
1955 +static struct lock swap_lock;
1956 +
1957 +/* Number of sectors per page. */
1958 +#define PAGE_SECTORS (PGSIZE / DISK_SECTOR_SIZE)
1959 +
1960 +/* Sets up swap. */
1961 +void
1962 +swap_init (void) 
1963 +{
1964 +  swap_disk = disk_get (1, 1);
1965 +  if (swap_disk == NULL) 
1966 +    {
1967 +      printf ("no swap disk--swap disabled\n");
1968 +      swap_bitmap = bitmap_create (0);
1969 +    }
1970 +  else
1971 +    swap_bitmap = bitmap_create (disk_size (swap_disk) / PAGE_SECTORS);
1972 +  if (swap_bitmap == NULL)
1973 +    PANIC ("couldn't create swap bitmap");
1974 +  lock_init (&swap_lock);
1975 +}
1976 +
1977 +/* Swaps in page P, which must have a locked frame
1978 +   (and be swapped out). */
1979 +void
1980 +swap_in (struct page *p) 
1981 +{
1982 +  size_t i;
1983 +  
1984 +  ASSERT (p->frame != NULL);
1985 +  ASSERT (lock_held_by_current_thread (&p->frame->lock));
1986 +  ASSERT (p->sector != (disk_sector_t) -1);
1987 +
1988 +  for (i = 0; i < PAGE_SECTORS; i++)
1989 +    disk_read (swap_disk, p->sector + i,
1990 +               p->frame->base + i * DISK_SECTOR_SIZE);
1991 +  bitmap_reset (swap_bitmap, p->sector / PAGE_SECTORS);
1992 +  p->sector = (disk_sector_t) -1;
1993 +}
1994 +
1995 +/* Swaps out page P, which must have a locked frame. */
1996 +bool
1997 +swap_out (struct page *p) 
1998 +{
1999 +  size_t slot;
2000 +  size_t i;
2001 +
2002 +  ASSERT (p->frame != NULL);
2003 +  ASSERT (lock_held_by_current_thread (&p->frame->lock));
2004 +
2005 +  lock_acquire (&swap_lock);
2006 +  slot = bitmap_scan_and_flip (swap_bitmap, 0, 1, false);
2007 +  lock_release (&swap_lock);
2008 +  if (slot == BITMAP_ERROR) 
2009 +    return false; 
2010 +
2011 +  p->sector = slot * PAGE_SECTORS;
2012 +  for (i = 0; i < PAGE_SECTORS; i++)
2013 +    disk_write (swap_disk, p->sector + i,
2014 +                p->frame->base + i * DISK_SECTOR_SIZE);
2015 +  
2016 +  p->private = false;
2017 +  p->file = NULL;
2018 +  p->file_offset = 0;
2019 +  p->file_bytes = 0;
2020 +
2021 +  return true;
2022 +}
2023 diff -u src/vm/swap.h~ src/vm/swap.h
2024 --- src/vm/swap.h~ 1969-12-31 16:00:00.000000000 -0800
2025 +++ src/vm/swap.h 2005-06-08 14:10:54.000000000 -0700
2026 @@ -0,0 +1,11 @@
2027 +#ifndef VM_SWAP_H
2028 +#define VM_SWAP_H 1
2029 +
2030 +#include <stdbool.h>
2031 +
2032 +struct page;
2033 +void swap_init (void);
2034 +void swap_in (struct page *);
2035 +bool swap_out (struct page *);
2036 +
2037 +#endif /* vm/swap.h */