xref: /haiku/src/system/kernel/arch/x86/arch_int.cpp (revision fccd8899fcb583bfb73c5c26c9fcd714b963959b)
1 /*
2  * Copyright 2008-2011, Michael Lotz, mmlr@mlotz.ch.
3  * Copyright 2010, Clemens Zeidler, haiku@clemens-zeidler.de.
4  * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
5  * Copyright 2002-2010, Axel Dörfler, axeld@pinc-software.de.
6  * Distributed under the terms of the MIT License.
7  *
8  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
9  * Distributed under the terms of the NewOS License.
10  */
11 
12 
13 #include <cpu.h>
14 #include <int.h>
15 #include <kscheduler.h>
16 #include <ksyscalls.h>
17 #include <smp.h>
18 #include <team.h>
19 #include <thread.h>
20 #include <util/AutoLock.h>
21 #include <vm/vm.h>
22 #include <vm/vm_priv.h>
23 
24 #include <arch/cpu.h>
25 #include <arch/int.h>
26 #include <arch/smp.h>
27 #include <arch/user_debugger.h>
28 #include <arch/vm.h>
29 
30 #include <arch/x86/apic.h>
31 #include <arch/x86/descriptors.h>
32 #include <arch/x86/msi.h>
33 #include <arch/x86/vm86.h>
34 
35 #include "interrupts.h"
36 
37 #include <stdio.h>
38 
39 // interrupt controllers
40 #include <arch/x86/ioapic.h>
41 #include <arch/x86/pic.h>
42 
43 
44 //#define TRACE_ARCH_INT
45 #ifdef TRACE_ARCH_INT
46 #	define TRACE(x) dprintf x
47 #else
48 #	define TRACE(x) ;
49 #endif
50 
51 
52 static const interrupt_controller *sCurrentPIC = NULL;
53 
54 static const char *kInterruptNames[] = {
55 	/*  0 */ "Divide Error Exception",
56 	/*  1 */ "Debug Exception",
57 	/*  2 */ "NMI Interrupt",
58 	/*  3 */ "Breakpoint Exception",
59 	/*  4 */ "Overflow Exception",
60 	/*  5 */ "BOUND Range Exceeded Exception",
61 	/*  6 */ "Invalid Opcode Exception",
62 	/*  7 */ "Device Not Available Exception",
63 	/*  8 */ "Double Fault Exception",
64 	/*  9 */ "Coprocessor Segment Overrun",
65 	/* 10 */ "Invalid TSS Exception",
66 	/* 11 */ "Segment Not Present",
67 	/* 12 */ "Stack Fault Exception",
68 	/* 13 */ "General Protection Exception",
69 	/* 14 */ "Page-Fault Exception",
70 	/* 15 */ "-",
71 	/* 16 */ "x87 FPU Floating-Point Error",
72 	/* 17 */ "Alignment Check Exception",
73 	/* 18 */ "Machine-Check Exception",
74 	/* 19 */ "SIMD Floating-Point Exception",
75 };
76 static const int kInterruptNameCount = 20;
77 
78 #define MAX_ARGS 16
79 
80 typedef struct {
81 	uint32 a, b;
82 } desc_table;
83 static desc_table* sIDTs[B_MAX_CPU_COUNT];
84 
85 // table with functions handling respective interrupts
86 typedef void interrupt_handler_function(struct iframe* frame);
87 
88 #define INTERRUPT_HANDLER_TABLE_SIZE 256
89 interrupt_handler_function* gInterruptHandlerTable[
90 	INTERRUPT_HANDLER_TABLE_SIZE];
91 
92 
93 /*!	Initializes a descriptor in an IDT.
94 */
95 static void
96 set_gate(desc_table *gate_addr, addr_t addr, int type, int dpl)
97 {
98 	unsigned int gate1; // first byte of gate desc
99 	unsigned int gate2; // second byte of gate desc
100 
101 	gate1 = (KERNEL_CODE_SEG << 16) | (0x0000ffff & addr);
102 	gate2 = (0xffff0000 & addr) | 0x8000 | (dpl << 13) | (type << 8);
103 
104 	gate_addr->a = gate1;
105 	gate_addr->b = gate2;
106 }
107 
108 
109 /*!	Initializes the descriptor for interrupt vector \a n in the IDT of the
110 	specified CPU to an interrupt-gate descriptor with the given procedure
111 	address.
112 	For CPUs other than the boot CPU it must not be called before
113 	arch_int_init_post_vm().
114 */
115 static void
116 set_interrupt_gate(int32 cpu, int n, void (*addr)())
117 {
118 	set_gate(&sIDTs[cpu][n], (addr_t)addr, 14, DPL_KERNEL);
119 }
120 
121 
122 /*!	Initializes the descriptor for interrupt vector \a n in the IDT of the
123 	specified CPU to an trap-gate descriptor with the given procedure address.
124 	For CPUs other than the boot CPU it must not be called before
125 	arch_int_init_post_vm().
126 */
127 static void
128 set_trap_gate(int32 cpu, int n, void (*addr)())
129 {
130 	set_gate(&sIDTs[cpu][n], (unsigned int)addr, 15, DPL_USER);
131 }
132 
133 
134 /*!	Initializes the descriptor for interrupt vector \a n in the IDT of CPU
135 	\a cpu to a task-gate descripter referring to the TSS segment identified
136 	by TSS segment selector \a segment.
137 	For CPUs other than the boot CPU it must not be called before
138 	arch_int_init_post_vm() (arch_cpu_init_post_vm() is fine).
139 */
140 void
141 x86_set_task_gate(int32 cpu, int32 n, int32 segment)
142 {
143 	sIDTs[cpu][n].a = (segment << 16);
144 	sIDTs[cpu][n].b = 0x8000 | (0 << 13) | (0x5 << 8); // present, dpl 0, type 5
145 }
146 
147 
148 /*!	Returns the virtual IDT address for CPU \a cpu. */
149 void*
150 x86_get_idt(int32 cpu)
151 {
152 	return sIDTs[cpu];
153 }
154 
155 
156 // #pragma mark -
157 
158 
159 void
160 arch_int_enable_io_interrupt(int irq)
161 {
162 	sCurrentPIC->enable_io_interrupt(irq);
163 }
164 
165 
166 void
167 arch_int_disable_io_interrupt(int irq)
168 {
169 	sCurrentPIC->disable_io_interrupt(irq);
170 }
171 
172 
173 void
174 arch_int_configure_io_interrupt(int irq, uint32 config)
175 {
176 	sCurrentPIC->configure_io_interrupt(irq, config);
177 }
178 
179 
180 #undef arch_int_enable_interrupts
181 #undef arch_int_disable_interrupts
182 #undef arch_int_restore_interrupts
183 #undef arch_int_are_interrupts_enabled
184 
185 
186 void
187 arch_int_enable_interrupts(void)
188 {
189 	arch_int_enable_interrupts_inline();
190 }
191 
192 
193 int
194 arch_int_disable_interrupts(void)
195 {
196 	return arch_int_disable_interrupts_inline();
197 }
198 
199 
200 void
201 arch_int_restore_interrupts(int oldState)
202 {
203 	arch_int_restore_interrupts_inline(oldState);
204 }
205 
206 
207 bool
208 arch_int_are_interrupts_enabled(void)
209 {
210 	return arch_int_are_interrupts_enabled_inline();
211 }
212 
213 
214 static const char *
215 exception_name(int number, char *buffer, int32 bufferSize)
216 {
217 	if (number >= 0 && number < kInterruptNameCount)
218 		return kInterruptNames[number];
219 
220 	snprintf(buffer, bufferSize, "exception %d", number);
221 	return buffer;
222 }
223 
224 
225 static void
226 invalid_exception(struct iframe* frame)
227 {
228 	Thread* thread = thread_get_current_thread();
229 	char name[32];
230 	panic("unhandled trap 0x%lx (%s) at ip 0x%lx, thread %ld!\n",
231 		frame->vector, exception_name(frame->vector, name, sizeof(name)),
232 		frame->eip, thread ? thread->id : -1);
233 }
234 
235 
236 static void
237 fatal_exception(struct iframe *frame)
238 {
239 	char name[32];
240 	panic("Fatal exception \"%s\" occurred! Error code: 0x%lx\n",
241 		exception_name(frame->vector, name, sizeof(name)), frame->error_code);
242 }
243 
244 
245 static void
246 unexpected_exception(struct iframe* frame)
247 {
248 	debug_exception_type type;
249 	uint32 signalNumber;
250 	int32 signalCode;
251 	addr_t signalAddress = 0;
252 	int32 signalError = B_ERROR;
253 
254 	if (IFRAME_IS_VM86(frame)) {
255 		x86_vm86_return((struct vm86_iframe *)frame, (frame->vector == 13) ?
256 			B_OK : B_ERROR);
257 		// won't get here
258 	}
259 
260 	switch (frame->vector) {
261 		case 0:		// Divide Error Exception (#DE)
262 			type = B_DIVIDE_ERROR;
263 			signalNumber = SIGFPE;
264 			signalCode = FPE_INTDIV;
265 			signalAddress = frame->eip;
266 			break;
267 
268 		case 4:		// Overflow Exception (#OF)
269 			type = B_OVERFLOW_EXCEPTION;
270 			signalNumber = SIGFPE;
271 			signalCode = FPE_INTOVF;
272 			signalAddress = frame->eip;
273 			break;
274 
275 		case 5:		// BOUND Range Exceeded Exception (#BR)
276 			type = B_BOUNDS_CHECK_EXCEPTION;
277 			signalNumber = SIGTRAP;
278 			signalCode = SI_USER;
279 			break;
280 
281 		case 6:		// Invalid Opcode Exception (#UD)
282 			type = B_INVALID_OPCODE_EXCEPTION;
283 			signalNumber = SIGILL;
284 			signalCode = ILL_ILLOPC;
285 			signalAddress = frame->eip;
286 			break;
287 
288 		case 13: 	// General Protection Exception (#GP)
289 			type = B_GENERAL_PROTECTION_FAULT;
290 			signalNumber = SIGILL;
291 			signalCode = ILL_PRVOPC;	// or ILL_PRVREG
292 			signalAddress = frame->eip;
293 			break;
294 
295 		case 16: 	// x87 FPU Floating-Point Error (#MF)
296 			type = B_FLOATING_POINT_EXCEPTION;
297 			signalNumber = SIGFPE;
298 			signalCode = FPE_FLTDIV;
299 				// TODO: Determine the correct cause via the FPU status
300 				// register!
301 			signalAddress = frame->eip;
302 			break;
303 
304 		case 17: 	// Alignment Check Exception (#AC)
305 			type = B_ALIGNMENT_EXCEPTION;
306 			signalNumber = SIGBUS;
307 			signalCode = BUS_ADRALN;
308 			// TODO: Also get the address (from where?). Since we don't enable
309 			// alignment checking this exception should never happen, though.
310 			signalError = EFAULT;
311 			break;
312 
313 		case 19: 	// SIMD Floating-Point Exception (#XF)
314 			type = B_FLOATING_POINT_EXCEPTION;
315 			signalNumber = SIGFPE;
316 			signalCode = FPE_FLTDIV;
317 				// TODO: Determine the correct cause via the MXCSR register!
318 			signalAddress = frame->eip;
319 			break;
320 
321 		default:
322 			invalid_exception(frame);
323 			return;
324 	}
325 
326 	if (IFRAME_IS_USER(frame)) {
327 		struct sigaction action;
328 		Thread* thread = thread_get_current_thread();
329 
330 		enable_interrupts();
331 
332 		// If the thread has a signal handler for the signal, we simply send it
333 		// the signal. Otherwise we notify the user debugger first.
334 		if ((sigaction(signalNumber, NULL, &action) == 0
335 				&& action.sa_handler != SIG_DFL
336 				&& action.sa_handler != SIG_IGN)
337 			|| user_debug_exception_occurred(type, signalNumber)) {
338 			Signal signal(signalNumber, signalCode, signalError,
339 				thread->team->id);
340 			signal.SetAddress((void*)signalAddress);
341 			send_signal_to_thread(thread, signal, 0);
342 		}
343 	} else {
344 		char name[32];
345 		panic("Unexpected exception \"%s\" occurred in kernel mode! "
346 			"Error code: 0x%lx\n",
347 			exception_name(frame->vector, name, sizeof(name)),
348 			frame->error_code);
349 	}
350 }
351 
352 
353 void
354 x86_double_fault_exception(struct iframe* frame)
355 {
356 	int cpu = x86_double_fault_get_cpu();
357 
358 	// The double fault iframe contains no useful information (as
359 	// per Intel's architecture spec). Thus we simply save the
360 	// information from the (unhandlable) exception which caused the
361 	// double in our iframe. This will result even in useful stack
362 	// traces. Only problem is that we trust that at least the
363 	// TSS is still accessible.
364 	struct tss *tss = &gCPU[cpu].arch.tss;
365 
366 	frame->cs = tss->cs;
367 	frame->es = tss->es;
368 	frame->ds = tss->ds;
369 	frame->fs = tss->fs;
370 	frame->gs = tss->gs;
371 	frame->eip = tss->eip;
372 	frame->ebp = tss->ebp;
373 	frame->esp = tss->esp;
374 	frame->eax = tss->eax;
375 	frame->ebx = tss->ebx;
376 	frame->ecx = tss->ecx;
377 	frame->edx = tss->edx;
378 	frame->esi = tss->esi;
379 	frame->edi = tss->edi;
380 	frame->flags = tss->eflags;
381 
382 	// Use a special handler for page faults which avoids the triple fault
383 	// pitfalls.
384 	set_interrupt_gate(cpu, 14, &trap14_double_fault);
385 
386 	debug_double_fault(cpu);
387 }
388 
389 
390 void
391 x86_page_fault_exception_double_fault(struct iframe* frame)
392 {
393 	uint32 cr2;
394 	asm("movl %%cr2, %0" : "=r" (cr2));
395 
396 	// Only if this CPU has a fault handler, we're allowed to be here.
397 	cpu_ent& cpu = gCPU[x86_double_fault_get_cpu()];
398 	addr_t faultHandler = cpu.fault_handler;
399 	if (faultHandler != 0) {
400 		debug_set_page_fault_info(cr2, frame->eip,
401 			(frame->error_code & 0x2) != 0 ? DEBUG_PAGE_FAULT_WRITE : 0);
402 		frame->eip = faultHandler;
403 		frame->ebp = cpu.fault_handler_stack_pointer;
404 		return;
405 	}
406 
407 	// No fault handler. This is bad. Since we originally came from a double
408 	// fault, we don't try to reenter the kernel debugger. Instead we just
409 	// print the info we've got and enter an infinite loop.
410 	kprintf("Page fault in double fault debugger without fault handler! "
411 		"Touching address %p from eip %p. Entering infinite loop...\n",
412 		(void*)cr2, (void*)frame->eip);
413 
414 	while (true);
415 }
416 
417 
418 static void
419 page_fault_exception(struct iframe* frame)
420 {
421 	Thread *thread = thread_get_current_thread();
422 	uint32 cr2;
423 	addr_t newip;
424 
425 	asm("movl %%cr2, %0" : "=r" (cr2));
426 
427 	if (debug_debugger_running()) {
428 		// If this CPU or this thread has a fault handler, we're allowed to be
429 		// here.
430 		if (thread != NULL) {
431 			cpu_ent* cpu = &gCPU[smp_get_current_cpu()];
432 			if (cpu->fault_handler != 0) {
433 				debug_set_page_fault_info(cr2, frame->eip,
434 					(frame->error_code & 0x2) != 0
435 						? DEBUG_PAGE_FAULT_WRITE : 0);
436 				frame->eip = cpu->fault_handler;
437 				frame->ebp = cpu->fault_handler_stack_pointer;
438 				return;
439 			}
440 
441 			if (thread->fault_handler != 0) {
442 				kprintf("ERROR: thread::fault_handler used in kernel "
443 					"debugger!\n");
444 				debug_set_page_fault_info(cr2, frame->eip,
445 					(frame->error_code & 0x2) != 0
446 						? DEBUG_PAGE_FAULT_WRITE : 0);
447 				frame->eip = thread->fault_handler;
448 				return;
449 			}
450 		}
451 
452 		// otherwise, not really
453 		panic("page fault in debugger without fault handler! Touching "
454 			"address %p from eip %p\n", (void *)cr2, (void *)frame->eip);
455 		return;
456 	} else if ((frame->flags & 0x200) == 0) {
457 		// interrupts disabled
458 
459 		// If a page fault handler is installed, we're allowed to be here.
460 		// TODO: Now we are generally allowing user_memcpy() with interrupts
461 		// disabled, which in most cases is a bug. We should add some thread
462 		// flag allowing to explicitly indicate that this handling is desired.
463 		if (thread && thread->fault_handler != 0) {
464 			if (frame->eip != thread->fault_handler) {
465 				frame->eip = thread->fault_handler;
466 				return;
467 			}
468 
469 			// The fault happened at the fault handler address. This is a
470 			// certain infinite loop.
471 			panic("page fault, interrupts disabled, fault handler loop. "
472 				"Touching address %p from eip %p\n", (void*)cr2,
473 				(void*)frame->eip);
474 		}
475 
476 		// If we are not running the kernel startup the page fault was not
477 		// allowed to happen and we must panic.
478 		panic("page fault, but interrupts were disabled. Touching address "
479 			"%p from eip %p\n", (void *)cr2, (void *)frame->eip);
480 		return;
481 	} else if (thread != NULL && thread->page_faults_allowed < 1) {
482 		panic("page fault not allowed at this place. Touching address "
483 			"%p from eip %p\n", (void *)cr2, (void *)frame->eip);
484 		return;
485 	}
486 
487 	enable_interrupts();
488 
489 	vm_page_fault(cr2, frame->eip,
490 		(frame->error_code & 0x2) != 0,	// write access
491 		(frame->error_code & 0x4) != 0,	// userland
492 		&newip);
493 	if (newip != 0) {
494 		// the page fault handler wants us to modify the iframe to set the
495 		// IP the cpu will return to to be this ip
496 		frame->eip = newip;
497 	}
498 }
499 
500 
501 static void
502 hardware_interrupt(struct iframe* frame)
503 {
504 	int32 vector = frame->vector - ARCH_INTERRUPT_BASE;
505 	bool levelTriggered = false;
506 	Thread* thread = thread_get_current_thread();
507 
508 	if (sCurrentPIC->is_spurious_interrupt(vector)) {
509 		TRACE(("got spurious interrupt at vector %ld\n", vector));
510 		return;
511 	}
512 
513 	levelTriggered = sCurrentPIC->is_level_triggered_interrupt(vector);
514 
515 	if (!levelTriggered) {
516 		// if it's not handled by the current pic then it's an apic generated
517 		// interrupt like local interrupts, msi or ipi.
518 		if (!sCurrentPIC->end_of_interrupt(vector))
519 			apic_end_of_interrupt();
520 	}
521 
522 	int_io_interrupt_handler(vector, levelTriggered);
523 
524 	if (levelTriggered) {
525 		if (!sCurrentPIC->end_of_interrupt(vector))
526 			apic_end_of_interrupt();
527 	}
528 
529 	cpu_status state = disable_interrupts();
530 	if (thread->cpu->invoke_scheduler) {
531 		SpinLocker schedulerLocker(gSchedulerLock);
532 		scheduler_reschedule();
533 		schedulerLocker.Unlock();
534 		restore_interrupts(state);
535 	} else if (thread->post_interrupt_callback != NULL) {
536 		void (*callback)(void*) = thread->post_interrupt_callback;
537 		void* data = thread->post_interrupt_data;
538 
539 		thread->post_interrupt_callback = NULL;
540 		thread->post_interrupt_data = NULL;
541 
542 		restore_interrupts(state);
543 
544 		callback(data);
545 	}
546 }
547 
548 
549 status_t
550 arch_int_init(struct kernel_args *args)
551 {
552 	int i;
553 	interrupt_handler_function** table;
554 
555 	// set the global sIDT variable
556 	sIDTs[0] = (desc_table *)args->arch_args.vir_idt;
557 
558 	// setup the standard programmable interrupt controller
559 	pic_init();
560 
561 	set_interrupt_gate(0, 0, &trap0);
562 	set_interrupt_gate(0, 1, &trap1);
563 	set_interrupt_gate(0, 2, &trap2);
564 	set_trap_gate(0, 3, &trap3);
565 	set_interrupt_gate(0, 4, &trap4);
566 	set_interrupt_gate(0, 5, &trap5);
567 	set_interrupt_gate(0, 6, &trap6);
568 	set_interrupt_gate(0, 7, &trap7);
569 	// trap8 (double fault) is set in arch_cpu.c
570 	set_interrupt_gate(0, 9, &trap9);
571 	set_interrupt_gate(0, 10, &trap10);
572 	set_interrupt_gate(0, 11, &trap11);
573 	set_interrupt_gate(0, 12, &trap12);
574 	set_interrupt_gate(0, 13, &trap13);
575 	set_interrupt_gate(0, 14, &trap14);
576 //	set_interrupt_gate(0, 15, &trap15);
577 	set_interrupt_gate(0, 16, &trap16);
578 	set_interrupt_gate(0, 17, &trap17);
579 	set_interrupt_gate(0, 18, &trap18);
580 	set_interrupt_gate(0, 19, &trap19);
581 
582 	// legacy or ioapic interrupts
583 	set_interrupt_gate(0, 32, &trap32);
584 	set_interrupt_gate(0, 33, &trap33);
585 	set_interrupt_gate(0, 34, &trap34);
586 	set_interrupt_gate(0, 35, &trap35);
587 	set_interrupt_gate(0, 36, &trap36);
588 	set_interrupt_gate(0, 37, &trap37);
589 	set_interrupt_gate(0, 38, &trap38);
590 	set_interrupt_gate(0, 39, &trap39);
591 	set_interrupt_gate(0, 40, &trap40);
592 	set_interrupt_gate(0, 41, &trap41);
593 	set_interrupt_gate(0, 42, &trap42);
594 	set_interrupt_gate(0, 43, &trap43);
595 	set_interrupt_gate(0, 44, &trap44);
596 	set_interrupt_gate(0, 45, &trap45);
597 	set_interrupt_gate(0, 46, &trap46);
598 	set_interrupt_gate(0, 47, &trap47);
599 
600 	// additional ioapic interrupts
601 	set_interrupt_gate(0, 48, &trap48);
602 	set_interrupt_gate(0, 49, &trap49);
603 	set_interrupt_gate(0, 50, &trap50);
604 	set_interrupt_gate(0, 51, &trap51);
605 	set_interrupt_gate(0, 52, &trap52);
606 	set_interrupt_gate(0, 53, &trap53);
607 	set_interrupt_gate(0, 54, &trap54);
608 	set_interrupt_gate(0, 55, &trap55);
609 
610 	// configurable msi or msi-x interrupts
611 	set_interrupt_gate(0, 56, &trap56);
612 	set_interrupt_gate(0, 57, &trap57);
613 	set_interrupt_gate(0, 58, &trap58);
614 	set_interrupt_gate(0, 59, &trap59);
615 	set_interrupt_gate(0, 60, &trap60);
616 	set_interrupt_gate(0, 61, &trap61);
617 	set_interrupt_gate(0, 62, &trap62);
618 	set_interrupt_gate(0, 63, &trap63);
619 	set_interrupt_gate(0, 64, &trap64);
620 	set_interrupt_gate(0, 65, &trap65);
621 	set_interrupt_gate(0, 66, &trap66);
622 	set_interrupt_gate(0, 67, &trap67);
623 	set_interrupt_gate(0, 68, &trap68);
624 	set_interrupt_gate(0, 69, &trap69);
625 	set_interrupt_gate(0, 70, &trap70);
626 	set_interrupt_gate(0, 71, &trap71);
627 	set_interrupt_gate(0, 72, &trap72);
628 	set_interrupt_gate(0, 73, &trap73);
629 	set_interrupt_gate(0, 74, &trap74);
630 	set_interrupt_gate(0, 75, &trap75);
631 	set_interrupt_gate(0, 76, &trap76);
632 	set_interrupt_gate(0, 77, &trap77);
633 	set_interrupt_gate(0, 78, &trap78);
634 	set_interrupt_gate(0, 79, &trap79);
635 	set_interrupt_gate(0, 80, &trap80);
636 	set_interrupt_gate(0, 81, &trap81);
637 	set_interrupt_gate(0, 82, &trap82);
638 	set_interrupt_gate(0, 83, &trap83);
639 	set_interrupt_gate(0, 84, &trap84);
640 	set_interrupt_gate(0, 85, &trap85);
641 	set_interrupt_gate(0, 86, &trap86);
642 	set_interrupt_gate(0, 87, &trap87);
643 	set_interrupt_gate(0, 88, &trap88);
644 	set_interrupt_gate(0, 89, &trap89);
645 	set_interrupt_gate(0, 90, &trap90);
646 	set_interrupt_gate(0, 91, &trap91);
647 	set_interrupt_gate(0, 92, &trap92);
648 	set_interrupt_gate(0, 93, &trap93);
649 	set_interrupt_gate(0, 94, &trap94);
650 	set_interrupt_gate(0, 95, &trap95);
651 	set_interrupt_gate(0, 96, &trap96);
652 	set_interrupt_gate(0, 97, &trap97);
653 
654 	set_trap_gate(0, 98, &trap98);	// for performance testing only
655 	set_trap_gate(0, 99, &trap99);	// syscall interrupt
656 
657 	reserve_io_interrupt_vectors(2, 98);
658 
659 	// configurable msi or msi-x interrupts
660 	set_interrupt_gate(0, 100, &trap100);
661 	set_interrupt_gate(0, 101, &trap101);
662 	set_interrupt_gate(0, 102, &trap102);
663 	set_interrupt_gate(0, 103, &trap103);
664 	set_interrupt_gate(0, 104, &trap104);
665 	set_interrupt_gate(0, 105, &trap105);
666 	set_interrupt_gate(0, 106, &trap106);
667 	set_interrupt_gate(0, 107, &trap107);
668 	set_interrupt_gate(0, 108, &trap108);
669 	set_interrupt_gate(0, 109, &trap109);
670 	set_interrupt_gate(0, 110, &trap110);
671 	set_interrupt_gate(0, 111, &trap111);
672 	set_interrupt_gate(0, 112, &trap112);
673 	set_interrupt_gate(0, 113, &trap113);
674 	set_interrupt_gate(0, 114, &trap114);
675 	set_interrupt_gate(0, 115, &trap115);
676 	set_interrupt_gate(0, 116, &trap116);
677 	set_interrupt_gate(0, 117, &trap117);
678 	set_interrupt_gate(0, 118, &trap118);
679 	set_interrupt_gate(0, 119, &trap119);
680 	set_interrupt_gate(0, 120, &trap120);
681 	set_interrupt_gate(0, 121, &trap121);
682 	set_interrupt_gate(0, 122, &trap122);
683 	set_interrupt_gate(0, 123, &trap123);
684 	set_interrupt_gate(0, 124, &trap124);
685 	set_interrupt_gate(0, 125, &trap125);
686 	set_interrupt_gate(0, 126, &trap126);
687 	set_interrupt_gate(0, 127, &trap127);
688 	set_interrupt_gate(0, 128, &trap128);
689 	set_interrupt_gate(0, 129, &trap129);
690 	set_interrupt_gate(0, 130, &trap130);
691 	set_interrupt_gate(0, 131, &trap131);
692 	set_interrupt_gate(0, 132, &trap132);
693 	set_interrupt_gate(0, 133, &trap133);
694 	set_interrupt_gate(0, 134, &trap134);
695 	set_interrupt_gate(0, 135, &trap135);
696 	set_interrupt_gate(0, 136, &trap136);
697 	set_interrupt_gate(0, 137, &trap137);
698 	set_interrupt_gate(0, 138, &trap138);
699 	set_interrupt_gate(0, 139, &trap139);
700 	set_interrupt_gate(0, 140, &trap140);
701 	set_interrupt_gate(0, 141, &trap141);
702 	set_interrupt_gate(0, 142, &trap142);
703 	set_interrupt_gate(0, 143, &trap143);
704 	set_interrupt_gate(0, 144, &trap144);
705 	set_interrupt_gate(0, 145, &trap145);
706 	set_interrupt_gate(0, 146, &trap146);
707 	set_interrupt_gate(0, 147, &trap147);
708 	set_interrupt_gate(0, 148, &trap148);
709 	set_interrupt_gate(0, 149, &trap149);
710 	set_interrupt_gate(0, 150, &trap150);
711 	set_interrupt_gate(0, 151, &trap151);
712 	set_interrupt_gate(0, 152, &trap152);
713 	set_interrupt_gate(0, 153, &trap153);
714 	set_interrupt_gate(0, 154, &trap154);
715 	set_interrupt_gate(0, 155, &trap155);
716 	set_interrupt_gate(0, 156, &trap156);
717 	set_interrupt_gate(0, 157, &trap157);
718 	set_interrupt_gate(0, 158, &trap158);
719 	set_interrupt_gate(0, 159, &trap159);
720 	set_interrupt_gate(0, 160, &trap160);
721 	set_interrupt_gate(0, 161, &trap161);
722 	set_interrupt_gate(0, 162, &trap162);
723 	set_interrupt_gate(0, 163, &trap163);
724 	set_interrupt_gate(0, 164, &trap164);
725 	set_interrupt_gate(0, 165, &trap165);
726 	set_interrupt_gate(0, 166, &trap166);
727 	set_interrupt_gate(0, 167, &trap167);
728 	set_interrupt_gate(0, 168, &trap168);
729 	set_interrupt_gate(0, 169, &trap169);
730 	set_interrupt_gate(0, 170, &trap170);
731 	set_interrupt_gate(0, 171, &trap171);
732 	set_interrupt_gate(0, 172, &trap172);
733 	set_interrupt_gate(0, 173, &trap173);
734 	set_interrupt_gate(0, 174, &trap174);
735 	set_interrupt_gate(0, 175, &trap175);
736 	set_interrupt_gate(0, 176, &trap176);
737 	set_interrupt_gate(0, 177, &trap177);
738 	set_interrupt_gate(0, 178, &trap178);
739 	set_interrupt_gate(0, 179, &trap179);
740 	set_interrupt_gate(0, 180, &trap180);
741 	set_interrupt_gate(0, 181, &trap181);
742 	set_interrupt_gate(0, 182, &trap182);
743 	set_interrupt_gate(0, 183, &trap183);
744 	set_interrupt_gate(0, 184, &trap184);
745 	set_interrupt_gate(0, 185, &trap185);
746 	set_interrupt_gate(0, 186, &trap186);
747 	set_interrupt_gate(0, 187, &trap187);
748 	set_interrupt_gate(0, 188, &trap188);
749 	set_interrupt_gate(0, 189, &trap189);
750 	set_interrupt_gate(0, 190, &trap190);
751 	set_interrupt_gate(0, 191, &trap191);
752 	set_interrupt_gate(0, 192, &trap192);
753 	set_interrupt_gate(0, 193, &trap193);
754 	set_interrupt_gate(0, 194, &trap194);
755 	set_interrupt_gate(0, 195, &trap195);
756 	set_interrupt_gate(0, 196, &trap196);
757 	set_interrupt_gate(0, 197, &trap197);
758 	set_interrupt_gate(0, 198, &trap198);
759 	set_interrupt_gate(0, 199, &trap199);
760 	set_interrupt_gate(0, 200, &trap200);
761 	set_interrupt_gate(0, 201, &trap201);
762 	set_interrupt_gate(0, 202, &trap202);
763 	set_interrupt_gate(0, 203, &trap203);
764 	set_interrupt_gate(0, 204, &trap204);
765 	set_interrupt_gate(0, 205, &trap205);
766 	set_interrupt_gate(0, 206, &trap206);
767 	set_interrupt_gate(0, 207, &trap207);
768 	set_interrupt_gate(0, 208, &trap208);
769 	set_interrupt_gate(0, 209, &trap209);
770 	set_interrupt_gate(0, 210, &trap210);
771 	set_interrupt_gate(0, 211, &trap211);
772 	set_interrupt_gate(0, 212, &trap212);
773 	set_interrupt_gate(0, 213, &trap213);
774 	set_interrupt_gate(0, 214, &trap214);
775 	set_interrupt_gate(0, 215, &trap215);
776 	set_interrupt_gate(0, 216, &trap216);
777 	set_interrupt_gate(0, 217, &trap217);
778 	set_interrupt_gate(0, 218, &trap218);
779 	set_interrupt_gate(0, 219, &trap219);
780 	set_interrupt_gate(0, 220, &trap220);
781 	set_interrupt_gate(0, 221, &trap221);
782 	set_interrupt_gate(0, 222, &trap222);
783 	set_interrupt_gate(0, 223, &trap223);
784 	set_interrupt_gate(0, 224, &trap224);
785 	set_interrupt_gate(0, 225, &trap225);
786 	set_interrupt_gate(0, 226, &trap226);
787 	set_interrupt_gate(0, 227, &trap227);
788 	set_interrupt_gate(0, 228, &trap228);
789 	set_interrupt_gate(0, 229, &trap229);
790 	set_interrupt_gate(0, 230, &trap230);
791 	set_interrupt_gate(0, 231, &trap231);
792 	set_interrupt_gate(0, 232, &trap232);
793 	set_interrupt_gate(0, 233, &trap233);
794 	set_interrupt_gate(0, 234, &trap234);
795 	set_interrupt_gate(0, 235, &trap235);
796 	set_interrupt_gate(0, 236, &trap236);
797 	set_interrupt_gate(0, 237, &trap237);
798 	set_interrupt_gate(0, 238, &trap238);
799 	set_interrupt_gate(0, 239, &trap239);
800 	set_interrupt_gate(0, 240, &trap240);
801 	set_interrupt_gate(0, 241, &trap241);
802 	set_interrupt_gate(0, 242, &trap242);
803 	set_interrupt_gate(0, 243, &trap243);
804 	set_interrupt_gate(0, 244, &trap244);
805 	set_interrupt_gate(0, 245, &trap245);
806 	set_interrupt_gate(0, 246, &trap246);
807 	set_interrupt_gate(0, 247, &trap247);
808 	set_interrupt_gate(0, 248, &trap248);
809 	set_interrupt_gate(0, 249, &trap249);
810 	set_interrupt_gate(0, 250, &trap250);
811 
812 	// smp / apic local interrupts
813 	set_interrupt_gate(0, 251, &trap251);
814 	set_interrupt_gate(0, 252, &trap252);
815 	set_interrupt_gate(0, 253, &trap253);
816 	set_interrupt_gate(0, 254, &trap254);
817 	set_interrupt_gate(0, 255, &trap255);
818 
819 	// init interrupt handler table
820 	table = gInterruptHandlerTable;
821 
822 	// defaults
823 	for (i = 0; i < ARCH_INTERRUPT_BASE; i++)
824 		table[i] = invalid_exception;
825 	for (i = ARCH_INTERRUPT_BASE; i < INTERRUPT_HANDLER_TABLE_SIZE; i++)
826 		table[i] = hardware_interrupt;
827 
828 	table[0] = unexpected_exception;	// Divide Error Exception (#DE)
829 	table[1] = x86_handle_debug_exception; // Debug Exception (#DB)
830 	table[2] = fatal_exception;			// NMI Interrupt
831 	table[3] = x86_handle_breakpoint_exception; // Breakpoint Exception (#BP)
832 	table[4] = unexpected_exception;	// Overflow Exception (#OF)
833 	table[5] = unexpected_exception;	// BOUND Range Exceeded Exception (#BR)
834 	table[6] = unexpected_exception;	// Invalid Opcode Exception (#UD)
835 	table[7] = fatal_exception;			// Device Not Available Exception (#NM)
836 	table[8] = x86_double_fault_exception; // Double Fault Exception (#DF)
837 	table[9] = fatal_exception;			// Coprocessor Segment Overrun
838 	table[10] = fatal_exception;		// Invalid TSS Exception (#TS)
839 	table[11] = fatal_exception;		// Segment Not Present (#NP)
840 	table[12] = fatal_exception;		// Stack Fault Exception (#SS)
841 	table[13] = unexpected_exception;	// General Protection Exception (#GP)
842 	table[14] = page_fault_exception;	// Page-Fault Exception (#PF)
843 	table[16] = unexpected_exception;	// x87 FPU Floating-Point Error (#MF)
844 	table[17] = unexpected_exception;	// Alignment Check Exception (#AC)
845 	table[18] = fatal_exception;		// Machine-Check Exception (#MC)
846 	table[19] = unexpected_exception;	// SIMD Floating-Point Exception (#XF)
847 
848 	return B_OK;
849 }
850 
851 
852 status_t
853 arch_int_init_post_vm(struct kernel_args *args)
854 {
855 	// Always init the local apic as it can be used for timers even if we
856 	// don't end up using the io apic
857 	apic_init(args);
858 
859 	// create IDT area for the boot CPU
860 	area_id area = create_area("idt", (void**)&sIDTs[0], B_EXACT_ADDRESS,
861 		B_PAGE_SIZE, B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
862 	if (area < 0)
863 		return area;
864 
865 	// create IDTs for the off-boot CPU
866 	size_t idtSize = 256 * 8;
867 		// 256 8 bytes-sized descriptors
868 	int32 cpuCount = smp_get_num_cpus();
869 	if (cpuCount > 0) {
870 		size_t areaSize = ROUNDUP(cpuCount * idtSize, B_PAGE_SIZE);
871 		desc_table* idt;
872 		virtual_address_restrictions virtualRestrictions = {};
873 		virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS;
874 		physical_address_restrictions physicalRestrictions = {};
875 		area = create_area_etc(B_SYSTEM_TEAM, "idt", areaSize, B_CONTIGUOUS,
876 			B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, CREATE_AREA_DONT_WAIT,
877 			&virtualRestrictions, &physicalRestrictions, (void**)&idt);
878 		if (area < 0)
879 			return area;
880 
881 		for (int32 i = 1; i < cpuCount; i++) {
882 			sIDTs[i] = idt;
883 			memcpy(idt, sIDTs[0], idtSize);
884 			idt += 256;
885 			// The CPU's IDTR will be set in arch_cpu_init_percpu().
886 		}
887 	}
888 
889 	return area >= B_OK ? B_OK : area;
890 }
891 
892 
893 status_t
894 arch_int_init_io(kernel_args* args)
895 {
896 	ioapic_init(args);
897 	msi_init();
898 	return B_OK;
899 }
900 
901 
902 status_t
903 arch_int_init_post_device_manager(struct kernel_args *args)
904 {
905 	return B_OK;
906 }
907 
908 
909 void
910 arch_int_set_interrupt_controller(const interrupt_controller &controller)
911 {
912 	sCurrentPIC = &controller;
913 }
914