Print a message instead of panicking upon an unexpected interrupt.
[pintos-anon] / src / threads / interrupt.c
1 #include "threads/interrupt.h"
2 #include <debug.h>
3 #include <inttypes.h>
4 #include <stdint.h>
5 #include <stdio.h>
6 #include "threads/flags.h"
7 #include "threads/intr-stubs.h"
8 #include "threads/io.h"
9 #include "threads/thread.h"
10 #include "threads/vaddr.h"
11 #include "devices/timer.h"
12
13 /* Programmable Interrupt Controller (PIC) registers.
14    A PC has two PICs, called the master and slave PICs, with the
15    slave attached ("cascaded") to the master IRQ line 2. */
16 #define PIC0_CTRL       0x20    /* Master PIC control register address. */
17 #define PIC0_DATA       0x21    /* Master PIC data register address. */
18 #define PIC1_CTRL       0xa0    /* Slave PIC control register address. */
19 #define PIC1_DATA       0xa1    /* Slave PIC data register address. */
20
21 /* Number of x86 interrupts. */
22 #define INTR_CNT 256
23
24 /* The Interrupt Descriptor Table (IDT).  The format is fixed by
25    the CPU.  See [IA32-v3a] sections 5.10 "Interrupt Descriptor
26    Table (IDT)", 5.11 "IDT Descriptors", 5.12.1.2 "Flag Usage By
27    Exception- or Interrupt-Handler Procedure". */
28 static uint64_t idt[INTR_CNT];
29
30 /* Interrupt handler functions for each interrupt. */
31 static intr_handler_func *intr_handlers[INTR_CNT];
32
33 /* Names for each interrupt, for debugging purposes. */
34 static const char *intr_names[INTR_CNT];
35
36 /* Number of unexpected interrupts for each vector.  An
37    unexpected interrupt is one that has no registered handler. */
38 static unsigned int unexpected_cnt[INTR_CNT];
39
40 /* External interrupts are those generated by devices outside the
41    CPU, such as the timer.  External interrupts run with
42    interrupts turned off, so they never nest, nor are they ever
43    pre-empted.  Handlers for external interrupts also may not
44    sleep, although they may invoke intr_yield_on_return() to
45    request that a new process be scheduled just before the
46    interrupt returns. */
47 static bool in_external_intr;   /* Are we processing an external interrupt? */
48 static bool yield_on_return;    /* Should we yield on interrupt return? */
49
50 /* Programmable Interrupt Controller helpers. */
51 static void pic_init (void);
52 static void pic_end_of_interrupt (int irq);
53
54 /* Interrupt Descriptor Table helpers. */
55 static uint64_t make_intr_gate (void (*) (void), int dpl);
56 static uint64_t make_trap_gate (void (*) (void), int dpl);
57 static inline uint64_t make_idtr_operand (uint16_t limit, void *base);
58
59 /* Interrupt handlers. */
60 void intr_handler (struct intr_frame *args);
61 static void unexpected_interrupt (const struct intr_frame *);
62 \f
63 /* Returns the current interrupt status. */
64 enum intr_level
65 intr_get_level (void) 
66 {
67   uint32_t flags;
68
69   /* Push the flags register on the processor stack, then pop the
70      value off the stack into `flags'.  See [IA32-v2b] "PUSHF"
71      and "POP" and [IA32-v3a] 5.8.1 "Masking Maskable Hardware
72      Interrupts". */
73   asm volatile ("pushfl; popl %0" : "=g" (flags));
74
75   return flags & FLAG_IF ? INTR_ON : INTR_OFF;
76 }
77
78 /* Enables or disables interrupts as specified by LEVEL and
79    returns the previous interrupt status. */
80 enum intr_level
81 intr_set_level (enum intr_level level) 
82 {
83   return level == INTR_ON ? intr_enable () : intr_disable ();
84 }
85
86 /* Enables interrupts and returns the previous interrupt status. */
87 enum intr_level
88 intr_enable (void) 
89 {
90   enum intr_level old_level = intr_get_level ();
91   ASSERT (!intr_context ());
92
93   /* Enable interrupts by setting the interrupt flag.
94
95      See [IA32-v2b] "STI" and [IA32-v3a] 5.8.1 "Masking Maskable
96      Hardware Interrupts". */
97   asm volatile ("sti");
98
99   return old_level;
100 }
101
102 /* Disables interrupts and returns the previous interrupt status. */
103 enum intr_level
104 intr_disable (void) 
105 {
106   enum intr_level old_level = intr_get_level ();
107
108   /* Disable interrupts by clearing the interrupt flag.
109      See [IA32-v2b] "CLI" and [IA32-v3a] 5.8.1 "Masking Maskable
110      Hardware Interrupts". */
111   asm volatile ("cli" : : : "memory");
112
113   return old_level;
114 }
115 \f
116 /* Initializes the interrupt system. */
117 void
118 intr_init (void)
119 {
120   uint64_t idtr_operand;
121   int i;
122
123   /* Initialize interrupt controller. */
124   pic_init ();
125
126   /* Initialize IDT. */
127   for (i = 0; i < INTR_CNT; i++)
128     idt[i] = make_intr_gate (intr_stubs[i], 0);
129
130   /* Load IDT register.
131      See [IA32-v2a] "LIDT" and [IA32-v3a] 5.10 "Interrupt
132      Descriptor Table (IDT)". */
133   idtr_operand = make_idtr_operand (sizeof idt - 1, idt);
134   asm volatile ("lidt %0" : : "m" (idtr_operand));
135
136   /* Initialize intr_names. */
137   for (i = 0; i < INTR_CNT; i++)
138     intr_names[i] = "unknown";
139   intr_names[0] = "#DE Divide Error";
140   intr_names[1] = "#DB Debug Exception";
141   intr_names[2] = "NMI Interrupt";
142   intr_names[3] = "#BP Breakpoint Exception";
143   intr_names[4] = "#OF Overflow Exception";
144   intr_names[5] = "#BR BOUND Range Exceeded Exception";
145   intr_names[6] = "#UD Invalid Opcode Exception";
146   intr_names[7] = "#NM Device Not Available Exception";
147   intr_names[8] = "#DF Double Fault Exception";
148   intr_names[9] = "Coprocessor Segment Overrun";
149   intr_names[10] = "#TS Invalid TSS Exception";
150   intr_names[11] = "#NP Segment Not Present";
151   intr_names[12] = "#SS Stack Fault Exception";
152   intr_names[13] = "#GP General Protection Exception";
153   intr_names[14] = "#PF Page-Fault Exception";
154   intr_names[16] = "#MF x87 FPU Floating-Point Error";
155   intr_names[17] = "#AC Alignment Check Exception";
156   intr_names[18] = "#MC Machine-Check Exception";
157   intr_names[19] = "#XF SIMD Floating-Point Exception";
158 }
159
160 /* Registers interrupt VEC_NO to invoke HANDLER with descriptor
161    privilege level DPL.  Names the interrupt NAME for debugging
162    purposes.  The interrupt handler will be invoked with
163    interrupt status set to LEVEL. */
164 static void
165 register_handler (uint8_t vec_no, int dpl, enum intr_level level,
166                   intr_handler_func *handler, const char *name)
167 {
168   ASSERT (intr_handlers[vec_no] == NULL);
169   if (level == INTR_ON)
170     idt[vec_no] = make_trap_gate (intr_stubs[vec_no], dpl);
171   else
172     idt[vec_no] = make_intr_gate (intr_stubs[vec_no], dpl);
173   intr_handlers[vec_no] = handler;
174   intr_names[vec_no] = name;
175 }
176
177 /* Registers external interrupt VEC_NO to invoke HANDLER, which
178    is named NAME for debugging purposes.  The handler will
179    execute with interrupts disabled. */
180 void
181 intr_register_ext (uint8_t vec_no, intr_handler_func *handler,
182                    const char *name) 
183 {
184   ASSERT (vec_no >= 0x20 && vec_no <= 0x2f);
185   register_handler (vec_no, 0, INTR_OFF, handler, name);
186 }
187
188 /* Registers internal interrupt VEC_NO to invoke HANDLER, which
189    is named NAME for debugging purposes.  The interrupt handler
190    will be invoked with interrupt status LEVEL.
191
192    The handler will have descriptor privilege level DPL, meaning
193    that it can be invoked intentionally when the processor is in
194    the DPL or lower-numbered ring.  In practice, DPL==3 allows
195    user mode to invoke the interrupts and DPL==0 prevents such
196    invocation.  Faults and exceptions that occur in user mode
197    still cause interrupts with DPL==0 to be invoked.  See
198    [IA32-v3a] sections 4.5 "Privilege Levels" and 4.8.1.1
199    "Accessing Nonconforming Code Segments" for further
200    discussion. */
201 void
202 intr_register_int (uint8_t vec_no, int dpl, enum intr_level level,
203                    intr_handler_func *handler, const char *name)
204 {
205   ASSERT (vec_no < 0x20 || vec_no > 0x2f);
206   register_handler (vec_no, dpl, level, handler, name);
207 }
208
209 /* Returns true during processing of an external interrupt
210    and false at all other times. */
211 bool
212 intr_context (void) 
213 {
214   return in_external_intr;
215 }
216
217 /* During processing of an external interrupt, directs the
218    interrupt handler to yield to a new process just before
219    returning from the interrupt.  May not be called at any other
220    time. */
221 void
222 intr_yield_on_return (void) 
223 {
224   ASSERT (intr_context ());
225   yield_on_return = true;
226 }
227 \f
228 /* 8259A Programmable Interrupt Controller. */
229
230 /* Initializes the PICs.  Refer to [8259A] for details.
231
232    By default, interrupts 0...15 delivered by the PICs will go to
233    interrupt vectors 0...15.  Those vectors are also used for CPU
234    traps and exceptions, so we reprogram the PICs so that
235    interrupts 0...15 are delivered to interrupt vectors 32...47
236    (0x20...0x2f) instead. */
237 static void
238 pic_init (void)
239 {
240   /* Mask all interrupts on both PICs. */
241   outb (PIC0_DATA, 0xff);
242   outb (PIC1_DATA, 0xff);
243
244   /* Initialize master. */
245   outb (PIC0_CTRL, 0x11); /* ICW1: single mode, edge triggered, expect ICW4. */
246   outb (PIC0_DATA, 0x20); /* ICW2: line IR0...7 -> irq 0x20...0x27. */
247   outb (PIC0_DATA, 0x04); /* ICW3: slave PIC on line IR2. */
248   outb (PIC0_DATA, 0x01); /* ICW4: 8086 mode, normal EOI, non-buffered. */
249
250   /* Initialize slave. */
251   outb (PIC1_CTRL, 0x11); /* ICW1: single mode, edge triggered, expect ICW4. */
252   outb (PIC1_DATA, 0x28); /* ICW2: line IR0...7 -> irq 0x28...0x2f. */
253   outb (PIC1_DATA, 0x02); /* ICW3: slave ID is 2. */
254   outb (PIC1_DATA, 0x01); /* ICW4: 8086 mode, normal EOI, non-buffered. */
255
256   /* Unmask all interrupts. */
257   outb (PIC0_DATA, 0x00);
258   outb (PIC1_DATA, 0x00);
259 }
260
261 /* Sends an end-of-interrupt signal to the PIC for the given IRQ.
262    If we don't acknowledge the IRQ, it will never be delivered to
263    us again, so this is important.  */
264 static void
265 pic_end_of_interrupt (int irq) 
266 {
267   ASSERT (irq >= 0x20 && irq < 0x30);
268
269   /* Acknowledge master PIC. */
270   outb (0x20, 0x20);
271
272   /* Acknowledge slave PIC if this is a slave interrupt. */
273   if (irq >= 0x28)
274     outb (0xa0, 0x20);
275 }
276 \f
277 /* Creates an gate that invokes FUNCTION.
278
279    The gate has descriptor privilege level DPL, meaning that it
280    can be invoked intentionally when the processor is in the DPL
281    or lower-numbered ring.  In practice, DPL==3 allows user mode
282    to call into the gate and DPL==0 prevents such calls.  Faults
283    and exceptions that occur in user mode still cause gates with
284    DPL==0 to be invoked.  See [IA32-v3a] sections 4.5 "Privilege
285    Levels" and 4.8.1.1 "Accessing Nonconforming Code Segments"
286    for further discussion.
287
288    TYPE must be either 14 (for an interrupt gate) or 15 (for a
289    trap gate).  The difference is that entering an interrupt gate
290    disables interrupts, but entering a trap gate does not.  See
291    [IA32-v3a] section 5.12.1.2 "Flag Usage By Exception- or
292    Interrupt-Handler Procedure" for discussion. */
293 static uint64_t
294 make_gate (void (*function) (void), int dpl, int type)
295 {
296   uint32_t e0, e1;
297
298   ASSERT (function != NULL);
299   ASSERT (dpl >= 0 && dpl <= 3);
300   ASSERT (type >= 0 && type <= 15);
301
302   e0 = (((uint32_t) function & 0xffff)     /* Offset 15:0. */
303         | (SEL_KCSEG << 16));              /* Target code segment. */
304
305   e1 = (((uint32_t) function & 0xffff0000) /* Offset 31:16. */
306         | (1 << 15)                        /* Present. */
307         | ((uint32_t) dpl << 13)           /* Descriptor privilege level. */
308         | (0 << 12)                        /* System. */
309         | ((uint32_t) type << 8));         /* Gate type. */
310
311   return e0 | ((uint64_t) e1 << 32);
312 }
313
314 /* Creates an interrupt gate that invokes FUNCTION with the given
315    DPL. */
316 static uint64_t
317 make_intr_gate (void (*function) (void), int dpl)
318 {
319   return make_gate (function, dpl, 14);
320 }
321
322 /* Creates a trap gate that invokes FUNCTION with the given
323    DPL. */
324 static uint64_t
325 make_trap_gate (void (*function) (void), int dpl)
326 {
327   return make_gate (function, dpl, 15);
328 }
329
330 /* Returns a descriptor that yields the given LIMIT and BASE when
331    used as an operand for the LIDT instruction. */
332 static inline uint64_t
333 make_idtr_operand (uint16_t limit, void *base)
334 {
335   return limit | ((uint64_t) (uint32_t) base << 16);
336 }
337 \f
338 /* Interrupt handlers. */
339
340 /* Handler for all interrupts, faults, and exceptions.  This
341    function is called by the assembly language interrupt stubs in
342    intr-stubs.S.  FRAME describes the interrupt and the
343    interrupted thread's registers. */
344 void
345 intr_handler (struct intr_frame *frame) 
346 {
347   bool external;
348   intr_handler_func *handler;
349
350   /* External interrupts are special.
351      We only handle one at a time (so interrupts must be off)
352      and they need to be acknowledged on the PIC (see below).
353      An external interrupt handler cannot sleep. */
354   external = frame->vec_no >= 0x20 && frame->vec_no < 0x30;
355   if (external) 
356     {
357       ASSERT (intr_get_level () == INTR_OFF);
358       ASSERT (!intr_context ());
359
360       in_external_intr = true;
361       yield_on_return = false;
362     }
363
364   /* Invoke the interrupt's handler. */
365   handler = intr_handlers[frame->vec_no];
366   if (handler != NULL)
367     handler (frame);
368   else if (frame->vec_no == 0x27 || frame->vec_no == 0x2f)
369     {
370       /* There is no handler, but this interrupt can trigger
371          spuriously due to a hardware fault or hardware race
372          condition.  Ignore it. */
373     }
374   else
375     unexpected_interrupt (frame);
376
377   /* Complete the processing of an external interrupt. */
378   if (external) 
379     {
380       ASSERT (intr_get_level () == INTR_OFF);
381       ASSERT (intr_context ());
382
383       in_external_intr = false;
384       pic_end_of_interrupt (frame->vec_no); 
385
386       if (yield_on_return) 
387         thread_yield (); 
388     }
389 }
390
391 /* Handles an unexpected interrupt with interrupt frame F.  An
392    unexpected interrupt is one that has no registered handler. */
393 static void
394 unexpected_interrupt (const struct intr_frame *f)
395 {
396   /* Count the number so far. */
397   unsigned int n = ++unexpected_cnt[f->vec_no];
398
399   /* If the number is a power of 2, print a message.  This rate
400      limiting means that we get information about an uncommon
401      unexpected interrupt the first time and fairly often after
402      that, but one that occurs many times will not overwhelm the
403      console. */
404   if ((n & (n - 1)) == 0)
405     printf ("Unexpected interrupt %#04x (%s)\n",
406     f->vec_no, intr_names[f->vec_no]);
407 }
408
409 /* Dumps interrupt frame F to the console, for debugging. */
410 void
411 intr_dump_frame (const struct intr_frame *f) 
412 {
413   uint32_t cr2;
414
415   /* Store current value of CR2 into `cr2'.
416      CR2 is the linear address of the last page fault.
417      See [IA32-v2a] "MOV--Move to/from Control Registers" and
418      [IA32-v3a] 5.14 "Interrupt 14--Page Fault Exception
419      (#PF)". */
420   asm ("movl %%cr2, %0" : "=r" (cr2));
421
422   printf ("Interrupt %#04x (%s) at eip=%p\n",
423           f->vec_no, intr_names[f->vec_no], f->eip);
424   printf (" cr2=%08"PRIx32" error=%08"PRIx32"\n", cr2, f->error_code);
425   printf (" eax=%08"PRIx32" ebx=%08"PRIx32" ecx=%08"PRIx32" edx=%08"PRIx32"\n",
426           f->eax, f->ebx, f->ecx, f->edx);
427   printf (" esi=%08"PRIx32" edi=%08"PRIx32" esp=%08"PRIx32" ebp=%08"PRIx32"\n",
428           f->esi, f->edi, (uint32_t) f->esp, f->ebp);
429   printf (" cs=%04"PRIx16" ds=%04"PRIx16" es=%04"PRIx16" ss=%04"PRIx16"\n",
430           f->cs, f->ds, f->es, f->ss);
431 }
432
433 /* Returns the name of interrupt VEC. */
434 const char *
435 intr_name (uint8_t vec) 
436 {
437   return intr_names[vec];
438 }