3 #include "intr-stubs.h"
16 asm ("pushfl; popl %0" : "=g" (flags));
18 return flags & (1 << 9) ? IF_ON : IF_OFF;
22 intr_set_level (enum if_level level)
24 enum if_level old_level = intr_get_level ();
35 enum if_level old_level = intr_get_level ();
43 enum if_level old_level = intr_get_level ();
51 /* Every PC has two 8259A Programmable Interrupt Controller
52 (PIC) chips. One is a "master" accessible at ports 0x20 and
53 0x21. The other is a "slave" cascaded onto the master's IRQ
54 2 line and accessible at ports 0xa0 and 0xa1. Accesses to
55 port 0x20 set the A0 line to 0 and accesses to 0x21 set the
56 A1 line to 1. The situation is similar for the slave PIC.
57 Refer to the 8259A datasheet for details.
59 By default, interrupts 0...15 delivered by the PICs will go
60 to interrupt vectors 0...15. Unfortunately, those vectors
61 are also used for CPU traps and exceptions. We reprogram
62 the PICs so that interrupts 0...15 are delivered to
63 interrupt vectors 32...47 instead. */
65 /* Mask all interrupts on both PICs. */
69 /* Initialize master. */
70 outb (0x20, 0x11); /* ICW1: single mode, edge triggered, expect ICW4. */
71 outb (0x21, 0x20); /* ICW2: line IR0...7 -> irq 0x20...0x27. */
72 outb (0x21, 0x04); /* ICW3: slave PIC on line IR2. */
73 outb (0x21, 0x01); /* ICW4: 8086 mode, normal EOI, non-buffered. */
75 /* Initialize slave. */
76 outb (0xa0, 0x11); /* ICW1: single mode, edge triggered, expect ICW4. */
77 outb (0xa1, 0x28); /* ICW2: line IR0...7 -> irq 0x28...0x2f. */
78 outb (0xa1, 0x02); /* ICW3: slave ID is 2. */
79 outb (0xa1, 0x01); /* ICW4: 8086 mode, normal EOI, non-buffered. */
81 /* Unmask all interrupts. */
86 /* Sends an end-of-interrupt signal to the PIC for the given IRQ.
87 If we don't acknowledge the IRQ, we'll never get it again, so
92 /* FIXME? The Linux code is much more complicated. */
98 intr_handler_func *intr_handlers[256];
100 void intr_handler (struct intr_frame *args);
102 bool intr_in_progress;
103 bool yield_on_return;
106 intr_handler (struct intr_frame *args)
110 yield_on_return = false;
112 external = args->vec_no >= 0x20 && args->vec_no < 0x30;
115 ASSERT (intr_get_level () == IF_OFF);
116 ASSERT (!intr_context ());
117 intr_in_progress = true;
120 intr_handlers[args->vec_no] (args);
124 ASSERT (intr_get_level () == IF_OFF);
125 ASSERT (intr_context ());
126 intr_in_progress = false;
140 return intr_in_progress;
144 intr_yield_on_return (void)
146 yield_on_return = true;
149 /* Handles interrupts we don't know about. */
150 intr_handler_func intr_unexpected;
152 /* Handlers for CPU exceptions. */
153 intr_handler_func excp00_divide_error;
154 intr_handler_func excp01_debug;
155 intr_handler_func excp02_nmi;
156 intr_handler_func excp03_breakpoint;
157 intr_handler_func excp04_overflow;
158 intr_handler_func excp05_bound;
159 intr_handler_func excp06_invalid_opcode;
160 intr_handler_func excp07_device_not_available;
161 intr_handler_func excp08_double_fault;
162 intr_handler_func excp09_coprocessor_overrun;
163 intr_handler_func excp0a_invalid_tss;
164 intr_handler_func excp0b_segment_not_present;
165 intr_handler_func excp0c_stack_fault;
166 intr_handler_func excp0d_general_protection;
167 intr_handler_func excp0e_page_fault;
168 intr_handler_func excp10_fp_error;
169 intr_handler_func excp11_alignment;
170 intr_handler_func excp12_machine_check;
171 intr_handler_func excp13_simd_error;
174 make_intr_gate (void (*target) (void),
177 uint32_t offset = (uint32_t) target;
178 uint32_t e0 = ((offset & 0xffff) /* Offset 15:0. */
179 | (SEL_KCSEG << 16)); /* Target code segment. */
180 uint32_t e1 = ((offset & 0xffff0000) /* Offset 31:16. */
181 | (1 << 15) /* Present. */
182 | (dpl << 13) /* Descriptor privilege. */
183 | (SYS_SYSTEM << 12) /* System. */
184 | (TYPE_INT_32 << 8)); /* 32-bit interrupt gate. */
185 return e0 | ((uint64_t) e1 << 32);
189 make_trap_gate (void (*target) (void),
192 return make_intr_gate (target, dpl) | (1 << 8);
195 /* We don't support nested interrupts generated by external
196 hardware, so these interrupts (vec_no 0x20...0x2f) should
197 specify IF_OFF for LEVEL. Otherwise a timer interrupt could
198 cause a task switch during interrupt handling. Most other
199 interrupts can and should be handled with interrupts
202 intr_register (uint8_t vec_no, int dpl, enum if_level level,
203 intr_handler_func *handler)
206 idt[vec_no] = make_trap_gate (intr_stubs[vec_no], dpl);
208 idt[vec_no] = make_intr_gate (intr_stubs[vec_no], dpl);
209 intr_handlers[vec_no] = handler;
215 uint64_t idtr_operand;
220 /* Install default handlers. */
221 for (i = 0; i < 256; i++)
222 intr_register (i, 0, IF_OFF, intr_unexpected);
224 /* Most exceptions require ring 0.
225 Exceptions 3, 4, and 5 can be caused by ring 3 directly.
227 Most exceptions can be handled with interrupts turned on.
228 We need to disable interrupts for page faults because the
229 fault address is stored in CR2 and needs to be preserved.
232 intr_register (0x00, 0, IF_ON, excp00_divide_error);
233 intr_register (0x01, 0, IF_ON, excp01_debug);
234 intr_register (0x02, 0, IF_ON, excp02_nmi);
235 intr_register (0x03, 3, IF_ON, excp03_breakpoint);
236 intr_register (0x04, 3, IF_ON, excp04_overflow);
237 intr_register (0x05, 3, IF_ON, excp05_bound);
238 intr_register (0x06, 0, IF_ON, excp06_invalid_opcode);
239 intr_register (0x07, 0, IF_ON, excp07_device_not_available);
240 intr_register (0x08, 0, IF_ON, excp08_double_fault);
241 intr_register (0x09, 0, IF_ON, excp09_coprocessor_overrun);
242 intr_register (0x0a, 0, IF_ON, excp0a_invalid_tss);
243 intr_register (0x0b, 0, IF_ON, excp0b_segment_not_present);
244 intr_register (0x0c, 0, IF_ON, excp0c_stack_fault);
245 intr_register (0x0d, 0, IF_ON, excp0d_general_protection);
246 intr_register (0x0e, 0, IF_OFF, excp0e_page_fault);
247 intr_register (0x10, 0, IF_ON, excp10_fp_error);
248 intr_register (0x11, 0, IF_ON, excp11_alignment);
249 intr_register (0x12, 0, IF_ON, excp12_machine_check);
250 intr_register (0x13, 0, IF_ON, excp13_simd_error);
253 idtr_operand = make_dtr_operand (sizeof idt - 1, idt);
254 asm volatile ("lidt %0" :: "m" (idtr_operand));
258 intr_unexpected (struct intr_frame *regs)
261 asm ("movl %%cr2, %0" : "=r" (cr2));
262 panic ("Unexpected interrupt 0x%02x, error code %08x, cr2=%08x, eip=%p",
263 regs->vec_no, regs->error_code, cr2, (void *) regs->eip);