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