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