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