diff options
| -rw-r--r-- | Makefile.build | 2 | ||||
| -rw-r--r-- | proj0.txt | 12 | ||||
| -rw-r--r-- | proj1.txt | 18 | ||||
| -rw-r--r-- | threads/synch.c | 8 | ||||
| -rw-r--r-- | threads/thread.c | 2 | ||||
| -rw-r--r-- | threads/thread.h | 3 | ||||
| -rw-r--r-- | userprog/exception.c | 16 | ||||
| -rw-r--r-- | userprog/process.c | 35 | ||||
| -rw-r--r-- | userprog/process.h | 1 | ||||
| -rw-r--r-- | vm/page.c | 147 | ||||
| -rw-r--r-- | vm/page.h | 41 |
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. | |||
| 62 | userprog_SRC += userprog/tss.c # TSS management. | 62 | userprog_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. | 65 | vm_SRC = vm/page.c |
| 66 | 66 | ||
| 67 | # Filesystem code. | 67 | # Filesystem code. |
| 68 | filesys_SRC = filesys/filesys.c # Filesystem core. | 68 | filesys_SRC = filesys/filesys.c # Filesystem core. |
| @@ -35,9 +35,8 @@ Stallings, W. - Operating Systems | |||
| 35 | struct thread: | 35 | struct thread: |
| 36 | int64_t wakeup_tick ...absolute tick when to wake up the thread | 36 | int64_t wakeup_tick ...absolute tick when to wake up the thread |
| 37 | 37 | ||
| 38 | |||
| 39 | timer.c: | 38 | timer.c: |
| 40 | static struct list wakeup_list ...list of processes waiting for an | 39 | static struct list wakeup_list ...list of processes waiting for an |
| 41 | wakeup event and currently put to sleep | 40 | wakeup 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 | ||
| 65 | Each thread has its own variable for saving its sleep period | 64 | Each thread has its own variable for saving its sleep period |
| 66 | therefore no race conditions arise while setting the latter. Furthermore | 65 | therefore no race conditions arise while setting the latter. Furthermore |
| 67 | during the access to the static wakup_list, interrupts are disabled to prevent | 66 | during the access to the static wakup_list, interrupts are disabled to prevent |
| 68 | thread preemption. | 67 | thread 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 | ||
| 164 | It took us about 25 hours to complete this assignment. \ No newline at end of file | 162 | It took us about 25 hours to complete this assignment. |
| @@ -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 | |||
| 25 | http://en.wikipedia.org/wiki/Priority_inversion | 25 | http://en.wikipedia.org/wiki/Priority_inversion |
| 26 | http://hynek.me/studies/sched_ausarbeitung.pdf | 26 | http://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 | |||
| 214 | the thread structure. Thus we simply sort the whole list inside sema_up()/ | 214 | the thread structure. Thus we simply sort the whole list inside sema_up()/ |
| 215 | cond_signal() before unblocking the next thread. | 215 | cond_signal() before unblocking the next thread. |
| 216 | 216 | ||
| 217 | SURVEY QUESTIONS | 217 | SURVEY QUESTIONS |
| 218 | ================ | 218 | ================ |
| 219 | 219 | ||
| 220 | Answering these questions is optional, but it will help us improve the | 220 | Answering these questions is optional, but it will help us improve the |
| 221 | course in future quarters. Feel free to tell us anything you | 221 | course 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 | ||
| 35 | static bool lock_priority_cmp_greater(const struct list_elem *a, const struct list_elem *b, | 35 | static bool lock_priority_cmp_greater (const struct list_elem *a, const struct list_elem *b, |
| 36 | void *AUX UNUSED); | 36 | void *AUX UNUSED); |
| 37 | static bool semaphore_priority_cmp_greater(const struct list_elem *a, const struct list_elem *b, | 37 | static 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. */ |
| 204 | static bool | 204 | static bool |
| 205 | lock_priority_cmp_greater(const struct list_elem *a, const struct list_elem *b, | 205 | lock_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. */ |
| 357 | static bool | 357 | static bool |
| 358 | semaphore_priority_cmp_greater(const struct list_elem *a, const struct list_elem *b, | 358 | semaphore_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. */ |
| 75 | bool | 75 | bool |
| 76 | thread_priority_cmp_greater(const struct list_elem *a, const struct list_elem *b, | 76 | thread_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. */ |
| 10 | static long long page_fault_cnt; | 11 | static 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". */ |
| 123 | static void | 124 | static void |
| 124 | page_fault (struct intr_frame *f) | 125 | page_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 */ |
| 23 | struct start_aux_data { | 24 | struct 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 | ||
| 481 | static 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. */ |
| 485 | static bool | 488 | static 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. */ |
| 709 | static bool | 698 | bool |
| 710 | install_page (void *upage, void *kpage, bool writable) | 699 | process_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); | |||
| 37 | int process_wait (tid_t); | 37 | int process_wait (tid_t); |
| 38 | void process_exit (void); | 38 | void process_exit (void); |
| 39 | void process_activate (void); | 39 | void process_activate (void); |
| 40 | bool process_install_page (void *upage, void *kpage, bool writable); | ||
| 40 | 41 | ||
| 41 | int process_open_file(const char* fname); | 42 | int process_open_file(const char* fname); |
| 42 | struct file* process_get_file(int fd); | 43 | struct 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 | |||
| 9 | static void page_table_entry_free (struct hash_elem *e, void *aux UNUSED); | ||
| 10 | static unsigned page_table_hash (const struct hash_elem *e, void *aux UNUSED); | ||
| 11 | static bool page_table_cmp_less (const struct hash_elem *a, const struct hash_elem *b, | ||
| 12 | void *aux UNUSED); | ||
| 13 | static bool page_table_insert (struct hash *ht, struct page_table_entry *pte); | ||
| 14 | static bool page_load_segment (struct page_table_entry *pte); | ||
| 15 | static bool page_load_mmf (struct page_table_entry *pte); | ||
| 16 | |||
| 17 | void | ||
| 18 | page_table_init (struct hash *ht) | ||
| 19 | { | ||
| 20 | hash_init (ht, page_table_hash, page_table_cmp_less, NULL); | ||
| 21 | } | ||
| 22 | |||
| 23 | unsigned | ||
| 24 | page_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 | |||
| 30 | bool | ||
| 31 | page_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 | |||
| 39 | void | ||
| 40 | page_table_free (struct hash *ht) | ||
| 41 | { | ||
| 42 | hash_destroy (ht, page_table_entry_free); | ||
| 43 | } | ||
| 44 | |||
| 45 | void | ||
| 46 | page_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 | |||
| 52 | bool | ||
| 53 | page_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 | |||
| 60 | bool | ||
| 61 | page_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 | |||
| 80 | struct page_table_entry * | ||
| 81 | page_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 | |||
| 91 | bool | ||
| 92 | page_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 | |||
| 110 | bool | ||
| 111 | page_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 | |||
| 142 | bool | ||
| 143 | page_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 */ | ||
| 9 | struct 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 | |||
| 34 | void page_table_init (struct hash *ht); | ||
| 35 | void page_table_free (struct hash *ht); | ||
| 36 | struct page_table_entry *page_table_fetch (struct hash *ht, void *uvaddr); | ||
| 37 | bool page_table_insert_segment (struct file *file, off_t ofs, uint8_t *upage, | ||
| 38 | uint32_t read_bytes, uint32_t zero_bytes, bool writable); | ||
| 39 | bool page_load (struct page_table_entry *pte); | ||
| 40 | |||
| 41 | #endif | ||
