summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2012-06-19 01:44:56 +0200
committermanuel <manuel@mausz.at>2012-06-19 01:44:56 +0200
commite88a8c4c379d721e9901752d440a05295087da11 (patch)
treeb89070c525614267811a10b77a4dbc49ffd96b03
parentd9e0c55d118d0a3923b440b7811f8d1d6db9e1d7 (diff)
downloadprogos-e88a8c4c379d721e9901752d440a05295087da11.tar.gz
progos-e88a8c4c379d721e9901752d440a05295087da11.tar.bz2
progos-e88a8c4c379d721e9901752d440a05295087da11.zip
implement page table and use it for lazy loading of segments
-rw-r--r--Makefile.build2
-rw-r--r--proj0.txt12
-rw-r--r--proj1.txt18
-rw-r--r--threads/synch.c8
-rw-r--r--threads/thread.c2
-rw-r--r--threads/thread.h3
-rw-r--r--userprog/exception.c16
-rw-r--r--userprog/process.c35
-rw-r--r--userprog/process.h1
-rw-r--r--vm/page.c147
-rw-r--r--vm/page.h41
11 files changed, 239 insertions, 46 deletions
diff --git a/Makefile.build b/Makefile.build
index e997d27..e68e721 100644
--- a/Makefile.build
+++ b/Makefile.build
@@ -62,7 +62,7 @@ userprog_SRC += userprog/gdt.c # GDT initialization.
62userprog_SRC += userprog/tss.c # TSS management. 62userprog_SRC += userprog/tss.c # TSS management.
63 63
64# No virtual memory code yet. 64# No virtual memory code yet.
65#vm_SRC = vm/file.c # Some file. 65vm_SRC = vm/page.c
66 66
67# Filesystem code. 67# Filesystem code.
68filesys_SRC = filesys/filesys.c # Filesystem core. 68filesys_SRC = filesys/filesys.c # Filesystem core.
diff --git a/proj0.txt b/proj0.txt
index 24ea011..59a0d3c 100644
--- a/proj0.txt
+++ b/proj0.txt
@@ -35,9 +35,8 @@ Stallings, W. - Operating Systems
35struct thread: 35struct thread:
36int64_t wakeup_tick ...absolute tick when to wake up the thread 36int64_t wakeup_tick ...absolute tick when to wake up the thread
37 37
38
39timer.c: 38timer.c:
40static struct list wakeup_list ...list of processes waiting for an 39static struct list wakeup_list ...list of processes waiting for an
41wakeup event and currently put to sleep 40wakeup event and currently put to sleep
42 41
43---- ALGORITHMS ---- 42---- ALGORITHMS ----
@@ -62,7 +61,7 @@ Thus we can return as soon as the first thread doesn't need to get unblocked.
62>> A4: How are race conditions avoided when multiple threads call 61>> A4: How are race conditions avoided when multiple threads call
63>> timer_sleep() simultaneously? 62>> timer_sleep() simultaneously?
64 63
65Each thread has its own variable for saving its sleep period 64Each thread has its own variable for saving its sleep period
66therefore no race conditions arise while setting the latter. Furthermore 65therefore no race conditions arise while setting the latter. Furthermore
67during the access to the static wakup_list, interrupts are disabled to prevent 66during the access to the static wakup_list, interrupts are disabled to prevent
68thread preemption. 67thread preemption.
@@ -131,12 +130,11 @@ strtok() uses global data, so it is unsafe in threaded programs such as kernels.
131 execution with user privileges. Otherwise this could lead to a kernel oops 130 execution with user privileges. Otherwise this could lead to a kernel oops
132 or even worse code execution within the kernel. 131 or even worse code execution within the kernel.
133 132
134* Outsourcing command separation from the kernel leads to a leaner 133* Outsourcing command separation from the kernel leads to a leaner
135 less complex kernel implementation and reduces the kernel workload 134 less complex kernel implementation and reduces the kernel workload
136 because tasks like searching for a command name in file system 135 because tasks like searching for a command name in file system
137 can be delegated to the shell. 136 can be delegated to the shell.
138 137
139
140 SURVEY QUESTIONS 138 SURVEY QUESTIONS
141 ================ 139 ================
142 140
@@ -161,4 +159,4 @@ the quarter.
161 159
162>> Any other comments? 160>> Any other comments?
163 161
164It took us about 25 hours to complete this assignment. \ No newline at end of file 162It took us about 25 hours to complete this assignment.
diff --git a/proj1.txt b/proj1.txt
index 03c61f0..2eab2fa 100644
--- a/proj1.txt
+++ b/proj1.txt
@@ -1,8 +1,8 @@
1 +--------------------+ 1 +--------------------+
2 | CS 140 | 2 | CS 140 |
3 | PROJECT 1: THREADS | 3 | PROJECT 1: THREADS |
4 | DESIGN DOCUMENT | 4 | DESIGN DOCUMENT |
5 +--------------------+ 5 +--------------------+
6 6
7---- GROUP ---- 7---- GROUP ----
8 8
@@ -25,8 +25,8 @@ Stallings, W. - Operating Systems
25http://en.wikipedia.org/wiki/Priority_inversion 25http://en.wikipedia.org/wiki/Priority_inversion
26http://hynek.me/studies/sched_ausarbeitung.pdf 26http://hynek.me/studies/sched_ausarbeitung.pdf
27 27
28 PRIORITY SCHEDULING 28 PRIORITY SCHEDULING
29 =================== 29 ===================
30 30
31---- DATA STRUCTURES ---- 31---- DATA STRUCTURES ----
32 32
@@ -214,8 +214,8 @@ and we don't have any reference to currently used semaphores/conditions inside
214the thread structure. Thus we simply sort the whole list inside sema_up()/ 214the thread structure. Thus we simply sort the whole list inside sema_up()/
215cond_signal() before unblocking the next thread. 215cond_signal() before unblocking the next thread.
216 216
217 SURVEY QUESTIONS 217 SURVEY QUESTIONS
218 ================ 218 ================
219 219
220Answering these questions is optional, but it will help us improve the 220Answering these questions is optional, but it will help us improve the
221course in future quarters. Feel free to tell us anything you 221course in future quarters. Feel free to tell us anything you
diff --git a/threads/synch.c b/threads/synch.c
index a1b7549..a520f61 100644
--- a/threads/synch.c
+++ b/threads/synch.c
@@ -32,9 +32,9 @@
32#include "threads/interrupt.h" 32#include "threads/interrupt.h"
33#include "threads/thread.h" 33#include "threads/thread.h"
34 34
35static bool lock_priority_cmp_greater(const struct list_elem *a, const struct list_elem *b, 35static bool lock_priority_cmp_greater (const struct list_elem *a, const struct list_elem *b,
36 void *AUX UNUSED); 36 void *AUX UNUSED);
37static bool semaphore_priority_cmp_greater(const struct list_elem *a, const struct list_elem *b, 37static bool semaphore_priority_cmp_greater (const struct list_elem *a, const struct list_elem *b,
38 void *aux UNUSED); 38 void *aux UNUSED);
39 39
40/* Initializes semaphore SEMA to VALUE. A semaphore is a 40/* Initializes semaphore SEMA to VALUE. A semaphore is a
@@ -202,7 +202,7 @@ lock_init (struct lock *lock)
202 202
203/* comparison function for our descending ordered lock list. */ 203/* comparison function for our descending ordered lock list. */
204static bool 204static bool
205lock_priority_cmp_greater(const struct list_elem *a, const struct list_elem *b, 205lock_priority_cmp_greater (const struct list_elem *a, const struct list_elem *b,
206 void *AUX UNUSED) 206 void *AUX UNUSED)
207{ 207{
208 const struct lock *l1 = list_entry (a, struct lock, elem); 208 const struct lock *l1 = list_entry (a, struct lock, elem);
@@ -355,7 +355,7 @@ cond_init (struct condition *cond)
355 355
356/* comparison function for our descending ordered condition waiters list. */ 356/* comparison function for our descending ordered condition waiters list. */
357static bool 357static bool
358semaphore_priority_cmp_greater(const struct list_elem *a, const struct list_elem *b, 358semaphore_priority_cmp_greater (const struct list_elem *a, const struct list_elem *b,
359 void *aux UNUSED) 359 void *aux UNUSED)
360{ 360{
361 const struct semaphore_elem *s1 = list_entry (a, struct semaphore_elem, elem); 361 const struct semaphore_elem *s1 = list_entry (a, struct semaphore_elem, elem);
diff --git a/threads/thread.c b/threads/thread.c
index cf404b6..14889ca 100644
--- a/threads/thread.c
+++ b/threads/thread.c
@@ -73,7 +73,7 @@ static tid_t allocate_tid (void);
73 73
74/* comparison function for our descending ordered ready list. */ 74/* comparison function for our descending ordered ready list. */
75bool 75bool
76thread_priority_cmp_greater(const struct list_elem *a, const struct list_elem *b, 76thread_priority_cmp_greater (const struct list_elem *a, const struct list_elem *b,
77 void *AUX UNUSED) 77 void *AUX UNUSED)
78{ 78{
79 const struct thread *t1 = list_entry (a, struct thread, elem); 79 const struct thread *t1 = list_entry (a, struct thread, elem);
diff --git a/threads/thread.h b/threads/thread.h
index 9125937..293d14f 100644
--- a/threads/thread.h
+++ b/threads/thread.h
@@ -3,6 +3,7 @@
3 3
4#include <debug.h> 4#include <debug.h>
5#include <list.h> 5#include <list.h>
6#include <hash.h>
6#include <stdint.h> 7#include <stdint.h>
7#include "threads/synch.h" 8#include "threads/synch.h"
8 9
@@ -112,6 +113,8 @@ struct thread
112 int saved_priority; /* saved base priority in case of priority dontation */ 113 int saved_priority; /* saved base priority in case of priority dontation */
113 struct list locks; /* list of locks the thread currently holds */ 114 struct list locks; /* list of locks the thread currently holds */
114 struct lock *blocked_lock; /* the lock the thread currently tries to acquire (but hasn't yet) */ 115 struct lock *blocked_lock; /* the lock the thread currently tries to acquire (but hasn't yet) */
116
117 struct hash page_table;
115 }; 118 };
116 119
117/* If false (default), use round-robin scheduler. 120/* If false (default), use round-robin scheduler.
diff --git a/userprog/exception.c b/userprog/exception.c
index 17620ad..54621fa 100644
--- a/userprog/exception.c
+++ b/userprog/exception.c
@@ -5,6 +5,7 @@
5#include "threads/interrupt.h" 5#include "threads/interrupt.h"
6#include "threads/thread.h" 6#include "threads/thread.h"
7#include "threads/vaddr.h" 7#include "threads/vaddr.h"
8#include "vm/page.h"
8 9
9/* Number of page faults processed. */ 10/* Number of page faults processed. */
10static long long page_fault_cnt; 11static long long page_fault_cnt;
@@ -121,12 +122,13 @@ kill (struct intr_frame *f)
121 description of "Interrupt 14--Page Fault Exception (#PF)" in 122 description of "Interrupt 14--Page Fault Exception (#PF)" in
122 [IA32-v3a] section 5.15 "Exception and Interrupt Reference". */ 123 [IA32-v3a] section 5.15 "Exception and Interrupt Reference". */
123static void 124static void
124page_fault (struct intr_frame *f) 125page_fault (struct intr_frame *f)
125{ 126{
126 bool not_present; /* True: not-present page, false: writing r/o page. */ 127 bool not_present; /* True: not-present page, false: writing r/o page. */
127 bool write; /* True: access was write, false: access was read. */ 128 bool write; /* True: access was write, false: access was read. */
128 bool user; /* True: access by user, false: access by kernel. */ 129 bool user; /* True: access by user, false: access by kernel. */
129 void *fault_addr; /* Fault address. */ 130 void *fault_addr; /* Fault address. */
131 struct page_table_entry *pte;
130 132
131 /* Obtain faulting address, the virtual address that was 133 /* Obtain faulting address, the virtual address that was
132 accessed to cause the fault. It may point to code or to 134 accessed to cause the fault. It may point to code or to
@@ -153,6 +155,17 @@ page_fault (struct intr_frame *f)
153 body, adding code that brings in the page to 155 body, adding code that brings in the page to
154 which fault_addr refers. */ 156 which fault_addr refers. */
155 if (is_user_vaddr(fault_addr)) { 157 if (is_user_vaddr(fault_addr)) {
158 pte = page_table_fetch (&thread_current ()->page_table, pg_round_down (fault_addr));
159 if (pte != NULL)
160 page_load (pte);
161 else
162 {
163 printf ("Page fault %p\n", pte);
164 kill (f);
165 }
166
167 //TODO
168#if 0
156 if (! user) { 169 if (! user) {
157 /* syscall exception; set eax and eip */ 170 /* syscall exception; set eax and eip */
158 f->eip = (void*)f->eax; 171 f->eip = (void*)f->eax;
@@ -162,6 +175,7 @@ page_fault (struct intr_frame *f)
162 /* user process access violation */ 175 /* user process access violation */
163 thread_exit(); 176 thread_exit();
164 } 177 }
178#endif
165 } else { 179 } else {
166 printf ("Page fault at %p: %s error %s page in %s context.\n", 180 printf ("Page fault at %p: %s error %s page in %s context.\n",
167 fault_addr, 181 fault_addr,
diff --git a/userprog/process.c b/userprog/process.c
index c13c051..15883d9 100644
--- a/userprog/process.c
+++ b/userprog/process.c
@@ -18,6 +18,7 @@
18#include "threads/synch.h" 18#include "threads/synch.h"
19#include "threads/thread.h" 19#include "threads/thread.h"
20#include "threads/vaddr.h" 20#include "threads/vaddr.h"
21#include "vm/page.h"
21 22
22/* data structure to communicate with the thread initializing a new process */ 23/* data structure to communicate with the thread initializing a new process */
23struct start_aux_data { 24struct start_aux_data {
@@ -128,6 +129,8 @@ start_process (void *aux)
128 process->parent_tid = aux_data->parent_thread->tid; 129 process->parent_tid = aux_data->parent_thread->tid;
129 thread->process = process; 130 thread->process = process;
130 131
132 page_table_init (&thread->page_table);
133
131 /* Initialize interrupt frame and load executable. */ 134 /* Initialize interrupt frame and load executable. */
132 memset (&if_, 0, sizeof if_); 135 memset (&if_, 0, sizeof if_);
133 if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG; 136 if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG;
@@ -251,6 +254,8 @@ process_exit (void)
251 pagedir_destroy (pd); 254 pagedir_destroy (pd);
252 } 255 }
253 256
257 page_table_free (&thread->page_table);
258
254 /* Destroy the process structure if the parent is not alive 259 /* Destroy the process structure if the parent is not alive
255 * any more. Atomic test and set would be sufficient here. 260 * any more. Atomic test and set would be sufficient here.
256 */ 261 */
@@ -478,8 +483,6 @@ load (const char *args, void (**eip) (void), void **esp)
478 483
479/* load() helpers. */ 484/* load() helpers. */
480 485
481static bool install_page (void *upage, void *kpage, bool writable);
482
483/* Checks whether PHDR describes a valid, loadable segment in 486/* Checks whether PHDR describes a valid, loadable segment in
484 FILE and returns true if so, false otherwise. */ 487 FILE and returns true if so, false otherwise. */
485static bool 488static bool
@@ -556,29 +559,15 @@ load_segment (struct file *file, off_t ofs, uint8_t *upage,
556 size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE; 559 size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE;
557 size_t page_zero_bytes = PGSIZE - page_read_bytes; 560 size_t page_zero_bytes = PGSIZE - page_read_bytes;
558 561
559 /* Get a page of memory. */ 562 /* add segment to page table for on demand loading */
560 uint8_t *kpage = palloc_get_page (PAL_USER); 563 if (!page_table_insert_segment (file, ofs, upage, page_read_bytes,
561 if (kpage == NULL) 564 page_zero_bytes, writable))
562 return false;
563
564 /* Load this page. */
565 if (file_read (file, kpage, page_read_bytes) != (int) page_read_bytes)
566 {
567 palloc_free_page (kpage);
568 return false; 565 return false;
569 }
570 memset (kpage + page_read_bytes, 0, page_zero_bytes);
571
572 /* Add the page to the process's address space. */
573 if (!install_page (upage, kpage, writable))
574 {
575 palloc_free_page (kpage);
576 return false;
577 }
578 566
579 /* Advance. */ 567 /* Advance. */
580 read_bytes -= page_read_bytes; 568 read_bytes -= page_read_bytes;
581 zero_bytes -= page_zero_bytes; 569 zero_bytes -= page_zero_bytes;
570 ofs += page_read_bytes;
582 upage += PGSIZE; 571 upage += PGSIZE;
583 } 572 }
584 return true; 573 return true;
@@ -602,7 +591,7 @@ setup_stack (uint32_t **esp, const char *args)
602 if (kpage == NULL) 591 if (kpage == NULL)
603 return false; 592 return false;
604 593
605 if (! install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage, true)) { 594 if (! process_install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage, true)) {
606 palloc_free_page (kpage); 595 palloc_free_page (kpage);
607 return false; 596 return false;
608 } 597 }
@@ -706,8 +695,8 @@ setup_stack (uint32_t **esp, const char *args)
706 with palloc_get_page(). 695 with palloc_get_page().
707 Returns true on success, false if UPAGE is already mapped or 696 Returns true on success, false if UPAGE is already mapped or
708 if memory allocation fails. */ 697 if memory allocation fails. */
709static bool 698bool
710install_page (void *upage, void *kpage, bool writable) 699process_install_page (void *upage, void *kpage, bool writable)
711{ 700{
712 struct thread *t = thread_current (); 701 struct thread *t = thread_current ();
713 702
diff --git a/userprog/process.h b/userprog/process.h
index 1609801..b7bca5d 100644
--- a/userprog/process.h
+++ b/userprog/process.h
@@ -37,6 +37,7 @@ tid_t process_execute (const char *file_name);
37int process_wait (tid_t); 37int process_wait (tid_t);
38void process_exit (void); 38void process_exit (void);
39void process_activate (void); 39void process_activate (void);
40bool process_install_page (void *upage, void *kpage, bool writable);
40 41
41int process_open_file(const char* fname); 42int process_open_file(const char* fname);
42struct file* process_get_file(int fd); 43struct file* process_get_file(int fd);
diff --git a/vm/page.c b/vm/page.c
new file mode 100644
index 0000000..fa2433d
--- /dev/null
+++ b/vm/page.c
@@ -0,0 +1,147 @@
1#include <string.h>
2#include "filesys/file.h"
3#include "userprog/process.h"
4#include "threads/thread.h"
5#include "threads/malloc.h"
6#include "threads/palloc.h"
7#include "vm/page.h"
8
9static void page_table_entry_free (struct hash_elem *e, void *aux UNUSED);
10static unsigned page_table_hash (const struct hash_elem *e, void *aux UNUSED);
11static bool page_table_cmp_less (const struct hash_elem *a, const struct hash_elem *b,
12 void *aux UNUSED);
13static bool page_table_insert (struct hash *ht, struct page_table_entry *pte);
14static bool page_load_segment (struct page_table_entry *pte);
15static bool page_load_mmf (struct page_table_entry *pte);
16
17void
18page_table_init (struct hash *ht)
19{
20 hash_init (ht, page_table_hash, page_table_cmp_less, NULL);
21}
22
23unsigned
24page_table_hash (const struct hash_elem *e, void *aux UNUSED)
25{
26 const struct page_table_entry *pte = hash_entry (e, struct page_table_entry, elem);
27 return hash_bytes (&pte->uvaddr, sizeof pte->uvaddr);
28}
29
30bool
31page_table_cmp_less (const struct hash_elem *a, const struct hash_elem *b,
32 void *aux UNUSED)
33{
34 const struct page_table_entry *pte1 = hash_entry (a, struct page_table_entry, elem);
35 const struct page_table_entry *pte2 = hash_entry (b, struct page_table_entry, elem);
36 return (pte1->uvaddr < pte2->uvaddr);
37}
38
39void
40page_table_free (struct hash *ht)
41{
42 hash_destroy (ht, page_table_entry_free);
43}
44
45void
46page_table_entry_free (struct hash_elem *e, void *aux UNUSED)
47{
48 struct page_table_entry *pte = hash_entry (e, struct page_table_entry, elem);
49 free (pte);
50}
51
52bool
53page_table_insert (struct hash *ht, struct page_table_entry *pte)
54{
55 if (pte == NULL)
56 return false;
57 return (hash_insert (ht, &pte->elem) == NULL);
58}
59
60bool
61page_table_insert_segment (struct file *file, off_t ofs, uint8_t *upage,
62 uint32_t read_bytes, uint32_t zero_bytes, bool writable)
63{
64 struct page_table_entry *pte = malloc (sizeof *pte);
65 if (pte == NULL)
66 return false;
67
68 pte->uvaddr = upage;
69 pte->type = PAGE_SEGMENT;
70 pte->loaded = false;
71 pte->segment.file = file;
72 pte->segment.ofs = ofs;
73 pte->segment.read_bytes = read_bytes;
74 pte->segment.zero_bytes = zero_bytes;
75 pte->segment.writable = writable;
76
77 return page_table_insert (&thread_current ()->page_table, pte);
78}
79
80struct page_table_entry *
81page_table_fetch (struct hash *ht, void *uvaddr)
82{
83 struct page_table_entry pte;
84 struct hash_elem *e;
85
86 pte.uvaddr = uvaddr;
87 e = hash_find (ht, &pte.elem);
88 return ((e != NULL) ? hash_entry (e, struct page_table_entry, elem) : NULL);
89}
90
91bool
92page_load (struct page_table_entry *pte)
93{
94 if (pte->loaded)
95 return true;
96
97 switch (pte->type)
98 {
99 case PAGE_SEGMENT:
100 return page_load_segment (pte);
101 case PAGE_MEMORY_MAPPED_FILE:
102 return page_load_mmf (pte);
103 default:
104 ASSERT (false);
105 break;
106 }
107 return false;
108}
109
110bool
111page_load_segment (struct page_table_entry *pte)
112{
113 struct segment *data = &pte->segment;
114
115 file_seek (data->file, data->ofs);
116
117 /* Get a page of memory. */
118 uint8_t *kpage = palloc_get_page (PAL_USER);
119 if (kpage == NULL)
120 return false;
121
122 /* Load this page. */
123 if (file_read (data->file, kpage, data->read_bytes)
124 != (int) data->read_bytes)
125 {
126 palloc_free_page (kpage);
127 return false;
128 }
129 memset (kpage + data->read_bytes, 0, data->zero_bytes);
130
131 /* Add the page to the process's address space. */
132 if (!process_install_page (pte->uvaddr, kpage, data->writable))
133 {
134 palloc_free_page (kpage);
135 return false;
136 }
137
138 pte->loaded = true;
139 return true;
140}
141
142bool
143page_load_mmf (struct page_table_entry *pte)
144{
145 //TODO: implement
146 return false;
147}
diff --git a/vm/page.h b/vm/page.h
new file mode 100644
index 0000000..29159fb
--- /dev/null
+++ b/vm/page.h
@@ -0,0 +1,41 @@
1#ifndef VM_PAGE_H
2#define VM_PAGE_H
3
4#include <debug.h>
5#include "hash.h"
6#include "filesys/off_t.h"
7
8/* supplemental page table entry */
9struct page_table_entry
10{
11 void *uvaddr;
12 bool loaded;
13 enum
14 {
15 PAGE_SEGMENT,
16 PAGE_MEMORY_MAPPED_FILE,
17 } type;
18
19 union
20 {
21 struct segment
22 {
23 struct file *file;
24 off_t ofs;
25 uint32_t read_bytes;
26 uint32_t zero_bytes;
27 bool writable;
28 } segment;
29 };
30
31 struct hash_elem elem;
32};
33
34void page_table_init (struct hash *ht);
35void page_table_free (struct hash *ht);
36struct page_table_entry *page_table_fetch (struct hash *ht, void *uvaddr);
37bool page_table_insert_segment (struct file *file, off_t ofs, uint8_t *upage,
38 uint32_t read_bytes, uint32_t zero_bytes, bool writable);
39bool page_load (struct page_table_entry *pte);
40
41#endif