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