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