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