1 diff -urpN pintos.orig/src/Makefile.build pintos/src/Makefile.build
2 --- pintos.orig/src/Makefile.build 2004-09-20 20:26:41.000000000 -0700
3 +++ pintos/src/Makefile.build 2004-09-27 13:29:43.000000000 -0700
4 @@ -51,8 +51,9 @@ userprog_SRC += userprog/syscall.c # Sys
5 userprog_SRC += userprog/gdt.c # GDT initialization.
6 userprog_SRC += userprog/tss.c # TSS management.
8 -# No virtual memory code yet.
9 -#vm_SRC = vm/filename.c # Some file.
10 +# Virtual memory code.
11 +vm_SRC = vm/pageframe.c # Page frame management.
12 +vm_SRC += vm/swap.c # Swap file management.
15 filesys_SRC = filesys/filesys.c # Filesystem core.
16 diff -urpN pintos.orig/src/threads/init.c pintos/src/threads/init.c
17 --- pintos.orig/src/threads/init.c 2004-09-26 14:15:17.000000000 -0700
18 +++ pintos/src/threads/init.c 2004-09-27 16:08:03.000000000 -0700
20 #include "threads/test.h"
21 #include "threads/thread.h"
23 +#include "userprog/pagedir.h"
24 #include "userprog/process.h"
25 #include "userprog/exception.h"
26 #include "userprog/gdt.h"
27 #include "userprog/syscall.h"
28 #include "userprog/tss.h"
30 +#include "vm/pageframe.h"
33 #include "devices/disk.h"
34 #include "filesys/filesys.h"
35 @@ -78,6 +81,7 @@ main (void)
36 /* Initialize memory system, segments, paging. */
43 @@ -105,6 +109,7 @@ main (void)
45 filesys_init (format_filesys);
50 printf ("Boot complete.\n");
51 diff -urpN pintos.orig/src/threads/palloc.c pintos/src/threads/palloc.c
52 diff -urpN pintos.orig/src/threads/palloc.h pintos/src/threads/palloc.h
53 diff -urpN pintos.orig/src/threads/synch.c pintos/src/threads/synch.c
54 --- pintos.orig/src/threads/synch.c 2004-09-19 21:29:53.000000000 -0700
55 +++ pintos/src/threads/synch.c 2004-09-27 13:29:43.000000000 -0700
56 @@ -330,3 +330,35 @@ cond_name (const struct condition *cond)
62 +latch_init (struct latch *latch, const char *name)
64 + latch->released = false;
65 + lock_init (&latch->monitor_lock, name);
66 + cond_init (&latch->rel_cond, name);
70 +latch_acquire (struct latch *latch)
72 + lock_acquire (&latch->monitor_lock);
73 + if (!latch->released)
75 + cond_wait (&latch->rel_cond, &latch->monitor_lock);
76 + ASSERT (latch->released);
78 + lock_release (&latch->monitor_lock);
82 +latch_release (struct latch *latch)
84 + lock_acquire (&latch->monitor_lock);
85 + if (!latch->released)
87 + latch->released = true;
88 + cond_signal (&latch->rel_cond, &latch->monitor_lock);
90 + lock_release (&latch->monitor_lock);
92 diff -urpN pintos.orig/src/threads/synch.h pintos/src/threads/synch.h
93 --- pintos.orig/src/threads/synch.h 2004-09-19 21:29:53.000000000 -0700
94 +++ pintos/src/threads/synch.h 2004-09-27 13:29:43.000000000 -0700
95 @@ -44,4 +44,16 @@ void cond_signal (struct condition *, st
96 void cond_broadcast (struct condition *, struct lock *);
97 const char *cond_name (const struct condition *);
102 + bool released; /* Released yet? */
103 + struct lock monitor_lock; /* Monitor lock. */
104 + struct condition rel_cond; /* Signaled when released. */
107 +void latch_init (struct latch *, const char *);
108 +void latch_acquire (struct latch *);
109 +void latch_release (struct latch *);
111 #endif /* threads/synch.h */
112 diff -urpN pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
113 --- pintos.orig/src/threads/thread.c 2004-09-26 14:15:17.000000000 -0700
114 +++ pintos/src/threads/thread.c 2004-09-27 13:29:43.000000000 -0700
116 #include "threads/synch.h"
118 #include "userprog/process.h"
119 +#include "userprog/syscall.h"
122 /* Random value for struct thread's `magic' member.
123 @@ -80,6 +81,7 @@ thread_init (void)
124 init_thread (initial_thread, "main", PRI_DEFAULT);
125 initial_thread->status = THREAD_RUNNING;
126 initial_thread->tid = allocate_tid ();
127 + sema_up (&initial_thread->can_die);
130 /* Starts preemptive thread scheduling by enabling interrupts.
131 @@ -148,6 +150,7 @@ thread_create (const char *name, int pri
132 /* Initialize thread. */
133 init_thread (t, name, priority);
134 tid = t->tid = allocate_tid ();
135 + list_push_back (&thread_current ()->children, &t->children_elem);
137 /* Stack frame for kernel_thread(). */
138 kf = alloc_frame (t, sizeof *kf);
139 @@ -224,16 +227,36 @@ thread_tid (void)
143 + struct thread *t = thread_current ();
144 + list_elem *e, *next;
146 ASSERT (!intr_context ());
153 + /* Notify our parent that we're dying. */
154 + latch_release (&t->ready_to_die);
156 + /* Notify our children that they can die. */
157 + for (e = list_begin (&t->children); e != list_end (&t->children);
160 + struct thread *child = list_entry (e, struct thread, children_elem);
161 + next = list_next (e);
163 + sema_up (&child->can_die);
166 + /* Wait until our parent is ready for us to die. */
167 + sema_down (&t->can_die);
169 /* Just set our status to dying and schedule another process.
170 We will be destroyed during the call to schedule_tail(). */
172 - thread_current ()->status = THREAD_DYING;
173 + t->status = THREAD_DYING;
177 @@ -283,8 +290,22 @@ thread_block (void)
178 This function will be implemented in problem 1-2. For now, it
181 -thread_join (tid_t child_tid UNUSED)
184 +thread_join (tid_t child_tid)
186 + struct thread *cur = thread_current ();
189 + for (e = list_begin (&cur->children); e != list_end (&cur->children); )
191 + struct thread *child = list_entry (e, struct thread, children_elem);
193 + if (child->tid == child_tid)
195 + latch_acquire (&child->ready_to_die);
196 + return child->ret_code;
202 /* Sets the current thread's priority to NEW_PRIORITY. */
203 @@ -335,6 +378,12 @@ init_thread (struct thread *t, const cha
204 strlcpy (t->name, name, sizeof t->name);
205 t->stack = (uint8_t *) t + PGSIZE;
206 t->priority = priority;
207 + latch_init (&t->ready_to_die, "ready-to-die");
208 + sema_init (&t->can_die, 0, "can-die");
209 + list_init (&t->children);
211 + list_init (&t->fds);
212 + t->next_handle = 2;
213 t->magic = THREAD_MAGIC;
216 diff -urpN pintos.orig/src/threads/thread.h pintos/src/threads/thread.h
217 --- pintos.orig/src/threads/thread.h 2004-09-26 14:15:17.000000000 -0700
218 +++ pintos/src/threads/thread.h 2004-09-27 13:29:43.000000000 -0700
220 #define THREADS_THREAD_H
226 +#include "threads/synch.h"
228 /* States in a thread's life cycle. */
230 @@ -89,12 +91,24 @@ struct thread
231 uint8_t *stack; /* Saved stack pointer. */
232 int priority; /* Priority. */
234 + /* Members for implementing thread_join(). */
235 + struct latch ready_to_die; /* Release when thread about to die. */
236 + struct semaphore can_die; /* Up when thread allowed to die. */
237 + struct list children; /* List of child threads. */
238 + list_elem children_elem; /* Element of `children' list. */
239 + int ret_code; /* Return status. */
241 /* Shared between thread.c and synch.c. */
242 list_elem elem; /* List element. */
245 /* Owned by userprog/process.c. */
246 uint32_t *pagedir; /* Page directory. */
247 + struct hash pages; /* Hash of `struct user_page's. */
249 + /* Owned by syscall.c. */
250 + struct list fds; /* List of file descriptors. */
251 + int next_handle; /* Next handle value. */
254 /* Owned by thread.c */
255 @@ -120,7 +132,7 @@ void thread_exit (void) NO_RETURN;
256 void thread_exit (void) NO_RETURN;
257 void thread_yield (void);
259 -void thread_join (tid_t);
260 +int thread_join (tid_t);
262 void thread_set_priority (int);
263 int thread_get_priority (void);
264 diff -urpN pintos.orig/src/userprog/exception.c pintos/src/userprog/exception.c
265 --- pintos.orig/src/userprog/exception.c 2004-09-26 14:15:17.000000000 -0700
266 +++ pintos/src/userprog/exception.c 2004-09-27 13:29:44.000000000 -0700
268 #include "userprog/exception.h"
269 #include <inttypes.h>
272 #include "userprog/gdt.h"
273 +#include "userprog/pagedir.h"
274 +#include "userprog/process.h"
275 +#include "filesys/file.h"
276 #include "threads/interrupt.h"
277 +#include "threads/mmu.h"
278 #include "threads/thread.h"
279 +#include "vm/pageframe.h"
280 +#include "vm/swap.h"
282 /* Number of page faults processed. */
283 static long long page_fault_cnt;
284 @@ -124,10 +131,13 @@ kill (struct intr_frame *f)
286 page_fault (struct intr_frame *f)
289 bool not_present; /* True: not-present page, false: writing r/o page. */
290 bool write; /* True: access was write, false: access was read. */
291 bool user; /* True: access by user, false: access by kernel. */
292 void *fault_addr; /* Fault address. */
293 + struct user_page tmp_up, *up;
296 /* Obtain faulting address, the virtual address that was
297 accessed to cause the fault. It may point to code or to
298 @@ -147,14 +157,62 @@ page_fault (struct intr_frame *f)
299 write = (f->error_code & PF_W) != 0;
300 user = (f->error_code & PF_U) != 0;
302 - /* To implement virtual memory, delete the rest of the function
303 - body, and replace it with code that brings in the page to
304 - which fault_addr refers. */
305 - printf ("Page fault at %p: %s error %s page in %s context.\n",
307 - not_present ? "not present" : "rights violation",
308 - write ? "writing" : "reading",
309 - user ? "user" : "kernel");
314 + t = thread_current ();
315 + if (t->pagedir == NULL)
318 + //printf ("fault %p (page=%p)\n", fault_addr, pg_round_down (fault_addr));
319 + tmp_up.upage = pg_round_down (fault_addr);
320 + e = hash_find (&t->pages, &tmp_up.elem);
323 + printf ("no user_page for %p\n", fault_addr);
326 + up = hash_entry (e, struct user_page, elem);
328 + if (up->frame == NULL)
330 + if (!pageframe_allocate (up))
332 + printf ("virtual memory exhausted, killing process\n");
337 + if (up->file != NULL)
339 + off_t amt = file_read_at (up->file,
340 + up->frame->kpage, up->file_size,
342 + ASSERT (amt == (off_t) up->file_size);
343 + memset (up->frame->kpage + up->file_size, 0, PGSIZE - up->file_size);
345 + else if (up->swap_page != SIZE_MAX)
348 + memset (up->frame->kpage, 0, PGSIZE);
350 + pagedir_set_page (t->pagedir, up->upage, up->frame->kpage, true);
354 + if (user || fault_addr > PHYS_BASE)
356 + printf ("Page fault at %p: %s error %s page in %s context.\n",
358 + not_present ? "not present" : "rights violation",
359 + write ? "writing" : "reading",
360 + user ? "user" : "kernel");
365 + f->eip = (void (*) (void)) f->eax;
370 diff -urpN pintos.orig/src/userprog/process.c pintos/src/userprog/process.c
371 --- pintos.orig/src/userprog/process.c 2004-09-22 17:58:29.000000000 -0700
372 +++ pintos/src/userprog/process.c 2004-09-27 14:43:09.000000000 -0700
374 #include "userprog/gdt.h"
375 #include "userprog/pagedir.h"
376 #include "userprog/tss.h"
377 +#include "vm/pageframe.h"
378 #include "filesys/directory.h"
379 #include "filesys/file.h"
380 #include "filesys/filesys.h"
381 #include "threads/flags.h"
382 #include "threads/init.h"
383 #include "threads/interrupt.h"
384 +#include "threads/malloc.h"
385 #include "threads/mmu.h"
386 #include "threads/palloc.h"
387 #include "threads/thread.h"
388 +#include "vm/swap.h"
390 static thread_func execute_thread NO_RETURN;
391 static bool load (const char *cmdline, void (**eip) (void), void **esp);
392 @@ -100,6 +103,10 @@ process_exit (void)
394 pagedir_activate (NULL);
395 pagedir_destroy (pd);
397 + /* We maintain the invariant that `hash' is initialized iff
399 + hash_destroy (&cur->pages);
403 @@ -182,7 +189,10 @@ struct Elf32_Phdr
404 #define PF_R 4 /* Readable. */
406 static bool load_segment (struct file *, const struct Elf32_Phdr *);
407 -static bool setup_stack (void **esp);
408 +static bool setup_stack (const char *cmdline, void **esp);
409 +static unsigned user_page_hash (const hash_elem *, void *);
410 +static bool user_page_less (const hash_elem *, const hash_elem *, void *);
411 +static struct user_page *make_user_page (void *upage);
413 /* Aborts loading an executable, with an error message. */
414 #define LOAD_ERROR(MSG) \
415 @@ -198,19 +208,35 @@ static bool setup_stack (void **esp);
416 and its initial stack pointer into *ESP.
417 Returns true if successful, false otherwise. */
419 -load (const char *filename, void (**eip) (void), void **esp)
420 +load (const char *cmdline, void (**eip) (void), void **esp)
422 struct thread *t = thread_current ();
423 + char filename[NAME_MAX + 2];
424 struct Elf32_Ehdr ehdr;
425 struct file *file = NULL;
427 bool success = false;
431 + /* Create hash of user pages. */
432 + hash_init (&t->pages, user_page_hash, user_page_less, NULL);
434 /* Allocate page directory. */
435 t->pagedir = pagedir_create ();
436 - if (t->pagedir == NULL)
437 - LOAD_ERROR (("page directory allocation failed"));
438 + if (t->pagedir == NULL)
440 + hash_destroy (&t->pages);
441 + LOAD_ERROR (("page directory allocation failed"));
444 + /* Extract filename from command line. */
445 + while (*cmdline == ' ')
447 + strlcpy (filename, cmdline, sizeof filename);
448 + cp = strchr (filename, ' ');
452 /* Open executable file. */
453 file = filesys_open (filename);
454 @@ -269,8 +295,23 @@ load (const char *filename, void (**eip)
458 - if (!setup_stack (esp))
459 + if (!setup_stack (cmdline, esp))
464 + struct hash_iterator i;
466 + hash_first (&i, &thread_current ()->pages);
467 + while (hash_next (&i))
469 + struct user_page *up = hash_entry (hash_cur (&i),
470 + struct user_page, elem);
471 + printf ("%08x ", up->upage);
478 *eip = (void (*) (void)) ehdr.e_entry;
479 @@ -279,14 +320,12 @@ load (const char *filename, void (**eip)
482 /* We arrive here whether the load is successful or not. */
484 + //file_close (file); // FIXME
488 /* load() helpers. */
490 -static bool install_page (void *upage, void *kpage);
492 /* Loads the segment described by PHDR from FILE into user
493 address space. Return true if successful, false otherwise. */
495 @@ -296,6 +335,7 @@ load_segment (struct file *file, const s
496 uint8_t *upage; /* Iterator from start to end. */
497 off_t filesz_left; /* Bytes left of file data (as opposed to
498 zero-initialized bytes). */
501 /* Is this a read-only segment? Not currently used, so it's
502 commented out. You'll want to use it when implementing VM
503 @@ -340,70 +380,206 @@ load_segment (struct file *file, const s
505 /* Load the segment page-by-page into memory. */
506 filesz_left = phdr->p_filesz + (phdr->p_vaddr & PGMASK);
507 - file_seek (file, ROUND_DOWN (phdr->p_offset, PGSIZE));
508 + file_ofs = ROUND_DOWN (phdr->p_offset, PGSIZE);
509 for (upage = start; upage < (uint8_t *) end; upage += PGSIZE)
511 /* We want to read min(PGSIZE, filesz_left) bytes from the
512 file into the page and zero the rest. */
513 size_t read_bytes = filesz_left >= PGSIZE ? PGSIZE : filesz_left;
514 - size_t zero_bytes = PGSIZE - read_bytes;
515 - uint8_t *kpage = palloc_get_page (PAL_USER);
517 + struct user_page *up = make_user_page (upage);
521 - /* Do the reading and zeroing. */
522 - if (file_read (file, kpage, read_bytes) != (int) read_bytes)
523 + if (read_bytes > 0)
525 - palloc_free_page (kpage);
529 + up->file_ofs = file_ofs;
530 + up->file_size = read_bytes;
531 + file_ofs += read_bytes;
533 - memset (kpage + read_bytes, 0, zero_bytes);
534 - filesz_left -= read_bytes;
536 - /* Add the page to the process's address space. */
537 - if (!install_page (upage, kpage))
540 - palloc_free_page (kpage);
542 + /* Page is all zeros. Nothing to do. */
544 + filesz_left -= read_bytes;
551 +reverse (int argc, char **argv)
553 + for (; argc > 1; argc -= 2, argv++)
555 + char *tmp = argv[0];
556 + argv[0] = argv[argc - 1];
557 + argv[argc - 1] = tmp;
561 +push (uint8_t *kpage, size_t *ofs, const void *buf, size_t size)
563 + size_t padsize = ROUND_UP (size, sizeof (uint32_t));
564 + if (*ofs < padsize)
568 + memcpy (kpage + *ofs + (padsize - size), buf, size);
569 + return kpage + *ofs + (padsize - size);
573 +init_cmdline (uint8_t *kpage, uint8_t *upage, const char *cmdline,
576 + size_t ofs = PGSIZE;
577 + char *const null = NULL;
578 + char *cmdline_copy;
579 + char *karg, *saveptr;
583 + /* Push command line string. */
584 + cmdline_copy = push (kpage, &ofs, cmdline, strlen (cmdline) + 1);
585 + if (cmdline_copy == NULL)
588 + if (push (kpage, &ofs, &null, sizeof null) == NULL)
591 + /* Parse command line into arguments
592 + and push them in reverse order. */
594 + for (karg = strtok_r (cmdline_copy, " ", &saveptr); karg != NULL;
595 + karg = strtok_r (NULL, " ", &saveptr))
597 + char *uarg = upage + (karg - (char *) kpage);
598 + if (push (kpage, &ofs, &uarg, sizeof uarg) == NULL)
603 + /* Reverse the order of the command line arguments. */
604 + argv = (char **) (upage + ofs);
605 + reverse (argc, (char **) (kpage + ofs));
607 + /* Push argv, argc, "return address". */
608 + if (push (kpage, &ofs, &argv, sizeof argv) == NULL
609 + || push (kpage, &ofs, &argc, sizeof argc) == NULL
610 + || push (kpage, &ofs, &null, sizeof null) == NULL)
613 + /* Set initial stack pointer. */
614 + *esp = upage + ofs;
619 -/* Create a minimal stack by mapping a zeroed page at the top of
620 - user virtual memory. */
621 +/* Create a minimal stack for T by mapping a page at the
622 + top of user virtual memory. Fills in the page using CMDLINE
623 + and sets *ESP to the stack pointer. */
625 -setup_stack (void **esp)
626 +setup_stack (const char *cmdline, void **esp)
629 - bool success = false;
630 + struct user_page *up = make_user_page ((uint8_t *) PHYS_BASE - PGSIZE);
632 + && pageframe_allocate (up)
633 + && init_cmdline (up->frame->kpage, up->upage, cmdline, esp));
637 +user_page_hash (const hash_elem *e, void *aux UNUSED)
639 + struct user_page *up = hash_entry (e, struct user_page, elem);
640 + return hash_bytes (&up->upage, sizeof up->upage);
643 - kpage = palloc_get_page (PAL_USER | PAL_ZERO);
646 +user_page_less (const hash_elem *a_, const hash_elem *b_, void *aux UNUSED)
648 + struct user_page *a = hash_entry (a_, struct user_page, elem);
649 + struct user_page *b = hash_entry (b_, struct user_page, elem);
651 + return a->upage < b->upage;
654 +static struct user_page *
655 +make_user_page (void *upage)
657 + struct user_page *up;
659 + up = malloc (sizeof *up);
662 - success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage);
665 + memset (up, 0, sizeof *up);
666 + up->swap_page = SIZE_MAX;
669 + if (hash_insert (&thread_current ()->pages, &up->elem) != NULL)
676 - palloc_free_page (kpage);
677 + printf ("make_user_page(%p) okay\n", upage);
681 - printf ("failed to allocate process stack\n");
687 -/* Adds a mapping from user virtual address UPAGE to kernel
688 - virtual address KPAGE to the page table. Fails if UPAGE is
689 - already mapped or if memory allocation fails. */
691 -install_page (void *upage, void *kpage)
693 +dump_page (struct user_page *up)
695 - struct thread *t = thread_current ();
698 - /* Verify that there's not already a page at that virtual
699 - address, then map our page there. */
700 - return (pagedir_get_page (t->pagedir, upage) == NULL
701 - && pagedir_set_page (t->pagedir, upage, kpage, true));
702 + ASSERT (up->file != NULL);
703 + up->file_size = PGSIZE;
704 + amt = file_write_at (up->file, up->frame->kpage,
705 + up->file_size, up->file_ofs);
706 + ASSERT (amt == (off_t) up->file_size);
710 +process_evict_page (struct thread *t, struct user_page *up)
712 + ASSERT (up->frame != NULL);
714 + if (pagedir_test_accessed (t->pagedir, up->upage))
716 + pagedir_clear_accessed (t->pagedir, up->upage);
720 + if (up->file == NULL)
722 + if (!swap_write (up))
725 + else if (pagedir_test_dirty (t->pagedir, up->upage))
727 + /* Need to write out. */
730 + up->file = NULL; // FIXME
731 + up->private = false;
732 + if (!swap_write (up))
740 + /* Already on disk, not dirty.
744 + pagedir_clear_page (t->pagedir, up->upage);
745 + pageframe_free (up->frame);
749 diff -urpN pintos.orig/src/userprog/process.h pintos/src/userprog/process.h
750 --- pintos.orig/src/userprog/process.h 2004-09-21 22:42:17.000000000 -0700
751 +++ pintos/src/userprog/process.h 2004-09-27 14:43:13.000000000 -0700
753 #define USERPROG_PROCESS_H
755 #include "threads/thread.h"
756 +#include "filesys/off_t.h"
761 + void *upage; /* Virtual address of mapping. */
763 + /* If FRAME is nonnull, the page is in memory.
764 + If FILE is nonnull, the page is on disk.
765 + If both are null, the page is all zeroes.
766 + If both are nonnull, the page is in memory and backed by a
767 + file mapping (not the swap file). */
768 + struct page_frame *frame;
772 + size_t file_size; /* Number of bytes on disk, <= PGSIZE. */
776 + bool private : 1; /* Write dirty pages to swap or to FILE? */
779 tid_t process_execute (const char *filename);
780 void process_exit (void);
781 void process_activate (void);
782 +bool process_evict_page (struct thread *, struct user_page *);
784 #endif /* userprog/process.h */
785 diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
786 --- pintos.orig/src/userprog/syscall.c 2004-09-26 14:15:17.000000000 -0700
787 +++ pintos/src/userprog/syscall.c 2004-09-27 14:42:01.000000000 -0700
789 #include "userprog/syscall.h"
792 #include <syscall-nr.h>
793 +#include "threads/init.h"
794 #include "threads/interrupt.h"
795 +#include "threads/malloc.h"
796 +#include "threads/mmu.h"
797 +#include "threads/palloc.h"
798 #include "threads/thread.h"
799 +#include "userprog/pagedir.h"
800 +#include "userprog/process.h"
801 +#include "filesys/filesys.h"
802 +#include "filesys/file.h"
803 +#include "devices/kbd.h"
805 +typedef int syscall_function (int, int, int);
807 +static int sys_halt (void);
808 +static int sys_exit (int status);
809 +static int sys_exec (const char *ufile);
810 +static int sys_join (tid_t);
811 +static int sys_create (const char *ufile, unsigned initial_size);
812 +static int sys_remove (const char *ufile);
813 +static int sys_open (const char *ufile);
814 +static int sys_filesize (int handle);
815 +static int sys_read (int handle, void *udst_, unsigned size);
816 +static int sys_write (int handle, void *usrc_, unsigned size);
817 +static int sys_seek (int handle, unsigned position);
818 +static int sys_tell (int handle);
819 +static int sys_close (int handle);
824 + syscall_function *func;
827 +struct syscall syscall_table[] =
829 + {0, (syscall_function *) sys_halt},
830 + {1, (syscall_function *) sys_exit},
831 + {1, (syscall_function *) sys_exec},
832 + {1, (syscall_function *) sys_join},
833 + {2, (syscall_function *) sys_create},
834 + {1, (syscall_function *) sys_remove},
835 + {1, (syscall_function *) sys_open},
836 + {1, (syscall_function *) sys_filesize},
837 + {3, (syscall_function *) sys_read},
838 + {3, (syscall_function *) sys_write},
839 + {2, (syscall_function *) sys_seek},
840 + {1, (syscall_function *) sys_tell},
841 + {1, (syscall_function *) sys_close},
843 +static const int syscall_cnt = sizeof syscall_table / sizeof *syscall_table;
845 static void syscall_handler (struct intr_frame *);
846 +static void copy_in (void *, const void *, size_t);
848 +static struct lock fs_lock;
853 intr_register (0x30, 3, INTR_ON, syscall_handler, "syscall");
854 + lock_init (&fs_lock, "fs");
858 -syscall_handler (struct intr_frame *f UNUSED)
859 +syscall_handler (struct intr_frame *f)
865 + copy_in (&call_nr, f->esp, sizeof call_nr);
866 + if (call_nr < 0 || call_nr >= syscall_cnt)
868 + printf ("bad syscall number %d\n", call_nr);
872 + s = syscall_table + call_nr;
873 + ASSERT (s->arg_cnt <= sizeof args / sizeof *args);
874 + memset (args, 0, sizeof args);
875 + copy_in (args, (uint32_t *) f->esp + 1, sizeof *args * s->arg_cnt);
876 + f->eax = s->func (args[0], args[1], args[2]);
880 +verify_user (const void *uaddr)
882 + return pagedir_get_page (thread_current ()->pagedir, uaddr) != NULL;
885 +static inline bool get_user (uint8_t *dst, const uint8_t *usrc) {
887 + asm ("movl $1f, %%eax; movb %2, %%al; movb %%al, %0; 1:"
888 + : "=m" (*dst), "=&a" (eax) : "m" (*usrc));
892 +static inline bool put_user (uint8_t *udst, uint8_t byte) {
894 + asm ("movl $1f, %%eax; movb %b2, %0; 1:"
895 + : "=m" (*udst), "=&a" (eax) : "r" (byte));
900 +copy_in (void *dst_, const void *usrc_, size_t size)
902 + uint8_t *dst = dst_;
903 + const uint8_t *usrc = usrc_;
905 + for (; size > 0; size--, dst++, usrc++)
906 + if (usrc >= (uint8_t *) PHYS_BASE || !get_user (dst, usrc))
911 +copy_in_string (const char *us)
916 + ks = palloc_get_page (0);
919 + printf ("copy_in_string: out of memory\n");
923 + for (length = 0; length < PGSIZE; length++)
925 + if (us >= (char *) PHYS_BASE || !get_user (ks + length, us++))
927 + printf ("bad user reference (%p)\n", us + length);
931 + if (ks[length] == '\0')
935 + printf ("copy_in_string: string too long\n");
936 + palloc_free_page (ks);
947 +sys_exit (int ret_code)
949 - printf ("system call!\n");
950 + thread_current ()->ret_code = ret_code;
956 +sys_exec (const char *ufile)
959 + char *kfile = copy_in_string (ufile);
961 + lock_acquire (&fs_lock);
962 + tid = process_execute (kfile);
963 + lock_release (&fs_lock);
965 + palloc_free_page (kfile);
971 +sys_join (tid_t child)
973 + return thread_join (child);
977 +sys_create (const char *ufile, unsigned initial_size)
979 + char *kfile = copy_in_string (ufile);
982 + lock_acquire (&fs_lock);
983 + ok = filesys_create (kfile, initial_size);
984 + lock_release (&fs_lock);
986 + palloc_free_page (kfile);
992 +sys_remove (const char *ufile)
994 + char *kfile = copy_in_string (ufile);
997 + lock_acquire (&fs_lock);
998 + ok = filesys_remove (kfile);
999 + lock_release (&fs_lock);
1001 + palloc_free_page (kfile);
1009 + struct file *file;
1014 +sys_open (const char *ufile)
1016 + char *kfile = copy_in_string (ufile);
1017 + struct fildes *fd;
1020 + fd = malloc (sizeof *fd);
1024 + lock_acquire (&fs_lock);
1025 + fd->file = filesys_open (kfile);
1026 + if (fd->file != NULL)
1028 + struct thread *cur = thread_current ();
1029 + handle = fd->handle = cur->next_handle++;
1030 + list_push_front (&cur->fds, &fd->elem);
1034 + lock_release (&fs_lock);
1037 + palloc_free_page (kfile);
1041 +static struct fildes *
1042 +lookup_fd (int handle)
1044 + struct thread *cur = thread_current ();
1047 + for (e = list_begin (&cur->fds); e != list_end (&cur->fds);
1048 + e = list_next (e))
1050 + struct fildes *fd = list_entry (e, struct fildes, elem);
1051 + if (fd->handle == handle)
1055 + printf ("no handle %d\n", handle);
1060 +sys_filesize (int handle)
1062 + struct fildes *fd = lookup_fd (handle);
1065 + lock_acquire (&fs_lock);
1066 + size = file_length (fd->file);
1067 + lock_release (&fs_lock);
1073 +sys_read (int handle, void *udst_, unsigned size)
1075 + uint8_t *udst = udst_;
1076 + struct fildes *fd;
1077 + int bytes_read = 0;
1079 + if (handle == STDIN_FILENO)
1081 + for (bytes_read = 0; (size_t) bytes_read < size; bytes_read++)
1082 + if (udst >= (uint8_t *) PHYS_BASE || !put_user (udst++, kbd_getc ()))
1084 + return bytes_read;
1087 + lock_acquire (&fs_lock);
1088 + fd = lookup_fd (handle);
1091 + size_t page_left = PGSIZE - pg_ofs (udst);
1092 + size_t read_amt = size < page_left ? size : page_left;
1095 + if (!verify_user (udst))
1097 + lock_release (&fs_lock);
1101 + retval = file_read (fd->file, udst, read_amt);
1104 + if (bytes_read == 0)
1109 + bytes_read += retval;
1110 + if (retval != (off_t) read_amt)
1116 + lock_release (&fs_lock);
1118 + return bytes_read;
1122 +sys_write (int handle, void *usrc_, unsigned size)
1124 + uint8_t *usrc = usrc_;
1125 + struct fildes *fd = NULL;
1126 + int bytes_written = 0;
1128 + lock_acquire (&fs_lock);
1129 + if (handle != STDOUT_FILENO)
1130 + fd = lookup_fd (handle);
1133 + size_t page_left = PGSIZE - pg_ofs (usrc);
1134 + size_t write_amt = size < page_left ? size : page_left;
1137 + if (!verify_user (usrc))
1139 + lock_release (&fs_lock);
1143 + if (handle == STDOUT_FILENO)
1145 + putbuf (usrc, write_amt);
1146 + retval = write_amt;
1149 + retval = file_write (fd->file, usrc, write_amt);
1152 + if (bytes_written == 0)
1153 + bytes_written = -1;
1157 + bytes_written += retval;
1158 + if (retval != (off_t) write_amt)
1164 + lock_release (&fs_lock);
1166 + return bytes_written;
1170 +sys_seek (int handle, unsigned position)
1172 + struct fildes *fd = lookup_fd (handle);
1174 + lock_acquire (&fs_lock);
1175 + file_seek (fd->file, position);
1176 + lock_release (&fs_lock);
1182 +sys_tell (int handle)
1184 + struct fildes *fd = lookup_fd (handle);
1185 + unsigned position;
1187 + lock_acquire (&fs_lock);
1188 + position = file_tell (fd->file);
1189 + lock_release (&fs_lock);
1195 +sys_close (int handle)
1197 + struct fildes *fd = lookup_fd (handle);
1198 + lock_acquire (&fs_lock);
1199 + file_close (fd->file);
1200 + lock_release (&fs_lock);
1201 + list_remove (&fd->elem);
1207 +syscall_exit (void)
1209 + struct thread *cur = thread_current ();
1210 + list_elem *e, *next;
1212 + for (e = list_begin (&cur->fds); e != list_end (&cur->fds); e = next)
1214 + struct fildes *fd = list_entry (e, struct fildes, elem);
1215 + next = list_next (e);
1216 + file_close (fd->file);
1220 diff -urpN pintos.orig/src/userprog/syscall.h pintos/src/userprog/syscall.h
1221 --- pintos.orig/src/userprog/syscall.h 2004-09-05 22:38:45.000000000 -0700
1222 +++ pintos/src/userprog/syscall.h 2004-09-27 13:29:44.000000000 -0700
1224 #define USERPROG_SYSCALL_H
1226 void syscall_init (void);
1227 +void syscall_exit (void);
1229 #endif /* userprog/syscall.h */
1230 diff -urpN pintos.orig/src/vm/pageframe.c pintos/src/vm/pageframe.c
1231 --- pintos.orig/src/vm/pageframe.c 1969-12-31 16:00:00.000000000 -0800
1232 +++ pintos/src/vm/pageframe.c 2004-09-27 13:29:44.000000000 -0700
1234 +#include "vm/pageframe.h"
1235 +#include <stdint.h>
1236 +#include "threads/init.h"
1237 +#include "threads/malloc.h"
1238 +#include "threads/mmu.h"
1239 +#include "threads/palloc.h"
1240 +#include "userprog/process.h"
1242 +static struct page_frame *frames;
1243 +static size_t frame_cnt;
1245 +static struct page_frame *next_frame;
1248 +in_use (const struct page_frame *pf)
1250 + ASSERT ((pf->owner != NULL) == (pf->user_page != NULL));
1251 + return pf->owner != NULL;
1255 +pageframe_init (void)
1259 + frame_cnt = ram_pages;
1260 + frames = calloc (sizeof *frames, frame_cnt);
1261 + if (frames == NULL)
1262 + PANIC ("can't allocate page frames");
1264 + while ((kpage = palloc_get_page (PAL_USER)) != NULL)
1266 + struct page_frame *pf = frames + (vtop (kpage) >> PGBITS);
1267 + pf->kpage = kpage;
1270 + next_frame = frames;
1274 +pageframe_allocate (struct user_page *up)
1276 + struct page_frame *pf;
1279 + ASSERT (up->frame == NULL);
1284 + pf = next_frame++;
1285 + if (next_frame >= frames + frame_cnt)
1286 + next_frame = frames;
1287 + if (loops++ > 2 * frame_cnt)
1290 + while (pf->kpage == NULL
1291 + || (in_use (pf) && !process_evict_page (pf->owner, pf->user_page)));
1293 + ASSERT (!in_use (pf));
1294 + pf->owner = thread_current ();
1295 + pf->user_page = up;
1301 +pageframe_free (struct page_frame *pf)
1303 + ASSERT (in_use (pf));
1306 + pf->user_page->frame = NULL;
1307 + pf->user_page = NULL;
1309 diff -urpN pintos.orig/src/vm/pageframe.h pintos/src/vm/pageframe.h
1310 --- pintos.orig/src/vm/pageframe.h 1969-12-31 16:00:00.000000000 -0800
1311 +++ pintos/src/vm/pageframe.h 2004-09-27 13:29:44.000000000 -0700
1313 +#ifndef VM_PAGEFRAME_H
1314 +#define VM_PAGEFRAME_H 1
1316 +#include <stdbool.h>
1321 + struct thread *owner;
1322 + struct user_page *user_page;
1325 +void pageframe_init (void);
1326 +bool pageframe_allocate (struct user_page *);
1327 +void pageframe_free (struct page_frame *);
1329 +#endif /* vm/pageframe.h */
1330 diff -urpN pintos.orig/src/vm/swap.c pintos/src/vm/swap.c
1331 --- pintos.orig/src/vm/swap.c 1969-12-31 16:00:00.000000000 -0800
1332 +++ pintos/src/vm/swap.c 2004-09-27 13:29:44.000000000 -0700
1334 +#include "vm/swap.h"
1335 +#include <bitmap.h>
1337 +#include "vm/pageframe.h"
1338 +#include "threads/mmu.h"
1339 +#include "filesys/file.h"
1340 +#include "filesys/filesys.h"
1341 +#include "userprog/process.h"
1343 +static size_t swap_pages;
1344 +static struct disk *swap_disk;
1345 +static struct bitmap *used_pages;
1350 + swap_disk = disk_get (1, 1);
1351 + if (swap_disk == NULL)
1352 + PANIC ("no swap disk");
1353 + swap_pages = disk_size (swap_disk) / (PGSIZE / DISK_SECTOR_SIZE);
1354 + printf ("swap disk has room for %zu pages\n", swap_pages);
1356 + used_pages = bitmap_create (swap_pages);
1357 + if (used_pages == NULL)
1358 + PANIC ("couldn't create swap bitmap");
1362 +swap_write (struct user_page *up)
1365 + disk_sector_t sector;
1368 + ASSERT (up->frame != NULL);
1369 + ASSERT (up->file == NULL);
1371 + page = bitmap_scan_and_flip (used_pages, 0, 1, false);
1372 + if (page == BITMAP_ERROR)
1375 + up->swap_page = page;
1376 + sector = (disk_sector_t) page * (PGSIZE / DISK_SECTOR_SIZE);
1377 + for (i = 0; i < PGSIZE / DISK_SECTOR_SIZE; i++)
1378 + disk_write (swap_disk, sector++, up->frame->kpage + i * DISK_SECTOR_SIZE);
1384 +swap_read (struct user_page *up)
1386 + disk_sector_t sector;
1389 + ASSERT (up->frame != NULL);
1391 + ASSERT (bitmap_test (used_pages, up->swap_page));
1392 + bitmap_reset (used_pages, up->swap_page);
1394 + sector = (disk_sector_t) up->swap_page * (PGSIZE / DISK_SECTOR_SIZE);
1395 + for (i = 0; i < PGSIZE / DISK_SECTOR_SIZE; i++)
1396 + disk_read (swap_disk, sector++, up->frame->kpage + i * DISK_SECTOR_SIZE);
1398 + up->swap_page = SIZE_MAX;
1400 diff -urpN pintos.orig/src/vm/swap.h pintos/src/vm/swap.h
1401 --- pintos.orig/src/vm/swap.h 1969-12-31 16:00:00.000000000 -0800
1402 +++ pintos/src/vm/swap.h 2004-09-27 13:29:44.000000000 -0700
1405 +#define VM_SWAP_H 1
1407 +#include <stdbool.h>
1410 +void swap_init (void);
1411 +bool swap_write (struct user_page *);
1412 +void swap_read (struct user_page *);
1414 +#endif /* vm/swap.h */