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