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. */
94 ASSERT (irq >= 0x20 && irq < 0x30);
102 static uint64_t idt[INTR_CNT];
103 static intr_handler_func *intr_handlers[INTR_CNT];
104 static const char *intr_names[INTR_CNT];
106 void intr_handler (struct intr_frame *args);
108 static bool intr_in_progress;
109 static bool yield_on_return;
114 if (vec < 0 || vec >= INTR_CNT || intr_names[vec] == NULL)
117 return intr_names[vec];
121 intr_handler (struct intr_frame *args)
123 bool external = args->vec_no >= 0x20 && args->vec_no < 0x30;
126 ASSERT (intr_get_level () == IF_OFF);
127 ASSERT (!intr_context ());
128 intr_in_progress = true;
129 yield_on_return = false;
132 intr_handlers[args->vec_no] (args);
136 ASSERT (intr_get_level () == IF_OFF);
137 ASSERT (intr_context ());
138 intr_in_progress = false;
139 pic_eoi (args->vec_no);
149 return intr_in_progress;
153 intr_yield_on_return (void)
155 ASSERT (intr_context ());
156 yield_on_return = true;
159 intr_handler_func intr_panic NO_RETURN;
160 intr_handler_func intr_kill NO_RETURN;
163 make_gate (void (*target) (void), int dpl, enum seg_type type)
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 | ((uint32_t) dpl << 13) /* Descriptor privilege. */
171 | (SYS_SYSTEM << 12) /* System. */
172 | ((uint32_t) type << 8)); /* Gate type. */
173 return e0 | ((uint64_t) e1 << 32);
177 make_intr_gate (void (*target) (void), int dpl)
179 return make_gate (target, dpl, TYPE_INT_32);
183 make_trap_gate (void (*target) (void), int dpl)
185 return make_gate (target, dpl, TYPE_TRAP_32);
189 intr_register (uint8_t vec_no, int dpl, enum if_level level,
190 intr_handler_func *handler,
193 /* Interrupts generated by external hardware (0x20 <= VEC_NO <=
194 0x2f) should specify IF_OFF for LEVEL. Otherwise a timer
195 interrupt could cause a task switch during interrupt
196 handling. Most other interrupts can and should be handled
197 with interrupts enabled. */
198 ASSERT (vec_no < 0x20 || vec_no > 0x2f || level == IF_OFF);
201 idt[vec_no] = make_trap_gate (intr_stubs[vec_no], dpl);
203 idt[vec_no] = make_intr_gate (intr_stubs[vec_no], dpl);
204 intr_handlers[vec_no] = handler;
205 intr_names[vec_no] = name;
211 uint64_t idtr_operand;
216 /* Install default handlers. */
217 for (i = 0; i < 256; i++)
218 intr_register (i, 0, IF_OFF, intr_panic, NULL);
220 /* Most exceptions require ring 0.
221 Exceptions 3, 4, and 5 can be caused by ring 3 directly. */
222 intr_register (0, 0, IF_ON, intr_kill, "#DE Divide Error");
223 intr_register (1, 0, IF_ON, intr_kill, "#DB Debug Exception");
224 intr_register (2, 0, IF_ON, intr_panic, "NMI Interrupt");
225 intr_register (3, 3, IF_ON, intr_kill, "#BP Breakpoint Exception");
226 intr_register (4, 3, IF_ON, intr_kill, "#OF Overflow Exception");
227 intr_register (5, 3, IF_ON, intr_kill, "#BR BOUND Range Exceeded Exception");
228 intr_register (6, 0, IF_ON, intr_kill, "#UD Invalid Opcode Exception");
229 intr_register (7, 0, IF_ON, intr_kill, "#NM Device Not Available Exception");
230 intr_register (8, 0, IF_ON, intr_panic, "#DF Double Fault Exception");
231 intr_register (9, 0, IF_ON, intr_panic, "Coprocessor Segment Overrun");
232 intr_register (10, 0, IF_ON, intr_panic, "#TS Invalid TSS Exception");
233 intr_register (11, 0, IF_ON, intr_kill, "#NP Segment Not Present");
234 intr_register (12, 0, IF_ON, intr_kill, "#SS Stack Fault Exception");
235 intr_register (13, 0, IF_ON, intr_kill, "#GP General Protection Exception");
236 intr_register (16, 0, IF_ON, intr_kill, "#MF x87 FPU Floating-Point Error");
237 intr_register (17, 0, IF_ON, intr_panic, "#AC Alignment Check Exception");
238 intr_register (18, 0, IF_ON, intr_panic, "#MC Machine-Check Exception");
239 intr_register (19, 0, IF_ON, intr_kill, "#XF SIMD Floating-Point Exception");
241 /* Most exceptions can be handled with interrupts turned on.
242 We need to disable interrupts for page faults because the
243 fault address is stored in CR2 and needs to be preserved. */
244 intr_register (14, 0, IF_OFF, intr_kill, "#PF Page-Fault Exception");
246 idtr_operand = make_dtr_operand (sizeof idt - 1, idt);
247 asm volatile ("lidt %0" :: "m" (idtr_operand));
251 dump_intr_frame (struct intr_frame *f)
254 asm ("movl %%cr2, %0" : "=r" (cr2));
255 asm ("movl %%ss, %0" : "=r" (ss));
257 printk ("Interrupt %#04x (%s) at eip=%p\n",
258 f->vec_no, intr_name (f->vec_no), f->eip);
259 printk (" cr2=%08"PRIx32" error=%08"PRIx32"\n", cr2, f->error_code);
260 printk (" eax=%08"PRIx32" ebx=%08"PRIx32" ecx=%08"PRIx32" edx=%08"PRIx32"\n",
261 f->eax, f->ebx, f->ecx, f->edx);
262 printk (" esi=%08"PRIx32" edi=%08"PRIx32" esp=%08"PRIx32" ebp=%08"PRIx32"\n",
263 f->esi, f->edi, (uint32_t) f->esp, f->ebp);
264 printk (" cs=%04"PRIx16" ds=%04"PRIx16" es=%04"PRIx16" ss=%04"PRIx16"\n",
265 f->cs, f->ds, f->es, f->cs != SEL_KCSEG ? f->ss : ss);
269 intr_panic (struct intr_frame *regs)
271 dump_intr_frame (regs);
276 intr_kill (struct intr_frame *f)
281 printk ("%s: dying due to interrupt %#04x (%s).\n",
282 thread_current ()->name, f->vec_no, intr_name (f->vec_no));
286 printk ("Kernel bug - unexpected interrupt in kernel context\n");
290 printk ("Interrupt %#04x (%s) in unknown segment %04x\n",
291 f->vec_no, intr_name (f->vec_no), f->cs);