summaryrefslogtreecommitdiffstats
path: root/userprog
diff options
context:
space:
mode:
Diffstat (limited to 'userprog')
-rw-r--r--userprog/exception.c80
-rw-r--r--userprog/process.c54
-rw-r--r--userprog/process.h3
-rw-r--r--userprog/syscall.c9
-rw-r--r--userprog/syscall.h2
5 files changed, 98 insertions, 50 deletions
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 */
691bool
692process_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) */
7struct fd_table { 9struct fd_table {
8 struct file** fds; 10 struct file** fds;
@@ -37,6 +39,7 @@ tid_t process_execute (const char *file_name);
37int process_wait (tid_t); 39int process_wait (tid_t);
38void process_exit (void); 40void process_exit (void);
39void process_activate (void); 41void process_activate (void);
42bool process_grow_stack (void *upage);
40bool process_install_page (void *upage, void *kpage, bool writable); 43bool process_install_page (void *upage, void *kpage, bool writable);
41 44
42int process_open_file(const char* fname); 45int 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 */
21void *syscall_sp;
22
20/* Prototypes for Utilities */ 23/* Prototypes for Utilities */
21static int get_user (const uint8_t *uaddr); 24static int get_user (const uint8_t *uaddr);
22static bool put_user (uint8_t *udst, uint8_t byte); 25static 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
4void syscall_init (void); 4void syscall_init (void);
5extern void *syscall_sp;
6
5#endif /* userprog/syscall.h */ 7#endif /* userprog/syscall.h */