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 <team.h> 17 #include <thread.h> 18 #include <util/AutoLock.h> 19 #include <vm/vm.h> 20 #include <vm/vm_priv.h> 21 22 #include <arch/cpu.h> 23 #include <arch/int.h> 24 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> 29 30 #include <stdio.h> 31 32 // interrupt controllers 33 #include <arch/x86/ioapic.h> 34 #include <arch/x86/pic.h> 35 36 37 //#define TRACE_ARCH_INT 38 #ifdef TRACE_ARCH_INT 39 # define TRACE(x) dprintf x 40 #else 41 # define TRACE(x) ; 42 #endif 43 44 45 static irq_source sVectorSources[NUM_IO_VECTORS]; 46 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", 68 }; 69 static const int kInterruptNameCount = 20; 70 71 static const interrupt_controller* sCurrentPIC = NULL; 72 73 74 static const char* 75 exception_name(int number, char* buffer, int32 bufferSize) 76 { 77 if (number >= 0 && number < kInterruptNameCount) 78 return kInterruptNames[number]; 79 80 snprintf(buffer, bufferSize, "exception %d", number); 81 return buffer; 82 } 83 84 85 void 86 x86_invalid_exception(iframe* frame) 87 { 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); 93 } 94 95 96 void 97 x86_fatal_exception(iframe* frame) 98 { 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); 102 } 103 104 105 void 106 x86_unexpected_exception(iframe* frame) 107 { 108 debug_exception_type type; 109 uint32 signalNumber; 110 int32 signalCode; 111 addr_t signalAddress = 0; 112 int32 signalError = B_ERROR; 113 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; 121 122 case 4: // Overflow Exception (#OF) 123 type = B_OVERFLOW_EXCEPTION; 124 signalNumber = SIGFPE; 125 signalCode = FPE_INTOVF; 126 signalAddress = frame->ip; 127 break; 128 129 case 5: // BOUND Range Exceeded Exception (#BR) 130 type = B_BOUNDS_CHECK_EXCEPTION; 131 signalNumber = SIGTRAP; 132 signalCode = SI_USER; 133 break; 134 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; 141 142 case 12: // Stack Fault (#SS) 143 type = B_STACK_FAULT; 144 signalNumber = SIGBUS; 145 signalCode = BUS_ADRERR; 146 signalAddress = frame->ip; 147 break; 148 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; 155 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; 164 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; 173 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; 181 182 default: 183 x86_invalid_exception(frame); 184 return; 185 } 186 187 if (IFRAME_IS_USER(frame)) { 188 struct sigaction action; 189 Thread* thread = thread_get_current_thread(); 190 191 enable_interrupts(); 192 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); 203 } 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); 210 } 211 } 212 213 214 void 215 x86_hardware_interrupt(struct iframe* frame) 216 { 217 int32 vector = frame->vector - ARCH_INTERRUPT_BASE; 218 bool levelTriggered = false; 219 Thread* thread = thread_get_current_thread(); 220 221 if (sCurrentPIC->is_spurious_interrupt(vector)) { 222 TRACE(("got spurious interrupt at vector %ld\n", vector)); 223 return; 224 } 225 226 levelTriggered = sCurrentPIC->is_level_triggered_interrupt(vector); 227 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(); 233 } 234 235 int_io_interrupt_handler(vector, levelTriggered); 236 237 if (levelTriggered) { 238 if (!sCurrentPIC->end_of_interrupt(vector)) 239 apic_end_of_interrupt(); 240 } 241 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; 251 252 thread->post_interrupt_callback = NULL; 253 thread->post_interrupt_data = NULL; 254 255 restore_interrupts(state); 256 257 callback(data); 258 } 259 } 260 261 262 void 263 x86_page_fault_exception(struct iframe* frame) 264 { 265 Thread* thread = thread_get_current_thread(); 266 addr_t cr2 = x86_read_cr2(); 267 addr_t newip; 268 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; 281 } 282 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; 291 } 292 } 293 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 300 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; 311 } 312 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); 318 } 319 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; 329 } 330 331 enable_interrupts(); 332 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; 342 } 343 } 344 345 346 void 347 x86_set_irq_source(int irq, irq_source source) 348 { 349 sVectorSources[irq] = source; 350 } 351 352 353 // #pragma mark - 354 355 356 void 357 arch_int_enable_io_interrupt(int irq) 358 { 359 sCurrentPIC->enable_io_interrupt(irq); 360 } 361 362 363 void 364 arch_int_disable_io_interrupt(int irq) 365 { 366 sCurrentPIC->disable_io_interrupt(irq); 367 } 368 369 370 void 371 arch_int_configure_io_interrupt(int irq, uint32 config) 372 { 373 sCurrentPIC->configure_io_interrupt(irq, config); 374 } 375 376 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 381 382 383 void 384 arch_int_enable_interrupts(void) 385 { 386 arch_int_enable_interrupts_inline(); 387 } 388 389 390 int 391 arch_int_disable_interrupts(void) 392 { 393 return arch_int_disable_interrupts_inline(); 394 } 395 396 397 void 398 arch_int_restore_interrupts(int oldState) 399 { 400 arch_int_restore_interrupts_inline(oldState); 401 } 402 403 404 bool 405 arch_int_are_interrupts_enabled(void) 406 { 407 return arch_int_are_interrupts_enabled_inline(); 408 } 409 410 411 void 412 arch_int_assign_to_cpu(int32 irq, int32 cpu) 413 { 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; 419 420 case IRQ_SOURCE_MSI: 421 msi_assign_interrupt_to_cpu(irq, cpu); 422 break; 423 424 default: 425 break; 426 } 427 } 428 429 430 status_t 431 arch_int_init(kernel_args* args) 432 { 433 // setup the standard programmable interrupt controller 434 pic_init(); 435 return B_OK; 436 } 437 438 439 status_t 440 arch_int_init_post_vm(kernel_args* args) 441 { 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; 446 } 447 448 449 status_t 450 arch_int_init_io(kernel_args* args) 451 { 452 msi_init(args); 453 ioapic_init(args); 454 return B_OK; 455 } 456 457 458 status_t 459 arch_int_init_post_device_manager(kernel_args* args) 460 { 461 return B_OK; 462 } 463 464 465 void 466 arch_int_set_interrupt_controller(const interrupt_controller& controller) 467 { 468 sCurrentPIC = &controller; 469 } 470