CS318 - Pintos
Pintos source browser for JHU CS318 course
exception.c
Go to the documentation of this file.
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 
8 /** Number of page faults processed. */
9 static long long page_fault_cnt;
10 
11 static void kill (struct intr_frame *);
12 static void page_fault (struct intr_frame *);
13 
14 /** Registers handlers for interrupts that can be caused by user
15  programs.
16 
17  In a real Unix-like OS, most of these interrupts would be
18  passed along to the user process in the form of signals, as
19  described in [SV-386] 3-24 and 3-25, but we don't implement
20  signals. Instead, we'll make them simply kill the user
21  process.
22 
23  Page faults are an exception. Here they are treated the same
24  way as other exceptions, but this will need to change to
25  implement virtual memory.
26 
27  Refer to [IA32-v3a] section 5.15 "Exception and Interrupt
28  Reference" for a description of each of these exceptions. */
29 void
31 {
32  /* These exceptions can be raised explicitly by a user program,
33  e.g. via the INT, INT3, INTO, and BOUND instructions. Thus,
34  we set DPL==3, meaning that user programs are allowed to
35  invoke them via these instructions. */
36  intr_register_int (3, 3, INTR_ON, kill, "#BP Breakpoint Exception");
37  intr_register_int (4, 3, INTR_ON, kill, "#OF Overflow Exception");
39  "#BR BOUND Range Exceeded Exception");
40 
41  /* These exceptions have DPL==0, preventing user processes from
42  invoking them via the INT instruction. They can still be
43  caused indirectly, e.g. #DE can be caused by dividing by
44  0. */
45  intr_register_int (0, 0, INTR_ON, kill, "#DE Divide Error");
46  intr_register_int (1, 0, INTR_ON, kill, "#DB Debug Exception");
47  intr_register_int (6, 0, INTR_ON, kill, "#UD Invalid Opcode Exception");
49  "#NM Device Not Available Exception");
50  intr_register_int (11, 0, INTR_ON, kill, "#NP Segment Not Present");
51  intr_register_int (12, 0, INTR_ON, kill, "#SS Stack Fault Exception");
52  intr_register_int (13, 0, INTR_ON, kill, "#GP General Protection Exception");
53  intr_register_int (16, 0, INTR_ON, kill, "#MF x87 FPU Floating-Point Error");
55  "#XF SIMD Floating-Point Exception");
56 
57  /* Most exceptions can be handled with interrupts turned on.
58  We need to disable interrupts for page faults because the
59  fault address is stored in CR2 and needs to be preserved. */
60  intr_register_int (14, 0, INTR_OFF, page_fault, "#PF Page-Fault Exception");
61 }
62 
63 /** Prints exception statistics. */
64 void
66 {
67  printf ("Exception: %lld page faults\n", page_fault_cnt);
68 }
69 
70 /** Handler for an exception (probably) caused by a user process. */
71 static void
72 kill (struct intr_frame *f)
73 {
74  /* This interrupt is one (probably) caused by a user process.
75  For example, the process might have tried to access unmapped
76  virtual memory (a page fault). For now, we simply kill the
77  user process. Later, we'll want to handle page faults in
78  the kernel. Real Unix-like operating systems pass most
79  exceptions back to the process via signals, but we don't
80  implement them. */
81 
82  /* The interrupt frame's code segment value tells us where the
83  exception originated. */
84  switch (f->cs)
85  {
86  case SEL_UCSEG:
87  /* User's code segment, so it's a user exception, as we
88  expected. Kill the user process. */
89  printf ("%s: dying due to interrupt %#04x (%s).\n",
90  thread_name (), f->vec_no, intr_name (f->vec_no));
91  intr_dump_frame (f);
92  thread_exit ();
93 
94  case SEL_KCSEG:
95  /* Kernel's code segment, which indicates a kernel bug.
96  Kernel code shouldn't throw exceptions. (Page faults
97  may cause kernel exceptions--but they shouldn't arrive
98  here.) Panic the kernel to make the point. */
99  intr_dump_frame (f);
100  PANIC ("Kernel bug - unexpected interrupt in kernel");
101 
102  default:
103  /* Some other code segment? Shouldn't happen. Panic the
104  kernel. */
105  printf ("Interrupt %#04x (%s) in unknown segment %04x\n",
106  f->vec_no, intr_name (f->vec_no), f->cs);
107  thread_exit ();
108  }
109 }
110 
111 /** Page fault handler. This is a skeleton that must be filled in
112  to implement virtual memory. Some solutions to project 2 may
113  also require modifying this code.
114 
115  At entry, the address that faulted is in CR2 (Control Register
116  2) and information about the fault, formatted as described in
117  the PF_* macros in exception.h, is in F's error_code member. The
118  example code here shows how to parse that information. You
119  can find more information about both of these in the
120  description of "Interrupt 14--Page Fault Exception (#PF)" in
121  [IA32-v3a] section 5.15 "Exception and Interrupt Reference". */
122 static void
123 page_fault (struct intr_frame *f)
124 {
125  bool not_present; /**< True: not-present page, false: writing r/o page. */
126  bool write; /**< True: access was write, false: access was read. */
127  bool user; /**< True: access by user, false: access by kernel. */
128  void *fault_addr; /**< Fault address. */
129 
130  /* Obtain faulting address, the virtual address that was
131  accessed to cause the fault. It may point to code or to
132  data. It is not necessarily the address of the instruction
133  that caused the fault (that's f->eip).
134  See [IA32-v2a] "MOV--Move to/from Control Registers" and
135  [IA32-v3a] 5.15 "Interrupt 14--Page Fault Exception
136  (#PF)". */
137  asm ("movl %%cr2, %0" : "=r" (fault_addr));
138 
139  /* Turn interrupts back on (they were only off so that we could
140  be assured of reading CR2 before it changed). */
141  intr_enable ();
142 
143  /* Count page faults. */
144  page_fault_cnt++;
145 
146  /* Determine cause. */
147  not_present = (f->error_code & PF_P) == 0;
148  write = (f->error_code & PF_W) != 0;
149  user = (f->error_code & PF_U) != 0;
150 
151  /* To implement virtual memory, delete the rest of the function
152  body, and replace it with code that brings in the page to
153  which fault_addr refers. */
154  printf ("Page fault at %p: %s error %s page in %s context.\n",
155  fault_addr,
156  not_present ? "not present" : "rights violation",
157  write ? "writing" : "reading",
158  user ? "user" : "kernel");
159  kill (f);
160 }
161 
gdt.h
kill
static void kill(struct intr_frame *)
Handler for an exception (probably) caused by a user process.
Definition: exception.c:72
write
int write(int fd, const void *buffer, unsigned size)
Definition: syscall.c:121
SEL_KCSEG
#define SEL_KCSEG
Kernel code selector.
Definition: loader.h:30
thread_name
const char * thread_name(void)
Returns the name of the running thread.
Definition: thread.c:247
PF_W
#define PF_W
0: read, 1: write.
Definition: exception.h:6
intr_frame::cs
uint16_t cs
Definition: interrupt.h:52
page_fault
static void page_fault(struct intr_frame *)
Page fault handler.
Definition: exception.c:123
PF_P
#define PF_P
Page fault error code bits that describe the cause of the exception.
Definition: exception.h:5
PANIC
#define PANIC(...)
Halts the OS, printing the source file name, line number, and function name, plus a user-specific mes...
Definition: debug.h:14
interrupt.h
printf
int printf(const char *format,...)
Writes formatted output to the console.
Definition: stdio.c:79
intr_enable
enum intr_level intr_enable(void)
Enables interrupts and returns the previous interrupt status.
Definition: interrupt.c:88
page_fault_cnt
static long long page_fault_cnt
Number of page faults processed.
Definition: exception.c:9
intr_name
const char * intr_name(uint8_t vec)
Returns the name of interrupt VEC.
Definition: interrupt.c:435
thread_exit
void thread_exit(void)
Deschedules the current thread and destroys it.
Definition: thread.c:281
INTR_OFF
Interrupts disabled.
Definition: interrupt.h:10
intr_register_int
void intr_register_int(uint8_t vec_no, int dpl, enum intr_level level, intr_handler_func *handler, const char *name)
Registers internal interrupt VEC_NO to invoke HANDLER, which is named NAME for debugging purposes.
Definition: interrupt.c:202
SEL_UCSEG
#define SEL_UCSEG
Segment selectors.
Definition: gdt.h:8
intr_dump_frame
void intr_dump_frame(const struct intr_frame *f)
Dumps interrupt frame F to the console, for debugging.
Definition: interrupt.c:411
exception_print_stats
void exception_print_stats(void)
Prints exception statistics.
Definition: exception.c:65
exception.h
intr_frame::vec_no
uint16_t uint16_t uint16_t uint16_t uint32_t vec_no
Saved DS segment register.
Definition: interrupt.h:32
intr_frame
Interrupt stack frame.
Definition: interrupt.h:20
thread.h
inttypes.h
intr_frame::error_code
uint32_t error_code
Error code.
Definition: interrupt.h:43
PF_U
#define PF_U
0: kernel, 1: user process.
Definition: exception.h:7
INTR_ON
Interrupts enabled.
Definition: interrupt.h:11
exception_init
void exception_init(void)
Registers handlers for interrupts that can be caused by user programs.
Definition: exception.c:30