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)
120 bool external = args->vec_no >= 0x20 && args->vec_no < 0x30;
123 ASSERT (intr_get_level () == IF_OFF);
124 ASSERT (!intr_context ());
125 intr_in_progress = true;
126 yield_on_return = false;
129 intr_handlers[args->vec_no] (args);
133 ASSERT (intr_get_level () == IF_OFF);
134 ASSERT (intr_context ());
135 intr_in_progress = false;
146 return intr_in_progress;
150 intr_yield_on_return (void)
152 ASSERT (intr_context ());
153 yield_on_return = true;
156 intr_handler_func intr_panic NO_RETURN;
157 intr_handler_func intr_kill NO_RETURN;
160 make_gate (void (*target) (void), int dpl, enum seg_type type)
162 uint32_t offset = (uint32_t) target;
163 uint32_t e0 = ((offset & 0xffff) /* Offset 15:0. */
164 | (SEL_KCSEG << 16)); /* Target code segment. */
165 uint32_t e1 = ((offset & 0xffff0000) /* Offset 31:16. */
166 | (1 << 15) /* Present. */
167 | ((uint32_t) dpl << 13) /* Descriptor privilege. */
168 | (SYS_SYSTEM << 12) /* System. */
169 | ((uint32_t) type << 8)); /* Gate type. */
170 return e0 | ((uint64_t) e1 << 32);
174 make_intr_gate (void (*target) (void), int dpl)
176 return make_gate (target, dpl, TYPE_INT_32);
180 make_trap_gate (void (*target) (void), int dpl)
182 return make_gate (target, dpl, TYPE_TRAP_32);
186 intr_register (uint8_t vec_no, int dpl, enum if_level level,
187 intr_handler_func *handler,
190 /* Interrupts generated by external hardware (0x20 <= VEC_NO <=
191 0x2f) should specify IF_OFF for LEVEL. Otherwise a timer
192 interrupt could cause a task switch during interrupt
193 handling. Most other interrupts can and should be handled
194 with interrupts enabled. */
195 ASSERT (vec_no < 0x20 || vec_no > 0x2f || level == IF_OFF);
198 idt[vec_no] = make_trap_gate (intr_stubs[vec_no], dpl);
200 idt[vec_no] = make_intr_gate (intr_stubs[vec_no], dpl);
201 intr_handlers[vec_no] = handler;
202 intr_names[vec_no] = name;
208 uint64_t idtr_operand;
213 /* Install default handlers. */
214 for (i = 0; i < 256; i++)
215 intr_register (i, 0, IF_OFF, intr_panic, NULL);
217 /* Most exceptions require ring 0.
218 Exceptions 3, 4, and 5 can be caused by ring 3 directly. */
219 intr_register (0, 0, IF_ON, intr_kill, "#DE Divide Error");
220 intr_register (1, 0, IF_ON, intr_kill, "#DB Debug Exception");
221 intr_register (2, 0, IF_ON, intr_panic, "NMI Interrupt");
222 intr_register (3, 3, IF_ON, intr_kill, "#BP Breakpoint Exception");
223 intr_register (4, 3, IF_ON, intr_kill, "#OF Overflow Exception");
224 intr_register (5, 3, IF_ON, intr_kill, "#BR BOUND Range Exceeded Exception");
225 intr_register (6, 0, IF_ON, intr_kill, "#UD Invalid Opcode Exception");
226 intr_register (7, 0, IF_ON, intr_kill, "#NM Device Not Available Exception");
227 intr_register (8, 0, IF_ON, intr_panic, "#DF Double Fault Exception");
228 intr_register (9, 0, IF_ON, intr_panic, "Coprocessor Segment Overrun");
229 intr_register (10, 0, IF_ON, intr_panic, "#TS Invalid TSS Exception");
230 intr_register (11, 0, IF_ON, intr_kill, "#NP Segment Not Present");
231 intr_register (12, 0, IF_ON, intr_kill, "#SS Stack Fault Exception");
232 intr_register (13, 0, IF_ON, intr_kill, "#GP General Protection Exception");
233 intr_register (16, 0, IF_ON, intr_kill, "#MF x87 FPU Floating-Point Error");
234 intr_register (17, 0, IF_ON, intr_panic, "#AC Alignment Check Exception");
235 intr_register (18, 0, IF_ON, intr_panic, "#MC Machine-Check Exception");
236 intr_register (19, 0, IF_ON, intr_kill, "#XF SIMD Floating-Point Exception");
238 /* Most exceptions can be handled with interrupts turned on.
239 We need to disable interrupts for page faults because the
240 fault address is stored in CR2 and needs to be preserved. */
241 intr_register (14, 0, IF_OFF, intr_kill, "#PF Page-Fault Exception");
243 idtr_operand = make_dtr_operand (sizeof idt - 1, idt);
244 asm volatile ("lidt %0" :: "m" (idtr_operand));
248 dump_intr_frame (struct intr_frame *f)
251 asm ("movl %%cr2, %0" : "=r" (cr2));
252 asm ("movl %%ss, %0" : "=r" (ss));
254 printk ("Interrupt %#04x (%s) at eip=%p\n",
255 f->vec_no, intr_name (f->vec_no), f->eip);
256 printk (" cr2=%08"PRIx32" error=%08"PRIx32"\n", cr2, f->error_code);
257 printk (" eax=%08"PRIx32" ebx=%08"PRIx32" ecx=%08"PRIx32" edx=%08"PRIx32"\n",
258 f->eax, f->ebx, f->ecx, f->edx);
259 printk (" esi=%08"PRIx32" edi=%08"PRIx32" esp=%08"PRIx32" ebp=%08"PRIx32"\n",
260 f->esi, f->edi, (uint32_t) f->esp, f->ebp);
261 printk (" cs=%04"PRIx16" ds=%04"PRIx16" es=%04"PRIx16" ss=%04"PRIx16"\n",
262 f->cs, f->ds, f->es, f->cs != SEL_KCSEG ? f->ss : ss);
266 intr_panic (struct intr_frame *regs)
268 dump_intr_frame (regs);
273 intr_kill (struct intr_frame *f)
278 printk ("[%p] Interrupt %#04x (%s), killing process.\n",
279 thread_current (), f->vec_no, intr_name (f->vec_no));
283 printk ("Kernel bug - unexpected interrupt in kernel context\n");
287 printk ("Interrupt %#04x (%s) in unknown segment %04x\n",
288 f->vec_no, intr_name (f->vec_no), f->cs);