4 #include "intr-stubs.h"
17 asm ("pushfl; popl %0" : "=g" (flags));
19 return flags & (1 << 9) ? IF_ON : IF_OFF;
23 intr_set_level (enum if_level level)
25 enum if_level old_level = intr_get_level ();
36 enum if_level old_level = intr_get_level ();
44 enum if_level old_level = intr_get_level ();
52 /* Every PC has two 8259A Programmable Interrupt Controller
53 (PIC) chips. One is a "master" accessible at ports 0x20 and
54 0x21. The other is a "slave" cascaded onto the master's IRQ
55 2 line and accessible at ports 0xa0 and 0xa1. Accesses to
56 port 0x20 set the A0 line to 0 and accesses to 0x21 set the
57 A1 line to 1. The situation is similar for the slave PIC.
58 Refer to the 8259A datasheet for details.
60 By default, interrupts 0...15 delivered by the PICs will go
61 to interrupt vectors 0...15. Unfortunately, those vectors
62 are also used for CPU traps and exceptions. We reprogram
63 the PICs so that interrupts 0...15 are delivered to
64 interrupt vectors 32...47 instead. */
66 /* Mask all interrupts on both PICs. */
70 /* Initialize master. */
71 outb (0x20, 0x11); /* ICW1: single mode, edge triggered, expect ICW4. */
72 outb (0x21, 0x20); /* ICW2: line IR0...7 -> irq 0x20...0x27. */
73 outb (0x21, 0x04); /* ICW3: slave PIC on line IR2. */
74 outb (0x21, 0x01); /* ICW4: 8086 mode, normal EOI, non-buffered. */
76 /* Initialize slave. */
77 outb (0xa0, 0x11); /* ICW1: single mode, edge triggered, expect ICW4. */
78 outb (0xa1, 0x28); /* ICW2: line IR0...7 -> irq 0x28...0x2f. */
79 outb (0xa1, 0x02); /* ICW3: slave ID is 2. */
80 outb (0xa1, 0x01); /* ICW4: 8086 mode, normal EOI, non-buffered. */
82 /* Unmask all interrupts. */
87 /* Sends an end-of-interrupt signal to the PIC for the given IRQ.
88 If we don't acknowledge the IRQ, we'll never get it again, so
93 /* FIXME? The Linux code is much more complicated. */
99 static uint64_t idt[INTR_CNT];
100 static intr_handler_func *intr_handlers[INTR_CNT];
101 static const char *intr_names[INTR_CNT];
103 void intr_handler (struct intr_frame *args);
105 bool intr_in_progress;
106 bool yield_on_return;
111 if (vec < 0 || vec >= INTR_CNT || intr_names[vec] == NULL)
114 return intr_names[vec];
118 intr_handler (struct intr_frame *args)
122 yield_on_return = false;
124 external = args->vec_no >= 0x20 && args->vec_no < 0x30;
127 ASSERT (intr_get_level () == IF_OFF);
128 ASSERT (!intr_context ());
129 intr_in_progress = true;
132 intr_handlers[args->vec_no] (args);
136 ASSERT (intr_get_level () == IF_OFF);
137 ASSERT (intr_context ());
138 intr_in_progress = false;
149 return intr_in_progress;
153 intr_yield_on_return (void)
155 yield_on_return = true;
158 intr_handler_func intr_panic NO_RETURN;
159 intr_handler_func intr_kill NO_RETURN;
162 make_intr_gate (void (*target) (void),
165 uint32_t offset = (uint32_t) target;
166 uint32_t e0 = ((offset & 0xffff) /* Offset 15:0. */
167 | (SEL_KCSEG << 16)); /* Target code segment. */
168 uint32_t e1 = ((offset & 0xffff0000) /* Offset 31:16. */
169 | (1 << 15) /* Present. */
170 | (dpl << 13) /* Descriptor privilege. */
171 | (SYS_SYSTEM << 12) /* System. */
172 | (TYPE_INT_32 << 8)); /* 32-bit interrupt gate. */
173 return e0 | ((uint64_t) e1 << 32);
177 make_trap_gate (void (*target) (void),
180 return make_intr_gate (target, dpl) | (1 << 8);
183 /* We don't support nested interrupts generated by external
184 hardware, so these interrupts (vec_no 0x20...0x2f) should
185 specify IF_OFF for LEVEL. Otherwise a timer interrupt could
186 cause a task switch during interrupt handling. Most other
187 interrupts can and should be handled with interrupts
190 intr_register (uint8_t vec_no, int dpl, enum if_level level,
191 intr_handler_func *handler,
195 idt[vec_no] = make_trap_gate (intr_stubs[vec_no], dpl);
197 idt[vec_no] = make_intr_gate (intr_stubs[vec_no], dpl);
198 intr_handlers[vec_no] = handler;
199 intr_names[vec_no] = name;
205 uint64_t idtr_operand;
210 /* Install default handlers. */
211 for (i = 0; i < 256; i++)
212 intr_register (i, 0, IF_OFF, intr_panic, NULL);
214 /* Most exceptions require ring 0.
215 Exceptions 3, 4, and 5 can be caused by ring 3 directly. */
216 intr_register (0, 0, IF_ON, intr_kill, "#DE Divide Error");
217 intr_register (1, 0, IF_ON, intr_kill, "#DB Debug Exception");
218 intr_register (2, 0, IF_ON, intr_panic, "NMI Interrupt");
219 intr_register (3, 3, IF_ON, intr_kill, "#BP Breakpoint Exception");
220 intr_register (4, 3, IF_ON, intr_kill, "#OF Overflow Exception");
221 intr_register (5, 3, IF_ON, intr_kill, "#BR BOUND Range Exceeded Exception");
222 intr_register (6, 0, IF_ON, intr_kill, "#UD Invalid Opcode Exception");
223 intr_register (7, 0, IF_ON, intr_kill, "#NM Device Not Available Exception");
224 intr_register (8, 0, IF_ON, intr_panic, "#DF Double Fault Exception");
225 intr_register (9, 0, IF_ON, intr_panic, "Coprocessor Segment Overrun");
226 intr_register (10, 0, IF_ON, intr_panic, "#TS Invalid TSS Exception");
227 intr_register (11, 0, IF_ON, intr_kill, "#NP Segment Not Present");
228 intr_register (12, 0, IF_ON, intr_kill, "#SS Stack Fault Exception");
229 intr_register (13, 0, IF_ON, intr_kill, "#GP General Protection Exception");
230 intr_register (16, 0, IF_ON, intr_kill, "#MF x87 FPU Floating-Point Error");
231 intr_register (17, 0, IF_ON, intr_panic, "#AC Alignment Check Exception");
232 intr_register (18, 0, IF_ON, intr_panic, "#MC Machine-Check Exception");
233 intr_register (19, 0, IF_ON, intr_kill, "#XF SIMD Floating-Point Exception");
235 /* Most exceptions can be handled with interrupts turned on.
236 We need to disable interrupts for page faults because the
237 fault address is stored in CR2 and needs to be preserved. */
238 intr_register (14, 0, IF_OFF, intr_kill, "#PF Page-Fault Exception");
240 idtr_operand = make_dtr_operand (sizeof idt - 1, idt);
241 asm volatile ("lidt %0" :: "m" (idtr_operand));
245 dump_intr_frame (struct intr_frame *f)
248 asm ("movl %%cr2, %0" : "=r" (cr2));
249 asm ("movl %%ss, %0" : "=r" (ss));
251 printk ("Interrupt %#04x (%s) at eip=%p\n",
252 f->vec_no, intr_name (f->vec_no), f->eip);
253 printk (" cr2=%08"PRIx32" error=%08"PRIx32"\n", cr2, f->error_code);
254 printk (" eax=%08"PRIx32" ebx=%08"PRIx32" ecx=%08"PRIx32" edx=%08"PRIx32"\n",
255 f->eax, f->ebx, f->ecx, f->edx);
256 printk (" esi=%08"PRIx32" edi=%08"PRIx32" esp=%08"PRIx32" ebp=%08"PRIx32"\n",
257 f->esi, f->edi, (uint32_t) f->esp, f->ebp);
258 printk (" cs=%04"PRIx16" ds=%04"PRIx16" es=%04"PRIx16" ss=%04"PRIx16"\n",
259 f->cs, f->ds, f->es, f->cs != SEL_KCSEG ? f->ss : ss);
263 intr_panic (struct intr_frame *regs)
265 dump_intr_frame (regs);
270 intr_kill (struct intr_frame *f)
275 printk ("[%p] Interrupt %#04x (%s), killing process.\n",
276 thread_current (), f->vec_no, intr_name (f->vec_no));
280 panic ("Interrupt %#04x (%s) in unknown segment %04x",
281 f->vec_no, intr_name (f->vec_no), f->cs);
284 printk ("intr_kill -> panic %d\n", f->vec_no);