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/constants.h pintos/src/constants.h
17 --- pintos.orig/src/constants.h 2004-09-21 17:26:39.000000000 -0700
18 +++ pintos/src/constants.h 2004-09-27 13:29:43.000000000 -0700
20 /*#define MACRONAME 1 */
22 /* Uncomment if if you've implemented thread_join(). */
23 -/*#define THREAD_JOIN_IMPLEMENTED 1*/
24 +#define THREAD_JOIN_IMPLEMENTED 1
25 diff -urpN pintos.orig/src/threads/init.c pintos/src/threads/init.c
26 --- pintos.orig/src/threads/init.c 2004-09-26 14:15:17.000000000 -0700
27 +++ pintos/src/threads/init.c 2004-09-27 16:08:03.000000000 -0700
29 #include "threads/test.h"
30 #include "threads/thread.h"
32 +#include "userprog/pagedir.h"
33 #include "userprog/process.h"
34 #include "userprog/exception.h"
35 #include "userprog/gdt.h"
36 #include "userprog/syscall.h"
37 #include "userprog/tss.h"
39 +#include "vm/pageframe.h"
42 #include "devices/disk.h"
43 #include "filesys/filesys.h"
44 @@ -78,6 +81,7 @@ main (void)
45 /* Initialize memory system, segments, paging. */
52 @@ -105,6 +109,7 @@ main (void)
54 filesys_init (format_filesys);
59 printf ("Boot complete.\n");
60 diff -urpN pintos.orig/src/threads/palloc.c pintos/src/threads/palloc.c
61 diff -urpN pintos.orig/src/threads/palloc.h pintos/src/threads/palloc.h
62 diff -urpN pintos.orig/src/threads/synch.c pintos/src/threads/synch.c
63 --- pintos.orig/src/threads/synch.c 2004-09-19 21:29:53.000000000 -0700
64 +++ pintos/src/threads/synch.c 2004-09-27 13:29:43.000000000 -0700
65 @@ -330,3 +330,35 @@ cond_name (const struct condition *cond)
71 +latch_init (struct latch *latch, const char *name)
73 + latch->released = false;
74 + lock_init (&latch->monitor_lock, name);
75 + cond_init (&latch->rel_cond, name);
79 +latch_acquire (struct latch *latch)
81 + lock_acquire (&latch->monitor_lock);
82 + if (!latch->released)
84 + cond_wait (&latch->rel_cond, &latch->monitor_lock);
85 + ASSERT (latch->released);
87 + lock_release (&latch->monitor_lock);
91 +latch_release (struct latch *latch)
93 + lock_acquire (&latch->monitor_lock);
94 + if (!latch->released)
96 + latch->released = true;
97 + cond_signal (&latch->rel_cond, &latch->monitor_lock);
99 + lock_release (&latch->monitor_lock);
101 diff -urpN pintos.orig/src/threads/synch.h pintos/src/threads/synch.h
102 --- pintos.orig/src/threads/synch.h 2004-09-19 21:29:53.000000000 -0700
103 +++ pintos/src/threads/synch.h 2004-09-27 13:29:43.000000000 -0700
104 @@ -44,4 +44,16 @@ void cond_signal (struct condition *, st
105 void cond_broadcast (struct condition *, struct lock *);
106 const char *cond_name (const struct condition *);
111 + bool released; /* Released yet? */
112 + struct lock monitor_lock; /* Monitor lock. */
113 + struct condition rel_cond; /* Signaled when released. */
116 +void latch_init (struct latch *, const char *);
117 +void latch_acquire (struct latch *);
118 +void latch_release (struct latch *);
120 #endif /* threads/synch.h */
121 diff -urpN pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
122 --- pintos.orig/src/threads/thread.c 2004-09-26 14:15:17.000000000 -0700
123 +++ pintos/src/threads/thread.c 2004-09-27 13:29:43.000000000 -0700
125 #include "threads/synch.h"
127 #include "userprog/process.h"
128 +#include "userprog/syscall.h"
131 /* Random value for struct thread's `magic' member.
132 @@ -80,6 +81,7 @@ thread_init (void)
133 init_thread (initial_thread, "main", PRI_DEFAULT);
134 initial_thread->status = THREAD_RUNNING;
135 initial_thread->tid = allocate_tid ();
136 + sema_up (&initial_thread->can_die);
139 /* Starts preemptive thread scheduling by enabling interrupts.
140 @@ -148,6 +150,7 @@ thread_create (const char *name, int pri
141 /* Initialize thread. */
142 init_thread (t, name, priority);
143 tid = t->tid = allocate_tid ();
144 + list_push_back (&thread_current ()->children, &t->children_elem);
146 /* Stack frame for kernel_thread(). */
147 kf = alloc_frame (t, sizeof *kf);
148 @@ -224,16 +227,36 @@ thread_tid (void)
152 + struct thread *t = thread_current ();
153 + list_elem *e, *next;
155 ASSERT (!intr_context ());
162 + /* Notify our parent that we're dying. */
163 + latch_release (&t->ready_to_die);
165 + /* Notify our children that they can die. */
166 + for (e = list_begin (&t->children); e != list_end (&t->children);
169 + struct thread *child = list_entry (e, struct thread, children_elem);
170 + next = list_next (e);
172 + sema_up (&child->can_die);
175 + /* Wait until our parent is ready for us to die. */
176 + sema_down (&t->can_die);
178 /* Just set our status to dying and schedule another process.
179 We will be destroyed during the call to schedule_tail(). */
181 - thread_current ()->status = THREAD_DYING;
182 + t->status = THREAD_DYING;
186 @@ -270,6 +293,26 @@ thread_block (void)
187 thread_current ()->status = THREAD_BLOCKED;
191 +/* Waits for thread with tid CHILD_TID to die. */
193 +thread_join (tid_t child_tid)
195 + struct thread *cur = thread_current ();
198 + for (e = list_begin (&cur->children); e != list_end (&cur->children); )
200 + struct thread *child = list_entry (e, struct thread, children_elem);
202 + if (child->tid == child_tid)
204 + latch_acquire (&child->ready_to_die);
205 + return child->ret_code;
211 /* Idle thread. Executes when no other thread is ready to run. */
213 @@ -335,6 +378,12 @@ init_thread (struct thread *t, const cha
214 strlcpy (t->name, name, sizeof t->name);
215 t->stack = (uint8_t *) t + PGSIZE;
216 t->priority = priority;
217 + latch_init (&t->ready_to_die, "ready-to-die");
218 + sema_init (&t->can_die, 0, "can-die");
219 + list_init (&t->children);
221 + list_init (&t->fds);
222 + t->next_handle = 2;
223 t->magic = THREAD_MAGIC;
226 diff -urpN pintos.orig/src/threads/thread.h pintos/src/threads/thread.h
227 --- pintos.orig/src/threads/thread.h 2004-09-26 14:15:17.000000000 -0700
228 +++ pintos/src/threads/thread.h 2004-09-27 13:29:43.000000000 -0700
230 #define THREADS_THREAD_H
236 +#include "threads/synch.h"
238 /* States in a thread's life cycle. */
240 @@ -89,12 +91,24 @@ struct thread
241 uint8_t *stack; /* Saved stack pointer. */
242 int priority; /* Priority. */
244 + /* Members for implementing thread_join(). */
245 + struct latch ready_to_die; /* Release when thread about to die. */
246 + struct semaphore can_die; /* Up when thread allowed to die. */
247 + struct list children; /* List of child threads. */
248 + list_elem children_elem; /* Element of `children' list. */
249 + int ret_code; /* Return status. */
251 /* Shared between thread.c and synch.c. */
252 list_elem elem; /* List element. */
255 /* Owned by userprog/process.c. */
256 uint32_t *pagedir; /* Page directory. */
257 + struct hash pages; /* Hash of `struct user_page's. */
259 + /* Owned by syscall.c. */
260 + struct list fds; /* List of file descriptors. */
261 + int next_handle; /* Next handle value. */
264 /* Owned by thread.c */
265 @@ -119,7 +133,7 @@ void thread_yield (void);
266 void thread_block (void);
268 /* This function will be implemented in problem 1-2. */
269 -void thread_join (tid_t);
270 +int thread_join (tid_t);
272 /* These functions will be implemented in problem 1-3. */
273 void thread_set_priority (int);
274 diff -urpN pintos.orig/src/userprog/exception.c pintos/src/userprog/exception.c
275 --- pintos.orig/src/userprog/exception.c 2004-09-26 14:15:17.000000000 -0700
276 +++ pintos/src/userprog/exception.c 2004-09-27 13:29:44.000000000 -0700
278 #include "userprog/exception.h"
279 #include <inttypes.h>
282 #include "userprog/gdt.h"
283 +#include "userprog/pagedir.h"
284 +#include "userprog/process.h"
285 +#include "filesys/file.h"
286 #include "threads/interrupt.h"
287 +#include "threads/mmu.h"
288 #include "threads/thread.h"
289 +#include "vm/pageframe.h"
290 +#include "vm/swap.h"
292 /* Number of page faults processed. */
293 static long long page_fault_cnt;
294 @@ -124,10 +131,13 @@ kill (struct intr_frame *f)
296 page_fault (struct intr_frame *f)
299 bool not_present; /* True: not-present page, false: writing r/o page. */
300 bool write; /* True: access was write, false: access was read. */
301 bool user; /* True: access by user, false: access by kernel. */
302 void *fault_addr; /* Fault address. */
303 + struct user_page tmp_up, *up;
306 /* Obtain faulting address, the virtual address that was
307 accessed to cause the fault. It may point to code or to
308 @@ -147,14 +157,62 @@ page_fault (struct intr_frame *f)
309 write = (f->error_code & PF_W) != 0;
310 user = (f->error_code & PF_U) != 0;
312 - /* To implement virtual memory, delete the rest of the function
313 - body, and replace it with code that brings in the page to
314 - which fault_addr refers. */
315 - printf ("Page fault at %p: %s error %s page in %s context.\n",
317 - not_present ? "not present" : "rights violation",
318 - write ? "writing" : "reading",
319 - user ? "user" : "kernel");
324 + t = thread_current ();
325 + if (t->pagedir == NULL)
328 + //printf ("fault %p (page=%p)\n", fault_addr, pg_round_down (fault_addr));
329 + tmp_up.upage = pg_round_down (fault_addr);
330 + e = hash_find (&t->pages, &tmp_up.elem);
333 + printf ("no user_page for %p\n", fault_addr);
336 + up = hash_entry (e, struct user_page, elem);
338 + if (up->frame == NULL)
340 + if (!pageframe_allocate (up))
342 + printf ("virtual memory exhausted, killing process\n");
347 + if (up->file != NULL)
349 + off_t amt = file_read_at (up->file,
350 + up->frame->kpage, up->file_size,
352 + ASSERT (amt == (off_t) up->file_size);
353 + memset (up->frame->kpage + up->file_size, 0, PGSIZE - up->file_size);
355 + else if (up->swap_page != SIZE_MAX)
358 + memset (up->frame->kpage, 0, PGSIZE);
360 + pagedir_set_page (t->pagedir, up->upage, up->frame->kpage, true);
364 + if (user || fault_addr > PHYS_BASE)
366 + printf ("Page fault at %p: %s error %s page in %s context.\n",
368 + not_present ? "not present" : "rights violation",
369 + write ? "writing" : "reading",
370 + user ? "user" : "kernel");
375 + f->eip = (void (*) (void)) f->eax;
380 diff -urpN pintos.orig/src/userprog/process.c pintos/src/userprog/process.c
381 --- pintos.orig/src/userprog/process.c 2004-09-22 17:58:29.000000000 -0700
382 +++ pintos/src/userprog/process.c 2004-09-27 14:43:09.000000000 -0700
384 #include "userprog/gdt.h"
385 #include "userprog/pagedir.h"
386 #include "userprog/tss.h"
387 +#include "vm/pageframe.h"
388 #include "filesys/directory.h"
389 #include "filesys/file.h"
390 #include "filesys/filesys.h"
391 #include "threads/flags.h"
392 #include "threads/init.h"
393 #include "threads/interrupt.h"
394 +#include "threads/malloc.h"
395 #include "threads/mmu.h"
396 #include "threads/palloc.h"
397 #include "threads/thread.h"
398 +#include "vm/swap.h"
400 static thread_func execute_thread NO_RETURN;
401 static bool load (const char *cmdline, void (**eip) (void), void **esp);
402 @@ -100,6 +103,10 @@ process_exit (void)
404 pagedir_activate (NULL);
405 pagedir_destroy (pd);
407 + /* We maintain the invariant that `hash' is initialized iff
409 + hash_destroy (&cur->pages);
413 @@ -182,7 +189,10 @@ struct Elf32_Phdr
414 #define PF_R 4 /* Readable. */
416 static bool load_segment (struct file *, const struct Elf32_Phdr *);
417 -static bool setup_stack (void **esp);
418 +static bool setup_stack (const char *cmdline, void **esp);
419 +static unsigned user_page_hash (const hash_elem *, void *);
420 +static bool user_page_less (const hash_elem *, const hash_elem *, void *);
421 +static struct user_page *make_user_page (void *upage);
423 /* Aborts loading an executable, with an error message. */
424 #define LOAD_ERROR(MSG) \
425 @@ -198,19 +208,35 @@ static bool setup_stack (void **esp);
426 and its initial stack pointer into *ESP.
427 Returns true if successful, false otherwise. */
429 -load (const char *filename, void (**eip) (void), void **esp)
430 +load (const char *cmdline, void (**eip) (void), void **esp)
432 struct thread *t = thread_current ();
433 + char filename[NAME_MAX + 2];
434 struct Elf32_Ehdr ehdr;
435 struct file *file = NULL;
437 bool success = false;
441 + /* Create hash of user pages. */
442 + hash_init (&t->pages, user_page_hash, user_page_less, NULL);
444 /* Allocate page directory. */
445 t->pagedir = pagedir_create ();
446 - if (t->pagedir == NULL)
447 - LOAD_ERROR (("page directory allocation failed"));
448 + if (t->pagedir == NULL)
450 + hash_destroy (&t->pages);
451 + LOAD_ERROR (("page directory allocation failed"));
454 + /* Extract filename from command line. */
455 + while (*cmdline == ' ')
457 + strlcpy (filename, cmdline, sizeof filename);
458 + cp = strchr (filename, ' ');
462 /* Open executable file. */
463 file = filesys_open (filename);
464 @@ -269,8 +295,23 @@ load (const char *filename, void (**eip)
468 - if (!setup_stack (esp))
469 + if (!setup_stack (cmdline, esp))
474 + struct hash_iterator i;
476 + hash_first (&i, &thread_current ()->pages);
477 + while (hash_next (&i))
479 + struct user_page *up = hash_entry (hash_cur (&i),
480 + struct user_page, elem);
481 + printf ("%08x ", up->upage);
488 *eip = (void (*) (void)) ehdr.e_entry;
489 @@ -279,14 +320,12 @@ load (const char *filename, void (**eip)
492 /* We arrive here whether the load is successful or not. */
494 + //file_close (file); // FIXME
498 /* load() helpers. */
500 -static bool install_page (void *upage, void *kpage);
502 /* Loads the segment described by PHDR from FILE into user
503 address space. Return true if successful, false otherwise. */
505 @@ -296,6 +335,7 @@ load_segment (struct file *file, const s
506 uint8_t *upage; /* Iterator from start to end. */
507 off_t filesz_left; /* Bytes left of file data (as opposed to
508 zero-initialized bytes). */
511 /* Is this a read-only segment? Not currently used, so it's
512 commented out. You'll want to use it when implementing VM
513 @@ -340,70 +380,206 @@ load_segment (struct file *file, const s
515 /* Load the segment page-by-page into memory. */
516 filesz_left = phdr->p_filesz + (phdr->p_vaddr & PGMASK);
517 - file_seek (file, ROUND_DOWN (phdr->p_offset, PGSIZE));
518 + file_ofs = ROUND_DOWN (phdr->p_offset, PGSIZE);
519 for (upage = start; upage < (uint8_t *) end; upage += PGSIZE)
521 /* We want to read min(PGSIZE, filesz_left) bytes from the
522 file into the page and zero the rest. */
523 size_t read_bytes = filesz_left >= PGSIZE ? PGSIZE : filesz_left;
524 - size_t zero_bytes = PGSIZE - read_bytes;
525 - uint8_t *kpage = palloc_get_page (PAL_USER);
527 + struct user_page *up = make_user_page (upage);
531 - /* Do the reading and zeroing. */
532 - if (file_read (file, kpage, read_bytes) != (int) read_bytes)
533 + if (read_bytes > 0)
535 - palloc_free_page (kpage);
539 + up->file_ofs = file_ofs;
540 + up->file_size = read_bytes;
541 + file_ofs += read_bytes;
543 - memset (kpage + read_bytes, 0, zero_bytes);
544 - filesz_left -= read_bytes;
546 - /* Add the page to the process's address space. */
547 - if (!install_page (upage, kpage))
550 - palloc_free_page (kpage);
552 + /* Page is all zeros. Nothing to do. */
554 + filesz_left -= read_bytes;
561 +reverse (int argc, char **argv)
563 + for (; argc > 1; argc -= 2, argv++)
565 + char *tmp = argv[0];
566 + argv[0] = argv[argc - 1];
567 + argv[argc - 1] = tmp;
571 +push (uint8_t *kpage, size_t *ofs, const void *buf, size_t size)
573 + size_t padsize = ROUND_UP (size, sizeof (uint32_t));
574 + if (*ofs < padsize)
578 + memcpy (kpage + *ofs + (padsize - size), buf, size);
579 + return kpage + *ofs + (padsize - size);
583 +init_cmdline (uint8_t *kpage, uint8_t *upage, const char *cmdline,
586 + size_t ofs = PGSIZE;
587 + char *const null = NULL;
588 + char *cmdline_copy;
589 + char *karg, *saveptr;
593 + /* Push command line string. */
594 + cmdline_copy = push (kpage, &ofs, cmdline, strlen (cmdline) + 1);
595 + if (cmdline_copy == NULL)
598 + if (push (kpage, &ofs, &null, sizeof null) == NULL)
601 + /* Parse command line into arguments
602 + and push them in reverse order. */
604 + for (karg = strtok_r (cmdline_copy, " ", &saveptr); karg != NULL;
605 + karg = strtok_r (NULL, " ", &saveptr))
607 + char *uarg = upage + (karg - (char *) kpage);
608 + if (push (kpage, &ofs, &uarg, sizeof uarg) == NULL)
613 + /* Reverse the order of the command line arguments. */
614 + argv = (char **) (upage + ofs);
615 + reverse (argc, (char **) (kpage + ofs));
617 + /* Push argv, argc, "return address". */
618 + if (push (kpage, &ofs, &argv, sizeof argv) == NULL
619 + || push (kpage, &ofs, &argc, sizeof argc) == NULL
620 + || push (kpage, &ofs, &null, sizeof null) == NULL)
623 + /* Set initial stack pointer. */
624 + *esp = upage + ofs;
629 -/* Create a minimal stack by mapping a zeroed page at the top of
630 - user virtual memory. */
631 +/* Create a minimal stack for T by mapping a page at the
632 + top of user virtual memory. Fills in the page using CMDLINE
633 + and sets *ESP to the stack pointer. */
635 -setup_stack (void **esp)
636 +setup_stack (const char *cmdline, void **esp)
639 - bool success = false;
640 + struct user_page *up = make_user_page ((uint8_t *) PHYS_BASE - PGSIZE);
642 + && pageframe_allocate (up)
643 + && init_cmdline (up->frame->kpage, up->upage, cmdline, esp));
647 +user_page_hash (const hash_elem *e, void *aux UNUSED)
649 + struct user_page *up = hash_entry (e, struct user_page, elem);
650 + return hash_bytes (&up->upage, sizeof up->upage);
653 - kpage = palloc_get_page (PAL_USER | PAL_ZERO);
656 +user_page_less (const hash_elem *a_, const hash_elem *b_, void *aux UNUSED)
658 + struct user_page *a = hash_entry (a_, struct user_page, elem);
659 + struct user_page *b = hash_entry (b_, struct user_page, elem);
661 + return a->upage < b->upage;
664 +static struct user_page *
665 +make_user_page (void *upage)
667 + struct user_page *up;
669 + up = malloc (sizeof *up);
672 - success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage);
675 + memset (up, 0, sizeof *up);
676 + up->swap_page = SIZE_MAX;
679 + if (hash_insert (&thread_current ()->pages, &up->elem) != NULL)
686 - palloc_free_page (kpage);
687 + printf ("make_user_page(%p) okay\n", upage);
691 - printf ("failed to allocate process stack\n");
697 -/* Adds a mapping from user virtual address UPAGE to kernel
698 - virtual address KPAGE to the page table. Fails if UPAGE is
699 - already mapped or if memory allocation fails. */
701 -install_page (void *upage, void *kpage)
703 +dump_page (struct user_page *up)
705 - struct thread *t = thread_current ();
708 - /* Verify that there's not already a page at that virtual
709 - address, then map our page there. */
710 - return (pagedir_get_page (t->pagedir, upage) == NULL
711 - && pagedir_set_page (t->pagedir, upage, kpage, true));
712 + ASSERT (up->file != NULL);
713 + up->file_size = PGSIZE;
714 + amt = file_write_at (up->file, up->frame->kpage,
715 + up->file_size, up->file_ofs);
716 + ASSERT (amt == (off_t) up->file_size);
720 +process_evict_page (struct thread *t, struct user_page *up)
722 + ASSERT (up->frame != NULL);
724 + if (pagedir_test_accessed (t->pagedir, up->upage))
726 + pagedir_clear_accessed (t->pagedir, up->upage);
730 + if (up->file == NULL)
732 + if (!swap_write (up))
735 + else if (pagedir_test_dirty (t->pagedir, up->upage))
737 + /* Need to write out. */
740 + up->file = NULL; // FIXME
741 + up->private = false;
742 + if (!swap_write (up))
750 + /* Already on disk, not dirty.
754 + pagedir_clear_page (t->pagedir, up->upage);
755 + pageframe_free (up->frame);
759 diff -urpN pintos.orig/src/userprog/process.h pintos/src/userprog/process.h
760 --- pintos.orig/src/userprog/process.h 2004-09-21 22:42:17.000000000 -0700
761 +++ pintos/src/userprog/process.h 2004-09-27 14:43:13.000000000 -0700
763 #define USERPROG_PROCESS_H
765 #include "threads/thread.h"
766 +#include "filesys/off_t.h"
771 + void *upage; /* Virtual address of mapping. */
773 + /* If FRAME is nonnull, the page is in memory.
774 + If FILE is nonnull, the page is on disk.
775 + If both are null, the page is all zeroes.
776 + If both are nonnull, the page is in memory and backed by a
777 + file mapping (not the swap file). */
778 + struct page_frame *frame;
782 + size_t file_size; /* Number of bytes on disk, <= PGSIZE. */
786 + bool private : 1; /* Write dirty pages to swap or to FILE? */
789 tid_t process_execute (const char *filename);
790 void process_exit (void);
791 void process_activate (void);
792 +bool process_evict_page (struct thread *, struct user_page *);
794 #endif /* userprog/process.h */
795 diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
796 --- pintos.orig/src/userprog/syscall.c 2004-09-26 14:15:17.000000000 -0700
797 +++ pintos/src/userprog/syscall.c 2004-09-27 14:42:01.000000000 -0700
799 #include "userprog/syscall.h"
802 #include <syscall-nr.h>
803 +#include "threads/init.h"
804 #include "threads/interrupt.h"
805 +#include "threads/malloc.h"
806 +#include "threads/mmu.h"
807 +#include "threads/palloc.h"
808 #include "threads/thread.h"
809 +#include "userprog/pagedir.h"
810 +#include "userprog/process.h"
811 +#include "filesys/filesys.h"
812 +#include "filesys/file.h"
813 +#include "devices/kbd.h"
815 +typedef int syscall_function (int, int, int);
817 +static int sys_halt (void);
818 +static int sys_exit (int status);
819 +static int sys_exec (const char *ufile);
820 +static int sys_join (tid_t);
821 +static int sys_create (const char *ufile, unsigned initial_size);
822 +static int sys_remove (const char *ufile);
823 +static int sys_open (const char *ufile);
824 +static int sys_filesize (int handle);
825 +static int sys_read (int handle, void *udst_, unsigned size);
826 +static int sys_write (int handle, void *usrc_, unsigned size);
827 +static int sys_seek (int handle, unsigned position);
828 +static int sys_tell (int handle);
829 +static int sys_close (int handle);
834 + syscall_function *func;
837 +struct syscall syscall_table[] =
839 + {0, (syscall_function *) sys_halt},
840 + {1, (syscall_function *) sys_exit},
841 + {1, (syscall_function *) sys_exec},
842 + {1, (syscall_function *) sys_join},
843 + {2, (syscall_function *) sys_create},
844 + {1, (syscall_function *) sys_remove},
845 + {1, (syscall_function *) sys_open},
846 + {1, (syscall_function *) sys_filesize},
847 + {3, (syscall_function *) sys_read},
848 + {3, (syscall_function *) sys_write},
849 + {2, (syscall_function *) sys_seek},
850 + {1, (syscall_function *) sys_tell},
851 + {1, (syscall_function *) sys_close},
853 +static const int syscall_cnt = sizeof syscall_table / sizeof *syscall_table;
855 static void syscall_handler (struct intr_frame *);
856 +static void copy_in (void *, const void *, size_t);
858 +static struct lock fs_lock;
863 intr_register (0x30, 3, INTR_ON, syscall_handler, "syscall");
864 + lock_init (&fs_lock, "fs");
868 -syscall_handler (struct intr_frame *f UNUSED)
869 +syscall_handler (struct intr_frame *f)
875 + copy_in (&call_nr, f->esp, sizeof call_nr);
876 + if (call_nr < 0 || call_nr >= syscall_cnt)
878 + printf ("bad syscall number %d\n", call_nr);
882 + s = syscall_table + call_nr;
883 + ASSERT (s->arg_cnt <= sizeof args / sizeof *args);
884 + memset (args, 0, sizeof args);
885 + copy_in (args, (uint32_t *) f->esp + 1, sizeof *args * s->arg_cnt);
886 + f->eax = s->func (args[0], args[1], args[2]);
890 +verify_user (const void *uaddr)
892 + return pagedir_get_page (thread_current ()->pagedir, uaddr) != NULL;
895 +static inline bool get_user (uint8_t *dst, const uint8_t *usrc) {
897 + asm ("movl $1f, %%eax; movb %2, %%al; movb %%al, %0; 1:"
898 + : "=m" (*dst), "=&a" (eax) : "m" (*usrc));
902 +static inline bool put_user (uint8_t *udst, uint8_t byte) {
904 + asm ("movl $1f, %%eax; movb %b2, %0; 1:"
905 + : "=m" (*udst), "=&a" (eax) : "r" (byte));
910 +copy_in (void *dst_, const void *usrc_, size_t size)
912 + uint8_t *dst = dst_;
913 + const uint8_t *usrc = usrc_;
915 + for (; size > 0; size--, dst++, usrc++)
916 + if (usrc >= (uint8_t *) PHYS_BASE || !get_user (dst, usrc))
921 +copy_in_string (const char *us)
926 + ks = palloc_get_page (0);
929 + printf ("copy_in_string: out of memory\n");
933 + for (length = 0; length < PGSIZE; length++)
935 + if (us >= (char *) PHYS_BASE || !get_user (ks + length, us++))
937 + printf ("bad user reference (%p)\n", us + length);
941 + if (ks[length] == '\0')
945 + printf ("copy_in_string: string too long\n");
946 + palloc_free_page (ks);
957 +sys_exit (int ret_code)
959 - printf ("system call!\n");
960 + thread_current ()->ret_code = ret_code;
966 +sys_exec (const char *ufile)
969 + char *kfile = copy_in_string (ufile);
971 + lock_acquire (&fs_lock);
972 + tid = process_execute (kfile);
973 + lock_release (&fs_lock);
975 + palloc_free_page (kfile);
981 +sys_join (tid_t child)
983 + return thread_join (child);
987 +sys_create (const char *ufile, unsigned initial_size)
989 + char *kfile = copy_in_string (ufile);
992 + lock_acquire (&fs_lock);
993 + ok = filesys_create (kfile, initial_size);
994 + lock_release (&fs_lock);
996 + palloc_free_page (kfile);
1002 +sys_remove (const char *ufile)
1004 + char *kfile = copy_in_string (ufile);
1007 + lock_acquire (&fs_lock);
1008 + ok = filesys_remove (kfile);
1009 + lock_release (&fs_lock);
1011 + palloc_free_page (kfile);
1019 + struct file *file;
1024 +sys_open (const char *ufile)
1026 + char *kfile = copy_in_string (ufile);
1027 + struct fildes *fd;
1030 + fd = malloc (sizeof *fd);
1034 + lock_acquire (&fs_lock);
1035 + fd->file = filesys_open (kfile);
1036 + if (fd->file != NULL)
1038 + struct thread *cur = thread_current ();
1039 + handle = fd->handle = cur->next_handle++;
1040 + list_push_front (&cur->fds, &fd->elem);
1044 + lock_release (&fs_lock);
1047 + palloc_free_page (kfile);
1051 +static struct fildes *
1052 +lookup_fd (int handle)
1054 + struct thread *cur = thread_current ();
1057 + for (e = list_begin (&cur->fds); e != list_end (&cur->fds);
1058 + e = list_next (e))
1060 + struct fildes *fd = list_entry (e, struct fildes, elem);
1061 + if (fd->handle == handle)
1065 + printf ("no handle %d\n", handle);
1070 +sys_filesize (int handle)
1072 + struct fildes *fd = lookup_fd (handle);
1075 + lock_acquire (&fs_lock);
1076 + size = file_length (fd->file);
1077 + lock_release (&fs_lock);
1083 +sys_read (int handle, void *udst_, unsigned size)
1085 + uint8_t *udst = udst_;
1086 + struct fildes *fd;
1087 + int bytes_read = 0;
1089 + if (handle == STDIN_FILENO)
1091 + for (bytes_read = 0; (size_t) bytes_read < size; bytes_read++)
1092 + if (udst >= (uint8_t *) PHYS_BASE || !put_user (udst++, kbd_getc ()))
1094 + return bytes_read;
1097 + lock_acquire (&fs_lock);
1098 + fd = lookup_fd (handle);
1101 + size_t page_left = PGSIZE - pg_ofs (udst);
1102 + size_t read_amt = size < page_left ? size : page_left;
1105 + if (!verify_user (udst))
1107 + lock_release (&fs_lock);
1111 + retval = file_read (fd->file, udst, read_amt);
1114 + if (bytes_read == 0)
1119 + bytes_read += retval;
1120 + if (retval != (off_t) read_amt)
1126 + lock_release (&fs_lock);
1128 + return bytes_read;
1132 +sys_write (int handle, void *usrc_, unsigned size)
1134 + uint8_t *usrc = usrc_;
1135 + struct fildes *fd = NULL;
1136 + int bytes_written = 0;
1138 + lock_acquire (&fs_lock);
1139 + if (handle != STDOUT_FILENO)
1140 + fd = lookup_fd (handle);
1143 + size_t page_left = PGSIZE - pg_ofs (usrc);
1144 + size_t write_amt = size < page_left ? size : page_left;
1147 + if (!verify_user (usrc))
1149 + lock_release (&fs_lock);
1153 + if (handle == STDOUT_FILENO)
1155 + putbuf (usrc, write_amt);
1156 + retval = write_amt;
1159 + retval = file_write (fd->file, usrc, write_amt);
1162 + if (bytes_written == 0)
1163 + bytes_written = -1;
1167 + bytes_written += retval;
1168 + if (retval != (off_t) write_amt)
1174 + lock_release (&fs_lock);
1176 + return bytes_written;
1180 +sys_seek (int handle, unsigned position)
1182 + struct fildes *fd = lookup_fd (handle);
1184 + lock_acquire (&fs_lock);
1185 + file_seek (fd->file, position);
1186 + lock_release (&fs_lock);
1192 +sys_tell (int handle)
1194 + struct fildes *fd = lookup_fd (handle);
1195 + unsigned position;
1197 + lock_acquire (&fs_lock);
1198 + position = file_tell (fd->file);
1199 + lock_release (&fs_lock);
1205 +sys_close (int handle)
1207 + struct fildes *fd = lookup_fd (handle);
1208 + lock_acquire (&fs_lock);
1209 + file_close (fd->file);
1210 + lock_release (&fs_lock);
1211 + list_remove (&fd->elem);
1217 +syscall_exit (void)
1219 + struct thread *cur = thread_current ();
1220 + list_elem *e, *next;
1222 + for (e = list_begin (&cur->fds); e != list_end (&cur->fds); e = next)
1224 + struct fildes *fd = list_entry (e, struct fildes, elem);
1225 + next = list_next (e);
1226 + file_close (fd->file);
1230 diff -urpN pintos.orig/src/userprog/syscall.h pintos/src/userprog/syscall.h
1231 --- pintos.orig/src/userprog/syscall.h 2004-09-05 22:38:45.000000000 -0700
1232 +++ pintos/src/userprog/syscall.h 2004-09-27 13:29:44.000000000 -0700
1234 #define USERPROG_SYSCALL_H
1236 void syscall_init (void);
1237 +void syscall_exit (void);
1239 #endif /* userprog/syscall.h */
1240 diff -urpN pintos.orig/src/vm/pageframe.c pintos/src/vm/pageframe.c
1241 --- pintos.orig/src/vm/pageframe.c 1969-12-31 16:00:00.000000000 -0800
1242 +++ pintos/src/vm/pageframe.c 2004-09-27 13:29:44.000000000 -0700
1244 +#include "vm/pageframe.h"
1245 +#include <stdint.h>
1246 +#include "threads/init.h"
1247 +#include "threads/malloc.h"
1248 +#include "threads/mmu.h"
1249 +#include "threads/palloc.h"
1250 +#include "userprog/process.h"
1252 +static struct page_frame *frames;
1253 +static size_t frame_cnt;
1255 +static struct page_frame *next_frame;
1258 +in_use (const struct page_frame *pf)
1260 + ASSERT ((pf->owner != NULL) == (pf->user_page != NULL));
1261 + return pf->owner != NULL;
1265 +pageframe_init (void)
1269 + frame_cnt = ram_pages;
1270 + frames = calloc (sizeof *frames, frame_cnt);
1271 + if (frames == NULL)
1272 + PANIC ("can't allocate page frames");
1274 + while ((kpage = palloc_get_page (PAL_USER)) != NULL)
1276 + struct page_frame *pf = frames + (vtop (kpage) >> PGBITS);
1277 + pf->kpage = kpage;
1280 + next_frame = frames;
1284 +pageframe_allocate (struct user_page *up)
1286 + struct page_frame *pf;
1289 + ASSERT (up->frame == NULL);
1294 + pf = next_frame++;
1295 + if (next_frame >= frames + frame_cnt)
1296 + next_frame = frames;
1297 + if (loops++ > 2 * frame_cnt)
1300 + while (pf->kpage == NULL
1301 + || (in_use (pf) && !process_evict_page (pf->owner, pf->user_page)));
1303 + ASSERT (!in_use (pf));
1304 + pf->owner = thread_current ();
1305 + pf->user_page = up;
1311 +pageframe_free (struct page_frame *pf)
1313 + ASSERT (in_use (pf));
1316 + pf->user_page->frame = NULL;
1317 + pf->user_page = NULL;
1319 diff -urpN pintos.orig/src/vm/pageframe.h pintos/src/vm/pageframe.h
1320 --- pintos.orig/src/vm/pageframe.h 1969-12-31 16:00:00.000000000 -0800
1321 +++ pintos/src/vm/pageframe.h 2004-09-27 13:29:44.000000000 -0700
1323 +#ifndef VM_PAGEFRAME_H
1324 +#define VM_PAGEFRAME_H 1
1326 +#include <stdbool.h>
1331 + struct thread *owner;
1332 + struct user_page *user_page;
1335 +void pageframe_init (void);
1336 +bool pageframe_allocate (struct user_page *);
1337 +void pageframe_free (struct page_frame *);
1339 +#endif /* vm/pageframe.h */
1340 diff -urpN pintos.orig/src/vm/swap.c pintos/src/vm/swap.c
1341 --- pintos.orig/src/vm/swap.c 1969-12-31 16:00:00.000000000 -0800
1342 +++ pintos/src/vm/swap.c 2004-09-27 13:29:44.000000000 -0700
1344 +#include "vm/swap.h"
1345 +#include <bitmap.h>
1347 +#include "vm/pageframe.h"
1348 +#include "threads/mmu.h"
1349 +#include "filesys/file.h"
1350 +#include "filesys/filesys.h"
1351 +#include "userprog/process.h"
1353 +static size_t swap_pages;
1354 +static struct disk *swap_disk;
1355 +static struct bitmap *used_pages;
1360 + swap_disk = disk_get (1, 1);
1361 + if (swap_disk == NULL)
1362 + PANIC ("no swap disk");
1363 + swap_pages = disk_size (swap_disk) / (PGSIZE / DISK_SECTOR_SIZE);
1364 + printf ("swap disk has room for %zu pages\n", swap_pages);
1366 + used_pages = bitmap_create (swap_pages);
1367 + if (used_pages == NULL)
1368 + PANIC ("couldn't create swap bitmap");
1372 +swap_write (struct user_page *up)
1375 + disk_sector_t sector;
1378 + ASSERT (up->frame != NULL);
1379 + ASSERT (up->file == NULL);
1381 + page = bitmap_scan_and_flip (used_pages, 0, 1, false);
1382 + if (page == BITMAP_ERROR)
1385 + up->swap_page = page;
1386 + sector = (disk_sector_t) page * (PGSIZE / DISK_SECTOR_SIZE);
1387 + for (i = 0; i < PGSIZE / DISK_SECTOR_SIZE; i++)
1388 + disk_write (swap_disk, sector++, up->frame->kpage + i * DISK_SECTOR_SIZE);
1394 +swap_read (struct user_page *up)
1396 + disk_sector_t sector;
1399 + ASSERT (up->frame != NULL);
1401 + ASSERT (bitmap_test (used_pages, up->swap_page));
1402 + bitmap_reset (used_pages, up->swap_page);
1404 + sector = (disk_sector_t) up->swap_page * (PGSIZE / DISK_SECTOR_SIZE);
1405 + for (i = 0; i < PGSIZE / DISK_SECTOR_SIZE; i++)
1406 + disk_read (swap_disk, sector++, up->frame->kpage + i * DISK_SECTOR_SIZE);
1408 + up->swap_page = SIZE_MAX;
1410 diff -urpN pintos.orig/src/vm/swap.h pintos/src/vm/swap.h
1411 --- pintos.orig/src/vm/swap.h 1969-12-31 16:00:00.000000000 -0800
1412 +++ pintos/src/vm/swap.h 2004-09-27 13:29:44.000000000 -0700
1415 +#define VM_SWAP_H 1
1417 +#include <stdbool.h>
1420 +void swap_init (void);
1421 +bool swap_write (struct user_page *);
1422 +void swap_read (struct user_page *);
1424 +#endif /* vm/swap.h */