summaryrefslogtreecommitdiffstats
path: root/userprog/exception.c
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2012-03-27 11:51:08 +0200
committermanuel <manuel@mausz.at>2012-03-27 11:51:08 +0200
commit4f670845ff9ab6c48bcb5f7bf4d4ef6dc3c3064b (patch)
tree868c52e06f207b5ec8a3cc141f4b8b2bdfcc165c /userprog/exception.c
parenteae0bd57f0a26314a94785061888d193d186944a (diff)
downloadprogos-4f670845ff9ab6c48bcb5f7bf4d4ef6dc3c3064b.tar.gz
progos-4f670845ff9ab6c48bcb5f7bf4d4ef6dc3c3064b.tar.bz2
progos-4f670845ff9ab6c48bcb5f7bf4d4ef6dc3c3064b.zip
reorganize file structure to match the upstream requirements
Diffstat (limited to 'userprog/exception.c')
-rw-r--r--userprog/exception.c174
1 files changed, 174 insertions, 0 deletions
diff --git a/userprog/exception.c b/userprog/exception.c
new file mode 100644
index 0000000..17620ad
--- /dev/null
+++ b/userprog/exception.c
@@ -0,0 +1,174 @@
1#include "userprog/exception.h"
2#include <inttypes.h>
3#include <stdio.h>
4#include "userprog/gdt.h"
5#include "threads/interrupt.h"
6#include "threads/thread.h"
7#include "threads/vaddr.h"
8
9/* Number of page faults processed. */
10static long long page_fault_cnt;
11
12static void kill (struct intr_frame *);
13static void page_fault (struct intr_frame *);
14
15/* Registers handlers for interrupts that can be caused by user
16 programs.
17
18 In a real Unix-like OS, most of these interrupts would be
19 passed along to the user process in the form of signals, as
20 described in [SV-386] 3-24 and 3-25, but we don't implement
21 signals. Instead, we'll make them simply kill the user
22 process.
23
24 Page faults are an exception. Here they are treated the same
25 way as other exceptions, but this will need to change to
26 implement virtual memory.
27
28 Refer to [IA32-v3a] section 5.15 "Exception and Interrupt
29 Reference" for a description of each of these exceptions. */
30void
31exception_init (void)
32{
33 /* These exceptions can be raised explicitly by a user program,
34 e.g. via the INT, INT3, INTO, and BOUND instructions. Thus,
35 we set DPL==3, meaning that user programs are allowed to
36 invoke them via these instructions. */
37 intr_register_int (3, 3, INTR_ON, kill, "#BP Breakpoint Exception");
38 intr_register_int (4, 3, INTR_ON, kill, "#OF Overflow Exception");
39 intr_register_int (5, 3, INTR_ON, kill,
40 "#BR BOUND Range Exceeded Exception");
41
42 /* These exceptions have DPL==0, preventing user processes from
43 invoking them via the INT instruction. They can still be
44 caused indirectly, e.g. #DE can be caused by dividing by
45 0. */
46 intr_register_int (0, 0, INTR_ON, kill, "#DE Divide Error");
47 intr_register_int (1, 0, INTR_ON, kill, "#DB Debug Exception");
48 intr_register_int (6, 0, INTR_ON, kill, "#UD Invalid Opcode Exception");
49 intr_register_int (7, 0, INTR_ON, kill,
50 "#NM Device Not Available Exception");
51 intr_register_int (11, 0, INTR_ON, kill, "#NP Segment Not Present");
52 intr_register_int (12, 0, INTR_ON, kill, "#SS Stack Fault Exception");
53 intr_register_int (13, 0, INTR_ON, kill, "#GP General Protection Exception");
54 intr_register_int (16, 0, INTR_ON, kill, "#MF x87 FPU Floating-Point Error");
55 intr_register_int (19, 0, INTR_ON, kill,
56 "#XF SIMD Floating-Point Exception");
57
58 /* Most exceptions can be handled with interrupts turned on.
59 We need to disable interrupts for page faults because the
60 fault address is stored in CR2 and needs to be preserved. */
61 intr_register_int (14, 0, INTR_OFF, page_fault, "#PF Page-Fault Exception");
62}
63
64/* Prints exception statistics. */
65void
66exception_print_stats (void)
67{
68 printf ("Exception: %lld page faults\n", page_fault_cnt);
69}
70
71/* Handler for an exception (probably) caused by a user process. */
72static void
73kill (struct intr_frame *f)
74{
75 /* This interrupt is one (probably) caused by a user process.
76 For example, the process might have tried to access unmapped
77 virtual memory (a page fault). For now, we simply kill the
78 user process. Later, we'll want to handle page faults in
79 the kernel. Real Unix-like operating systems pass most
80 exceptions back to the process via signals, but we don't
81 implement them. */
82
83 /* The interrupt frame's code segment value tells us where the
84 exception originated. */
85 switch (f->cs)
86 {
87 case SEL_UCSEG:
88 /* User's code segment, so it's a user exception, as we
89 expected. Kill the user process. */
90 printf ("%s: dying due to interrupt %#04x (%s).\n",
91 thread_name (), f->vec_no, intr_name (f->vec_no));
92 intr_dump_frame (f);
93 thread_exit ();
94
95 case SEL_KCSEG:
96 /* Kernel's code segment, which indicates a kernel bug.
97 Kernel code shouldn't throw exceptions. (Page faults
98 may cause kernel exceptions--but they shouldn't arrive
99 here.) Panic the kernel to make the point. */
100 intr_dump_frame (f);
101 PANIC ("Kernel bug - unexpected interrupt in kernel");
102
103 default:
104 /* Some other code segment? Shouldn't happen. Panic the
105 kernel. */
106 printf ("Interrupt %#04x (%s) in unknown segment %04x\n",
107 f->vec_no, intr_name (f->vec_no), f->cs);
108 thread_exit ();
109 }
110}
111
112/* Page fault handler. This is a skeleton that must be filled in
113 to implement virtual memory. Some solutions to project 2 may
114 also require modifying this code.
115
116 At entry, the address that faulted is in CR2 (Control Register
117 2) and information about the fault, formatted as described in
118 the PF_* macros in exception.h, is in F's error_code member. The
119 example code here shows how to parse that information. You
120 can find more information about both of these in the
121 description of "Interrupt 14--Page Fault Exception (#PF)" in
122 [IA32-v3a] section 5.15 "Exception and Interrupt Reference". */
123static void
124page_fault (struct intr_frame *f)
125{
126 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 user; /* True: access by user, false: access by kernel. */
129 void *fault_addr; /* Fault address. */
130
131 /* Obtain faulting address, the virtual address that was
132 accessed to cause the fault. It may point to code or to
133 data. It is not necessarily the address of the instruction
134 that caused the fault (that's f->eip).
135 See [IA32-v2a] "MOV--Move to/from Control Registers" and
136 [IA32-v3a] 5.15 "Interrupt 14--Page Fault Exception
137 (#PF)". */
138 asm ("movl %%cr2, %0" : "=r" (fault_addr));
139
140 /* Turn interrupts back on (they were only off so that we could
141 be assured of reading CR2 before it changed). */
142 intr_enable ();
143
144 /* Count page faults. */
145 page_fault_cnt++;
146
147 /* Determine cause. */
148 not_present = (f->error_code & PF_P) == 0;
149 write = (f->error_code & PF_W) != 0;
150 user = (f->error_code & PF_U) != 0;
151
152 /* To implement virtual memory, adapt the rest of the function
153 body, adding code that brings in the page to
154 which fault_addr refers. */
155 if (is_user_vaddr(fault_addr)) {
156 if (! user) {
157 /* syscall exception; set eax and eip */
158 f->eip = (void*)f->eax;
159 f->eax = 0xFFFFFFFF;
160 return;
161 } else {
162 /* user process access violation */
163 thread_exit();
164 }
165 } else {
166 printf ("Page fault at %p: %s error %s page in %s context.\n",
167 fault_addr,
168 not_present ? "not present" : "rights violation",
169 write ? "writing" : "reading",
170 user ? "user" : "kernel");
171 kill (f);
172 }
173}
174