806177e853f8763abf0c11f87833fff212a683b4
[pintos-anon] / solutions / p3.patch
1 diff -urpN pintos.orig/src/Makefile.build pintos/src/Makefile.build
2 --- pintos.orig/src/Makefile.build      2004-09-20 20:26:41.000000000 -0700
3 +++ pintos/src/Makefile.build   2004-09-27 13:29:43.000000000 -0700
4 @@ -51,8 +51,9 @@ userprog_SRC += userprog/syscall.c    # Sys
5  userprog_SRC += userprog/gdt.c         # GDT initialization.
6  userprog_SRC += userprog/tss.c         # TSS management.
7  
8 -# No virtual memory code yet.
9 -#vm_SRC = vm/filename.c                        # Some file.
10 +# Virtual memory code.
11 +vm_SRC = vm/pageframe.c                        # Page frame management.
12 +vm_SRC += vm/swap.c                    # Swap file management.
13  
14  # Filesystem code.
15  filesys_SRC  = filesys/filesys.c       # Filesystem core.
16 diff -urpN pintos.orig/src/threads/init.c pintos/src/threads/init.c
17 --- pintos.orig/src/threads/init.c      2004-09-26 14:15:17.000000000 -0700
18 +++ pintos/src/threads/init.c   2004-09-27 16:08:03.000000000 -0700
19 @@ -21,12 +21,15 @@
20  #include "threads/test.h"
21  #include "threads/thread.h"
22  #ifdef USERPROG
23 +#include "userprog/pagedir.h"
24  #include "userprog/process.h"
25  #include "userprog/exception.h"
26  #include "userprog/gdt.h"
27  #include "userprog/syscall.h"
28  #include "userprog/tss.h"
29  #endif
30 +#include "vm/pageframe.h"
31 +#include "vm/swap.h"
32  #ifdef FILESYS
33  #include "devices/disk.h"
34  #include "filesys/filesys.h"
35 @@ -78,6 +81,7 @@ main (void)
36    /* Initialize memory system, segments, paging. */
37    palloc_init ();
38    paging_init ();
39 +  pageframe_init ();
40  #ifdef USERPROG
41    tss_init ();
42    gdt_init ();
43 @@ -105,6 +109,7 @@ main (void)
44    disk_init ();
45    filesys_init (format_filesys);
46    fsutil_run ();
47 +  swap_init ();
48  #endif
49  
50    printf ("Boot complete.\n");
51 diff -urpN pintos.orig/src/threads/palloc.c pintos/src/threads/palloc.c
52 diff -urpN pintos.orig/src/threads/palloc.h pintos/src/threads/palloc.h
53 diff -urpN pintos.orig/src/threads/synch.c pintos/src/threads/synch.c
54 --- pintos.orig/src/threads/synch.c     2004-09-19 21:29:53.000000000 -0700
55 +++ pintos/src/threads/synch.c  2004-09-27 13:29:43.000000000 -0700
56 @@ -330,3 +330,35 @@ cond_name (const struct condition *cond)
57  
58    return cond->name;
59  }
60 +\f
61 +void
62 +latch_init (struct latch *latch, const char *name) 
63 +{
64 +  latch->released = false;
65 +  lock_init (&latch->monitor_lock, name);
66 +  cond_init (&latch->rel_cond, name);
67 +}
68 +
69 +void
70 +latch_acquire (struct latch *latch) 
71 +{
72 +  lock_acquire (&latch->monitor_lock);
73 +  if (!latch->released) 
74 +    {
75 +      cond_wait (&latch->rel_cond, &latch->monitor_lock);
76 +      ASSERT (latch->released); 
77 +    }
78 +  lock_release (&latch->monitor_lock);
79 +}
80 +
81 +void
82 +latch_release (struct latch *latch) 
83 +{
84 +  lock_acquire (&latch->monitor_lock);
85 +  if (!latch->released)
86 +    {
87 +      latch->released = true;
88 +      cond_signal (&latch->rel_cond, &latch->monitor_lock);
89 +    }
90 +  lock_release (&latch->monitor_lock);
91 +}
92 diff -urpN pintos.orig/src/threads/synch.h pintos/src/threads/synch.h
93 --- pintos.orig/src/threads/synch.h     2004-09-19 21:29:53.000000000 -0700
94 +++ pintos/src/threads/synch.h  2004-09-27 13:29:43.000000000 -0700
95 @@ -44,4 +44,16 @@ void cond_signal (struct condition *, st
96  void cond_broadcast (struct condition *, struct lock *);
97  const char *cond_name (const struct condition *);
98  
99 +/* Latch. */
100 +struct latch 
101 +  {
102 +    bool released;              /* Released yet? */
103 +    struct lock monitor_lock;   /* Monitor lock. */
104 +    struct condition rel_cond;  /* Signaled when released. */
105 +  };
106 +
107 +void latch_init (struct latch *, const char *);
108 +void latch_acquire (struct latch *);
109 +void latch_release (struct latch *);
110 +
111  #endif /* threads/synch.h */
112 diff -urpN pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
113 --- pintos.orig/src/threads/thread.c    2004-09-26 14:15:17.000000000 -0700
114 +++ pintos/src/threads/thread.c 2004-09-27 13:29:43.000000000 -0700
115 @@ -13,6 +13,7 @@
116  #include "threads/synch.h"
117  #ifdef USERPROG
118  #include "userprog/process.h"
119 +#include "userprog/syscall.h"
120  #endif
121  
122  /* Random value for struct thread's `magic' member.
123 @@ -80,6 +81,7 @@ thread_init (void) 
124    init_thread (initial_thread, "main", PRI_DEFAULT);
125    initial_thread->status = THREAD_RUNNING;
126    initial_thread->tid = allocate_tid ();
127 +  sema_up (&initial_thread->can_die);
128  }
129  
130  /* Starts preemptive thread scheduling by enabling interrupts.
131 @@ -148,6 +150,7 @@ thread_create (const char *name, int pri
132    /* Initialize thread. */
133    init_thread (t, name, priority);
134    tid = t->tid = allocate_tid ();
135 +  list_push_back (&thread_current ()->children, &t->children_elem);
136  
137    /* Stack frame for kernel_thread(). */
138    kf = alloc_frame (t, sizeof *kf);
139 @@ -224,16 +227,36 @@ thread_tid (void) 
140  void
141  thread_exit (void) 
142  {
143 +  struct thread *t = thread_current ();
144 +  list_elem *e, *next;
145 +
146    ASSERT (!intr_context ());
147  
148  #ifdef USERPROG
149    process_exit ();
150  #endif
151 +  syscall_exit ();
152 +  
153 +  /* Notify our parent that we're dying. */
154 +  latch_release (&t->ready_to_die);
155 +
156 +  /* Notify our children that they can die. */
157 +  for (e = list_begin (&t->children); e != list_end (&t->children);
158 +       e = next) 
159 +    {
160 +      struct thread *child = list_entry (e, struct thread, children_elem);
161 +      next = list_next (e);
162 +      list_remove (e);
163 +      sema_up (&child->can_die); 
164 +    }
165 +
166 +  /* Wait until our parent is ready for us to die. */
167 +  sema_down (&t->can_die);
168  
169    /* Just set our status to dying and schedule another process.
170       We will be destroyed during the call to schedule_tail(). */
171    intr_disable ();
172 -  thread_current ()->status = THREAD_DYING;
173 +  t->status = THREAD_DYING;
174    schedule ();
175    NOT_REACHED ();
176  }
177 @@ -283,8 +290,22 @@ thread_block (void) 
178     This function will be implemented in problem 1-2.  For now, it
179     does nothing. */
180 -void
181 -thread_join (tid_t child_tid UNUSED) 
182 -{
183 +int
184 +thread_join (tid_t child_tid) 
185 +{
186 +  struct thread *cur = thread_current ();
187 +  list_elem *e;
188 +
189 +  for (e = list_begin (&cur->children); e != list_end (&cur->children); ) 
190 +    {
191 +      struct thread *child = list_entry (e, struct thread, children_elem);
192 +      e = list_next (e);
193 +      if (child->tid == child_tid) 
194 +        {
195 +          latch_acquire (&child->ready_to_die);
196 +          return child->ret_code;
197 +        }
198 +    }
199 +  return -1;
200  }
201  
202  /* Sets the current thread's priority to NEW_PRIORITY. */
203 @@ -335,6 +378,12 @@ init_thread (struct thread *t, const cha
204    strlcpy (t->name, name, sizeof t->name);
205    t->stack = (uint8_t *) t + PGSIZE;
206    t->priority = priority;
207 +  latch_init (&t->ready_to_die, "ready-to-die");
208 +  sema_init (&t->can_die, 0, "can-die");
209 +  list_init (&t->children);
210 +  t->ret_code = -1;
211 +  list_init (&t->fds);
212 +  t->next_handle = 2;
213    t->magic = THREAD_MAGIC;
214  }
215  
216 diff -urpN pintos.orig/src/threads/thread.h pintos/src/threads/thread.h
217 --- pintos.orig/src/threads/thread.h    2004-09-26 14:15:17.000000000 -0700
218 +++ pintos/src/threads/thread.h 2004-09-27 13:29:43.000000000 -0700
219 @@ -2,8 +2,10 @@
220  #define THREADS_THREAD_H
221  
222  #include <debug.h>
223 +#include <hash.h>
224  #include <list.h>
225  #include <stdint.h>
226 +#include "threads/synch.h"
227  
228  /* States in a thread's life cycle. */
229  enum thread_status
230 @@ -89,12 +91,24 @@ struct thread
231      uint8_t *stack;                     /* Saved stack pointer. */
232      int priority;                       /* Priority. */
233  
234 +    /* Members for implementing thread_join(). */
235 +    struct latch ready_to_die;          /* Release when thread about to die. */
236 +    struct semaphore can_die;           /* Up when thread allowed to die. */
237 +    struct list children;               /* List of child threads. */
238 +    list_elem children_elem;            /* Element of `children' list. */
239 +    int ret_code;                       /* Return status. */
240 +
241      /* Shared between thread.c and synch.c. */
242      list_elem elem;                     /* List element. */
243  
244  #ifdef USERPROG
245      /* Owned by userprog/process.c. */
246      uint32_t *pagedir;                  /* Page directory. */
247 +    struct hash pages;                  /* Hash of `struct user_page's. */
248 +
249 +    /* Owned by syscall.c. */
250 +    struct list fds;                    /* List of file descriptors. */
251 +    int next_handle;                    /* Next handle value. */
252  #endif
253  
254      /* Owned by thread.c */
255 @@ -120,7 +132,7 @@ void thread_exit (void) NO_RETURN;
256  void thread_exit (void) NO_RETURN;
257  void thread_yield (void);
258  
259 -void thread_join (tid_t);
260 +int thread_join (tid_t);
261  
262  void thread_set_priority (int);
263  int thread_get_priority (void);
264 diff -urpN pintos.orig/src/userprog/exception.c pintos/src/userprog/exception.c
265 --- pintos.orig/src/userprog/exception.c        2004-09-26 14:15:17.000000000 -0700
266 +++ pintos/src/userprog/exception.c     2004-09-27 13:29:44.000000000 -0700
267 @@ -1,9 +1,16 @@
268  #include "userprog/exception.h"
269  #include <inttypes.h>
270  #include <stdio.h>
271 +#include <string.h>
272  #include "userprog/gdt.h"
273 +#include "userprog/pagedir.h"
274 +#include "userprog/process.h"
275 +#include "filesys/file.h"
276  #include "threads/interrupt.h"
277 +#include "threads/mmu.h"
278  #include "threads/thread.h"
279 +#include "vm/pageframe.h"
280 +#include "vm/swap.h"
281  
282  /* Number of page faults processed. */
283  static long long page_fault_cnt;
284 @@ -124,10 +131,13 @@ kill (struct intr_frame *f) 
285  static void
286  page_fault (struct intr_frame *f) 
287  {
288 +  struct thread *t;
289    bool not_present;  /* True: not-present page, false: writing r/o page. */
290    bool write;        /* True: access was write, false: access was read. */
291    bool user;         /* True: access by user, false: access by kernel. */
292    void *fault_addr;  /* Fault address. */
293 +  struct user_page tmp_up, *up;
294 +  hash_elem *e;
295  
296    /* Obtain faulting address, the virtual address that was
297       accessed to cause the fault.  It may point to code or to
298 @@ -147,14 +157,62 @@ page_fault (struct intr_frame *f) 
299    write = (f->error_code & PF_W) != 0;
300    user = (f->error_code & PF_U) != 0;
301  
302 -  /* To implement virtual memory, delete the rest of the function
303 -     body, and replace it with code that brings in the page to
304 -     which fault_addr refers. */
305 -  printf ("Page fault at %p: %s error %s page in %s context.\n",
306 -          fault_addr,
307 -          not_present ? "not present" : "rights violation",
308 -          write ? "writing" : "reading",
309 -          user ? "user" : "kernel");
310 -  kill (f);
311 +  if (!not_present) 
312 +    goto bad_access;
313 +
314 +  t = thread_current ();
315 +  if (t->pagedir == NULL)
316 +    goto bad_access;
317 +
318 +  //printf ("fault %p (page=%p)\n", fault_addr, pg_round_down (fault_addr));
319 +  tmp_up.upage = pg_round_down (fault_addr);
320 +  e = hash_find (&t->pages, &tmp_up.elem);
321 +  if (e == NULL) 
322 +    {
323 +      printf ("no user_page for %p\n", fault_addr);
324 +      goto bad_access; 
325 +    }
326 +  up = hash_entry (e, struct user_page, elem);
327 +
328 +  if (up->frame == NULL) 
329 +    {
330 +      if (!pageframe_allocate (up))
331 +        {
332 +          printf ("virtual memory exhausted, killing process\n");
333 +          if (!user)
334 +            goto bad_access;
335 +          thread_exit ();
336 +        }
337 +      if (up->file != NULL) 
338 +        {
339 +          off_t amt = file_read_at (up->file,
340 +                                    up->frame->kpage, up->file_size,
341 +                                    up->file_ofs);
342 +          ASSERT (amt == (off_t) up->file_size);
343 +          memset (up->frame->kpage + up->file_size, 0, PGSIZE - up->file_size);
344 +        }
345 +      else if (up->swap_page != SIZE_MAX)
346 +        swap_read (up);
347 +      else
348 +        memset (up->frame->kpage, 0, PGSIZE);
349 +    }
350 +  pagedir_set_page (t->pagedir, up->upage, up->frame->kpage, true);
351 +  return;
352 +
353 + bad_access:
354 +  if (user || fault_addr > PHYS_BASE) 
355 +    {
356 +      printf ("Page fault at %p: %s error %s page in %s context.\n",
357 +              fault_addr,
358 +              not_present ? "not present" : "rights violation",
359 +              write ? "writing" : "reading",
360 +              user ? "user" : "kernel");
361 +      kill (f);
362 +    }
363 +  else
364 +    {
365 +      f->eip = (void (*) (void)) f->eax;
366 +      f->eax = 0;
367 +    }
368  }
369  
370 diff -urpN pintos.orig/src/userprog/process.c pintos/src/userprog/process.c
371 --- pintos.orig/src/userprog/process.c  2004-09-22 17:58:29.000000000 -0700
372 +++ pintos/src/userprog/process.c       2004-09-27 14:43:09.000000000 -0700
373 @@ -7,15 +7,18 @@
374  #include "userprog/gdt.h"
375  #include "userprog/pagedir.h"
376  #include "userprog/tss.h"
377 +#include "vm/pageframe.h"
378  #include "filesys/directory.h"
379  #include "filesys/file.h"
380  #include "filesys/filesys.h"
381  #include "threads/flags.h"
382  #include "threads/init.h"
383  #include "threads/interrupt.h"
384 +#include "threads/malloc.h"
385  #include "threads/mmu.h"
386  #include "threads/palloc.h"
387  #include "threads/thread.h"
388 +#include "vm/swap.h"
389  
390  static thread_func execute_thread NO_RETURN;
391  static bool load (const char *cmdline, void (**eip) (void), void **esp);
392 @@ -100,6 +103,10 @@ process_exit (void)
393        cur->pagedir = NULL;
394        pagedir_activate (NULL);
395        pagedir_destroy (pd);
396 +
397 +      /* We maintain the invariant that `hash' is initialized iff
398 +         `pd != NULL'. */
399 +      hash_destroy (&cur->pages);
400      }
401  }
402  
403 @@ -182,7 +189,10 @@ struct Elf32_Phdr
404  #define PF_R 4          /* Readable. */
405  
406  static bool load_segment (struct file *, const struct Elf32_Phdr *);
407 -static bool setup_stack (void **esp);
408 +static bool setup_stack (const char *cmdline, void **esp);
409 +static unsigned user_page_hash (const hash_elem *, void *);
410 +static bool user_page_less (const hash_elem *, const hash_elem *, void *);
411 +static struct user_page *make_user_page (void *upage);
412  
413  /* Aborts loading an executable, with an error message. */
414  #define LOAD_ERROR(MSG)                                         \
415 @@ -198,19 +208,35 @@ static bool setup_stack (void **esp);
416     and its initial stack pointer into *ESP.
417     Returns true if successful, false otherwise. */
418  bool
419 -load (const char *filename, void (**eip) (void), void **esp) 
420 +load (const char *cmdline, void (**eip) (void), void **esp) 
421  {
422    struct thread *t = thread_current ();
423 +  char filename[NAME_MAX + 2];
424    struct Elf32_Ehdr ehdr;
425    struct file *file = NULL;
426    off_t file_ofs;
427    bool success = false;
428 +  char *cp;
429    int i;
430  
431 +  /* Create hash of user pages. */
432 +  hash_init (&t->pages, user_page_hash, user_page_less, NULL);
433 +
434    /* Allocate page directory. */
435    t->pagedir = pagedir_create ();
436 -  if (t->pagedir == NULL)
437 -    LOAD_ERROR (("page directory allocation failed"));
438 +  if (t->pagedir == NULL) 
439 +    {
440 +      hash_destroy (&t->pages);
441 +      LOAD_ERROR (("page directory allocation failed")); 
442 +    }
443 +
444 +  /* Extract filename from command line. */
445 +  while (*cmdline == ' ')
446 +    cmdline++;
447 +  strlcpy (filename, cmdline, sizeof filename);
448 +  cp = strchr (filename, ' ');
449 +  if (cp != NULL)
450 +    *cp = '\0';
451  
452    /* Open executable file. */
453    file = filesys_open (filename);
454 @@ -269,8 +295,23 @@ load (const char *filename, void (**eip)
455      }
456  
457    /* Set up stack. */
458 -  if (!setup_stack (esp))
459 +  if (!setup_stack (cmdline, esp))
460      goto done;
461 +  
462 +#if 0
463 +  {
464 +    struct hash_iterator i;
465 +
466 +    hash_first (&i, &thread_current ()->pages);
467 +    while (hash_next (&i))
468 +      {
469 +        struct user_page *up = hash_entry (hash_cur (&i),
470 +                                           struct user_page, elem);
471 +        printf ("%08x ", up->upage);
472 +      }
473 +    printf ("\n");
474 +  }
475 +#endif
476  
477    /* Start address. */
478    *eip = (void (*) (void)) ehdr.e_entry;
479 @@ -279,14 +320,12 @@ load (const char *filename, void (**eip)
480  
481   done:
482    /* We arrive here whether the load is successful or not. */
483 -  file_close (file);
484 +  //file_close (file);                  // FIXME
485    return success;
486  }
487  \f
488  /* load() helpers. */
489  
490 -static bool install_page (void *upage, void *kpage);
491 -
492  /* Loads the segment described by PHDR from FILE into user
493     address space.  Return true if successful, false otherwise. */
494  static bool
495 @@ -296,6 +335,7 @@ load_segment (struct file *file, const s
496    uint8_t *upage;     /* Iterator from start to end. */
497    off_t filesz_left;  /* Bytes left of file data (as opposed to
498                           zero-initialized bytes). */
499 +  off_t file_ofs;
500  
501    /* Is this a read-only segment?  Not currently used, so it's
502       commented out.  You'll want to use it when implementing VM
503 @@ -340,70 +380,206 @@ load_segment (struct file *file, const s
504  
505    /* Load the segment page-by-page into memory. */
506    filesz_left = phdr->p_filesz + (phdr->p_vaddr & PGMASK);
507 -  file_seek (file, ROUND_DOWN (phdr->p_offset, PGSIZE));
508 +  file_ofs = ROUND_DOWN (phdr->p_offset, PGSIZE);
509    for (upage = start; upage < (uint8_t *) end; upage += PGSIZE) 
510      {
511        /* We want to read min(PGSIZE, filesz_left) bytes from the
512           file into the page and zero the rest. */
513        size_t read_bytes = filesz_left >= PGSIZE ? PGSIZE : filesz_left;
514 -      size_t zero_bytes = PGSIZE - read_bytes;
515 -      uint8_t *kpage = palloc_get_page (PAL_USER);
516 -      if (kpage == NULL)
517 +      struct user_page *up = make_user_page (upage);
518 +      if (up == NULL)
519          return false;
520  
521 -      /* Do the reading and zeroing. */
522 -      if (file_read (file, kpage, read_bytes) != (int) read_bytes) 
523 +      if (read_bytes > 0) 
524          {
525 -          palloc_free_page (kpage);
526 -          return false; 
527 +          /* Map page. */
528 +          up->file = file;
529 +          up->file_ofs = file_ofs;
530 +          up->file_size = read_bytes;
531 +          file_ofs += read_bytes;
532          }
533 -      memset (kpage + read_bytes, 0, zero_bytes);
534 -      filesz_left -= read_bytes;
535 -
536 -      /* Add the page to the process's address space. */
537 -      if (!install_page (upage, kpage)) 
538 +      else 
539          {
540 -          palloc_free_page (kpage);
541 -          return false; 
542 +          /* Page is all zeros.  Nothing to do. */
543          }
544 +      filesz_left -= read_bytes;
545      }
546 +  
547 +  return true;
548 +}
549 +
550 +static void
551 +reverse (int argc, char **argv) 
552 +{
553 +  for (; argc > 1; argc -= 2, argv++) 
554 +    {
555 +      char *tmp = argv[0];
556 +      argv[0] = argv[argc - 1];
557 +      argv[argc - 1] = tmp;
558 +    }
559 +}
560 +static void *
561 +push (uint8_t *kpage, size_t *ofs, const void *buf, size_t size) 
562 +{
563 +  size_t padsize = ROUND_UP (size, sizeof (uint32_t));
564 +  if (*ofs < padsize)
565 +    return NULL;
566 +
567 +  *ofs -= padsize;
568 +  memcpy (kpage + *ofs + (padsize - size), buf, size);
569 +  return kpage + *ofs + (padsize - size);
570 +}
571 +
572 +static bool
573 +init_cmdline (uint8_t *kpage, uint8_t *upage, const char *cmdline,
574 +              void **esp) 
575 +{
576 +  size_t ofs = PGSIZE;
577 +  char *const null = NULL;
578 +  char *cmdline_copy;
579 +  char *karg, *saveptr;
580 +  int argc;
581 +  char **argv;
582 +
583 +  /* Push command line string. */
584 +  cmdline_copy = push (kpage, &ofs, cmdline, strlen (cmdline) + 1);
585 +  if (cmdline_copy == NULL)
586 +    return false;
587 +
588 +  if (push (kpage, &ofs, &null, sizeof null) == NULL)
589 +    return false;
590 +
591 +  /* Parse command line into arguments
592 +     and push them in reverse order. */
593 +  argc = 0;
594 +  for (karg = strtok_r (cmdline_copy, " ", &saveptr); karg != NULL;
595 +       karg = strtok_r (NULL, " ", &saveptr))
596 +    {
597 +      char *uarg = upage + (karg - (char *) kpage);
598 +      if (push (kpage, &ofs, &uarg, sizeof uarg) == NULL)
599 +        return false;
600 +      argc++;
601 +    }
602 +
603 +  /* Reverse the order of the command line arguments. */
604 +  argv = (char **) (upage + ofs);
605 +  reverse (argc, (char **) (kpage + ofs));
606 +
607 +  /* Push argv, argc, "return address". */
608 +  if (push (kpage, &ofs, &argv, sizeof argv) == NULL
609 +      || push (kpage, &ofs, &argc, sizeof argc) == NULL
610 +      || push (kpage, &ofs, &null, sizeof null) == NULL)
611 +    return false;
612 +
613 +  /* Set initial stack pointer. */
614 +  *esp = upage + ofs;
615  
616    return true;
617  }
618  
619 -/* Create a minimal stack by mapping a zeroed page at the top of
620 -   user virtual memory. */
621 +/* Create a minimal stack for T by mapping a page at the
622 +   top of user virtual memory.  Fills in the page using CMDLINE
623 +   and sets *ESP to the stack pointer. */
624  static bool
625 -setup_stack (void **esp) 
626 +setup_stack (const char *cmdline, void **esp) 
627  {
628 -  uint8_t *kpage;
629 -  bool success = false;
630 +  struct user_page *up = make_user_page ((uint8_t *) PHYS_BASE - PGSIZE);
631 +  return (up != NULL
632 +          && pageframe_allocate (up)
633 +          && init_cmdline (up->frame->kpage, up->upage, cmdline, esp));
634 +}
635 +
636 +static unsigned
637 +user_page_hash (const hash_elem *e, void *aux UNUSED) 
638 +{
639 +  struct user_page *up = hash_entry (e, struct user_page, elem);
640 +  return hash_bytes (&up->upage, sizeof up->upage);
641 +}
642  
643 -  kpage = palloc_get_page (PAL_USER | PAL_ZERO);
644 -  if (kpage != NULL) 
645 +static bool
646 +user_page_less (const hash_elem *a_, const hash_elem *b_, void *aux UNUSED) 
647 +{
648 +  struct user_page *a = hash_entry (a_, struct user_page, elem);
649 +  struct user_page *b = hash_entry (b_, struct user_page, elem);
650 +
651 +  return a->upage < b->upage;
652 +}
653 +
654 +static struct user_page *
655 +make_user_page (void *upage) 
656 +{
657 +  struct user_page *up;
658 +
659 +  up = malloc (sizeof *up);
660 +  if (up != NULL) 
661      {
662 -      success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage);
663 -      if (success)
664 -        *esp = PHYS_BASE;
665 +      memset (up, 0, sizeof *up);
666 +      up->swap_page = SIZE_MAX;
667 +
668 +      up->upage = upage;
669 +      if (hash_insert (&thread_current ()->pages, &up->elem) != NULL) 
670 +        {
671 +          free (up);
672 +          up = NULL;
673 +        }
674 +#if 0
675        else
676 -        palloc_free_page (kpage);
677 +        printf ("make_user_page(%p) okay\n", upage);
678 +#endif
679      }
680 -  else
681 -    printf ("failed to allocate process stack\n");
682  
683 -  return success;
684 +  return up;
685  }
686  
687 -/* Adds a mapping from user virtual address UPAGE to kernel
688 -   virtual address KPAGE to the page table.  Fails if UPAGE is
689 -   already mapped or if memory allocation fails. */
690 -static bool
691 -install_page (void *upage, void *kpage)
692 +static void
693 +dump_page (struct user_page *up) 
694  {
695 -  struct thread *t = thread_current ();
696 +  off_t amt;
697  
698 -  /* Verify that there's not already a page at that virtual
699 -     address, then map our page there. */
700 -  return (pagedir_get_page (t->pagedir, upage) == NULL
701 -          && pagedir_set_page (t->pagedir, upage, kpage, true));
702 +  ASSERT (up->file != NULL);
703 +  up->file_size = PGSIZE;
704 +  amt = file_write_at (up->file, up->frame->kpage,
705 +                       up->file_size, up->file_ofs);
706 +  ASSERT (amt == (off_t) up->file_size);
707  }
708 +
709 +bool
710 +process_evict_page (struct thread *t, struct user_page *up) 
711 +{
712 +  ASSERT (up->frame != NULL);
713 +
714 +  if (pagedir_test_accessed (t->pagedir, up->upage)) 
715 +    {
716 +      pagedir_clear_accessed (t->pagedir, up->upage);
717 +      return false;
718 +    }
719 +
720 +  if (up->file == NULL) 
721 +    {
722 +      if (!swap_write (up))
723 +        return false;
724 +    }
725 +  else if (pagedir_test_dirty (t->pagedir, up->upage)) 
726 +    {
727 +      /* Need to write out. */
728 +      if (up->private) 
729 +        {
730 +          up->file = NULL; // FIXME
731 +          up->private = false;
732 +          if (!swap_write (up))
733 +            return false;
734 +        }
735 +
736 +      dump_page (up);
737 +    }
738 +  else 
739 +    {
740 +      /* Already on disk, not dirty.
741 +         Nothing to do. */
742 +    }
743 +
744 +  pagedir_clear_page (t->pagedir, up->upage);
745 +  pageframe_free (up->frame);
746 +  return true;
747 +}
748 +
749 diff -urpN pintos.orig/src/userprog/process.h pintos/src/userprog/process.h
750 --- pintos.orig/src/userprog/process.h  2004-09-21 22:42:17.000000000 -0700
751 +++ pintos/src/userprog/process.h       2004-09-27 14:43:13.000000000 -0700
752 @@ -2,9 +2,32 @@
753  #define USERPROG_PROCESS_H
754  
755  #include "threads/thread.h"
756 +#include "filesys/off_t.h"
757 +
758 +struct user_page 
759 +  {
760 +    hash_elem elem;
761 +    void *upage;                /* Virtual address of mapping. */
762 +
763 +    /* If FRAME is nonnull, the page is in memory.
764 +       If FILE is nonnull, the page is on disk.
765 +       If both are null, the page is all zeroes.
766 +       If both are nonnull, the page is in memory and backed by a
767 +       file mapping (not the swap file). */
768 +    struct page_frame *frame;
769 +    size_t swap_page;
770 +    struct file *file;
771 +    off_t file_ofs;
772 +    size_t file_size;           /* Number of bytes on disk, <= PGSIZE. */
773 +
774 +    bool dirty : 1;
775 +    bool accessed : 1;
776 +    bool private : 1;           /* Write dirty pages to swap or to FILE? */
777 +  };
778  
779  tid_t process_execute (const char *filename);
780  void process_exit (void);
781  void process_activate (void);
782 +bool process_evict_page (struct thread *, struct user_page *);
783  
784  #endif /* userprog/process.h */
785 diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
786 --- pintos.orig/src/userprog/syscall.c  2004-09-26 14:15:17.000000000 -0700
787 +++ pintos/src/userprog/syscall.c       2004-09-27 14:42:01.000000000 -0700
788 @@ -1,20 +1,429 @@
789  #include "userprog/syscall.h"
790  #include <stdio.h>
791 +#include <string.h>
792  #include <syscall-nr.h>
793 +#include "threads/init.h"
794  #include "threads/interrupt.h"
795 +#include "threads/malloc.h"
796 +#include "threads/mmu.h"
797 +#include "threads/palloc.h"
798  #include "threads/thread.h"
799 +#include "userprog/pagedir.h"
800 +#include "userprog/process.h"
801 +#include "filesys/filesys.h"
802 +#include "filesys/file.h"
803 +#include "devices/kbd.h"
804 +
805 +typedef int syscall_function (int, int, int);
806 +
807 +static int sys_halt (void);
808 +static int sys_exit (int status);
809 +static int sys_exec (const char *ufile);
810 +static int sys_join (tid_t);
811 +static int sys_create (const char *ufile, unsigned initial_size);
812 +static int sys_remove (const char *ufile);
813 +static int sys_open (const char *ufile);
814 +static int sys_filesize (int handle);
815 +static int sys_read (int handle, void *udst_, unsigned size);
816 +static int sys_write (int handle, void *usrc_, unsigned size);
817 +static int sys_seek (int handle, unsigned position);
818 +static int sys_tell (int handle);
819 +static int sys_close (int handle);
820 +
821 +struct syscall 
822 +  {
823 +    size_t arg_cnt;
824 +    syscall_function *func;
825 +  };
826 +
827 +struct syscall syscall_table[] = 
828 +  {
829 +    {0, (syscall_function *) sys_halt},
830 +    {1, (syscall_function *) sys_exit},
831 +    {1, (syscall_function *) sys_exec},
832 +    {1, (syscall_function *) sys_join},
833 +    {2, (syscall_function *) sys_create},
834 +    {1, (syscall_function *) sys_remove},
835 +    {1, (syscall_function *) sys_open},
836 +    {1, (syscall_function *) sys_filesize},
837 +    {3, (syscall_function *) sys_read},
838 +    {3, (syscall_function *) sys_write},
839 +    {2, (syscall_function *) sys_seek},
840 +    {1, (syscall_function *) sys_tell},
841 +    {1, (syscall_function *) sys_close},
842 +  };
843 +static const int syscall_cnt = sizeof syscall_table / sizeof *syscall_table;
844  
845  static void syscall_handler (struct intr_frame *);
846 +static void copy_in (void *, const void *, size_t);
847 +
848 +static struct lock fs_lock;
849  
850  void
851  syscall_init (void) 
852  {
853    intr_register (0x30, 3, INTR_ON, syscall_handler, "syscall");
854 +  lock_init (&fs_lock, "fs");
855  }
856  
857  static void
858 -syscall_handler (struct intr_frame *f UNUSED) 
859 +syscall_handler (struct intr_frame *f) 
860 +{
861 +  struct syscall *s;
862 +  int call_nr;
863 +  int args[3];
864 +
865 +  copy_in (&call_nr, f->esp, sizeof call_nr);
866 +  if (call_nr < 0 || call_nr >= syscall_cnt)
867 +    {
868 +      printf ("bad syscall number %d\n", call_nr);
869 +      thread_exit ();
870 +    }
871 +
872 +  s = syscall_table + call_nr;
873 +  ASSERT (s->arg_cnt <= sizeof args / sizeof *args);
874 +  memset (args, 0, sizeof args);
875 +  copy_in (args, (uint32_t *) f->esp + 1, sizeof *args * s->arg_cnt);
876 +  f->eax = s->func (args[0], args[1], args[2]);
877 +}
878 +
879 +static bool
880 +verify_user (const void *uaddr) 
881 +{
882 +  return pagedir_get_page (thread_current ()->pagedir, uaddr) != NULL;
883 +}
884 +
885 +static inline bool get_user (uint8_t *dst, const uint8_t *usrc) {
886 +  int eax;
887 +  asm ("movl $1f, %%eax; movb %2, %%al; movb %%al, %0; 1:"
888 +       : "=m" (*dst), "=&a" (eax) : "m" (*usrc));
889 +  return eax != 0;
890 +}
891 +
892 +static inline bool put_user (uint8_t *udst, uint8_t byte) {
893 +  int eax;
894 +  asm ("movl $1f, %%eax; movb %b2, %0; 1:"
895 +       : "=m" (*udst), "=&a" (eax) : "r" (byte));
896 +  return eax != 0;
897 +}
898 +
899 +static void
900 +copy_in (void *dst_, const void *usrc_, size_t size) 
901 +{
902 +  uint8_t *dst = dst_;
903 +  const uint8_t *usrc = usrc_;
904 +
905 +  for (; size > 0; size--, dst++, usrc++) 
906 +    if (usrc >= (uint8_t *) PHYS_BASE || !get_user (dst, usrc)) 
907 +      thread_exit ();
908 +}
909 +
910 +static char *
911 +copy_in_string (const char *us) 
912 +{
913 +  char *ks;
914 +  size_t length;
915 +
916 +  ks = palloc_get_page (0);
917 +  if (ks == NULL) 
918 +    {
919 +      printf ("copy_in_string: out of memory\n");
920 +      thread_exit ();
921 +    }
922 +
923 +  for (length = 0; length < PGSIZE; length++)
924 +    {
925 +      if (us >= (char *) PHYS_BASE || !get_user (ks + length, us++)) 
926 +        {
927 +          printf ("bad user reference (%p)\n", us + length);
928 +          thread_exit (); 
929 +        }
930 +      
931 +      if (ks[length] == '\0')
932 +        return ks;
933 +    }
934 +
935 +  printf ("copy_in_string: string too long\n");
936 +  palloc_free_page (ks);
937 +  thread_exit ();
938 +}
939 +
940 +static int
941 +sys_halt (void)
942 +{
943 +  power_off ();
944 +}
945 +
946 +static int
947 +sys_exit (int ret_code) 
948  {
949 -  printf ("system call!\n");
950 +  thread_current ()->ret_code = ret_code;
951    thread_exit ();
952 +  NOT_REACHED ();
953 +}
954 +
955 +static int
956 +sys_exec (const char *ufile) 
957 +{
958 +  tid_t tid;
959 +  char *kfile = copy_in_string (ufile);
960 +
961 +  lock_acquire (&fs_lock);
962 +  tid = process_execute (kfile);
963 +  lock_release (&fs_lock);
964 +
965 +  palloc_free_page (kfile);
966 +
967 +  return tid;
968 +}
969 +
970 +static int
971 +sys_join (tid_t child) 
972 +{
973 +  return thread_join (child);
974 +}
975 +
976 +static int
977 +sys_create (const char *ufile, unsigned initial_size) 
978 +{
979 +  char *kfile = copy_in_string (ufile);
980 +  bool ok;
981 +  
982 +  lock_acquire (&fs_lock);
983 +  ok = filesys_create (kfile, initial_size);
984 +  lock_release (&fs_lock);
985 +
986 +  palloc_free_page (kfile);
987 +
988 +  return ok;
989 +}
990 +
991 +static int
992 +sys_remove (const char *ufile) 
993 +{
994 +  char *kfile = copy_in_string (ufile);
995 +  bool ok;
996 +  
997 +  lock_acquire (&fs_lock);
998 +  ok = filesys_remove (kfile);
999 +  lock_release (&fs_lock);
1000 +
1001 +  palloc_free_page (kfile);
1002 +
1003 +  return ok;
1004 +}
1005 +
1006 +struct fildes
1007 +  {
1008 +    list_elem elem;
1009 +    struct file *file;
1010 +    int handle;
1011 +  };
1012 +
1013 +static int
1014 +sys_open (const char *ufile) 
1015 +{
1016 +  char *kfile = copy_in_string (ufile);
1017 +  struct fildes *fd;
1018 +  int handle = -1;
1019 +
1020 +  fd = malloc (sizeof *fd);
1021 +  if (fd == NULL)
1022 +    goto exit;
1023 +
1024 +  lock_acquire (&fs_lock);
1025 +  fd->file = filesys_open (kfile);
1026 +  if (fd->file != NULL)
1027 +    {
1028 +      struct thread *cur = thread_current ();
1029 +      handle = fd->handle = cur->next_handle++;
1030 +      list_push_front (&cur->fds, &fd->elem);
1031 +    }
1032 +  else 
1033 +    free (fd);
1034 +  lock_release (&fs_lock);
1035 +
1036 + exit:
1037 +  palloc_free_page (kfile);
1038 +  return handle;
1039 +}
1040 +
1041 +static struct fildes *
1042 +lookup_fd (int handle) 
1043 +{
1044 +  struct thread *cur = thread_current ();
1045 +  list_elem *e;
1046 +  
1047 +  for (e = list_begin (&cur->fds); e != list_end (&cur->fds);
1048 +       e = list_next (e))
1049 +    {
1050 +      struct fildes *fd = list_entry (e, struct fildes, elem);
1051 +      if (fd->handle == handle)
1052 +        return fd;
1053 +    }
1054 +
1055 +  printf ("no handle %d\n", handle);
1056 +thread_exit ();
1057 +}
1058 +
1059 +static int
1060 +sys_filesize (int handle) 
1061 +{
1062 +  struct fildes *fd = lookup_fd (handle);
1063 +  int size;
1064 +
1065 +  lock_acquire (&fs_lock);
1066 +  size = file_length (fd->file);
1067 +  lock_release (&fs_lock);
1068 +
1069 +  return size;
1070 +}
1071 +
1072 +static int
1073 +sys_read (int handle, void *udst_, unsigned size) 
1074 +{
1075 +  uint8_t *udst = udst_;
1076 +  struct fildes *fd;
1077 +  int bytes_read = 0;
1078 +
1079 +  if (handle == STDIN_FILENO) 
1080 +    {
1081 +      for (bytes_read = 0; (size_t) bytes_read < size; bytes_read++)
1082 +        if (udst >= (uint8_t *) PHYS_BASE || !put_user (udst++, kbd_getc ()))
1083 +          thread_exit ();
1084 +      return bytes_read;
1085 +    }
1086 +
1087 +  lock_acquire (&fs_lock);
1088 +  fd = lookup_fd (handle);
1089 +  while (size > 0) 
1090 +    {
1091 +      size_t page_left = PGSIZE - pg_ofs (udst);
1092 +      size_t read_amt = size < page_left ? size : page_left;
1093 +      off_t retval;
1094 +
1095 +      if (!verify_user (udst)) 
1096 +        {
1097 +          lock_release (&fs_lock);
1098 +          thread_exit ();
1099 +        }
1100 +      
1101 +      retval = file_read (fd->file, udst, read_amt);
1102 +      if (retval < 0)
1103 +        {
1104 +          if (bytes_read == 0)
1105 +            bytes_read = -1; 
1106 +          break;
1107 +        }
1108 +
1109 +      bytes_read += retval;
1110 +      if (retval != (off_t) read_amt)
1111 +        break;
1112 +
1113 +      udst += retval;
1114 +      size -= retval;
1115 +    }
1116 +  lock_release (&fs_lock);
1117 +  
1118 +  return bytes_read;
1119 +}
1120 +
1121 +static int
1122 +sys_write (int handle, void *usrc_, unsigned size) 
1123 +{
1124 +  uint8_t *usrc = usrc_;
1125 +  struct fildes *fd = NULL;
1126 +  int bytes_written = 0;
1127 +
1128 +  lock_acquire (&fs_lock);
1129 +  if (handle != STDOUT_FILENO)
1130 +    fd = lookup_fd (handle);
1131 +  while (size > 0) 
1132 +    {
1133 +      size_t page_left = PGSIZE - pg_ofs (usrc);
1134 +      size_t write_amt = size < page_left ? size : page_left;
1135 +      off_t retval;
1136 +
1137 +      if (!verify_user (usrc)) 
1138 +        {
1139 +          lock_release (&fs_lock);
1140 +          thread_exit ();
1141 +        }
1142 +
1143 +      if (handle == STDOUT_FILENO)
1144 +        {
1145 +          putbuf (usrc, write_amt);
1146 +          retval = write_amt;
1147 +        }
1148 +      else
1149 +        retval = file_write (fd->file, usrc, write_amt);
1150 +      if (retval < 0) 
1151 +        {
1152 +          if (bytes_written == 0)
1153 +            bytes_written = -1;
1154 +          break;
1155 +        }
1156 +
1157 +      bytes_written += retval;
1158 +      if (retval != (off_t) write_amt)
1159 +        break;
1160 +
1161 +      usrc += retval;
1162 +      size -= retval;
1163 +    }
1164 +  lock_release (&fs_lock);
1165 +
1166 +  return bytes_written;
1167 +}
1168 +
1169 +static int
1170 +sys_seek (int handle, unsigned position) 
1171 +{
1172 +  struct fildes *fd = lookup_fd (handle);
1173 +  
1174 +  lock_acquire (&fs_lock);
1175 +  file_seek (fd->file, position);
1176 +  lock_release (&fs_lock);
1177 +
1178 +  return 0;
1179 +}
1180 +
1181 +static int
1182 +sys_tell (int handle) 
1183 +{
1184 +  struct fildes *fd = lookup_fd (handle);
1185 +  unsigned position;
1186 +  
1187 +  lock_acquire (&fs_lock);
1188 +  position = file_tell (fd->file);
1189 +  lock_release (&fs_lock);
1190 +
1191 +  return position;
1192 +}
1193 +
1194 +static int
1195 +sys_close (int handle) 
1196 +{
1197 +  struct fildes *fd = lookup_fd (handle);
1198 +  lock_acquire (&fs_lock);
1199 +  file_close (fd->file);
1200 +  lock_release (&fs_lock);
1201 +  list_remove (&fd->elem);
1202 +  free (fd);
1203 +  return 0;
1204 +}
1205 +
1206 +void
1207 +syscall_exit (void) 
1208 +{
1209 +  struct thread *cur = thread_current ();
1210 +  list_elem *e, *next;
1211 +  
1212 +  for (e = list_begin (&cur->fds); e != list_end (&cur->fds); e = next)
1213 +    {
1214 +      struct fildes *fd = list_entry (e, struct fildes, elem);
1215 +      next = list_next (e);
1216 +      file_close (fd->file);
1217 +      free (fd);
1218 +    }
1219  }
1220 diff -urpN pintos.orig/src/userprog/syscall.h pintos/src/userprog/syscall.h
1221 --- pintos.orig/src/userprog/syscall.h  2004-09-05 22:38:45.000000000 -0700
1222 +++ pintos/src/userprog/syscall.h       2004-09-27 13:29:44.000000000 -0700
1223 @@ -2,5 +2,6 @@
1224  #define USERPROG_SYSCALL_H
1225  
1226  void syscall_init (void);
1227 +void syscall_exit (void);
1228  
1229  #endif /* userprog/syscall.h */
1230 diff -urpN pintos.orig/src/vm/pageframe.c pintos/src/vm/pageframe.c
1231 --- pintos.orig/src/vm/pageframe.c      1969-12-31 16:00:00.000000000 -0800
1232 +++ pintos/src/vm/pageframe.c   2004-09-27 13:29:44.000000000 -0700
1233 @@ -0,0 +1,75 @@
1234 +#include "vm/pageframe.h"
1235 +#include <stdint.h>
1236 +#include "threads/init.h"
1237 +#include "threads/malloc.h"
1238 +#include "threads/mmu.h"
1239 +#include "threads/palloc.h"
1240 +#include "userprog/process.h"
1241 +
1242 +static struct page_frame *frames;
1243 +static size_t frame_cnt;
1244 +
1245 +static struct page_frame *next_frame;
1246 +
1247 +static inline bool
1248 +in_use (const struct page_frame *pf) 
1249 +{
1250 +  ASSERT ((pf->owner != NULL) == (pf->user_page != NULL));
1251 +  return pf->owner != NULL;
1252 +}
1253 +
1254 +void
1255 +pageframe_init (void) 
1256 +{
1257 +  uint8_t *kpage;
1258 +
1259 +  frame_cnt = ram_pages;
1260 +  frames = calloc (sizeof *frames, frame_cnt);
1261 +  if (frames == NULL)
1262 +    PANIC ("can't allocate page frames");
1263 +
1264 +  while ((kpage = palloc_get_page (PAL_USER)) != NULL)
1265 +    {
1266 +      struct page_frame *pf = frames + (vtop (kpage) >> PGBITS);
1267 +      pf->kpage = kpage;
1268 +    }
1269 +
1270 +  next_frame = frames;
1271 +}
1272 +
1273 +bool
1274 +pageframe_allocate (struct user_page *up) 
1275 +{
1276 +  struct page_frame *pf;
1277 +  size_t loops;
1278 +
1279 +  ASSERT (up->frame == NULL);
1280 +
1281 +  loops = 0;
1282 +  do 
1283 +    {
1284 +      pf = next_frame++;
1285 +      if (next_frame >= frames + frame_cnt)
1286 +        next_frame = frames;
1287 +      if (loops++ > 2 * frame_cnt)
1288 +        return false;
1289 +    }
1290 +  while (pf->kpage == NULL
1291 +         || (in_use (pf) && !process_evict_page (pf->owner, pf->user_page)));
1292 +
1293 +  ASSERT (!in_use (pf));
1294 +  pf->owner = thread_current ();
1295 +  pf->user_page = up;
1296 +  up->frame = pf;
1297 +  return true; 
1298 +}
1299 +
1300 +void
1301 +pageframe_free (struct page_frame *pf) 
1302 +{
1303 +  ASSERT (in_use (pf));
1304 +  
1305 +  pf->owner = NULL;
1306 +  pf->user_page->frame = NULL;
1307 +  pf->user_page = NULL;
1308 +}
1309 diff -urpN pintos.orig/src/vm/pageframe.h pintos/src/vm/pageframe.h
1310 --- pintos.orig/src/vm/pageframe.h      1969-12-31 16:00:00.000000000 -0800
1311 +++ pintos/src/vm/pageframe.h   2004-09-27 13:29:44.000000000 -0700
1312 @@ -0,0 +1,17 @@
1313 +#ifndef VM_PAGEFRAME_H
1314 +#define VM_PAGEFRAME_H 1
1315 +
1316 +#include <stdbool.h>
1317 +
1318 +struct page_frame 
1319 +  {
1320 +    void *kpage;
1321 +    struct thread *owner;
1322 +    struct user_page *user_page;
1323 +  };
1324 +
1325 +void pageframe_init (void);
1326 +bool pageframe_allocate (struct user_page *);
1327 +void pageframe_free (struct page_frame *);
1328 +
1329 +#endif /* vm/pageframe.h */
1330 diff -urpN pintos.orig/src/vm/swap.c pintos/src/vm/swap.c
1331 --- pintos.orig/src/vm/swap.c   1969-12-31 16:00:00.000000000 -0800
1332 +++ pintos/src/vm/swap.c        2004-09-27 13:29:44.000000000 -0700
1333 @@ -0,0 +1,66 @@
1334 +#include "vm/swap.h"
1335 +#include <bitmap.h>
1336 +#include <stdio.h>
1337 +#include "vm/pageframe.h"
1338 +#include "threads/mmu.h"
1339 +#include "filesys/file.h"
1340 +#include "filesys/filesys.h"
1341 +#include "userprog/process.h"
1342 +
1343 +static size_t swap_pages;
1344 +static struct disk *swap_disk;
1345 +static struct bitmap *used_pages;
1346 +
1347 +void
1348 +swap_init (void) 
1349 +{
1350 +  swap_disk = disk_get (1, 1);
1351 +  if (swap_disk == NULL)
1352 +    PANIC ("no swap disk");
1353 +  swap_pages = disk_size (swap_disk) / (PGSIZE / DISK_SECTOR_SIZE);
1354 +  printf ("swap disk has room for %zu pages\n", swap_pages);
1355 +
1356 +  used_pages = bitmap_create (swap_pages);
1357 +  if (used_pages == NULL)
1358 +    PANIC ("couldn't create swap bitmap");
1359 +}
1360 +
1361 +bool
1362 +swap_write (struct user_page *up) 
1363 +{
1364 +  size_t page;
1365 +  disk_sector_t sector;
1366 +  int i;
1367 +
1368 +  ASSERT (up->frame != NULL);
1369 +  ASSERT (up->file == NULL);
1370 +
1371 +  page = bitmap_scan_and_flip (used_pages, 0, 1, false);
1372 +  if (page == BITMAP_ERROR)
1373 +    return false;
1374 +
1375 +  up->swap_page = page;
1376 +  sector = (disk_sector_t) page * (PGSIZE / DISK_SECTOR_SIZE);
1377 +  for (i = 0; i < PGSIZE / DISK_SECTOR_SIZE; i++)
1378 +    disk_write (swap_disk, sector++, up->frame->kpage + i * DISK_SECTOR_SIZE);
1379 +
1380 +  return true;
1381 +}
1382 +
1383 +void
1384 +swap_read (struct user_page *up) 
1385 +{
1386 +  disk_sector_t sector;
1387 +  int i;
1388 +
1389 +  ASSERT (up->frame != NULL);
1390 +
1391 +  ASSERT (bitmap_test (used_pages, up->swap_page));
1392 +  bitmap_reset (used_pages, up->swap_page);
1393 +
1394 +  sector = (disk_sector_t) up->swap_page * (PGSIZE / DISK_SECTOR_SIZE);
1395 +  for (i = 0; i < PGSIZE / DISK_SECTOR_SIZE; i++)
1396 +    disk_read (swap_disk, sector++, up->frame->kpage + i * DISK_SECTOR_SIZE);
1397 +
1398 +  up->swap_page = SIZE_MAX;
1399 +}
1400 diff -urpN pintos.orig/src/vm/swap.h pintos/src/vm/swap.h
1401 --- pintos.orig/src/vm/swap.h   1969-12-31 16:00:00.000000000 -0800
1402 +++ pintos/src/vm/swap.h        2004-09-27 13:29:44.000000000 -0700
1403 @@ -0,0 +1,11 @@
1404 +#ifndef VM_SWAP_H
1405 +#define VM_SWAP_H 1
1406 +
1407 +#include <stdbool.h>
1408 +
1409 +struct user_page;
1410 +void swap_init (void);
1411 +bool swap_write (struct user_page *);
1412 +void swap_read (struct user_page *);
1413 +
1414 +#endif /* vm/swap.h */