Updated sample solutions to correspond with current code.
[pintos-anon] / solutions / p2.patch
1 diff --git a/src/threads/thread.c b/src/threads/thread.c
2 index 86614f5..9fa7f1c 100644
3 --- a/src/threads/thread.c
4 +++ b/src/threads/thread.c
5 @@ -15,6 +15,7 @@
6  #include "threads/vaddr.h"
7  #ifdef USERPROG
8  #include "userprog/process.h"
9 +#include "userprog/syscall.h"
10  #endif
11  
12  /* Random value for struct thread's `magic' member.
13 @@ -351,7 +352,8 @@ thread_exit (void)
14  #ifdef USERPROG
15    process_exit ();
16  #endif
17 -
18 +  syscall_exit ();
19 +  
20    /* Remove thread from all threads list, set our status to dying,
21       and schedule another process.  That process will destroy us
22       when it calls thread_schedule_tail(). */
23 @@ -608,6 +610,10 @@ init_thread (struct thread *t, const char *name, int priority)
24    strlcpy (t->name, name, sizeof t->name);
25    t->stack = (uint8_t *) t + PGSIZE;
26    t->priority = t->normal_priority = priority;
27 +  list_init (&t->children);
28 +  t->wait_status = NULL;
29 +  list_init (&t->fds);
30 +  t->next_handle = 2;
31    t->magic = THREAD_MAGIC;
32    sema_init (&t->timer_sema, 0);
33    list_init (&t->donors);
34 diff --git a/src/threads/thread.h b/src/threads/thread.h
35 index 6601963..2c85d88 100644
36 --- a/src/threads/thread.h
37 +++ b/src/threads/thread.h
38 @@ -101,6 +101,10 @@ struct thread
39      fixed_point_t recent_cpu;           /* Recent amount of CPU time. */    
40      struct list_elem allelem;           /* List element for all threads list. */
41  
42 +    /* Owned by process.c. */
43 +    struct wait_status *wait_status;    /* This process's completion status. */
44 +    struct list children;               /* Completion status of children. */
45 +
46      /* Shared between thread.c and synch.c. */
47      struct list_elem elem;              /* List element. */
48  
49 @@ -113,11 +117,31 @@ struct thread
50      /* Owned by userprog/process.c. */
51      uint32_t *pagedir;                  /* Page directory. */
52  #endif
53 +    struct file *bin_file;              /* Executable. */
54 +
55 +    /* Owned by syscall.c. */
56 +    struct list fds;                    /* List of file descriptors. */
57 +    int next_handle;                    /* Next handle value. */
58  
59      /* Owned by thread.c. */
60      unsigned magic;                     /* Detects stack overflow. */
61    };
62  
63 +/* Tracks the completion of a process.
64 +   Reference held by both the parent, in its `children' list,
65 +   and by the child, in its `wait_status' pointer. */
66 +struct wait_status
67 +  {
68 +    struct list_elem elem;              /* `children' list element. */
69 +    struct lock lock;                   /* Protects ref_cnt. */
70 +    int ref_cnt;                        /* 2=child and parent both alive,
71 +                                           1=either child or parent alive,
72 +                                           0=child and parent both dead. */
73 +    tid_t tid;                          /* Child thread id. */
74 +    int exit_code;                      /* Child exit code, if dead. */
75 +    struct semaphore dead;              /* 1=child alive, 0=child dead. */
76 +  };
77 +
78  /* If false (default), use round-robin scheduler.
79     If true, use multi-level feedback queue scheduler.
80     Controlled by kernel command-line option "-o mlfqs". */
81 diff --git a/src/userprog/exception.c b/src/userprog/exception.c
82 index 19aca12..3682478 100644
83 --- a/src/userprog/exception.c
84 +++ b/src/userprog/exception.c
85 @@ -148,6 +148,14 @@ page_fault (struct intr_frame *f)
86    write = (f->error_code & PF_W) != 0;
87    user = (f->error_code & PF_U) != 0;
88  
89 +  /* Handle bad dereferences from system call implementations. */
90 +  if (!user) 
91 +    {
92 +      f->eip = (void (*) (void)) f->eax;
93 +      f->eax = 0;
94 +      return;
95 +    }
96 +
97    /* To implement virtual memory, delete the rest of the function
98       body, and replace it with code that brings in the page to
99       which fault_addr refers. */
100 diff --git a/src/userprog/process.c b/src/userprog/process.c
101 index c0e5215..06ff27e 100644
102 --- a/src/userprog/process.c
103 +++ b/src/userprog/process.c
104 @@ -14,12 +14,24 @@
105  #include "threads/flags.h"
106  #include "threads/init.h"
107  #include "threads/interrupt.h"
108 +#include "threads/malloc.h"
109  #include "threads/palloc.h"
110  #include "threads/thread.h"
111  #include "threads/vaddr.h"
112  
113  static thread_func start_process NO_RETURN;
114 -static bool load (const char *cmdline, void (**eip) (void), void **esp);
115 +static bool load (const char *cmd_line, void (**eip) (void), void **esp);
116 +
117 +/* Data structure shared between process_execute() in the
118 +   invoking thread and start_process() in the newly invoked
119 +   thread. */
120 +struct exec_info 
121 +  {
122 +    const char *file_name;              /* Program to load. */
123 +    struct semaphore load_done;         /* "Up"ed when loading complete. */
124 +    struct wait_status *wait_status;    /* Child process. */
125 +    bool success;                       /* Program successfully loaded? */
126 +  };
127  
128  /* Starts a new thread running a user program loaded from
129     FILENAME.  The new thread may be scheduled (and may even exit)
130 @@ -28,29 +40,37 @@ static bool load (const char *cmdline, void (**eip) (void), void **esp);
131  tid_t
132  process_execute (const char *file_name) 
133  {
134 -  char *fn_copy;
135 +  struct exec_info exec;
136 +  char thread_name[16];
137 +  char *save_ptr;
138    tid_t tid;
139  
140 -  /* Make a copy of FILE_NAME.
141 -     Otherwise there's a race between the caller and load(). */
142 -  fn_copy = palloc_get_page (0);
143 -  if (fn_copy == NULL)
144 -    return TID_ERROR;
145 -  strlcpy (fn_copy, file_name, PGSIZE);
146 +  /* Initialize exec_info. */
147 +  exec.file_name = file_name;
148 +  sema_init (&exec.load_done, 0);
149  
150    /* Create a new thread to execute FILE_NAME. */
151 -  tid = thread_create (file_name, PRI_DEFAULT, start_process, fn_copy);
152 -  if (tid == TID_ERROR)
153 -    palloc_free_page (fn_copy); 
154 +  strlcpy (thread_name, file_name, sizeof thread_name);
155 +  strtok_r (thread_name, " ", &save_ptr);
156 +  tid = thread_create (thread_name, PRI_DEFAULT, start_process, &exec);
157 +  if (tid != TID_ERROR)
158 +    {
159 +      sema_down (&exec.load_done);
160 +      if (exec.success)
161 +        list_push_back (&thread_current ()->children, &exec.wait_status->elem);
162 +      else
163 +        tid = TID_ERROR;
164 +    }
165 +
166    return tid;
167  }
168  
169  /* A thread function that loads a user process and starts it
170     running. */
171  static void
172 -start_process (void *file_name_)
173 +start_process (void *exec_)
174  {
175 -  char *file_name = file_name_;
176 +  struct exec_info *exec = exec_;
177    struct intr_frame if_;
178    bool success;
179  
180 @@ -59,10 +79,29 @@ start_process (void *file_name_)
181    if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG;
182    if_.cs = SEL_UCSEG;
183    if_.eflags = FLAG_IF | FLAG_MBS;
184 -  success = load (file_name, &if_.eip, &if_.esp);
185 +  success = load (exec->file_name, &if_.eip, &if_.esp);
186 +
187 +  /* Allocate wait_status. */
188 +  if (success)
189 +    {
190 +      exec->wait_status = thread_current ()->wait_status
191 +        = malloc (sizeof *exec->wait_status);
192 +      success = exec->wait_status != NULL; 
193 +    }
194  
195 -  /* If load failed, quit. */
196 -  palloc_free_page (file_name);
197 +  /* Initialize wait_status. */
198 +  if (success) 
199 +    {
200 +      lock_init (&exec->wait_status->lock);
201 +      exec->wait_status->ref_cnt = 2;
202 +      exec->wait_status->tid = thread_current ()->tid;
203 +      exec->wait_status->exit_code = -1;
204 +      sema_init (&exec->wait_status->dead, 0);
205 +    }
206 +  
207 +  /* Notify parent thread and clean up. */
208 +  exec->success = success;
209 +  sema_up (&exec->load_done);
210    if (!success) 
211      thread_exit ();
212  
213 @@ -76,18 +115,47 @@ start_process (void *file_name_)
214    NOT_REACHED ();
215  }
216  
217 +/* Releases one reference to CS and, if it is now unreferenced,
218 +   frees it. */
219 +static void
220 +release_child (struct wait_status *cs) 
221 +{
222 +  int new_ref_cnt;
223 +  
224 +  lock_acquire (&cs->lock);
225 +  new_ref_cnt = --cs->ref_cnt;
226 +  lock_release (&cs->lock);
227 +
228 +  if (new_ref_cnt == 0)
229 +    free (cs);
230 +}
231 +
232  /* Waits for thread TID to die and returns its exit status.  If
233     it was terminated by the kernel (i.e. killed due to an
234     exception), returns -1.  If TID is invalid or if it was not a
235     child of the calling process, or if process_wait() has already
236     been successfully called for the given TID, returns -1
237 -   immediately, without waiting.
238 -
239 -   This function will be implemented in problem 2-2.  For now, it
240 -   does nothing. */
241 +   immediately, without waiting. */
242  int
243 -process_wait (tid_t child_tid UNUSED) 
244 +process_wait (tid_t child_tid) 
245  {
246 +  struct thread *cur = thread_current ();
247 +  struct list_elem *e;
248 +
249 +  for (e = list_begin (&cur->children); e != list_end (&cur->children);
250 +       e = list_next (e)) 
251 +    {
252 +      struct wait_status *cs = list_entry (e, struct wait_status, elem);
253 +      if (cs->tid == child_tid) 
254 +        {
255 +          int exit_code;
256 +          list_remove (e);
257 +          sema_down (&cs->dead);
258 +          exit_code = cs->exit_code;
259 +          release_child (cs);
260 +          return exit_code;
261 +        }
262 +    }
263    return -1;
264  }
265  
266 @@ -96,8 +164,30 @@ void
267  process_exit (void)
268  {
269    struct thread *cur = thread_current ();
270 +  struct list_elem *e, *next;
271    uint32_t *pd;
272  
273 +  /* Close executable (and allow writes). */
274 +  file_close (cur->bin_file);
275 +
276 +  /* Notify parent that we're dead. */
277 +  if (cur->wait_status != NULL) 
278 +    {
279 +      struct wait_status *cs = cur->wait_status;
280 +      printf ("%s: exit(%d)\n", cur->name, cs->exit_code);
281 +      sema_up (&cs->dead);
282 +      release_child (cs);
283 +    }
284 +
285 +  /* Free entries of children list. */
286 +  for (e = list_begin (&cur->children); e != list_end (&cur->children);
287 +       e = next) 
288 +    {
289 +      struct wait_status *cs = list_entry (e, struct wait_status, elem);
290 +      next = list_remove (e);
291 +      release_child (cs);
292 +    }
293 +  
294    /* Destroy the current process's page directory and switch back
295       to the kernel-only page directory. */
296    pd = cur->pagedir;
297 @@ -195,7 +285,7 @@ struct Elf32_Phdr
298  #define PF_W 2          /* Writable. */
299  #define PF_R 4          /* Readable. */
300  
301 -static bool setup_stack (void **esp);
302 +static bool setup_stack (const char *cmd_line, void **esp);
303  static bool validate_segment (const struct Elf32_Phdr *, struct file *);
304  static bool load_segment (struct file *file, off_t ofs, uint8_t *upage,
305                            uint32_t read_bytes, uint32_t zero_bytes,
306 @@ -206,13 +296,15 @@ static bool load_segment (struct file *file, off_t ofs, uint8_t *upage,
307     and its initial stack pointer into *ESP.
308     Returns true if successful, false otherwise. */
309  bool
310 -load (const char *file_name, void (**eip) (void), void **esp) 
311 +load (const char *cmd_line, void (**eip) (void), void **esp) 
312  {
313    struct thread *t = thread_current ();
314 +  char file_name[NAME_MAX + 2];
315    struct Elf32_Ehdr ehdr;
316    struct file *file = NULL;
317    off_t file_ofs;
318    bool success = false;
319 +  char *cp;
320    int i;
321  
322    /* Allocate and activate page directory. */
323 @@ -221,13 +313,22 @@ load (const char *file_name, void (**eip) (void), void **esp)
324      goto done;
325    process_activate ();
326  
327 +  /* Extract file_name from command line. */
328 +  while (*cmd_line == ' ')
329 +    cmd_line++;
330 +  strlcpy (file_name, cmd_line, sizeof file_name);
331 +  cp = strchr (file_name, ' ');
332 +  if (cp != NULL)
333 +    *cp = '\0';
334 +
335    /* Open executable file. */
336 -  file = filesys_open (file_name);
337 +  t->bin_file = file = filesys_open (file_name);
338    if (file == NULL) 
339      {
340        printf ("load: %s: open failed\n", file_name);
341        goto done; 
342      }
343 +  file_deny_write (file);
344  
345    /* Read and verify executable header. */
346    if (file_read (file, &ehdr, sizeof ehdr) != sizeof ehdr
347 @@ -302,7 +403,7 @@ load (const char *file_name, void (**eip) (void), void **esp)
348      }
349  
350    /* Set up stack. */
351 -  if (!setup_stack (esp))
352 +  if (!setup_stack (cmd_line, esp))
353      goto done;
354  
355    /* Start address. */
356 @@ -312,7 +413,6 @@ load (const char *file_name, void (**eip) (void), void **esp)
357  
358   done:
359    /* We arrive here whether the load is successful or not. */
360 -  file_close (file);
361    return success;
362  }
363  \f
364 @@ -424,10 +524,92 @@ load_segment (struct file *file, off_t ofs, uint8_t *upage,
365    return true;
366  }
367  
368 -/* Create a minimal stack by mapping a zeroed page at the top of
369 -   user virtual memory. */
370 +/* Reverse the order of the ARGC pointers to char in ARGV. */
371 +static void
372 +reverse (int argc, char **argv) 
373 +{
374 +  for (; argc > 1; argc -= 2, argv++) 
375 +    {
376 +      char *tmp = argv[0];
377 +      argv[0] = argv[argc - 1];
378 +      argv[argc - 1] = tmp;
379 +    }
380 +}
381 +
382 +/* Pushes the SIZE bytes in BUF onto the stack in KPAGE, whose
383 +   page-relative stack pointer is *OFS, and then adjusts *OFS
384 +   appropriately.  The bytes pushed are rounded to a 32-bit
385 +   boundary.
386 +
387 +   If successful, returns a pointer to the newly pushed object.
388 +   On failure, returns a null pointer. */
389 +static void *
390 +push (uint8_t *kpage, size_t *ofs, const void *buf, size_t size) 
391 +{
392 +  size_t padsize = ROUND_UP (size, sizeof (uint32_t));
393 +  if (*ofs < padsize)
394 +    return NULL;
395 +
396 +  *ofs -= padsize;
397 +  memcpy (kpage + *ofs + (padsize - size), buf, size);
398 +  return kpage + *ofs + (padsize - size);
399 +}
400 +
401 +/* Sets up command line arguments in KPAGE, which will be mapped
402 +   to UPAGE in user space.  The command line arguments are taken
403 +   from CMD_LINE, separated by spaces.  Sets *ESP to the initial
404 +   stack pointer for the process. */
405 +static bool
406 +init_cmd_line (uint8_t *kpage, uint8_t *upage, const char *cmd_line,
407 +               void **esp) 
408 +{
409 +  size_t ofs = PGSIZE;
410 +  char *const null = NULL;
411 +  char *cmd_line_copy;
412 +  char *karg, *saveptr;
413 +  int argc;
414 +  char **argv;
415 +
416 +  /* Push command line string. */
417 +  cmd_line_copy = push (kpage, &ofs, cmd_line, strlen (cmd_line) + 1);
418 +  if (cmd_line_copy == NULL)
419 +    return false;
420 +
421 +  if (push (kpage, &ofs, &null, sizeof null) == NULL)
422 +    return false;
423 +
424 +  /* Parse command line into arguments
425 +     and push them in reverse order. */
426 +  argc = 0;
427 +  for (karg = strtok_r (cmd_line_copy, " ", &saveptr); karg != NULL;
428 +       karg = strtok_r (NULL, " ", &saveptr))
429 +    {
430 +      void *uarg = upage + (karg - (char *) kpage);
431 +      if (push (kpage, &ofs, &uarg, sizeof uarg) == NULL)
432 +        return false;
433 +      argc++;
434 +    }
435 +
436 +  /* Reverse the order of the command line arguments. */
437 +  argv = (char **) (upage + ofs);
438 +  reverse (argc, (char **) (kpage + ofs));
439 +
440 +  /* Push argv, argc, "return address". */
441 +  if (push (kpage, &ofs, &argv, sizeof argv) == NULL
442 +      || push (kpage, &ofs, &argc, sizeof argc) == NULL
443 +      || push (kpage, &ofs, &null, sizeof null) == NULL)
444 +    return false;
445 +
446 +  /* Set initial stack pointer. */
447 +  *esp = upage + ofs;
448 +  return true;
449 +}
450 +
451 +/* Create a minimal stack for T by mapping a page at the
452 +   top of user virtual memory.  Fills in the page using CMD_LINE
453 +   and sets *ESP to the stack pointer. */
454  static bool
455 -setup_stack (void **esp) 
456 +setup_stack (const char *cmd_line, void **esp) 
457  {
458    uint8_t *kpage;
459    bool success = false;
460 @@ -435,9 +617,9 @@ setup_stack (void **esp)
461    kpage = palloc_get_page (PAL_USER | PAL_ZERO);
462    if (kpage != NULL) 
463      {
464 -      success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage, true);
465 -      if (success)
466 -        *esp = PHYS_BASE;
467 +      uint8_t *upage = ((uint8_t *) PHYS_BASE) - PGSIZE;
468 +      if (install_page (upage, kpage, true))
469 +        success = init_cmd_line (kpage, upage, cmd_line, esp);
470        else
471          palloc_free_page (kpage);
472      }
473 diff --git a/src/userprog/syscall.c b/src/userprog/syscall.c
474 index 370c89b..ef31316 100644
475 --- a/src/userprog/syscall.c
476 +++ b/src/userprog/syscall.c
477 @@ -1,20 +1,486 @@
478  #include "userprog/syscall.h"
479  #include <stdio.h>
480 +#include <string.h>
481  #include <syscall-nr.h>
482 +#include "userprog/process.h"
483 +#include "userprog/pagedir.h"
484 +#include "devices/input.h"
485 +#include "devices/shutdown.h"
486 +#include "filesys/filesys.h"
487 +#include "filesys/file.h"
488  #include "threads/interrupt.h"
489 +#include "threads/malloc.h"
490 +#include "threads/palloc.h"
491  #include "threads/thread.h"
492 -
493 +#include "threads/vaddr.h"
494
495
496 +static int sys_halt (void);
497 +static int sys_exit (int status);
498 +static int sys_exec (const char *ufile);
499 +static int sys_wait (tid_t);
500 +static int sys_create (const char *ufile, unsigned initial_size);
501 +static int sys_remove (const char *ufile);
502 +static int sys_open (const char *ufile);
503 +static int sys_filesize (int handle);
504 +static int sys_read (int handle, void *udst_, unsigned size);
505 +static int sys_write (int handle, void *usrc_, unsigned size);
506 +static int sys_seek (int handle, unsigned position);
507 +static int sys_tell (int handle);
508 +static int sys_close (int handle);
509
510  static void syscall_handler (struct intr_frame *);
511 -
512 +static void copy_in (void *, const void *, size_t);
513
514 +/* Serializes file system operations. */
515 +static struct lock fs_lock;
516
517  void
518  syscall_init (void) 
519  {
520    intr_register_int (0x30, 3, INTR_ON, syscall_handler, "syscall");
521 +  lock_init (&fs_lock);
522  }
523
524 +/* System call handler. */
525 +static void
526 +syscall_handler (struct intr_frame *f) 
527 +{
528 +  typedef int syscall_function (int, int, int);
529 +
530 +  /* A system call. */
531 +  struct syscall 
532 +    {
533 +      size_t arg_cnt;           /* Number of arguments. */
534 +      syscall_function *func;   /* Implementation. */
535 +    };
536 +
537 +  /* Table of system calls. */
538 +  static const struct syscall syscall_table[] =
539 +    {
540 +      {0, (syscall_function *) sys_halt},
541 +      {1, (syscall_function *) sys_exit},
542 +      {1, (syscall_function *) sys_exec},
543 +      {1, (syscall_function *) sys_wait},
544 +      {2, (syscall_function *) sys_create},
545 +      {1, (syscall_function *) sys_remove},
546 +      {1, (syscall_function *) sys_open},
547 +      {1, (syscall_function *) sys_filesize},
548 +      {3, (syscall_function *) sys_read},
549 +      {3, (syscall_function *) sys_write},
550 +      {2, (syscall_function *) sys_seek},
551 +      {1, (syscall_function *) sys_tell},
552 +      {1, (syscall_function *) sys_close},
553 +    };
554 +
555 +  const struct syscall *sc;
556 +  unsigned call_nr;
557 +  int args[3];
558 +
559 +  /* Get the system call. */
560 +  copy_in (&call_nr, f->esp, sizeof call_nr);
561 +  if (call_nr >= sizeof syscall_table / sizeof *syscall_table)
562 +    thread_exit ();
563 +  sc = syscall_table + call_nr;
564  
565 +  /* Get the system call arguments. */
566 +  ASSERT (sc->arg_cnt <= sizeof args / sizeof *args);
567 +  memset (args, 0, sizeof args);
568 +  copy_in (args, (uint32_t *) f->esp + 1, sizeof *args * sc->arg_cnt);
569 +
570 +  /* Execute the system call,
571 +     and set the return value. */
572 +  f->eax = sc->func (args[0], args[1], args[2]);
573 +}
574
575 +/* Returns true if UADDR is a valid, mapped user address,
576 +   false otherwise. */
577 +static bool
578 +verify_user (const void *uaddr) 
579 +{
580 +  return (uaddr < PHYS_BASE
581 +          && pagedir_get_page (thread_current ()->pagedir, uaddr) != NULL);
582 +}
583
584 +/* Copies a byte from user address USRC to kernel address DST.
585 +   USRC must be below PHYS_BASE.
586 +   Returns true if successful, false if a segfault occurred. */
587 +static inline bool
588 +get_user (uint8_t *dst, const uint8_t *usrc)
589 +{
590 +  int eax;
591 +  asm ("movl $1f, %%eax; movb %2, %%al; movb %%al, %0; 1:"
592 +       : "=m" (*dst), "=&a" (eax) : "m" (*usrc));
593 +  return eax != 0;
594 +}
595
596 +/* Writes BYTE to user address UDST.
597 +   UDST must be below PHYS_BASE.
598 +   Returns true if successful, false if a segfault occurred. */
599 +static inline bool
600 +put_user (uint8_t *udst, uint8_t byte)
601 +{
602 +  int eax;
603 +  asm ("movl $1f, %%eax; movb %b2, %0; 1:"
604 +       : "=m" (*udst), "=&a" (eax) : "q" (byte));
605 +  return eax != 0;
606 +}
607
608 +/* Copies SIZE bytes from user address USRC to kernel address
609 +   DST.
610 +   Call thread_exit() if any of the user accesses are invalid. */
611  static void
612 -syscall_handler (struct intr_frame *f UNUSED) 
613 +copy_in (void *dst_, const void *usrc_, size_t size) 
614 +{
615 +  uint8_t *dst = dst_;
616 +  const uint8_t *usrc = usrc_;
617
618 +  for (; size > 0; size--, dst++, usrc++) 
619 +    if (usrc >= (uint8_t *) PHYS_BASE || !get_user (dst, usrc)) 
620 +      thread_exit ();
621 +}
622
623 +/* Creates a copy of user string US in kernel memory
624 +   and returns it as a page that must be freed with
625 +   palloc_free_page().
626 +   Truncates the string at PGSIZE bytes in size.
627 +   Call thread_exit() if any of the user accesses are invalid. */
628 +static char *
629 +copy_in_string (const char *us) 
630 +{
631 +  char *ks;
632 +  size_t length;
633
634 +  ks = palloc_get_page (0);
635 +  if (ks == NULL) 
636 +    thread_exit ();
637
638 +  for (length = 0; length < PGSIZE; length++)
639 +    {
640 +      if (us >= (char *) PHYS_BASE || !get_user (ks + length, us++)) 
641 +        {
642 +          palloc_free_page (ks);
643 +          thread_exit (); 
644 +        }
645 +       
646 +      if (ks[length] == '\0')
647 +        return ks;
648 +    }
649 +  ks[PGSIZE - 1] = '\0';
650 +  return ks;
651 +}
652
653 +/* Halt system call. */
654 +static int
655 +sys_halt (void)
656 +{
657 +  shutdown_power_off ();
658 +}
659
660 +/* Exit system call. */
661 +static int
662 +sys_exit (int exit_code) 
663 +{
664 +  thread_current ()->wait_status->exit_code = exit_code;
665 +  thread_exit ();
666 +  NOT_REACHED ();
667 +}
668
669 +/* Exec system call. */
670 +static int
671 +sys_exec (const char *ufile) 
672 +{
673 +  tid_t tid;
674 +  char *kfile = copy_in_string (ufile);
675
676 +  lock_acquire (&fs_lock);
677 +  tid = process_execute (kfile);
678 +  lock_release (&fs_lock);
679
680 +  palloc_free_page (kfile);
681
682 +  return tid;
683 +}
684
685 +/* Wait system call. */
686 +static int
687 +sys_wait (tid_t child) 
688 +{
689 +  return process_wait (child);
690 +}
691
692 +/* Create system call. */
693 +static int
694 +sys_create (const char *ufile, unsigned initial_size) 
695 +{
696 +  char *kfile = copy_in_string (ufile);
697 +  bool ok;
698 +   
699 +  lock_acquire (&fs_lock);
700 +  ok = filesys_create (kfile, initial_size);
701 +  lock_release (&fs_lock);
702
703 +  palloc_free_page (kfile);
704
705 +  return ok;
706 +}
707
708 +/* Remove system call. */
709 +static int
710 +sys_remove (const char *ufile) 
711  {
712 -  printf ("system call!\n");
713 +  char *kfile = copy_in_string (ufile);
714 +  bool ok;
715 +   
716 +  lock_acquire (&fs_lock);
717 +  ok = filesys_remove (kfile);
718 +  lock_release (&fs_lock);
719
720 +  palloc_free_page (kfile);
721
722 +  return ok;
723 +}
724
725 +/* A file descriptor, for binding a file handle to a file. */
726 +struct file_descriptor
727 +  {
728 +    struct list_elem elem;      /* List element. */
729 +    struct file *file;          /* File. */
730 +    int handle;                 /* File handle. */
731 +  };
732
733 +/* Open system call. */
734 +static int
735 +sys_open (const char *ufile) 
736 +{
737 +  char *kfile = copy_in_string (ufile);
738 +  struct file_descriptor *fd;
739 +  int handle = -1;
740
741 +  fd = malloc (sizeof *fd);
742 +  if (fd != NULL)
743 +    {
744 +      lock_acquire (&fs_lock);
745 +      fd->file = filesys_open (kfile);
746 +      if (fd->file != NULL)
747 +        {
748 +          struct thread *cur = thread_current ();
749 +          handle = fd->handle = cur->next_handle++;
750 +          list_push_front (&cur->fds, &fd->elem);
751 +        }
752 +      else 
753 +        free (fd);
754 +      lock_release (&fs_lock);
755 +    }
756 +  
757 +  palloc_free_page (kfile);
758 +  return handle;
759 +}
760
761 +/* Returns the file descriptor associated with the given handle.
762 +   Terminates the process if HANDLE is not associated with an
763 +   open file. */
764 +static struct file_descriptor *
765 +lookup_fd (int handle) 
766 +{
767 +  struct thread *cur = thread_current ();
768 +  struct list_elem *e;
769 +   
770 +  for (e = list_begin (&cur->fds); e != list_end (&cur->fds);
771 +       e = list_next (e))
772 +    {
773 +      struct file_descriptor *fd;
774 +      fd = list_entry (e, struct file_descriptor, elem);
775 +      if (fd->handle == handle)
776 +        return fd;
777 +    }
778
779    thread_exit ();
780  }
781
782 +/* Filesize system call. */
783 +static int
784 +sys_filesize (int handle) 
785 +{
786 +  struct file_descriptor *fd = lookup_fd (handle);
787 +  int size;
788
789 +  lock_acquire (&fs_lock);
790 +  size = file_length (fd->file);
791 +  lock_release (&fs_lock);
792
793 +  return size;
794 +}
795
796 +/* Read system call. */
797 +static int
798 +sys_read (int handle, void *udst_, unsigned size) 
799 +{
800 +  uint8_t *udst = udst_;
801 +  struct file_descriptor *fd;
802 +  int bytes_read = 0;
803 +
804 +  /* Handle keyboard reads. */
805 +  if (handle == STDIN_FILENO) 
806 +    {
807 +      for (bytes_read = 0; (size_t) bytes_read < size; bytes_read++)
808 +        if (udst >= (uint8_t *) PHYS_BASE || !put_user (udst++, input_getc ()))
809 +          thread_exit ();
810 +      return bytes_read;
811 +    }
812 +
813 +  /* Handle all other reads. */
814 +  fd = lookup_fd (handle);
815 +  lock_acquire (&fs_lock);
816 +  while (size > 0) 
817 +    {
818 +      /* How much to read into this page? */
819 +      size_t page_left = PGSIZE - pg_ofs (udst);
820 +      size_t read_amt = size < page_left ? size : page_left;
821 +      off_t retval;
822 +
823 +      /* Check that touching this page is okay. */
824 +      if (!verify_user (udst)) 
825 +        {
826 +          lock_release (&fs_lock);
827 +          thread_exit ();
828 +        }
829 +
830 +      /* Read from file into page. */
831 +      retval = file_read (fd->file, udst, read_amt);
832 +      if (retval < 0)
833 +        {
834 +          if (bytes_read == 0)
835 +            bytes_read = -1; 
836 +          break;
837 +        }
838 +      bytes_read += retval;
839 +
840 +      /* If it was a short read we're done. */
841 +      if (retval != (off_t) read_amt)
842 +        break;
843 +
844 +      /* Advance. */
845 +      udst += retval;
846 +      size -= retval;
847 +    }
848 +  lock_release (&fs_lock);
849 +   
850 +  return bytes_read;
851 +}
852
853 +/* Write system call. */
854 +static int
855 +sys_write (int handle, void *usrc_, unsigned size) 
856 +{
857 +  uint8_t *usrc = usrc_;
858 +  struct file_descriptor *fd = NULL;
859 +  int bytes_written = 0;
860 +
861 +  /* Lookup up file descriptor. */
862 +  if (handle != STDOUT_FILENO)
863 +    fd = lookup_fd (handle);
864 +
865 +  lock_acquire (&fs_lock);
866 +  while (size > 0) 
867 +    {
868 +      /* How much bytes to write to this page? */
869 +      size_t page_left = PGSIZE - pg_ofs (usrc);
870 +      size_t write_amt = size < page_left ? size : page_left;
871 +      off_t retval;
872 +
873 +      /* Check that we can touch this user page. */
874 +      if (!verify_user (usrc)) 
875 +        {
876 +          lock_release (&fs_lock);
877 +          thread_exit ();
878 +        }
879 +
880 +      /* Do the write. */
881 +      if (handle == STDOUT_FILENO)
882 +        {
883 +          putbuf (usrc, write_amt);
884 +          retval = write_amt;
885 +        }
886 +      else
887 +        retval = file_write (fd->file, usrc, write_amt);
888 +      if (retval < 0) 
889 +        {
890 +          if (bytes_written == 0)
891 +            bytes_written = -1;
892 +          break;
893 +        }
894 +      bytes_written += retval;
895 +
896 +      /* If it was a short write we're done. */
897 +      if (retval != (off_t) write_amt)
898 +        break;
899 +
900 +      /* Advance. */
901 +      usrc += retval;
902 +      size -= retval;
903 +    }
904 +  lock_release (&fs_lock);
905
906 +  return bytes_written;
907 +}
908
909 +/* Seek system call. */
910 +static int
911 +sys_seek (int handle, unsigned position) 
912 +{
913 +  struct file_descriptor *fd = lookup_fd (handle);
914 +   
915 +  lock_acquire (&fs_lock);
916 +  if ((off_t) position >= 0)
917 +    file_seek (fd->file, position);
918 +  lock_release (&fs_lock);
919
920 +  return 0;
921 +}
922
923 +/* Tell system call. */
924 +static int
925 +sys_tell (int handle) 
926 +{
927 +  struct file_descriptor *fd = lookup_fd (handle);
928 +  unsigned position;
929 +   
930 +  lock_acquire (&fs_lock);
931 +  position = file_tell (fd->file);
932 +  lock_release (&fs_lock);
933
934 +  return position;
935 +}
936
937 +/* Close system call. */
938 +static int
939 +sys_close (int handle) 
940 +{
941 +  struct file_descriptor *fd = lookup_fd (handle);
942 +  lock_acquire (&fs_lock);
943 +  file_close (fd->file);
944 +  lock_release (&fs_lock);
945 +  list_remove (&fd->elem);
946 +  free (fd);
947 +  return 0;
948 +}
949
950 +/* On thread exit, close all open files. */
951 +void
952 +syscall_exit (void) 
953 +{
954 +  struct thread *cur = thread_current ();
955 +  struct list_elem *e, *next;
956 +   
957 +  for (e = list_begin (&cur->fds); e != list_end (&cur->fds); e = next)
958 +    {
959 +      struct file_descriptor *fd;
960 +      fd = list_entry (e, struct file_descriptor, elem);
961 +      next = list_next (e);
962 +      lock_acquire (&fs_lock);
963 +      file_close (fd->file);
964 +      lock_release (&fs_lock);
965 +      free (fd);
966 +    }
967 +}
968 diff --git a/src/userprog/syscall.h b/src/userprog/syscall.h
969 index 9059096..9d156f0 100644
970 --- a/src/userprog/syscall.h
971 +++ b/src/userprog/syscall.h
972 @@ -2,5 +2,6 @@
973  #define USERPROG_SYSCALL_H
974  
975  void syscall_init (void);
976 +void syscall_exit (void);
977  
978  #endif /* userprog/syscall.h */