1 #include "threads/interrupt.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"
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
23 /* Number of x86 interrupts. */
26 /* The Interrupt Descriptor Table (IDT). The format is fixed by
27 the CPU. See [IA32-v3a] sections 5.10 "Interrupt Descriptor
28 Table (IDT)", 5.11 "IDT Descriptors", 5.12.1.2 "Flag Usage By
29 Exception- or Interrupt-Handler Procedure". */
30 static uint64_t idt[INTR_CNT];
32 /* Interrupt handler functions for each interrupt. */
33 static intr_handler_func *intr_handlers[INTR_CNT];
35 /* Names for each interrupt, for debugging purposes. */
36 static const char *intr_names[INTR_CNT];
38 /* cached values for PIC */
39 static uint8_t pic_mask[2];
41 /* External interrupts are those generated by devices outside the
42 CPU, such as the timer. External interrupts run with
43 interrupts turned off, so they never nest, nor are they ever
44 pre-empted. Handlers for external interrupts also may not
45 sleep, although they may invoke intr_yield_on_return() to
46 request that a new process be scheduled just before the
48 static bool in_external_intr; /* Are we processing an external interrupt? */
49 static bool yield_on_return; /* Should we yield on interrupt return? */
51 /* Programmable Interrupt Controller helpers. */
52 static void pic_init (void);
53 static void pic_end_of_interrupt (int irq);
55 /* Interrupt Descriptor Table helpers. */
56 static uint64_t make_intr_gate (void (*) (void), int dpl);
57 static uint64_t make_trap_gate (void (*) (void), int dpl);
58 static inline uint64_t make_idtr_operand (uint16_t limit, void *base);
60 /* Interrupt handlers. */
61 void intr_handler (struct intr_frame *args);
63 /* Returns the current interrupt status. */
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
73 asm volatile ("pushfl; popl %0" : "=g" (flags));
75 return flags & FLAG_IF ? INTR_ON : INTR_OFF;
78 /* Enables or disables interrupts as specified by LEVEL and
79 returns the previous interrupt status. */
81 intr_set_level (enum intr_level level)
83 return level == INTR_ON ? intr_enable () : intr_disable ();
86 /* Enables interrupts and returns the previous interrupt status. */
90 enum intr_level old_level = intr_get_level ();
91 ASSERT (!intr_context ());
93 /* Enable interrupts by setting the interrupt flag.
95 See [IA32-v2b] "STI" and [IA32-v3a] 5.8.1 "Masking Maskable
96 Hardware Interrupts". */
102 /* Disables interrupts and returns the previous interrupt status. */
106 enum intr_level old_level = intr_get_level ();
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");
116 /* Initializes the interrupt system. */
120 uint64_t idtr_operand;
123 /* Initialize interrupt controller. */
126 /* Initialize IDT. */
127 for (i = 0; i < INTR_CNT; i++)
128 idt[i] = make_intr_gate (intr_stubs[i], 0);
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));
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";
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. */
165 register_handler (uint8_t vec_no, int dpl, enum intr_level level,
166 intr_handler_func *handler, const char *name)
168 ASSERT (intr_handlers[vec_no] == NULL);
169 if (level == INTR_ON)
170 idt[vec_no] = make_trap_gate (intr_stubs[vec_no], dpl);
172 idt[vec_no] = make_intr_gate (intr_stubs[vec_no], dpl);
173 intr_handlers[vec_no] = handler;
174 intr_names[vec_no] = name;
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. */
181 intr_register_ext (uint8_t vec_no, intr_handler_func *handler,
184 ASSERT (vec_no >= 0x20 && vec_no <= 0x2f);
185 register_handler (vec_no, 0, INTR_OFF, handler, name);
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.
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
202 intr_register_int (uint8_t vec_no, int dpl, enum intr_level level,
203 intr_handler_func *handler, const char *name)
205 ASSERT (vec_no < 0x20 || vec_no > 0x2f);
206 register_handler (vec_no, dpl, level, handler, name);
209 /* Returns true during processing of an external interrupt
210 and false at all other times. */
214 return in_external_intr;
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
222 intr_yield_on_return (void)
224 ASSERT (intr_context ());
225 yield_on_return = true;
228 /* 8259A Programmable Interrupt Controller. */
230 /* Initializes the PICs. Refer to [8259A] for details.
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. */
240 /* Mask all interrupts on both PICs. */
241 outb (PIC0_DATA, 0xff);
242 outb (PIC1_DATA, 0xff);
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. */
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. */
256 /* Unmask all interrupts. */
257 outb (PIC0_DATA, 0x00);
258 outb (PIC1_DATA, 0x00);
263 /* Sends an end-of-interrupt signal to the PIC for the given IRQ.
264 If we don't acknowledge the IRQ, it will never be delivered to
265 us again, so this is important. */
267 pic_end_of_interrupt (int irq)
269 ASSERT (irq >= 0x20 && irq < 0x30);
271 /* Acknowledge master PIC. */
274 /* Acknowledge slave PIC if this is a slave interrupt. */
279 /* Creates an gate that invokes FUNCTION.
281 The gate has descriptor privilege level DPL, meaning that it
282 can be invoked intentionally when the processor is in the DPL
283 or lower-numbered ring. In practice, DPL==3 allows user mode
284 to call into the gate and DPL==0 prevents such calls. Faults
285 and exceptions that occur in user mode still cause gates with
286 DPL==0 to be invoked. See [IA32-v3a] sections 4.5 "Privilege
287 Levels" and 4.8.1.1 "Accessing Nonconforming Code Segments"
288 for further discussion.
290 TYPE must be either 14 (for an interrupt gate) or 15 (for a
291 trap gate). The difference is that entering an interrupt gate
292 disables interrupts, but entering a trap gate does not. See
293 [IA32-v3a] section 5.12.1.2 "Flag Usage By Exception- or
294 Interrupt-Handler Procedure" for discussion. */
296 make_gate (void (*function) (void), int dpl, int type)
300 ASSERT (function != NULL);
301 ASSERT (dpl >= 0 && dpl <= 3);
302 ASSERT (type >= 0 && type <= 15);
304 e0 = (((uint32_t) function & 0xffff) /* Offset 15:0. */
305 | (SEL_KCSEG << 16)); /* Target code segment. */
307 e1 = (((uint32_t) function & 0xffff0000) /* Offset 31:16. */
308 | (1 << 15) /* Present. */
309 | ((uint32_t) dpl << 13) /* Descriptor privilege level. */
310 | (0 << 12) /* System. */
311 | ((uint32_t) type << 8)); /* Gate type. */
313 return e0 | ((uint64_t) e1 << 32);
316 /* Creates an interrupt gate that invokes FUNCTION with the given
319 make_intr_gate (void (*function) (void), int dpl)
321 return make_gate (function, dpl, 14);
324 /* Creates a trap gate that invokes FUNCTION with the given
327 make_trap_gate (void (*function) (void), int dpl)
329 return make_gate (function, dpl, 15);
332 /* Returns a descriptor that yields the given LIMIT and BASE when
333 used as an operand for the LIDT instruction. */
334 static inline uint64_t
335 make_idtr_operand (uint16_t limit, void *base)
337 return limit | ((uint64_t) (uint32_t) base << 16);
340 /* Interrupt handlers. */
342 /* Handler for all interrupts, faults, and exceptions. This
343 function is called by the assembly language interrupt stubs in
344 intr-stubs.S. FRAME describes the interrupt and the
345 interrupted thread's registers. */
347 intr_handler (struct intr_frame *frame)
350 intr_handler_func *handler;
352 /* External interrupts are special.
353 We only handle one at a time (so interrupts must be off)
354 and they need to be acknowledged on the PIC (see below).
355 An external interrupt handler cannot sleep. */
356 external = frame->vec_no >= 0x20 && frame->vec_no < 0x30;
359 ASSERT (intr_get_level () == INTR_OFF);
360 ASSERT (!intr_context ());
362 in_external_intr = true;
363 yield_on_return = false;
366 /* Invoke the interrupt's handler. */
367 handler = intr_handlers[frame->vec_no];
370 else if (frame->vec_no == 0x27 || frame->vec_no == 0x2f)
372 /* There is no handler, but this interrupt can trigger
373 spuriously due to a hardware fault or hardware race
374 condition. Ignore it. */
378 /* No handler and not spurious. Invoke the unexpected
379 interrupt handler. */
380 intr_dump_frame (frame);
381 PANIC ("Unexpected interrupt");
384 /* Complete the processing of an external interrupt. */
387 ASSERT (intr_get_level () == INTR_OFF);
388 ASSERT (intr_context ());
390 in_external_intr = false;
391 pic_end_of_interrupt (frame->vec_no);
398 /* Dumps interrupt frame F to the console, for debugging. */
400 intr_dump_frame (const struct intr_frame *f)
404 /* Store current value of CR2 into `cr2'.
405 CR2 is the linear address of the last page fault.
406 See [IA32-v2a] "MOV--Move to/from Control Registers" and
407 [IA32-v3a] 5.14 "Interrupt 14--Page Fault Exception
409 asm ("movl %%cr2, %0" : "=r" (cr2));
411 printf ("Interrupt %#04x (%s) at eip=%p\n",
412 f->vec_no, intr_names[f->vec_no], f->eip);
413 printf (" cr2=%08"PRIx32" error=%08"PRIx32"\n", cr2, f->error_code);
414 printf (" eax=%08"PRIx32" ebx=%08"PRIx32" ecx=%08"PRIx32" edx=%08"PRIx32"\n",
415 f->eax, f->ebx, f->ecx, f->edx);
416 printf (" esi=%08"PRIx32" edi=%08"PRIx32" esp=%08"PRIx32" ebp=%08"PRIx32"\n",
417 f->esi, f->edi, (uint32_t) f->esp, f->ebp);
418 printf (" cs=%04"PRIx16" ds=%04"PRIx16" es=%04"PRIx16" ss=%04"PRIx16"\n",
419 f->cs, f->ds, f->es, f->ss);
422 /* Returns the name of interrupt VEC. */
424 intr_name (uint8_t vec)
426 return intr_names[vec];
429 /** masks a given IRQ */
430 void intr_irq_mask(int irq)
433 pic_mask[0] |= 1 << irq;
434 outb (PIC0_DATA, pic_mask[0]);
436 pic_mask[1] |= 1 << (irq - 8);
437 outb (PIC1_DATA, pic_mask[1]);
441 /** unmasks a given IRQ */
442 void intr_irq_unmask(int irq)
445 /* enable cascade if not enabled for pic2 */
446 if(pic_mask[1] & (1 << (IRQ_CASCADE1 - 8)))
447 pic_mask[1] &= ~(1 << (IRQ_CASCADE1 - 8));
449 pic_mask[1] &= ~(1 << (irq - 8));
450 outb(PIC1_DATA, pic_mask[1]);
452 /* enable cascade if not enabled for pic1 */
453 if(pic_mask[0] & (1 << IRQ_CASCADE0))
458 pic_mask[0] &= ~(1 << irq);
459 outb (PIC0_DATA, pic_mask[0]);
464 /* return whether an interrupt vector is registered */
465 bool intr_is_registered(uint8_t vec_no)
467 return (intr_handlers[vec_no] != NULL);