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 + struct 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 ();
187 + struct list_elem *e;
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 + struct list_elem children_elem; /* Element of `children' list. */
239 + int ret_code; /* Return status. */
241 /* Shared between thread.c and synch.c. */
242 struct 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;
294 + struct hash_elem *e;
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,11 @@ 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 struct hash_elem *, void *);
410 +static bool user_page_less (const struct hash_elem *, const struct hash_elem *,
412 +static struct user_page *make_user_page (void *upage);
414 /* Aborts loading an executable, with an error message. */
415 #define LOAD_ERROR(MSG) \
416 @@ -198,19 +208,35 @@ static bool setup_stack (void **esp);
417 and its initial stack pointer into *ESP.
418 Returns true if successful, false otherwise. */
420 -load (const char *filename, void (**eip) (void), void **esp)
421 +load (const char *cmdline, void (**eip) (void), void **esp)
423 struct thread *t = thread_current ();
424 + char filename[NAME_MAX + 2];
425 struct Elf32_Ehdr ehdr;
426 struct file *file = NULL;
428 bool success = false;
432 + /* Create hash of user pages. */
433 + hash_init (&t->pages, user_page_hash, user_page_less, NULL);
435 /* Allocate page directory. */
436 t->pagedir = pagedir_create ();
437 - if (t->pagedir == NULL)
438 - LOAD_ERROR (("page directory allocation failed"));
439 + if (t->pagedir == NULL)
441 + hash_destroy (&t->pages);
442 + LOAD_ERROR (("page directory allocation failed"));
445 + /* Extract filename from command line. */
446 + while (*cmdline == ' ')
448 + strlcpy (filename, cmdline, sizeof filename);
449 + cp = strchr (filename, ' ');
453 /* Open executable file. */
454 file = filesys_open (filename);
455 @@ -269,8 +295,23 @@ load (const char *filename, void (**eip)
459 - if (!setup_stack (esp))
460 + if (!setup_stack (cmdline, esp))
465 + struct hash_iterator i;
467 + hash_first (&i, &thread_current ()->pages);
468 + while (hash_next (&i))
470 + struct user_page *up = hash_entry (hash_cur (&i),
471 + struct user_page, elem);
472 + printf ("%08x ", up->upage);
479 *eip = (void (*) (void)) ehdr.e_entry;
480 @@ -279,14 +320,12 @@ load (const char *filename, void (**eip)
483 /* We arrive here whether the load is successful or not. */
485 + //file_close (file); // FIXME
489 /* load() helpers. */
491 -static bool install_page (void *upage, void *kpage);
493 /* Loads the segment described by PHDR from FILE into user
494 address space. Return true if successful, false otherwise. */
496 @@ -296,6 +335,7 @@ load_segment (struct file *file, const s
497 uint8_t *upage; /* Iterator from start to end. */
498 off_t filesz_left; /* Bytes left of file data (as opposed to
499 zero-initialized bytes). */
502 /* Is this a read-only segment? Not currently used, so it's
503 commented out. You'll want to use it when implementing VM
504 @@ -340,70 +380,207 @@ load_segment (struct file *file, const s
506 /* Load the segment page-by-page into memory. */
507 filesz_left = phdr->p_filesz + (phdr->p_vaddr & PGMASK);
508 - file_seek (file, ROUND_DOWN (phdr->p_offset, PGSIZE));
509 + file_ofs = ROUND_DOWN (phdr->p_offset, PGSIZE);
510 for (upage = start; upage < (uint8_t *) end; upage += PGSIZE)
512 /* We want to read min(PGSIZE, filesz_left) bytes from the
513 file into the page and zero the rest. */
514 size_t read_bytes = filesz_left >= PGSIZE ? PGSIZE : filesz_left;
515 - size_t zero_bytes = PGSIZE - read_bytes;
516 - uint8_t *kpage = palloc_get_page (PAL_USER);
518 + struct user_page *up = make_user_page (upage);
522 - /* Do the reading and zeroing. */
523 - if (file_read (file, kpage, read_bytes) != (int) read_bytes)
524 + if (read_bytes > 0)
526 - palloc_free_page (kpage);
530 + up->file_ofs = file_ofs;
531 + up->file_size = read_bytes;
532 + file_ofs += read_bytes;
534 - memset (kpage + read_bytes, 0, zero_bytes);
535 - filesz_left -= read_bytes;
537 - /* Add the page to the process's address space. */
538 - if (!install_page (upage, kpage))
541 - palloc_free_page (kpage);
543 + /* Page is all zeros. Nothing to do. */
545 + filesz_left -= read_bytes;
552 +reverse (int argc, char **argv)
554 + for (; argc > 1; argc -= 2, argv++)
556 + char *tmp = argv[0];
557 + argv[0] = argv[argc - 1];
558 + argv[argc - 1] = tmp;
562 +push (uint8_t *kpage, size_t *ofs, const void *buf, size_t size)
564 + size_t padsize = ROUND_UP (size, sizeof (uint32_t));
565 + if (*ofs < padsize)
569 + memcpy (kpage + *ofs + (padsize - size), buf, size);
570 + return kpage + *ofs + (padsize - size);
574 +init_cmdline (uint8_t *kpage, uint8_t *upage, const char *cmdline,
577 + size_t ofs = PGSIZE;
578 + char *const null = NULL;
579 + char *cmdline_copy;
580 + char *karg, *saveptr;
584 + /* Push command line string. */
585 + cmdline_copy = push (kpage, &ofs, cmdline, strlen (cmdline) + 1);
586 + if (cmdline_copy == NULL)
589 + if (push (kpage, &ofs, &null, sizeof null) == NULL)
592 + /* Parse command line into arguments
593 + and push them in reverse order. */
595 + for (karg = strtok_r (cmdline_copy, " ", &saveptr); karg != NULL;
596 + karg = strtok_r (NULL, " ", &saveptr))
598 + char *uarg = upage + (karg - (char *) kpage);
599 + if (push (kpage, &ofs, &uarg, sizeof uarg) == NULL)
604 + /* Reverse the order of the command line arguments. */
605 + argv = (char **) (upage + ofs);
606 + reverse (argc, (char **) (kpage + ofs));
608 + /* Push argv, argc, "return address". */
609 + if (push (kpage, &ofs, &argv, sizeof argv) == NULL
610 + || push (kpage, &ofs, &argc, sizeof argc) == NULL
611 + || push (kpage, &ofs, &null, sizeof null) == NULL)
614 + /* Set initial stack pointer. */
615 + *esp = upage + ofs;
620 -/* Create a minimal stack by mapping a zeroed page at the top of
621 - user virtual memory. */
622 +/* Create a minimal stack for T by mapping a page at the
623 + top of user virtual memory. Fills in the page using CMDLINE
624 + and sets *ESP to the stack pointer. */
626 -setup_stack (void **esp)
627 +setup_stack (const char *cmdline, void **esp)
630 - bool success = false;
631 + struct user_page *up = make_user_page ((uint8_t *) PHYS_BASE - PGSIZE);
633 + && pageframe_allocate (up)
634 + && init_cmdline (up->frame->kpage, up->upage, cmdline, esp));
638 +user_page_hash (const struct hash_elem *e, void *aux UNUSED)
640 + struct user_page *up = hash_entry (e, struct user_page, elem);
641 + return hash_bytes (&up->upage, sizeof up->upage);
644 - kpage = palloc_get_page (PAL_USER | PAL_ZERO);
647 +user_page_less (const struct hash_elem *a_,
648 + const struct hash_elem *b_, void *aux UNUSED)
650 + struct user_page *a = hash_entry (a_, struct user_page, elem);
651 + struct user_page *b = hash_entry (b_, struct user_page, elem);
653 + return a->upage < b->upage;
656 +static struct user_page *
657 +make_user_page (void *upage)
659 + struct user_page *up;
661 + up = malloc (sizeof *up);
664 - success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage);
667 + memset (up, 0, sizeof *up);
668 + up->swap_page = SIZE_MAX;
671 + if (hash_insert (&thread_current ()->pages, &up->elem) != NULL)
678 - palloc_free_page (kpage);
679 + printf ("make_user_page(%p) okay\n", upage);
683 - printf ("failed to allocate process stack\n");
689 -/* Adds a mapping from user virtual address UPAGE to kernel
690 - virtual address KPAGE to the page table. Fails if UPAGE is
691 - already mapped or if memory allocation fails. */
693 -install_page (void *upage, void *kpage)
695 +dump_page (struct user_page *up)
697 - struct thread *t = thread_current ();
700 - /* Verify that there's not already a page at that virtual
701 - address, then map our page there. */
702 - return (pagedir_get_page (t->pagedir, upage) == NULL
703 - && pagedir_set_page (t->pagedir, upage, kpage, true));
704 + ASSERT (up->file != NULL);
705 + up->file_size = PGSIZE;
706 + amt = file_write_at (up->file, up->frame->kpage,
707 + up->file_size, up->file_ofs);
708 + ASSERT (amt == (off_t) up->file_size);
712 +process_evict_page (struct thread *t, struct user_page *up)
714 + ASSERT (up->frame != NULL);
716 + if (pagedir_test_accessed (t->pagedir, up->upage))
718 + pagedir_clear_accessed (t->pagedir, up->upage);
722 + if (up->file == NULL)
724 + if (!swap_write (up))
727 + else if (pagedir_test_dirty (t->pagedir, up->upage))
729 + /* Need to write out. */
732 + up->file = NULL; // FIXME
733 + up->private = false;
734 + if (!swap_write (up))
742 + /* Already on disk, not dirty.
746 + pagedir_clear_page (t->pagedir, up->upage);
747 + pageframe_free (up->frame);
751 diff -urpN pintos.orig/src/userprog/process.h pintos/src/userprog/process.h
752 --- pintos.orig/src/userprog/process.h 2004-09-21 22:42:17.000000000 -0700
753 +++ pintos/src/userprog/process.h 2004-09-27 14:43:13.000000000 -0700
755 #define USERPROG_PROCESS_H
757 #include "threads/thread.h"
758 +#include "filesys/off_t.h"
762 + struct hash_elem elem;
763 + void *upage; /* Virtual address of mapping. */
765 + /* If FRAME is nonnull, the page is in memory.
766 + If FILE is nonnull, the page is on disk.
767 + If both are null, the page is all zeroes.
768 + If both are nonnull, the page is in memory and backed by a
769 + file mapping (not the swap file). */
770 + struct page_frame *frame;
774 + size_t file_size; /* Number of bytes on disk, <= PGSIZE. */
778 + bool private : 1; /* Write dirty pages to swap or to FILE? */
781 tid_t process_execute (const char *filename);
782 void process_exit (void);
783 void process_activate (void);
784 +bool process_evict_page (struct thread *, struct user_page *);
786 #endif /* userprog/process.h */
787 diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
788 --- pintos.orig/src/userprog/syscall.c 2004-09-26 14:15:17.000000000 -0700
789 +++ pintos/src/userprog/syscall.c 2004-09-27 14:42:01.000000000 -0700
791 #include "userprog/syscall.h"
794 #include <syscall-nr.h>
795 +#include "threads/init.h"
796 #include "threads/interrupt.h"
797 +#include "threads/malloc.h"
798 +#include "threads/mmu.h"
799 +#include "threads/palloc.h"
800 #include "threads/thread.h"
801 +#include "userprog/pagedir.h"
802 +#include "userprog/process.h"
803 +#include "filesys/filesys.h"
804 +#include "filesys/file.h"
805 +#include "devices/kbd.h"
807 +typedef int syscall_function (int, int, int);
809 +static int sys_halt (void);
810 +static int sys_exit (int status);
811 +static int sys_exec (const char *ufile);
812 +static int sys_join (tid_t);
813 +static int sys_create (const char *ufile, unsigned initial_size);
814 +static int sys_remove (const char *ufile);
815 +static int sys_open (const char *ufile);
816 +static int sys_filesize (int handle);
817 +static int sys_read (int handle, void *udst_, unsigned size);
818 +static int sys_write (int handle, void *usrc_, unsigned size);
819 +static int sys_seek (int handle, unsigned position);
820 +static int sys_tell (int handle);
821 +static int sys_close (int handle);
826 + syscall_function *func;
829 +struct syscall syscall_table[] =
831 + {0, (syscall_function *) sys_halt},
832 + {1, (syscall_function *) sys_exit},
833 + {1, (syscall_function *) sys_exec},
834 + {1, (syscall_function *) sys_join},
835 + {2, (syscall_function *) sys_create},
836 + {1, (syscall_function *) sys_remove},
837 + {1, (syscall_function *) sys_open},
838 + {1, (syscall_function *) sys_filesize},
839 + {3, (syscall_function *) sys_read},
840 + {3, (syscall_function *) sys_write},
841 + {2, (syscall_function *) sys_seek},
842 + {1, (syscall_function *) sys_tell},
843 + {1, (syscall_function *) sys_close},
845 +static const int syscall_cnt = sizeof syscall_table / sizeof *syscall_table;
847 static void syscall_handler (struct intr_frame *);
848 +static void copy_in (void *, const void *, size_t);
850 +static struct lock fs_lock;
855 intr_register (0x30, 3, INTR_ON, syscall_handler, "syscall");
856 + lock_init (&fs_lock, "fs");
860 -syscall_handler (struct intr_frame *f UNUSED)
861 +syscall_handler (struct intr_frame *f)
867 + copy_in (&call_nr, f->esp, sizeof call_nr);
868 + if (call_nr < 0 || call_nr >= syscall_cnt)
870 + printf ("bad syscall number %d\n", call_nr);
874 + s = syscall_table + call_nr;
875 + ASSERT (s->arg_cnt <= sizeof args / sizeof *args);
876 + memset (args, 0, sizeof args);
877 + copy_in (args, (uint32_t *) f->esp + 1, sizeof *args * s->arg_cnt);
878 + f->eax = s->func (args[0], args[1], args[2]);
882 +verify_user (const void *uaddr)
884 + return pagedir_get_page (thread_current ()->pagedir, uaddr) != NULL;
887 +static inline bool get_user (uint8_t *dst, const uint8_t *usrc) {
889 + asm ("movl $1f, %%eax; movb %2, %%al; movb %%al, %0; 1:"
890 + : "=m" (*dst), "=&a" (eax) : "m" (*usrc));
894 +static inline bool put_user (uint8_t *udst, uint8_t byte) {
896 + asm ("movl $1f, %%eax; movb %b2, %0; 1:"
897 + : "=m" (*udst), "=&a" (eax) : "r" (byte));
902 +copy_in (void *dst_, const void *usrc_, size_t size)
904 + uint8_t *dst = dst_;
905 + const uint8_t *usrc = usrc_;
907 + for (; size > 0; size--, dst++, usrc++)
908 + if (usrc >= (uint8_t *) PHYS_BASE || !get_user (dst, usrc))
913 +copy_in_string (const char *us)
918 + ks = palloc_get_page (0);
921 + printf ("copy_in_string: out of memory\n");
925 + for (length = 0; length < PGSIZE; length++)
927 + if (us >= (char *) PHYS_BASE || !get_user (ks + length, us++))
929 + printf ("bad user reference (%p)\n", us + length);
933 + if (ks[length] == '\0')
937 + printf ("copy_in_string: string too long\n");
938 + palloc_free_page (ks);
949 +sys_exit (int ret_code)
951 - printf ("system call!\n");
952 + thread_current ()->ret_code = ret_code;
958 +sys_exec (const char *ufile)
961 + char *kfile = copy_in_string (ufile);
963 + lock_acquire (&fs_lock);
964 + tid = process_execute (kfile);
965 + lock_release (&fs_lock);
967 + palloc_free_page (kfile);
973 +sys_join (tid_t child)
975 + return thread_join (child);
979 +sys_create (const char *ufile, unsigned initial_size)
981 + char *kfile = copy_in_string (ufile);
984 + lock_acquire (&fs_lock);
985 + ok = filesys_create (kfile, initial_size);
986 + lock_release (&fs_lock);
988 + palloc_free_page (kfile);
994 +sys_remove (const char *ufile)
996 + char *kfile = copy_in_string (ufile);
999 + lock_acquire (&fs_lock);
1000 + ok = filesys_remove (kfile);
1001 + lock_release (&fs_lock);
1003 + palloc_free_page (kfile);
1010 + struct list_elem elem;
1011 + struct file *file;
1016 +sys_open (const char *ufile)
1018 + char *kfile = copy_in_string (ufile);
1019 + struct fildes *fd;
1022 + fd = malloc (sizeof *fd);
1026 + lock_acquire (&fs_lock);
1027 + fd->file = filesys_open (kfile);
1028 + if (fd->file != NULL)
1030 + struct thread *cur = thread_current ();
1031 + handle = fd->handle = cur->next_handle++;
1032 + list_push_front (&cur->fds, &fd->elem);
1036 + lock_release (&fs_lock);
1039 + palloc_free_page (kfile);
1043 +static struct fildes *
1044 +lookup_fd (int handle)
1046 + struct thread *cur = thread_current ();
1047 + struct list_elem *e;
1049 + for (e = list_begin (&cur->fds); e != list_end (&cur->fds);
1050 + e = list_next (e))
1052 + struct fildes *fd = list_entry (e, struct fildes, elem);
1053 + if (fd->handle == handle)
1057 + printf ("no handle %d\n", handle);
1062 +sys_filesize (int handle)
1064 + struct fildes *fd = lookup_fd (handle);
1067 + lock_acquire (&fs_lock);
1068 + size = file_length (fd->file);
1069 + lock_release (&fs_lock);
1075 +sys_read (int handle, void *udst_, unsigned size)
1077 + uint8_t *udst = udst_;
1078 + struct fildes *fd;
1079 + int bytes_read = 0;
1081 + if (handle == STDIN_FILENO)
1083 + for (bytes_read = 0; (size_t) bytes_read < size; bytes_read++)
1084 + if (udst >= (uint8_t *) PHYS_BASE || !put_user (udst++, kbd_getc ()))
1086 + return bytes_read;
1089 + lock_acquire (&fs_lock);
1090 + fd = lookup_fd (handle);
1093 + size_t page_left = PGSIZE - pg_ofs (udst);
1094 + size_t read_amt = size < page_left ? size : page_left;
1097 + if (!verify_user (udst))
1099 + lock_release (&fs_lock);
1103 + retval = file_read (fd->file, udst, read_amt);
1106 + if (bytes_read == 0)
1111 + bytes_read += retval;
1112 + if (retval != (off_t) read_amt)
1118 + lock_release (&fs_lock);
1120 + return bytes_read;
1124 +sys_write (int handle, void *usrc_, unsigned size)
1126 + uint8_t *usrc = usrc_;
1127 + struct fildes *fd = NULL;
1128 + int bytes_written = 0;
1130 + lock_acquire (&fs_lock);
1131 + if (handle != STDOUT_FILENO)
1132 + fd = lookup_fd (handle);
1135 + size_t page_left = PGSIZE - pg_ofs (usrc);
1136 + size_t write_amt = size < page_left ? size : page_left;
1139 + if (!verify_user (usrc))
1141 + lock_release (&fs_lock);
1145 + if (handle == STDOUT_FILENO)
1147 + putbuf (usrc, write_amt);
1148 + retval = write_amt;
1151 + retval = file_write (fd->file, usrc, write_amt);
1154 + if (bytes_written == 0)
1155 + bytes_written = -1;
1159 + bytes_written += retval;
1160 + if (retval != (off_t) write_amt)
1166 + lock_release (&fs_lock);
1168 + return bytes_written;
1172 +sys_seek (int handle, unsigned position)
1174 + struct fildes *fd = lookup_fd (handle);
1176 + lock_acquire (&fs_lock);
1177 + file_seek (fd->file, position);
1178 + lock_release (&fs_lock);
1184 +sys_tell (int handle)
1186 + struct fildes *fd = lookup_fd (handle);
1187 + unsigned position;
1189 + lock_acquire (&fs_lock);
1190 + position = file_tell (fd->file);
1191 + lock_release (&fs_lock);
1197 +sys_close (int handle)
1199 + struct fildes *fd = lookup_fd (handle);
1200 + lock_acquire (&fs_lock);
1201 + file_close (fd->file);
1202 + lock_release (&fs_lock);
1203 + list_remove (&fd->elem);
1209 +syscall_exit (void)
1211 + struct thread *cur = thread_current ();
1212 + struct list_elem *e, *next;
1214 + for (e = list_begin (&cur->fds); e != list_end (&cur->fds); e = next)
1216 + struct fildes *fd = list_entry (e, struct fildes, elem);
1217 + next = list_next (e);
1218 + file_close (fd->file);
1222 diff -urpN pintos.orig/src/userprog/syscall.h pintos/src/userprog/syscall.h
1223 --- pintos.orig/src/userprog/syscall.h 2004-09-05 22:38:45.000000000 -0700
1224 +++ pintos/src/userprog/syscall.h 2004-09-27 13:29:44.000000000 -0700
1226 #define USERPROG_SYSCALL_H
1228 void syscall_init (void);
1229 +void syscall_exit (void);
1231 #endif /* userprog/syscall.h */
1232 diff -urpN pintos.orig/src/vm/pageframe.c pintos/src/vm/pageframe.c
1233 --- pintos.orig/src/vm/pageframe.c 1969-12-31 16:00:00.000000000 -0800
1234 +++ pintos/src/vm/pageframe.c 2004-09-27 13:29:44.000000000 -0700
1236 +#include "vm/pageframe.h"
1237 +#include <stdint.h>
1238 +#include "threads/init.h"
1239 +#include "threads/malloc.h"
1240 +#include "threads/mmu.h"
1241 +#include "threads/palloc.h"
1242 +#include "userprog/process.h"
1244 +static struct page_frame *frames;
1245 +static size_t frame_cnt;
1247 +static struct page_frame *next_frame;
1250 +in_use (const struct page_frame *pf)
1252 + ASSERT ((pf->owner != NULL) == (pf->user_page != NULL));
1253 + return pf->owner != NULL;
1257 +pageframe_init (void)
1261 + frame_cnt = ram_pages;
1262 + frames = calloc (sizeof *frames, frame_cnt);
1263 + if (frames == NULL)
1264 + PANIC ("can't allocate page frames");
1266 + while ((kpage = palloc_get_page (PAL_USER)) != NULL)
1268 + struct page_frame *pf = frames + (vtop (kpage) >> PGBITS);
1269 + pf->kpage = kpage;
1272 + next_frame = frames;
1276 +pageframe_allocate (struct user_page *up)
1278 + struct page_frame *pf;
1281 + ASSERT (up->frame == NULL);
1286 + pf = next_frame++;
1287 + if (next_frame >= frames + frame_cnt)
1288 + next_frame = frames;
1289 + if (loops++ > 2 * frame_cnt)
1292 + while (pf->kpage == NULL
1293 + || (in_use (pf) && !process_evict_page (pf->owner, pf->user_page)));
1295 + ASSERT (!in_use (pf));
1296 + pf->owner = thread_current ();
1297 + pf->user_page = up;
1303 +pageframe_free (struct page_frame *pf)
1305 + ASSERT (in_use (pf));
1308 + pf->user_page->frame = NULL;
1309 + pf->user_page = NULL;
1311 diff -urpN pintos.orig/src/vm/pageframe.h pintos/src/vm/pageframe.h
1312 --- pintos.orig/src/vm/pageframe.h 1969-12-31 16:00:00.000000000 -0800
1313 +++ pintos/src/vm/pageframe.h 2004-09-27 13:29:44.000000000 -0700
1315 +#ifndef VM_PAGEFRAME_H
1316 +#define VM_PAGEFRAME_H 1
1318 +#include <stdbool.h>
1323 + struct thread *owner;
1324 + struct user_page *user_page;
1327 +void pageframe_init (void);
1328 +bool pageframe_allocate (struct user_page *);
1329 +void pageframe_free (struct page_frame *);
1331 +#endif /* vm/pageframe.h */
1332 diff -urpN pintos.orig/src/vm/swap.c pintos/src/vm/swap.c
1333 --- pintos.orig/src/vm/swap.c 1969-12-31 16:00:00.000000000 -0800
1334 +++ pintos/src/vm/swap.c 2004-09-27 13:29:44.000000000 -0700
1336 +#include "vm/swap.h"
1337 +#include <bitmap.h>
1339 +#include "vm/pageframe.h"
1340 +#include "threads/mmu.h"
1341 +#include "filesys/file.h"
1342 +#include "filesys/filesys.h"
1343 +#include "userprog/process.h"
1345 +static size_t swap_pages;
1346 +static struct disk *swap_disk;
1347 +static struct bitmap *used_pages;
1352 + swap_disk = disk_get (1, 1);
1353 + if (swap_disk == NULL)
1354 + PANIC ("no swap disk");
1355 + swap_pages = disk_size (swap_disk) / (PGSIZE / DISK_SECTOR_SIZE);
1356 + printf ("swap disk has room for %zu pages\n", swap_pages);
1358 + used_pages = bitmap_create (swap_pages);
1359 + if (used_pages == NULL)
1360 + PANIC ("couldn't create swap bitmap");
1364 +swap_write (struct user_page *up)
1367 + disk_sector_t sector;
1370 + ASSERT (up->frame != NULL);
1371 + ASSERT (up->file == NULL);
1373 + page = bitmap_scan_and_flip (used_pages, 0, 1, false);
1374 + if (page == BITMAP_ERROR)
1377 + up->swap_page = page;
1378 + sector = (disk_sector_t) page * (PGSIZE / DISK_SECTOR_SIZE);
1379 + for (i = 0; i < PGSIZE / DISK_SECTOR_SIZE; i++)
1380 + disk_write (swap_disk, sector++, up->frame->kpage + i * DISK_SECTOR_SIZE);
1386 +swap_read (struct user_page *up)
1388 + disk_sector_t sector;
1391 + ASSERT (up->frame != NULL);
1393 + ASSERT (bitmap_test (used_pages, up->swap_page));
1394 + bitmap_reset (used_pages, up->swap_page);
1396 + sector = (disk_sector_t) up->swap_page * (PGSIZE / DISK_SECTOR_SIZE);
1397 + for (i = 0; i < PGSIZE / DISK_SECTOR_SIZE; i++)
1398 + disk_read (swap_disk, sector++, up->frame->kpage + i * DISK_SECTOR_SIZE);
1400 + up->swap_page = SIZE_MAX;
1402 diff -urpN pintos.orig/src/vm/swap.h pintos/src/vm/swap.h
1403 --- pintos.orig/src/vm/swap.h 1969-12-31 16:00:00.000000000 -0800
1404 +++ pintos/src/vm/swap.h 2004-09-27 13:29:44.000000000 -0700
1407 +#define VM_SWAP_H 1
1409 +#include <stdbool.h>
1412 +void swap_init (void);
1413 +bool swap_write (struct user_page *);
1414 +void swap_read (struct user_page *);
1416 +#endif /* vm/swap.h */