headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / kernel / arch / x86 / arch_int.cpp
blob090c3eb861295e130e894b7c42c72ecc330a373f
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.
8 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
9 * Distributed under the terms of the NewOS License.
13 #include <cpu.h>
14 #include <int.h>
15 #include <kscheduler.h>
16 #include <team.h>
17 #include <thread.h>
18 #include <util/AutoLock.h>
19 #include <vm/vm.h>
20 #include <vm/vm_priv.h>
22 #include <arch/cpu.h>
23 #include <arch/int.h>
25 #include <arch/x86/apic.h>
26 #include <arch/x86/descriptors.h>
27 #include <arch/x86/msi.h>
28 #include <arch/x86/msi_priv.h>
30 #include <stdio.h>
32 // interrupt controllers
33 #include <arch/x86/ioapic.h>
34 #include <arch/x86/pic.h>
37 //#define TRACE_ARCH_INT
38 #ifdef TRACE_ARCH_INT
39 # define TRACE(x) dprintf x
40 #else
41 # define TRACE(x) ;
42 #endif
45 static irq_source sVectorSources[NUM_IO_VECTORS];
47 static const char *kInterruptNames[] = {
48 /* 0 */ "Divide Error Exception",
49 /* 1 */ "Debug Exception",
50 /* 2 */ "NMI Interrupt",
51 /* 3 */ "Breakpoint Exception",
52 /* 4 */ "Overflow Exception",
53 /* 5 */ "BOUND Range Exceeded Exception",
54 /* 6 */ "Invalid Opcode Exception",
55 /* 7 */ "Device Not Available Exception",
56 /* 8 */ "Double Fault Exception",
57 /* 9 */ "Coprocessor Segment Overrun",
58 /* 10 */ "Invalid TSS Exception",
59 /* 11 */ "Segment Not Present",
60 /* 12 */ "Stack Fault Exception",
61 /* 13 */ "General Protection Exception",
62 /* 14 */ "Page-Fault Exception",
63 /* 15 */ "-",
64 /* 16 */ "x87 FPU Floating-Point Error",
65 /* 17 */ "Alignment Check Exception",
66 /* 18 */ "Machine-Check Exception",
67 /* 19 */ "SIMD Floating-Point Exception",
69 static const int kInterruptNameCount = 20;
71 static const interrupt_controller* sCurrentPIC = NULL;
74 static const char*
75 exception_name(int number, char* buffer, int32 bufferSize)
77 if (number >= 0 && number < kInterruptNameCount)
78 return kInterruptNames[number];
80 snprintf(buffer, bufferSize, "exception %d", number);
81 return buffer;
85 void
86 x86_invalid_exception(iframe* frame)
88 Thread* thread = thread_get_current_thread();
89 char name[32];
90 panic("unhandled trap 0x%lx (%s) at ip 0x%lx, thread %" B_PRId32 "!\n",
91 frame->vector, exception_name(frame->vector, name, sizeof(name)),
92 frame->ip, thread ? thread->id : -1);
96 void
97 x86_fatal_exception(iframe* frame)
99 char name[32];
100 panic("Fatal exception \"%s\" occurred! Error code: 0x%lx\n",
101 exception_name(frame->vector, name, sizeof(name)), frame->error_code);
105 void
106 x86_unexpected_exception(iframe* frame)
108 debug_exception_type type;
109 uint32 signalNumber;
110 int32 signalCode;
111 addr_t signalAddress = 0;
112 int32 signalError = B_ERROR;
114 switch (frame->vector) {
115 case 0: // Divide Error Exception (#DE)
116 type = B_DIVIDE_ERROR;
117 signalNumber = SIGFPE;
118 signalCode = FPE_INTDIV;
119 signalAddress = frame->ip;
120 break;
122 case 4: // Overflow Exception (#OF)
123 type = B_OVERFLOW_EXCEPTION;
124 signalNumber = SIGFPE;
125 signalCode = FPE_INTOVF;
126 signalAddress = frame->ip;
127 break;
129 case 5: // BOUND Range Exceeded Exception (#BR)
130 type = B_BOUNDS_CHECK_EXCEPTION;
131 signalNumber = SIGTRAP;
132 signalCode = SI_USER;
133 break;
135 case 6: // Invalid Opcode Exception (#UD)
136 type = B_INVALID_OPCODE_EXCEPTION;
137 signalNumber = SIGILL;
138 signalCode = ILL_ILLOPC;
139 signalAddress = frame->ip;
140 break;
142 case 12: // Stack Fault (#SS)
143 type = B_STACK_FAULT;
144 signalNumber = SIGBUS;
145 signalCode = BUS_ADRERR;
146 signalAddress = frame->ip;
147 break;
149 case 13: // General Protection Exception (#GP)
150 type = B_GENERAL_PROTECTION_FAULT;
151 signalNumber = SIGILL;
152 signalCode = ILL_PRVOPC; // or ILL_PRVREG
153 signalAddress = frame->ip;
154 break;
156 case 16: // x87 FPU Floating-Point Error (#MF)
157 type = B_FLOATING_POINT_EXCEPTION;
158 signalNumber = SIGFPE;
159 signalCode = FPE_FLTDIV;
160 // TODO: Determine the correct cause via the FPU status
161 // register!
162 signalAddress = frame->ip;
163 break;
165 case 17: // Alignment Check Exception (#AC)
166 type = B_ALIGNMENT_EXCEPTION;
167 signalNumber = SIGBUS;
168 signalCode = BUS_ADRALN;
169 // TODO: Also get the address (from where?). Since we don't enable
170 // alignment checking this exception should never happen, though.
171 signalError = EFAULT;
172 break;
174 case 19: // SIMD Floating-Point Exception (#XF)
175 type = B_FLOATING_POINT_EXCEPTION;
176 signalNumber = SIGFPE;
177 signalCode = FPE_FLTDIV;
178 // TODO: Determine the correct cause via the MXCSR register!
179 signalAddress = frame->ip;
180 break;
182 default:
183 x86_invalid_exception(frame);
184 return;
187 if (IFRAME_IS_USER(frame)) {
188 struct sigaction action;
189 Thread* thread = thread_get_current_thread();
191 enable_interrupts();
193 // If the thread has a signal handler for the signal, we simply send it
194 // the signal. Otherwise we notify the user debugger first.
195 if ((sigaction(signalNumber, NULL, &action) == 0
196 && action.sa_handler != SIG_DFL
197 && action.sa_handler != SIG_IGN)
198 || user_debug_exception_occurred(type, signalNumber)) {
199 Signal signal(signalNumber, signalCode, signalError,
200 thread->team->id);
201 signal.SetAddress((void*)signalAddress);
202 send_signal_to_thread(thread, signal, 0);
204 } else {
205 char name[32];
206 panic("Unexpected exception \"%s\" occurred in kernel mode! "
207 "Error code: 0x%lx\n",
208 exception_name(frame->vector, name, sizeof(name)),
209 frame->error_code);
214 void
215 x86_hardware_interrupt(struct iframe* frame)
217 int32 vector = frame->vector - ARCH_INTERRUPT_BASE;
218 bool levelTriggered = false;
219 Thread* thread = thread_get_current_thread();
221 if (sCurrentPIC->is_spurious_interrupt(vector)) {
222 TRACE(("got spurious interrupt at vector %ld\n", vector));
223 return;
226 levelTriggered = sCurrentPIC->is_level_triggered_interrupt(vector);
228 if (!levelTriggered) {
229 // if it's not handled by the current pic then it's an apic generated
230 // interrupt like local interrupts, msi or ipi.
231 if (!sCurrentPIC->end_of_interrupt(vector))
232 apic_end_of_interrupt();
235 int_io_interrupt_handler(vector, levelTriggered);
237 if (levelTriggered) {
238 if (!sCurrentPIC->end_of_interrupt(vector))
239 apic_end_of_interrupt();
242 cpu_status state = disable_interrupts();
243 if (thread->cpu->invoke_scheduler) {
244 SpinLocker schedulerLocker(thread->scheduler_lock);
245 scheduler_reschedule(B_THREAD_READY);
246 schedulerLocker.Unlock();
247 restore_interrupts(state);
248 } else if (thread->post_interrupt_callback != NULL) {
249 void (*callback)(void*) = thread->post_interrupt_callback;
250 void* data = thread->post_interrupt_data;
252 thread->post_interrupt_callback = NULL;
253 thread->post_interrupt_data = NULL;
255 restore_interrupts(state);
257 callback(data);
262 void
263 x86_page_fault_exception(struct iframe* frame)
265 Thread* thread = thread_get_current_thread();
266 addr_t cr2 = x86_read_cr2();
267 addr_t newip;
269 if (debug_debugger_running()) {
270 // If this CPU or this thread has a fault handler, we're allowed to be
271 // here.
272 if (thread != NULL) {
273 cpu_ent* cpu = &gCPU[smp_get_current_cpu()];
274 if (cpu->fault_handler != 0) {
275 debug_set_page_fault_info(cr2, frame->ip,
276 (frame->error_code & 0x2) != 0
277 ? DEBUG_PAGE_FAULT_WRITE : 0);
278 frame->ip = cpu->fault_handler;
279 frame->bp = cpu->fault_handler_stack_pointer;
280 return;
283 if (thread->fault_handler != 0) {
284 kprintf("ERROR: thread::fault_handler used in kernel "
285 "debugger!\n");
286 debug_set_page_fault_info(cr2, frame->ip,
287 (frame->error_code & 0x2) != 0
288 ? DEBUG_PAGE_FAULT_WRITE : 0);
289 frame->ip = reinterpret_cast<uintptr_t>(thread->fault_handler);
290 return;
294 // otherwise, not really
295 panic("page fault in debugger without fault handler! Touching "
296 "address %p from ip %p\n", (void*)cr2, (void*)frame->ip);
297 return;
298 } else if ((frame->flags & 0x200) == 0) {
299 // interrupts disabled
301 // If a page fault handler is installed, we're allowed to be here.
302 // TODO: Now we are generally allowing user_memcpy() with interrupts
303 // disabled, which in most cases is a bug. We should add some thread
304 // flag allowing to explicitly indicate that this handling is desired.
305 if (thread != NULL && thread->fault_handler != 0) {
306 uintptr_t handler
307 = reinterpret_cast<uintptr_t>(thread->fault_handler);
308 if (frame->ip != handler) {
309 frame->ip = handler;
310 return;
313 // The fault happened at the fault handler address. This is a
314 // certain infinite loop.
315 panic("page fault, interrupts disabled, fault handler loop. "
316 "Touching address %p from ip %p\n", (void*)cr2,
317 (void*)frame->ip);
320 // If we are not running the kernel startup the page fault was not
321 // allowed to happen and we must panic.
322 panic("page fault, but interrupts were disabled. Touching address "
323 "%p from ip %p\n", (void*)cr2, (void*)frame->ip);
324 return;
325 } else if (thread != NULL && thread->page_faults_allowed < 1) {
326 panic("page fault not allowed at this place. Touching address "
327 "%p from ip %p\n", (void*)cr2, (void*)frame->ip);
328 return;
331 enable_interrupts();
333 vm_page_fault(cr2, frame->ip,
334 (frame->error_code & 0x2)!= 0, // write access
335 (frame->error_code & 0x10) != 0, // instruction fetch
336 (frame->error_code & 0x4) != 0, // userland
337 &newip);
338 if (newip != 0) {
339 // the page fault handler wants us to modify the iframe to set the
340 // IP the cpu will return to this ip
341 frame->ip = newip;
346 void
347 x86_set_irq_source(int irq, irq_source source)
349 sVectorSources[irq] = source;
353 // #pragma mark -
356 void
357 arch_int_enable_io_interrupt(int irq)
359 sCurrentPIC->enable_io_interrupt(irq);
363 void
364 arch_int_disable_io_interrupt(int irq)
366 sCurrentPIC->disable_io_interrupt(irq);
370 void
371 arch_int_configure_io_interrupt(int irq, uint32 config)
373 sCurrentPIC->configure_io_interrupt(irq, config);
377 #undef arch_int_enable_interrupts
378 #undef arch_int_disable_interrupts
379 #undef arch_int_restore_interrupts
380 #undef arch_int_are_interrupts_enabled
383 void
384 arch_int_enable_interrupts(void)
386 arch_int_enable_interrupts_inline();
391 arch_int_disable_interrupts(void)
393 return arch_int_disable_interrupts_inline();
397 void
398 arch_int_restore_interrupts(int oldState)
400 arch_int_restore_interrupts_inline(oldState);
404 bool
405 arch_int_are_interrupts_enabled(void)
407 return arch_int_are_interrupts_enabled_inline();
411 void
412 arch_int_assign_to_cpu(int32 irq, int32 cpu)
414 switch (sVectorSources[irq]) {
415 case IRQ_SOURCE_IOAPIC:
416 if (sCurrentPIC->assign_interrupt_to_cpu != NULL)
417 sCurrentPIC->assign_interrupt_to_cpu(irq, cpu);
418 break;
420 case IRQ_SOURCE_MSI:
421 msi_assign_interrupt_to_cpu(irq, cpu);
422 break;
424 default:
425 break;
430 status_t
431 arch_int_init(kernel_args* args)
433 // setup the standard programmable interrupt controller
434 pic_init();
435 return B_OK;
439 status_t
440 arch_int_init_post_vm(kernel_args* args)
442 // Always init the local apic as it can be used for timers even if we
443 // don't end up using the io apic
444 apic_init(args);
445 return B_OK;
449 status_t
450 arch_int_init_io(kernel_args* args)
452 msi_init(args);
453 ioapic_init(args);
454 return B_OK;
458 status_t
459 arch_int_init_post_device_manager(kernel_args* args)
461 return B_OK;
465 void
466 arch_int_set_interrupt_controller(const interrupt_controller& controller)
468 sCurrentPIC = &controller;