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. */
21 /* Number of x86 interrupts. */
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];
30 /* Interrupt handler functions for each interrupt. */
31 static intr_handler_func *intr_handlers[INTR_CNT];
33 /* Names for each interrupt, for debugging purposes. */
34 static const char *intr_names[INTR_CNT];
36 /* Number of unexpected interrupts for each vector. An
37 unexpected interrupt is one that has no registered handler. */
38 static unsigned int unexpected_cnt[INTR_CNT];
40 /* External interrupts are those generated by devices outside the
41 CPU, such as the timer. External interrupts run with
42 interrupts turned off, so they never nest, nor are they ever
43 pre-empted. Handlers for external interrupts also may not
44 sleep, although they may invoke intr_yield_on_return() to
45 request that a new process be scheduled just before the
47 static bool in_external_intr; /* Are we processing an external interrupt? */
48 static bool yield_on_return; /* Should we yield on interrupt return? */
50 /* Programmable Interrupt Controller helpers. */
51 static void pic_init (void);
52 static void pic_end_of_interrupt (int irq);
54 /* Interrupt Descriptor Table helpers. */
55 static uint64_t make_intr_gate (void (*) (void), int dpl);
56 static uint64_t make_trap_gate (void (*) (void), int dpl);
57 static inline uint64_t make_idtr_operand (uint16_t limit, void *base);
59 /* Interrupt handlers. */
60 void intr_handler (struct intr_frame *args);
61 static void unexpected_interrupt (const struct intr_frame *);
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);
261 /* Sends an end-of-interrupt signal to the PIC for the given IRQ.
262 If we don't acknowledge the IRQ, it will never be delivered to
263 us again, so this is important. */
265 pic_end_of_interrupt (int irq)
267 ASSERT (irq >= 0x20 && irq < 0x30);
269 /* Acknowledge master PIC. */
272 /* Acknowledge slave PIC if this is a slave interrupt. */
277 /* Creates an gate that invokes FUNCTION.
279 The gate has descriptor privilege level DPL, meaning that it
280 can be invoked intentionally when the processor is in the DPL
281 or lower-numbered ring. In practice, DPL==3 allows user mode
282 to call into the gate and DPL==0 prevents such calls. Faults
283 and exceptions that occur in user mode still cause gates with
284 DPL==0 to be invoked. See [IA32-v3a] sections 4.5 "Privilege
285 Levels" and 4.8.1.1 "Accessing Nonconforming Code Segments"
286 for further discussion.
288 TYPE must be either 14 (for an interrupt gate) or 15 (for a
289 trap gate). The difference is that entering an interrupt gate
290 disables interrupts, but entering a trap gate does not. See
291 [IA32-v3a] section 5.12.1.2 "Flag Usage By Exception- or
292 Interrupt-Handler Procedure" for discussion. */
294 make_gate (void (*function) (void), int dpl, int type)
298 ASSERT (function != NULL);
299 ASSERT (dpl >= 0 && dpl <= 3);
300 ASSERT (type >= 0 && type <= 15);
302 e0 = (((uint32_t) function & 0xffff) /* Offset 15:0. */
303 | (SEL_KCSEG << 16)); /* Target code segment. */
305 e1 = (((uint32_t) function & 0xffff0000) /* Offset 31:16. */
306 | (1 << 15) /* Present. */
307 | ((uint32_t) dpl << 13) /* Descriptor privilege level. */
308 | (0 << 12) /* System. */
309 | ((uint32_t) type << 8)); /* Gate type. */
311 return e0 | ((uint64_t) e1 << 32);
314 /* Creates an interrupt gate that invokes FUNCTION with the given
317 make_intr_gate (void (*function) (void), int dpl)
319 return make_gate (function, dpl, 14);
322 /* Creates a trap gate that invokes FUNCTION with the given
325 make_trap_gate (void (*function) (void), int dpl)
327 return make_gate (function, dpl, 15);
330 /* Returns a descriptor that yields the given LIMIT and BASE when
331 used as an operand for the LIDT instruction. */
332 static inline uint64_t
333 make_idtr_operand (uint16_t limit, void *base)
335 return limit | ((uint64_t) (uint32_t) base << 16);
338 /* Interrupt handlers. */
340 /* Handler for all interrupts, faults, and exceptions. This
341 function is called by the assembly language interrupt stubs in
342 intr-stubs.S. FRAME describes the interrupt and the
343 interrupted thread's registers. */
345 intr_handler (struct intr_frame *frame)
348 intr_handler_func *handler;
350 /* External interrupts are special.
351 We only handle one at a time (so interrupts must be off)
352 and they need to be acknowledged on the PIC (see below).
353 An external interrupt handler cannot sleep. */
354 external = frame->vec_no >= 0x20 && frame->vec_no < 0x30;
357 ASSERT (intr_get_level () == INTR_OFF);
358 ASSERT (!intr_context ());
360 in_external_intr = true;
361 yield_on_return = false;
364 /* Invoke the interrupt's handler. */
365 handler = intr_handlers[frame->vec_no];
368 else if (frame->vec_no == 0x27 || frame->vec_no == 0x2f)
370 /* There is no handler, but this interrupt can trigger
371 spuriously due to a hardware fault or hardware race
372 condition. Ignore it. */
375 unexpected_interrupt (frame);
377 /* Complete the processing of an external interrupt. */
380 ASSERT (intr_get_level () == INTR_OFF);
381 ASSERT (intr_context ());
383 in_external_intr = false;
384 pic_end_of_interrupt (frame->vec_no);
391 /* Handles an unexpected interrupt with interrupt frame F. An
392 unexpected interrupt is one that has no registered handler. */
394 unexpected_interrupt (const struct intr_frame *f)
396 /* Count the number so far. */
397 unsigned int n = ++unexpected_cnt[f->vec_no];
399 /* If the number is a power of 2, print a message. This rate
400 limiting means that we get information about an uncommon
401 unexpected interrupt the first time and fairly often after
402 that, but one that occurs many times will not overwhelm the
404 if ((n & (n - 1)) == 0)
405 printf ("Unexpected interrupt %#04x (%s)\n",
406 f->vec_no, intr_names[f->vec_no]);
409 /* Dumps interrupt frame F to the console, for debugging. */
411 intr_dump_frame (const struct intr_frame *f)
415 /* Store current value of CR2 into `cr2'.
416 CR2 is the linear address of the last page fault.
417 See [IA32-v2a] "MOV--Move to/from Control Registers" and
418 [IA32-v3a] 5.14 "Interrupt 14--Page Fault Exception
420 asm ("movl %%cr2, %0" : "=r" (cr2));
422 printf ("Interrupt %#04x (%s) at eip=%p\n",
423 f->vec_no, intr_names[f->vec_no], f->eip);
424 printf (" cr2=%08"PRIx32" error=%08"PRIx32"\n", cr2, f->error_code);
425 printf (" eax=%08"PRIx32" ebx=%08"PRIx32" ecx=%08"PRIx32" edx=%08"PRIx32"\n",
426 f->eax, f->ebx, f->ecx, f->edx);
427 printf (" esi=%08"PRIx32" edi=%08"PRIx32" esp=%08"PRIx32" ebp=%08"PRIx32"\n",
428 f->esi, f->edi, (uint32_t) f->esp, f->ebp);
429 printf (" cs=%04"PRIx16" ds=%04"PRIx16" es=%04"PRIx16" ss=%04"PRIx16"\n",
430 f->cs, f->ds, f->es, f->ss);
433 /* Returns the name of interrupt VEC. */
435 intr_name (uint8_t vec)
437 return intr_names[vec];