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