Clean up interrupts.[ch].
[pintos-anon] / src / threads / interrupt.c
1 #include "interrupt.h"
2 #include <inttypes.h>
3 #include <stdint.h>
4 #include "intr-stubs.h"
5 #include "debug.h"
6 #include "io.h"
7 #include "lib.h"
8 #include "mmu.h"
9 #include "thread.h"
10 #include "timer.h"
11
12 /* Number of x86 interrupts. */
13 #define INTR_CNT 256
14
15 /* The Interrupt Descriptor Table (IDT).  The format is fixed by
16    the CPU.  See [IA32-v3] sections 5.10, 5.11, 5.12.1.2. */
17 static uint64_t idt[INTR_CNT];
18
19 /* Interrupt handler functions for each interrupt. */
20 static intr_handler_func *intr_handlers[INTR_CNT];
21
22 /* Names for each interrupt, for debugging purposes. */
23 static const char *intr_names[INTR_CNT];
24
25 /* External interrupts are those generated by devices outside the
26    CPU, such as the timer.  External interrupts run with
27    interrupts turned off, so they never nest, nor are they ever
28    pre-empted.  Handlers for external interrupts also may not
29    sleep, although they may invoke intr_yield_on_return() to
30    request that a new process be scheduled just before the
31    interrupt returns. */
32 static bool in_external_intr;   /* Are we processing an external interrupt? */
33 static bool yield_on_return;    /* Should we yield on interrupt return? */
34
35 /* Programmable Interrupt Controller helpers. */
36 static void pic_init (void);
37 static void pic_end_of_interrupt (int irq);
38
39 /* Interrupt Descriptor Table helpers. */
40 static uint64_t make_intr_gate (void (*) (void), int dpl);
41 static uint64_t make_trap_gate (void (*) (void), int dpl);
42
43 /* Interrupt handlers. */
44 void intr_handler (struct intr_frame *args);
45 static intr_handler_func panic NO_RETURN;
46 static intr_handler_func kill NO_RETURN;
47 \f
48 /* Returns the current interrupt status. */
49 enum intr_level
50 intr_get_level (void) 
51 {
52   uint32_t flags;
53   
54   asm ("pushfl; popl %0" : "=g" (flags));
55
56   return flags & FLAG_IF ? INTR_ON : INTR_OFF;
57 }
58
59 /* Enables or disables interrupts as specified by LEVEL and
60    returns the previous interrupt status. */
61 enum intr_level
62 intr_set_level (enum intr_level level) 
63 {
64   return level == INTR_ON ? intr_enable () : intr_disable ();
65 }
66
67 /* Enables interrupts and returns the previous interrupt status. */
68 enum intr_level
69 intr_enable (void) 
70 {
71   enum intr_level old_level = intr_get_level ();
72   asm volatile ("sti");
73   return old_level;
74 }
75
76 /* Disables interrupts and returns the previous interrupt status. */
77 enum intr_level
78 intr_disable (void) 
79 {
80   enum intr_level old_level = intr_get_level ();
81   asm volatile ("cli");
82   return old_level;
83 }
84 \f
85 /* Initializes the interrupt system. */
86 void
87 intr_init (void)
88 {
89   uint64_t idtr_operand;
90   int i;
91
92   pic_init ();
93
94   /* Initialize intr_names. */
95   for (i = 0; i < INTR_CNT; i++)
96     intr_names[i] = "unknown";
97
98   /* Most exceptions require ring 0.
99      Exceptions 3, 4, and 5 can be caused by ring 3 directly. */
100   intr_register (0, 0, INTR_ON, kill, "#DE Divide Error");
101   intr_register (1, 0, INTR_ON, kill, "#DB Debug Exception");
102   intr_register (2, 0, INTR_ON, panic, "NMI Interrupt");
103   intr_register (3, 3, INTR_ON, kill, "#BP Breakpoint Exception");
104   intr_register (4, 3, INTR_ON, kill, "#OF Overflow Exception");
105   intr_register (5, 3, INTR_ON, kill, "#BR BOUND Range Exceeded Exception");
106   intr_register (6, 0, INTR_ON, kill, "#UD Invalid Opcode Exception");
107   intr_register (7, 0, INTR_ON, kill, "#NM Device Not Available Exception");
108   intr_register (8, 0, INTR_ON, panic, "#DF Double Fault Exception");
109   intr_register (9, 0, INTR_ON, panic, "Coprocessor Segment Overrun");
110   intr_register (10, 0, INTR_ON, panic, "#TS Invalid TSS Exception");
111   intr_register (11, 0, INTR_ON, kill, "#NP Segment Not Present");
112   intr_register (12, 0, INTR_ON, kill, "#SS Stack Fault Exception");
113   intr_register (13, 0, INTR_ON, kill, "#GP General Protection Exception");
114   intr_register (16, 0, INTR_ON, kill, "#MF x87 FPU Floating-Point Error");
115   intr_register (17, 0, INTR_ON, panic, "#AC Alignment Check Exception");
116   intr_register (18, 0, INTR_ON, panic, "#MC Machine-Check Exception");
117   intr_register (19, 0, INTR_ON, kill, "#XF SIMD Floating-Point Exception");
118
119   /* Most exceptions can be handled with interrupts turned on.
120      We need to disable interrupts for page faults because the
121      fault address is stored in CR2 and needs to be preserved. */
122   intr_register (14, 0, INTR_OFF, kill, "#PF Page-Fault Exception");
123
124   idtr_operand = make_dtr_operand (sizeof idt - 1, idt);
125   asm volatile ("lidt %0" :: "m" (idtr_operand));
126 }
127
128 /* Registers interrupt VEC_NO to invoke HANDLER, which is named
129    NAME for debugging purposes.  The interrupt handler will be
130    invoked with interrupt status set to LEVEL.
131
132    The handler will have descriptor privilege level DPL, meaning
133    that it can be invoked intentionally when the processor is in
134    the DPL or lower-numbered ring.  In practice, DPL==3 allows
135    user mode to invoke the interrupts and DPL==0 prevents such
136    invocation.  Faults and exceptions that occur in user mode
137    still cause interrupts with DPL==0 to be invoked.  See
138    [IA32-v3] sections 4.5 and 4.8.1.1 for further discussion. */
139 void
140 intr_register (uint8_t vec_no, int dpl, enum intr_level level,
141                intr_handler_func *handler,
142                const char *name) 
143 {
144   /* Make sure this handler isn't already registered to someone
145      else. */
146   ASSERT (intr_handlers[vec_no] == NULL);
147
148   /* Interrupts generated by external hardware (0x20 <= VEC_NO <=
149      0x2f) should specify INTR_OFF for LEVEL.  Otherwise a timer
150      interrupt could cause a task switch during interrupt
151      handling.  Most other interrupts can and should be handled
152      with interrupts enabled. */
153   ASSERT (vec_no < 0x20 || vec_no > 0x2f || level == INTR_OFF);
154
155   if (level == INTR_ON)
156     idt[vec_no] = make_trap_gate (intr_stubs[vec_no], dpl);
157   else
158     idt[vec_no] = make_intr_gate (intr_stubs[vec_no], dpl);
159   intr_handlers[vec_no] = handler;
160   intr_names[vec_no] = name;
161 }
162
163 /* Returns true during processing of an external interrupt
164    and false at all other times. */
165 bool
166 intr_context (void) 
167 {
168   return in_external_intr;
169 }
170
171 /* During processing of an external interrupt, directs the
172    interrupt handler to yield to a new process just before
173    returning from the interrupt.  May not be called at any other
174    time. */
175 void
176 intr_yield_on_return (void) 
177 {
178   ASSERT (intr_context ());
179   yield_on_return = true;
180 }
181 \f
182 /* 8259A Programmable Interrupt Controller. */
183
184 /* Every PC has two 8259A Programmable Interrupt Controller (PIC)
185    chips.  One is a "master" accessible at ports 0x20 and 0x21.
186    The other is a "slave" cascaded onto the master's IRQ 2 line
187    and accessible at ports 0xa0 and 0xa1.  Accesses to port 0x20
188    set the A0 line to 0 and accesses to 0x21 set the A1 line to
189    1.  The situation is similar for the slave PIC.
190
191    By default, interrupts 0...15 delivered by the PICs will go to
192    interrupt vectors 0...15.  Unfortunately, those vectors are
193    also used for CPU traps and exceptions.  We reprogram the PICs
194    so that interrupts 0...15 are delivered to interrupt vectors
195    32...47 (0x20...0x2f) instead. */
196
197 /* Initializes the PICs.  Refer to [8259A] for details. */
198 static void
199 pic_init (void)
200 {
201   /* Mask all interrupts on both PICs. */
202   outb (0x21, 0xff);
203   outb (0xa1, 0xff);
204
205   /* Initialize master. */
206   outb (0x20, 0x11); /* ICW1: single mode, edge triggered, expect ICW4. */
207   outb (0x21, 0x20); /* ICW2: line IR0...7 -> irq 0x20...0x27. */
208   outb (0x21, 0x04); /* ICW3: slave PIC on line IR2. */
209   outb (0x21, 0x01); /* ICW4: 8086 mode, normal EOI, non-buffered. */
210
211   /* Initialize slave. */
212   outb (0xa0, 0x11); /* ICW1: single mode, edge triggered, expect ICW4. */
213   outb (0xa1, 0x28); /* ICW2: line IR0...7 -> irq 0x28...0x2f. */
214   outb (0xa1, 0x02); /* ICW3: slave ID is 2. */
215   outb (0xa1, 0x01); /* ICW4: 8086 mode, normal EOI, non-buffered. */
216
217   /* Unmask all interrupts. */
218   outb (0x21, 0x00);
219   outb (0xa1, 0x00);
220 }
221
222 /* Sends an end-of-interrupt signal to the PIC for the given IRQ.
223    If we don't acknowledge the IRQ, it will never be delivered to
224    us again, so this is important.  */
225 static void
226 pic_end_of_interrupt (int irq) 
227 {
228   ASSERT (irq >= 0x20 && irq < 0x30);
229
230   /* Acknowledge master PIC. */
231   outb (0x20, 0x20);
232
233   /* Acknowledge slave PIC if this is a slave interrupt. */
234   if (irq >= 0x28)
235     outb (0xa0, 0x20);
236 }
237 \f
238 /* Creates an gate that invokes FUNCTION.
239
240    The gate has descriptor privilege level DPL, meaning that it
241    can be invoked intentionally when the processor is in the DPL
242    or lower-numbered ring.  In practice, DPL==3 allows user mode
243    to call into the gate and DPL==0 prevents such calls.  Faults
244    and exceptions that occur in user mode still cause gates with
245    DPL==0 to be invoked.  See [IA32-v3] sections 4.5 and 4.8.1.1
246    for further discussion.
247
248    TYPE must be either TYPE_INT_32 (for an interrupt gate) or
249    TYPE_TRAP_32 (for a trap gate).  The difference is that
250    entering an interrupt gate disables interrupts, but entering a
251    trap gate does not.  See [IA32-v3] section 5.12.1.2 for
252    discussion. */
253 static uint64_t
254 make_gate (void (*function) (void), int dpl, enum seg_type type)
255 {
256   uint32_t offset = (uint32_t) function;
257   uint32_t e0 = ((offset & 0xffff)            /* Offset 15:0. */
258                  | (SEL_KCSEG << 16));        /* Target code segment. */
259   uint32_t e1 = ((offset & 0xffff0000)        /* Offset 31:16. */
260                  | (1 << 15)                  /* Present. */
261                  | ((uint32_t) dpl << 13)     /* Descriptor privilege. */
262                  | (SYS_SYSTEM << 12)         /* System. */
263                  | ((uint32_t) type << 8));   /* Gate type. */
264   return e0 | ((uint64_t) e1 << 32);
265 }
266
267 /* Creates an interrupt gate that invokes FUNCTION with the given
268    DPL. */
269 static uint64_t
270 make_intr_gate (void (*function) (void), int dpl)
271 {
272   return make_gate (function, dpl, TYPE_INT_32);
273 }
274
275 /* Creates a trap gate that invokes FUNCTION with the given
276    DPL. */
277 static uint64_t
278 make_trap_gate (void (*function) (void), int dpl)
279 {
280   return make_gate (function, dpl, TYPE_TRAP_32);
281 }
282 \f
283 /* Interrupt handlers. */
284
285 static void dump_intr_frame (struct intr_frame *);
286
287 /* Handler for all interrupts, faults, and exceptions.  This
288    function is called by the assembly language interrupt stubs in
289    intr-stubs.S (see intr-stubs.pl).  ARGS describes the
290    interrupt and the interrupted thread's registers. */
291 void
292 intr_handler (struct intr_frame *args) 
293 {
294   bool external;
295   intr_handler_func *handler;
296
297   external = args->vec_no >= 0x20 && args->vec_no < 0x30;
298   if (external) 
299     {
300       ASSERT (intr_get_level () == INTR_OFF);
301       ASSERT (!intr_context ());
302
303       in_external_intr = true;
304       yield_on_return = false;
305     }
306
307   /* Invoke the interrupt's handler.
308      If there is no handler, invoke the unexpected interrupt
309      handler. */
310   handler = intr_handlers[args->vec_no];
311   if (handler == NULL)
312     handler = panic;
313   handler (args);
314
315   /* Complete the processing of an external interrupt. */
316   if (external) 
317     {
318       ASSERT (intr_get_level () == INTR_OFF);
319       ASSERT (intr_context ());
320
321       in_external_intr = false;
322       pic_end_of_interrupt (args->vec_no); 
323
324       if (yield_on_return) 
325         thread_yield (); 
326     }
327 }
328
329 /* Handler for an interrupt that should not have been invoked. */
330 static void
331 panic (struct intr_frame *regs) 
332 {
333   dump_intr_frame (regs);
334   PANIC ("Panic!");
335 }
336
337 /* Handler for an exception (probably) caused by a user process. */
338 static void
339 kill (struct intr_frame *f) 
340 {
341   /* This interrupt is one (probably) caused by a user process.
342      For example, the process might have tried to access unmapped
343      virtual memory (a page fault).  For now, we simply kill the
344      user process.  Later, we'll want to handle page faults in
345      the kernel.  Real Unix-like operating systems pass most
346      exceptions back to the process via signals, but we don't
347      implement them. */
348      
349   /* The interrupt frame's code segment value tells us where the
350      exception originated. */
351   switch (f->cs)
352     {
353     case SEL_UCSEG:
354       /* User's code segment, so it's a user exception, as we
355          expected. */
356       printk ("%s: dying due to interrupt %#04x (%s).\n",
357               thread_name (thread_current ()),
358               f->vec_no, intr_names[f->vec_no]);
359       dump_intr_frame (f);
360       thread_exit (); 
361
362     case SEL_KCSEG:
363       /* Kernel's code segment, which indicates a kernel bug.
364          Kernel code shouldn't throw exceptions.  (Page faults
365          may cause kernel exceptions--but they shouldn't arrive
366          here.) */
367       printk ("Kernel bug - unexpected interrupt in kernel\n");
368       panic (f);
369
370     default:
371       /* Some other code segment?  Shouldn't happen. */
372       printk ("Interrupt %#04x (%s) in unknown segment %04x\n",
373              f->vec_no, intr_names[f->vec_no], f->cs);
374       thread_exit ();
375     }
376 }
377
378 /* Dumps interrupt frame F to the console, for debugging. */
379 static void
380 dump_intr_frame (struct intr_frame *f) 
381 {
382   uint32_t cr2, ss;
383   asm ("movl %%cr2, %0" : "=r" (cr2));
384   asm ("movl %%ss, %0" : "=r" (ss));
385
386   printk ("Interrupt %#04x (%s) at eip=%p\n",
387           f->vec_no, intr_names[f->vec_no], f->eip);
388   printk (" cr2=%08"PRIx32" error=%08"PRIx32"\n", cr2, f->error_code);
389   printk (" eax=%08"PRIx32" ebx=%08"PRIx32" ecx=%08"PRIx32" edx=%08"PRIx32"\n",
390           f->eax, f->ebx, f->ecx, f->edx);
391   printk (" esi=%08"PRIx32" edi=%08"PRIx32" esp=%08"PRIx32" ebp=%08"PRIx32"\n",
392           f->esi, f->edi, (uint32_t) f->esp, f->ebp);
393   printk (" cs=%04"PRIx16" ds=%04"PRIx16" es=%04"PRIx16" ss=%04"PRIx16"\n",
394           f->cs, f->ds, f->es, f->cs != SEL_KCSEG ? f->ss : ss);
395 }
396