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 static bool intr_in_progress;
106 static 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_gate (void (*target) (void), int dpl, enum seg_type type)
164 uint32_t offset = (uint32_t) target;
165 uint32_t e0 = ((offset & 0xffff) /* Offset 15:0. */
166 | (SEL_KCSEG << 16)); /* Target code segment. */
167 uint32_t e1 = ((offset & 0xffff0000) /* Offset 31:16. */
168 | (1 << 15) /* Present. */
169 | ((uint32_t) dpl << 13) /* Descriptor privilege. */
170 | (SYS_SYSTEM << 12) /* System. */
171 | ((uint32_t) type << 8)); /* Gate type. */
172 return e0 | ((uint64_t) e1 << 32);
176 make_intr_gate (void (*target) (void), int dpl)
178 return make_gate (target, dpl, TYPE_INT_32);
182 make_trap_gate (void (*target) (void), int dpl)
184 return make_gate (target, dpl, TYPE_TRAP_32);
187 /* We don't support nested interrupts generated by external
188 hardware, so these interrupts (vec_no 0x20...0x2f) should
189 specify IF_OFF for LEVEL. Otherwise a timer interrupt could
190 cause a task switch during interrupt handling. Most other
191 interrupts can and should be handled with interrupts
194 intr_register (uint8_t vec_no, int dpl, enum if_level level,
195 intr_handler_func *handler,
199 idt[vec_no] = make_trap_gate (intr_stubs[vec_no], dpl);
201 idt[vec_no] = make_intr_gate (intr_stubs[vec_no], dpl);
202 intr_handlers[vec_no] = handler;
203 intr_names[vec_no] = name;
209 uint64_t idtr_operand;
214 /* Install default handlers. */
215 for (i = 0; i < 256; i++)
216 intr_register (i, 0, IF_OFF, intr_panic, NULL);
218 /* Most exceptions require ring 0.
219 Exceptions 3, 4, and 5 can be caused by ring 3 directly. */
220 intr_register (0, 0, IF_ON, intr_kill, "#DE Divide Error");
221 intr_register (1, 0, IF_ON, intr_kill, "#DB Debug Exception");
222 intr_register (2, 0, IF_ON, intr_panic, "NMI Interrupt");
223 intr_register (3, 3, IF_ON, intr_kill, "#BP Breakpoint Exception");
224 intr_register (4, 3, IF_ON, intr_kill, "#OF Overflow Exception");
225 intr_register (5, 3, IF_ON, intr_kill, "#BR BOUND Range Exceeded Exception");
226 intr_register (6, 0, IF_ON, intr_kill, "#UD Invalid Opcode Exception");
227 intr_register (7, 0, IF_ON, intr_kill, "#NM Device Not Available Exception");
228 intr_register (8, 0, IF_ON, intr_panic, "#DF Double Fault Exception");
229 intr_register (9, 0, IF_ON, intr_panic, "Coprocessor Segment Overrun");
230 intr_register (10, 0, IF_ON, intr_panic, "#TS Invalid TSS Exception");
231 intr_register (11, 0, IF_ON, intr_kill, "#NP Segment Not Present");
232 intr_register (12, 0, IF_ON, intr_kill, "#SS Stack Fault Exception");
233 intr_register (13, 0, IF_ON, intr_kill, "#GP General Protection Exception");
234 intr_register (16, 0, IF_ON, intr_kill, "#MF x87 FPU Floating-Point Error");
235 intr_register (17, 0, IF_ON, intr_panic, "#AC Alignment Check Exception");
236 intr_register (18, 0, IF_ON, intr_panic, "#MC Machine-Check Exception");
237 intr_register (19, 0, IF_ON, intr_kill, "#XF SIMD Floating-Point Exception");
239 /* Most exceptions can be handled with interrupts turned on.
240 We need to disable interrupts for page faults because the
241 fault address is stored in CR2 and needs to be preserved. */
242 intr_register (14, 0, IF_OFF, intr_kill, "#PF Page-Fault Exception");
244 idtr_operand = make_dtr_operand (sizeof idt - 1, idt);
245 asm volatile ("lidt %0" :: "m" (idtr_operand));
249 dump_intr_frame (struct intr_frame *f)
252 asm ("movl %%cr2, %0" : "=r" (cr2));
253 asm ("movl %%ss, %0" : "=r" (ss));
255 printk ("Interrupt %#04x (%s) at eip=%p\n",
256 f->vec_no, intr_name (f->vec_no), f->eip);
257 printk (" cr2=%08"PRIx32" error=%08"PRIx32"\n", cr2, f->error_code);
258 printk (" eax=%08"PRIx32" ebx=%08"PRIx32" ecx=%08"PRIx32" edx=%08"PRIx32"\n",
259 f->eax, f->ebx, f->ecx, f->edx);
260 printk (" esi=%08"PRIx32" edi=%08"PRIx32" esp=%08"PRIx32" ebp=%08"PRIx32"\n",
261 f->esi, f->edi, (uint32_t) f->esp, f->ebp);
262 printk (" cs=%04"PRIx16" ds=%04"PRIx16" es=%04"PRIx16" ss=%04"PRIx16"\n",
263 f->cs, f->ds, f->es, f->cs != SEL_KCSEG ? f->ss : ss);
267 intr_panic (struct intr_frame *regs)
269 dump_intr_frame (regs);
274 intr_kill (struct intr_frame *f)
279 printk ("[%p] Interrupt %#04x (%s), killing process.\n",
280 thread_current (), f->vec_no, intr_name (f->vec_no));
284 printk ("Kernel bug - unexpected interrupt in kernel context\n");
288 printk ("Interrupt %#04x (%s) in unknown segment %04x\n",
289 f->vec_no, intr_name (f->vec_no), f->cs);