diff options
| -rw-r--r-- | proj2.txt | 137 | ||||
| -rw-r--r-- | threads/thread.h | 2 | ||||
| -rw-r--r-- | userprog/exception.c | 80 | ||||
| -rw-r--r-- | userprog/process.c | 54 | ||||
| -rw-r--r-- | userprog/process.h | 3 | ||||
| -rw-r--r-- | userprog/syscall.c | 9 | ||||
| -rw-r--r-- | userprog/syscall.h | 2 | ||||
| -rw-r--r-- | vm/page.c | 76 | ||||
| -rw-r--r-- | vm/page.h | 35 |
9 files changed, 300 insertions, 98 deletions
diff --git a/proj2.txt b/proj2.txt new file mode 100644 index 0000000..5405336 --- /dev/null +++ b/proj2.txt | |||
| @@ -0,0 +1,137 @@ | |||
| 1 | +---------------------------+ | ||
| 2 | | ProgOS | | ||
| 3 | | PROJECT 2: VIRTUAL MEMORY | | ||
| 4 | | DESIGN DOCUMENT | | ||
| 5 | +---------------------------+ | ||
| 6 | |||
| 7 | ---- GROUP ---- | ||
| 8 | |||
| 9 | >> Fill in the names and email addresses of your group members. | ||
| 10 | |||
| 11 | Peter Ketscher <e9651415@mail.student.tuwien.ac.at> | ||
| 12 | Karoline Knoth <e0326266@student.tuwien.ac.at> | ||
| 13 | Manuel Mausz <manuel-uni@mausz.at> | ||
| 14 | |||
| 15 | ---- PRELIMINARIES ---- | ||
| 16 | |||
| 17 | >> If you have any preliminary comments on your submission, notes for the | ||
| 18 | >> TAs, or extra credit, please give them here. | ||
| 19 | |||
| 20 | >> Please cite any offline or online sources you consulted while | ||
| 21 | >> preparing your submission, other than the Pintos documentation, course | ||
| 22 | >> text, lecture notes, and course staff. | ||
| 23 | |||
| 24 | PAGE TABLE MANAGEMENT | ||
| 25 | ===================== | ||
| 26 | ---- DATA STRUCTURES ---- | ||
| 27 | |||
| 28 | >> A1: Copy here the declaration of each new or changed `struct' or | ||
| 29 | >> `struct' member, global or static variable, `typedef', or | ||
| 30 | >> enumeration. Identify the purpose of each in 25 words or less. | ||
| 31 | |||
| 32 | struct thread: | ||
| 33 | struct hash page_table ...page table of thread | ||
| 34 | |||
| 35 | struct page_table_entry: | ||
| 36 | void *upage ...virtual address of page | ||
| 37 | bool loaded ...indicates if page is loaded | ||
| 38 | enum type ...type of page | ||
| 39 | union struct segment ...structure needed for lazy loading of data segments | ||
| 40 | struct hash_elem elem ...Hash element. | ||
| 41 | |||
| 42 | ---- IMPLEMENTATION ---- | ||
| 43 | >> A2: Describe how you implemented lazy page loading. How do you | ||
| 44 | >> determine the file and file offset corresponding to a virtual | ||
| 45 | >> address? | ||
| 46 | |||
| 47 | TODO | ||
| 48 | |||
| 49 | ---- SYNCHRONIZATION ---- | ||
| 50 | >> A3: How do you deal with or prevent page faults in file system | ||
| 51 | >> routines. Argue why your solution is deadlock free. | ||
| 52 | |||
| 53 | TODO | ||
| 54 | |||
| 55 | STACK GROWTH | ||
| 56 | ============ | ||
| 57 | |||
| 58 | ---- DATA STRUCTURES ---- | ||
| 59 | |||
| 60 | >> B1: Copy here the declaration of each new or changed `struct' or | ||
| 61 | >> `struct' member, global or static variable, `typedef', or | ||
| 62 | >> enumeration. Identify the purpose of each in 25 words or less. | ||
| 63 | |||
| 64 | extern void *syscall_sp ...stored stack pointer for the "page fault inside | ||
| 65 | syscall/kernel"-case | ||
| 66 | |||
| 67 | ---- IMPLEMENTATION ---- | ||
| 68 | >> B2: Describe how you integrated the (potentially growing) stack segment | ||
| 69 | >> into your page table management implementation. | ||
| 70 | |||
| 71 | TODO | ||
| 72 | |||
| 73 | ---- ALGORITHMS ---- | ||
| 74 | >> B3: Explain how you detect a page fault which should trigger a | ||
| 75 | >> stack growth. What asssumptions are needed for your implementation | ||
| 76 | >> to work? | ||
| 77 | |||
| 78 | TODO | ||
| 79 | |||
| 80 | MEMORY MAPPED FILES | ||
| 81 | =================== | ||
| 82 | |||
| 83 | ---- DATA STRUCTURES ---- | ||
| 84 | |||
| 85 | >> C1: Copy here the declaration of each new or changed `struct' or | ||
| 86 | >> `struct' member, global or static variable, `typedef', or | ||
| 87 | >> enumeration. Identify the purpose of each in 25 words or less. | ||
| 88 | |||
| 89 | struct page_table_entry: | ||
| 90 | union struct TODO ...structure needed for loading of memory mapped files | ||
| 91 | |||
| 92 | ---- ALGORITHMS ---- | ||
| 93 | |||
| 94 | >> C2: Describe how memory mapped files integrate into your virtual | ||
| 95 | >> memory subsystem. | ||
| 96 | |||
| 97 | TODO | ||
| 98 | |||
| 99 | >> C3: Explain how you determine whether a new file mapping overlaps | ||
| 100 | >> any existing segment. | ||
| 101 | |||
| 102 | TODO | ||
| 103 | |||
| 104 | ---- RATIONALE ---- | ||
| 105 | |||
| 106 | >> C4: Mappings created with "mmap" have similar semantics to those of | ||
| 107 | >> data demand-paged from executables, except that "mmap" mappings are | ||
| 108 | >> written back to their original files, not to swap. This implies | ||
| 109 | >> that much of their implementation can be shared. Explain why your | ||
| 110 | >> implementation either does or does not share much of the code for | ||
| 111 | >> the two situations. | ||
| 112 | |||
| 113 | TODO | ||
| 114 | |||
| 115 | SURVEY QUESTIONS | ||
| 116 | ================ | ||
| 117 | |||
| 118 | Answering these questions is optional, but it will help us improve the | ||
| 119 | course in future quarters. Feel free to tell us anything you | ||
| 120 | want--these questions are just to spur your thoughts. You may also | ||
| 121 | choose to respond anonymously in the course evaluations at the end of | ||
| 122 | the quarter. | ||
| 123 | |||
| 124 | >> In your opinion, was this assignment, or any one of the three problems | ||
| 125 | >> in it, too easy or too hard? Did it take too long or too little time? | ||
| 126 | |||
| 127 | >> Did you find that working on a particular part of the assignment gave | ||
| 128 | >> you greater insight into some aspect of OS design? | ||
| 129 | |||
| 130 | >> Is there some particular fact or hint we should give students in | ||
| 131 | >> future quarters to help them solve the problems? Conversely, did you | ||
| 132 | >> find any of our guidance to be misleading? | ||
| 133 | |||
| 134 | >> Do you have any suggestions for the TAs to more effectively assist | ||
| 135 | >> students, either for future quarters or the remaining projects? | ||
| 136 | |||
| 137 | >> Any other comments? | ||
diff --git a/threads/thread.h b/threads/thread.h index 293d14f..ed591f4 100644 --- a/threads/thread.h +++ b/threads/thread.h | |||
| @@ -114,7 +114,7 @@ struct thread | |||
| 114 | struct list locks; /* list of locks the thread currently holds */ | 114 | struct list locks; /* list of locks the thread currently holds */ |
| 115 | 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 | 116 | ||
| 117 | struct hash page_table; | 117 | struct hash page_table; /* page table of thread */ |
| 118 | }; | 118 | }; |
| 119 | 119 | ||
| 120 | /* 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 54621fa..debe7f0 100644 --- a/userprog/exception.c +++ b/userprog/exception.c | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | #include <inttypes.h> | 2 | #include <inttypes.h> |
| 3 | #include <stdio.h> | 3 | #include <stdio.h> |
| 4 | #include "userprog/gdt.h" | 4 | #include "userprog/gdt.h" |
| 5 | #include "userprog/process.h" | ||
| 6 | #include "userprog/syscall.h" | ||
| 5 | #include "threads/interrupt.h" | 7 | #include "threads/interrupt.h" |
| 6 | #include "threads/thread.h" | 8 | #include "threads/thread.h" |
| 7 | #include "threads/vaddr.h" | 9 | #include "threads/vaddr.h" |
| @@ -128,7 +130,8 @@ page_fault (struct intr_frame *f) | |||
| 128 | bool write; /* True: access was write, false: access was read. */ | 130 | bool write; /* True: access was write, false: access was read. */ |
| 129 | bool user; /* True: access by user, false: access by kernel. */ | 131 | bool user; /* True: access by user, false: access by kernel. */ |
| 130 | void *fault_addr; /* Fault address. */ | 132 | void *fault_addr; /* Fault address. */ |
| 131 | struct page_table_entry *pte; | 133 | void *sp; /* Stack pointer. */ |
| 134 | struct page_table_entry *pte; /* Page table entry. */ | ||
| 132 | 135 | ||
| 133 | /* Obtain faulting address, the virtual address that was | 136 | /* Obtain faulting address, the virtual address that was |
| 134 | accessed to cause the fault. It may point to code or to | 137 | accessed to cause the fault. It may point to code or to |
| @@ -151,38 +154,57 @@ page_fault (struct intr_frame *f) | |||
| 151 | write = (f->error_code & PF_W) != 0; | 154 | write = (f->error_code & PF_W) != 0; |
| 152 | user = (f->error_code & PF_U) != 0; | 155 | user = (f->error_code & PF_U) != 0; |
| 153 | 156 | ||
| 154 | /* To implement virtual memory, adapt the rest of the function | 157 | /* accessing r/o page is always wrong */ |
| 155 | body, adding code that brings in the page to | 158 | if (!not_present) |
| 156 | which fault_addr refers. */ | 159 | thread_exit (); |
| 157 | if (is_user_vaddr(fault_addr)) { | 160 | |
| 158 | pte = page_table_fetch (&thread_current ()->page_table, pg_round_down (fault_addr)); | 161 | if (is_user_vaddr (fault_addr)) |
| 159 | if (pte != NULL) | ||
| 160 | page_load (pte); | ||
| 161 | else | ||
| 162 | { | 162 | { |
| 163 | printf ("Page fault %p\n", pte); | 163 | /* if page fault occurs during syscall, use saved stack pointer */ |
| 164 | kill (f); | 164 | sp = (!user) ? syscall_sp : f->esp; |
| 165 | } | 165 | |
| 166 | /* try to fetch page entry */ | ||
| 167 | pte = page_table_fetch (&thread_current ()->page_table, | ||
| 168 | pg_round_down (fault_addr)); | ||
| 169 | |||
| 170 | /* we got a page entry so try to load the page */ | ||
| 171 | if (pte != NULL) | ||
| 172 | { | ||
| 173 | if (page_load (pte)) | ||
| 174 | return; | ||
| 175 | printf ("Unable to load page at %p in %s context.\n", | ||
| 176 | fault_addr, user ? "user" : "kernel"); | ||
| 177 | } | ||
| 178 | /* there's no page in our page table but we might still have an valid | ||
| 179 | stack access and need to expand our stack. so just check for that. | ||
| 180 | the maxium offset we consider as a valid access is caused by the PUSHA | ||
| 181 | instruction. it's 32 bytes below the current stack pointer */ | ||
| 182 | else if (fault_addr >= (sp - 32) && (PHYS_BASE - fault_addr) <= STACK_SIZE) | ||
| 183 | { | ||
| 184 | if (process_grow_stack (pg_round_down (fault_addr))) | ||
| 185 | return; | ||
| 186 | printf ("Unable to grow stack %p in %s context.\n", | ||
| 187 | fault_addr, user ? "user" : "kernel"); | ||
| 188 | } | ||
| 166 | 189 | ||
| 167 | //TODO | ||
| 168 | #if 0 | ||
| 169 | if (! user) { | ||
| 170 | /* syscall exception; set eax and eip */ | 190 | /* syscall exception; set eax and eip */ |
| 171 | f->eip = (void*)f->eax; | 191 | if (!user) |
| 172 | f->eax = 0xFFFFFFFF; | 192 | { |
| 173 | return; | 193 | f->eip = (void*)f->eax; |
| 174 | } else { | 194 | f->eax = 0xFFFFFFFF; |
| 195 | return; | ||
| 196 | } | ||
| 197 | |||
| 175 | /* user process access violation */ | 198 | /* user process access violation */ |
| 176 | thread_exit(); | 199 | thread_exit (); |
| 200 | return; | ||
| 177 | } | 201 | } |
| 178 | #endif | 202 | |
| 179 | } else { | 203 | 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", | 204 | fault_addr, |
| 181 | fault_addr, | 205 | not_present ? "not present" : "rights violation", |
| 182 | not_present ? "not present" : "rights violation", | 206 | write ? "writing" : "reading", |
| 183 | write ? "writing" : "reading", | 207 | user ? "user" : "kernel"); |
| 184 | user ? "user" : "kernel"); | 208 | kill (f); |
| 185 | kill (f); | ||
| 186 | } | ||
| 187 | } | 209 | } |
| 188 | 210 | ||
diff --git a/userprog/process.c b/userprog/process.c index 15883d9..2771e76 100644 --- a/userprog/process.c +++ b/userprog/process.c | |||
| @@ -552,24 +552,24 @@ load_segment (struct file *file, off_t ofs, uint8_t *upage, | |||
| 552 | 552 | ||
| 553 | file_seek (file, ofs); | 553 | file_seek (file, ofs); |
| 554 | while (read_bytes > 0 || zero_bytes > 0) | 554 | while (read_bytes > 0 || zero_bytes > 0) |
| 555 | { | 555 | { |
| 556 | /* Calculate how to fill this page. | 556 | /* Calculate how to fill this page. |
| 557 | We will read PAGE_READ_BYTES bytes from FILE | 557 | We will read PAGE_READ_BYTES bytes from FILE |
| 558 | and zero the final PAGE_ZERO_BYTES bytes. */ | 558 | and zero the final PAGE_ZERO_BYTES bytes. */ |
| 559 | size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE; | 559 | size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE; |
| 560 | size_t page_zero_bytes = PGSIZE - page_read_bytes; | 560 | size_t page_zero_bytes = PGSIZE - page_read_bytes; |
| 561 | 561 | ||
| 562 | /* add segment to page table for on demand loading */ | 562 | /* add segment to page table for on demand loading */ |
| 563 | if (!page_table_insert_segment (file, ofs, upage, page_read_bytes, | 563 | if (!page_table_insert_segment (file, ofs, upage, page_read_bytes, |
| 564 | page_zero_bytes, writable)) | 564 | page_zero_bytes, writable)) |
| 565 | return false; | 565 | return false; |
| 566 | 566 | ||
| 567 | /* Advance. */ | 567 | /* Advance. */ |
| 568 | read_bytes -= page_read_bytes; | 568 | read_bytes -= page_read_bytes; |
| 569 | zero_bytes -= page_zero_bytes; | 569 | zero_bytes -= page_zero_bytes; |
| 570 | ofs += page_read_bytes; | 570 | ofs += page_read_bytes; |
| 571 | upage += PGSIZE; | 571 | upage += PGSIZE; |
| 572 | } | 572 | } |
| 573 | return true; | 573 | return true; |
| 574 | } | 574 | } |
| 575 | 575 | ||
| @@ -686,6 +686,24 @@ setup_stack (uint32_t **esp, const char *args) | |||
| 686 | return true; | 686 | return true; |
| 687 | } | 687 | } |
| 688 | 688 | ||
| 689 | /* expand the stack of the process by one new page | ||
| 690 | which will be installed at the address of UPAGE */ | ||
| 691 | bool | ||
| 692 | process_grow_stack (void *upage) | ||
| 693 | { | ||
| 694 | uint8_t *kpage = palloc_get_page (PAL_USER | PAL_ZERO); | ||
| 695 | if (kpage == NULL) | ||
| 696 | return false; | ||
| 697 | |||
| 698 | if (!process_install_page (upage, kpage, true)) | ||
| 699 | { | ||
| 700 | palloc_free_page (kpage); | ||
| 701 | return false; | ||
| 702 | } | ||
| 703 | |||
| 704 | return true; | ||
| 705 | } | ||
| 706 | |||
| 689 | /* Adds a mapping from user virtual address UPAGE to kernel | 707 | /* Adds a mapping from user virtual address UPAGE to kernel |
| 690 | virtual address KPAGE to the page table. | 708 | virtual address KPAGE to the page table. |
| 691 | If WRITABLE is true, the user process may modify the page; | 709 | If WRITABLE is true, the user process may modify the page; |
diff --git a/userprog/process.h b/userprog/process.h index b7bca5d..ccb94cb 100644 --- a/userprog/process.h +++ b/userprog/process.h | |||
| @@ -3,6 +3,8 @@ | |||
| 3 | 3 | ||
| 4 | #include "threads/thread.h" | 4 | #include "threads/thread.h" |
| 5 | 5 | ||
| 6 | #define STACK_SIZE (1 << 23) /* 8MB maxiumum stack size */ | ||
| 7 | |||
| 6 | /* In the current implementation, the capacity is fixed to 1024 (PGSIZE/4) */ | 8 | /* In the current implementation, the capacity is fixed to 1024 (PGSIZE/4) */ |
| 7 | struct fd_table { | 9 | struct fd_table { |
| 8 | struct file** fds; | 10 | struct file** fds; |
| @@ -37,6 +39,7 @@ tid_t process_execute (const char *file_name); | |||
| 37 | int process_wait (tid_t); | 39 | int process_wait (tid_t); |
| 38 | void process_exit (void); | 40 | void process_exit (void); |
| 39 | void process_activate (void); | 41 | void process_activate (void); |
| 42 | bool process_grow_stack (void *upage); | ||
| 40 | bool process_install_page (void *upage, void *kpage, bool writable); | 43 | bool process_install_page (void *upage, void *kpage, bool writable); |
| 41 | 44 | ||
| 42 | int process_open_file(const char* fname); | 45 | int process_open_file(const char* fname); |
diff --git a/userprog/syscall.c b/userprog/syscall.c index f8e0197..541668d 100644 --- a/userprog/syscall.c +++ b/userprog/syscall.c | |||
| @@ -17,6 +17,9 @@ | |||
| 17 | 17 | ||
| 18 | #define STACK_SLOT_SIZE sizeof(int) | 18 | #define STACK_SLOT_SIZE sizeof(int) |
| 19 | 19 | ||
| 20 | /* stored stack pointer for the "page fault inside syscall/kernel"-case */ | ||
| 21 | void *syscall_sp; | ||
| 22 | |||
| 20 | /* Prototypes for Utilities */ | 23 | /* Prototypes for Utilities */ |
| 21 | static int get_user (const uint8_t *uaddr); | 24 | static int get_user (const uint8_t *uaddr); |
| 22 | static bool put_user (uint8_t *udst, uint8_t byte); | 25 | static bool put_user (uint8_t *udst, uint8_t byte); |
| @@ -195,10 +198,10 @@ syscall_handler (struct intr_frame *f) | |||
| 195 | handler* fp; | 198 | handler* fp; |
| 196 | bool segfault = false; | 199 | bool segfault = false; |
| 197 | int result; | 200 | int result; |
| 198 | void *sp = f->esp; | 201 | syscall_sp = f->esp; |
| 199 | 202 | ||
| 200 | /* The system call number and the arguments are on the stack */ | 203 | /* The system call number and the arguments are on the stack */ |
| 201 | if (! copy_from_user (&syscall_nr,sp)) | 204 | if (! copy_from_user (&syscall_nr,syscall_sp)) |
| 202 | goto fail; | 205 | goto fail; |
| 203 | switch (syscall_nr) { | 206 | switch (syscall_nr) { |
| 204 | case SYS_HALT: fp = syscall_halt; break; | 207 | case SYS_HALT: fp = syscall_halt; break; |
| @@ -217,7 +220,7 @@ syscall_handler (struct intr_frame *f) | |||
| 217 | default: | 220 | default: |
| 218 | goto fail; | 221 | goto fail; |
| 219 | } | 222 | } |
| 220 | result = fp (sp, &segfault); | 223 | result = fp (syscall_sp, &segfault); |
| 221 | if (segfault) | 224 | if (segfault) |
| 222 | goto fail; | 225 | goto fail; |
| 223 | f->eax = result; | 226 | f->eax = result; |
diff --git a/userprog/syscall.h b/userprog/syscall.h index f7ab2f3..987ceaa 100644 --- a/userprog/syscall.h +++ b/userprog/syscall.h | |||
| @@ -2,4 +2,6 @@ | |||
| 2 | #define USERPROG_SYSCALL_H | 2 | #define USERPROG_SYSCALL_H |
| 3 | 3 | ||
| 4 | void syscall_init (void); | 4 | void syscall_init (void); |
| 5 | extern void *syscall_sp; | ||
| 6 | |||
| 5 | #endif /* userprog/syscall.h */ | 7 | #endif /* userprog/syscall.h */ |
| @@ -6,50 +6,59 @@ | |||
| 6 | #include "threads/palloc.h" | 6 | #include "threads/palloc.h" |
| 7 | #include "vm/page.h" | 7 | #include "vm/page.h" |
| 8 | 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); | 9 | 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, | 10 | static bool page_table_cmp_less (const struct hash_elem *a, const struct hash_elem *b, |
| 12 | void *aux UNUSED); | 11 | void *aux UNUSED); |
| 12 | static void page_table_entry_free (struct hash_elem *e, void *aux UNUSED); | ||
| 13 | static bool page_table_insert (struct hash *ht, struct page_table_entry *pte); | 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); | 14 | static bool page_load_segment (struct page_table_entry *pte); |
| 15 | static bool page_load_mmf (struct page_table_entry *pte); | 15 | static bool page_load_mmf (struct page_table_entry *pte); |
| 16 | 16 | ||
| 17 | /* initialize page table structure */ | ||
| 17 | void | 18 | void |
| 18 | page_table_init (struct hash *ht) | 19 | page_table_init (struct hash *ht) |
| 19 | { | 20 | { |
| 20 | hash_init (ht, page_table_hash, page_table_cmp_less, NULL); | 21 | hash_init (ht, page_table_hash, page_table_cmp_less, NULL); |
| 21 | } | 22 | } |
| 22 | 23 | ||
| 23 | unsigned | 24 | /* calulcates and returns the hash used as key of the hash/page table */ |
| 25 | static unsigned | ||
| 24 | page_table_hash (const struct hash_elem *e, void *aux UNUSED) | 26 | page_table_hash (const struct hash_elem *e, void *aux UNUSED) |
| 25 | { | 27 | { |
| 26 | const struct page_table_entry *pte = hash_entry (e, struct page_table_entry, elem); | 28 | const struct page_table_entry *pte = hash_entry (e, struct page_table_entry, elem); |
| 27 | return hash_bytes (&pte->uvaddr, sizeof pte->uvaddr); | 29 | return hash_bytes (&pte->upage, sizeof pte->upage); |
| 28 | } | 30 | } |
| 29 | 31 | ||
| 30 | bool | 32 | /* page table comperator needed by the hash table implementation |
| 33 | returns true if A is less than B, or false if A is greater than | ||
| 34 | or equal to B */ | ||
| 35 | static bool | ||
| 31 | page_table_cmp_less (const struct hash_elem *a, const struct hash_elem *b, | 36 | page_table_cmp_less (const struct hash_elem *a, const struct hash_elem *b, |
| 32 | void *aux UNUSED) | 37 | void *aux UNUSED) |
| 33 | { | 38 | { |
| 34 | const struct page_table_entry *pte1 = hash_entry (a, struct page_table_entry, elem); | 39 | 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); | 40 | const struct page_table_entry *pte2 = hash_entry (b, struct page_table_entry, elem); |
| 36 | return (pte1->uvaddr < pte2->uvaddr); | 41 | return (pte1->upage < pte2->upage); |
| 37 | } | 42 | } |
| 38 | 43 | ||
| 44 | /* frees the content of page table */ | ||
| 39 | void | 45 | void |
| 40 | page_table_free (struct hash *ht) | 46 | page_table_free (struct hash *ht) |
| 41 | { | 47 | { |
| 42 | hash_destroy (ht, page_table_entry_free); | 48 | hash_destroy (ht, page_table_entry_free); |
| 43 | } | 49 | } |
| 44 | 50 | ||
| 45 | void | 51 | /* frees a single page table entry */ |
| 52 | static void | ||
| 46 | page_table_entry_free (struct hash_elem *e, void *aux UNUSED) | 53 | page_table_entry_free (struct hash_elem *e, void *aux UNUSED) |
| 47 | { | 54 | { |
| 48 | struct page_table_entry *pte = hash_entry (e, struct page_table_entry, elem); | 55 | struct page_table_entry *pte = hash_entry (e, struct page_table_entry, elem); |
| 49 | free (pte); | 56 | free (pte); |
| 50 | } | 57 | } |
| 51 | 58 | ||
| 52 | bool | 59 | /* inserts a new entry into the page table |
| 60 | returns false if entry is invalid or already in the table */ | ||
| 61 | static bool | ||
| 53 | page_table_insert (struct hash *ht, struct page_table_entry *pte) | 62 | page_table_insert (struct hash *ht, struct page_table_entry *pte) |
| 54 | { | 63 | { |
| 55 | if (pte == NULL) | 64 | if (pte == NULL) |
| @@ -57,6 +66,8 @@ page_table_insert (struct hash *ht, struct page_table_entry *pte) | |||
| 57 | return (hash_insert (ht, &pte->elem) == NULL); | 66 | return (hash_insert (ht, &pte->elem) == NULL); |
| 58 | } | 67 | } |
| 59 | 68 | ||
| 69 | /* inserts a new entry of type segment into the page table | ||
| 70 | returns false if entry is invalid or already in the table */ | ||
| 60 | bool | 71 | bool |
| 61 | page_table_insert_segment (struct file *file, off_t ofs, uint8_t *upage, | 72 | page_table_insert_segment (struct file *file, off_t ofs, uint8_t *upage, |
| 62 | uint32_t read_bytes, uint32_t zero_bytes, bool writable) | 73 | uint32_t read_bytes, uint32_t zero_bytes, bool writable) |
| @@ -65,7 +76,7 @@ page_table_insert_segment (struct file *file, off_t ofs, uint8_t *upage, | |||
| 65 | if (pte == NULL) | 76 | if (pte == NULL) |
| 66 | return false; | 77 | return false; |
| 67 | 78 | ||
| 68 | pte->uvaddr = upage; | 79 | pte->upage = upage; |
| 69 | pte->type = PAGE_SEGMENT; | 80 | pte->type = PAGE_SEGMENT; |
| 70 | pte->loaded = false; | 81 | pte->loaded = false; |
| 71 | pte->segment.file = file; | 82 | pte->segment.file = file; |
| @@ -77,17 +88,20 @@ page_table_insert_segment (struct file *file, off_t ofs, uint8_t *upage, | |||
| 77 | return page_table_insert (&thread_current ()->page_table, pte); | 88 | return page_table_insert (&thread_current ()->page_table, pte); |
| 78 | } | 89 | } |
| 79 | 90 | ||
| 91 | /* fetch an entry from the page table. returns NULL if not found */ | ||
| 80 | struct page_table_entry * | 92 | struct page_table_entry * |
| 81 | page_table_fetch (struct hash *ht, void *uvaddr) | 93 | page_table_fetch (struct hash *ht, void *upage) |
| 82 | { | 94 | { |
| 83 | struct page_table_entry pte; | 95 | struct page_table_entry pte; |
| 84 | struct hash_elem *e; | 96 | struct hash_elem *e; |
| 85 | 97 | ||
| 86 | pte.uvaddr = uvaddr; | 98 | pte.upage = upage; |
| 87 | e = hash_find (ht, &pte.elem); | 99 | e = hash_find (ht, &pte.elem); |
| 88 | return ((e != NULL) ? hash_entry (e, struct page_table_entry, elem) : NULL); | 100 | return ((e != NULL) ? hash_entry (e, struct page_table_entry, elem) : NULL); |
| 89 | } | 101 | } |
| 90 | 102 | ||
| 103 | /* load the page referenced by the page table entry | ||
| 104 | returns true on success or already loaded, false otherwise */ | ||
| 91 | bool | 105 | bool |
| 92 | page_load (struct page_table_entry *pte) | 106 | page_load (struct page_table_entry *pte) |
| 93 | { | 107 | { |
| @@ -95,19 +109,20 @@ page_load (struct page_table_entry *pte) | |||
| 95 | return true; | 109 | return true; |
| 96 | 110 | ||
| 97 | switch (pte->type) | 111 | switch (pte->type) |
| 98 | { | 112 | { |
| 99 | case PAGE_SEGMENT: | 113 | case PAGE_SEGMENT: |
| 100 | return page_load_segment (pte); | 114 | return page_load_segment (pte); |
| 101 | case PAGE_MEMORY_MAPPED_FILE: | 115 | case PAGE_MEMORY_MAPPED_FILE: |
| 102 | return page_load_mmf (pte); | 116 | return page_load_mmf (pte); |
| 103 | default: | 117 | default: |
| 104 | ASSERT (false); | 118 | ASSERT (false); |
| 105 | break; | 119 | break; |
| 106 | } | 120 | } |
| 107 | return false; | 121 | return false; |
| 108 | } | 122 | } |
| 109 | 123 | ||
| 110 | bool | 124 | /* load the segment data page */ |
| 125 | static bool | ||
| 111 | page_load_segment (struct page_table_entry *pte) | 126 | page_load_segment (struct page_table_entry *pte) |
| 112 | { | 127 | { |
| 113 | struct segment *data = &pte->segment; | 128 | struct segment *data = &pte->segment; |
| @@ -122,24 +137,25 @@ page_load_segment (struct page_table_entry *pte) | |||
| 122 | /* Load this page. */ | 137 | /* Load this page. */ |
| 123 | if (file_read (data->file, kpage, data->read_bytes) | 138 | if (file_read (data->file, kpage, data->read_bytes) |
| 124 | != (int) data->read_bytes) | 139 | != (int) data->read_bytes) |
| 125 | { | 140 | { |
| 126 | palloc_free_page (kpage); | 141 | palloc_free_page (kpage); |
| 127 | return false; | 142 | return false; |
| 128 | } | 143 | } |
| 129 | memset (kpage + data->read_bytes, 0, data->zero_bytes); | 144 | memset (kpage + data->read_bytes, 0, data->zero_bytes); |
| 130 | 145 | ||
| 131 | /* Add the page to the process's address space. */ | 146 | /* Add the page to the process's address space. */ |
| 132 | if (!process_install_page (pte->uvaddr, kpage, data->writable)) | 147 | if (!process_install_page (pte->upage, kpage, data->writable)) |
| 133 | { | 148 | { |
| 134 | palloc_free_page (kpage); | 149 | palloc_free_page (kpage); |
| 135 | return false; | 150 | return false; |
| 136 | } | 151 | } |
| 137 | 152 | ||
| 138 | pte->loaded = true; | 153 | pte->loaded = true; |
| 139 | return true; | 154 | return true; |
| 140 | } | 155 | } |
| 141 | 156 | ||
| 142 | bool | 157 | /* load the memory mappged file page */ |
| 158 | static bool | ||
| 143 | page_load_mmf (struct page_table_entry *pte) | 159 | page_load_mmf (struct page_table_entry *pte) |
| 144 | { | 160 | { |
| 145 | //TODO: implement | 161 | //TODO: implement |
| @@ -8,32 +8,33 @@ | |||
| 8 | /* supplemental page table entry */ | 8 | /* supplemental page table entry */ |
| 9 | struct page_table_entry | 9 | struct page_table_entry |
| 10 | { | 10 | { |
| 11 | void *uvaddr; | 11 | void *upage; /* virtual address of page */ |
| 12 | bool loaded; | 12 | bool loaded; /* indicates if page is loaded */ |
| 13 | enum | 13 | enum |
| 14 | { | 14 | { |
| 15 | PAGE_SEGMENT, | 15 | PAGE_SEGMENT, |
| 16 | PAGE_MEMORY_MAPPED_FILE, | 16 | PAGE_MEMORY_MAPPED_FILE, |
| 17 | } type; | 17 | } type; /* type of page */ |
| 18 | 18 | ||
| 19 | union | 19 | union |
| 20 | { | ||
| 21 | struct segment | ||
| 22 | { | 20 | { |
| 23 | struct file *file; | 21 | /* structure needed for lazy loading of data segments */ |
| 24 | off_t ofs; | 22 | struct segment |
| 25 | uint32_t read_bytes; | 23 | { |
| 26 | uint32_t zero_bytes; | 24 | struct file *file; |
| 27 | bool writable; | 25 | off_t ofs; |
| 28 | } segment; | 26 | uint32_t read_bytes; |
| 29 | }; | 27 | uint32_t zero_bytes; |
| 28 | bool writable; | ||
| 29 | } segment; | ||
| 30 | }; | ||
| 30 | 31 | ||
| 31 | struct hash_elem elem; | 32 | struct hash_elem elem; /* Hash element. */ |
| 32 | }; | 33 | }; |
| 33 | 34 | ||
| 34 | void page_table_init (struct hash *ht); | 35 | void page_table_init (struct hash *ht); |
| 35 | void page_table_free (struct hash *ht); | 36 | void page_table_free (struct hash *ht); |
| 36 | struct page_table_entry *page_table_fetch (struct hash *ht, void *uvaddr); | 37 | struct page_table_entry *page_table_fetch (struct hash *ht, void *upage); |
| 37 | bool page_table_insert_segment (struct file *file, off_t ofs, uint8_t *upage, | 38 | 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 | uint32_t read_bytes, uint32_t zero_bytes, bool writable); |
| 39 | bool page_load (struct page_table_entry *pte); | 40 | bool page_load (struct page_table_entry *pte); |
