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 29 #include <stdio.h> 30 31 // interrupt controllers 32 #include <arch/x86/ioapic.h> 33 #include <arch/x86/pic.h> 34 35 36 //#define TRACE_ARCH_INT 37 #ifdef TRACE_ARCH_INT 38 # define TRACE(x) dprintf x 39 #else 40 # define TRACE(x) ; 41 #endif 42 43 44 static const char *kInterruptNames[] = { 45 /* 0 */ "Divide Error Exception", 46 /* 1 */ "Debug Exception", 47 /* 2 */ "NMI Interrupt", 48 /* 3 */ "Breakpoint Exception", 49 /* 4 */ "Overflow Exception", 50 /* 5 */ "BOUND Range Exceeded Exception", 51 /* 6 */ "Invalid Opcode Exception", 52 /* 7 */ "Device Not Available Exception", 53 /* 8 */ "Double Fault Exception", 54 /* 9 */ "Coprocessor Segment Overrun", 55 /* 10 */ "Invalid TSS Exception", 56 /* 11 */ "Segment Not Present", 57 /* 12 */ "Stack Fault Exception", 58 /* 13 */ "General Protection Exception", 59 /* 14 */ "Page-Fault Exception", 60 /* 15 */ "-", 61 /* 16 */ "x87 FPU Floating-Point Error", 62 /* 17 */ "Alignment Check Exception", 63 /* 18 */ "Machine-Check Exception", 64 /* 19 */ "SIMD Floating-Point Exception", 65 }; 66 static const int kInterruptNameCount = 20; 67 68 static const interrupt_controller* sCurrentPIC = NULL; 69 70 71 static const char* 72 exception_name(int number, char* buffer, int32 bufferSize) 73 { 74 if (number >= 0 && number < kInterruptNameCount) 75 return kInterruptNames[number]; 76 77 snprintf(buffer, bufferSize, "exception %d", number); 78 return buffer; 79 } 80 81 82 void 83 x86_invalid_exception(iframe* frame) 84 { 85 Thread* thread = thread_get_current_thread(); 86 char name[32]; 87 panic("unhandled trap 0x%lx (%s) at ip 0x%lx, thread %" B_PRId32 "!\n", 88 frame->vector, exception_name(frame->vector, name, sizeof(name)), 89 frame->ip, thread ? thread->id : -1); 90 } 91 92 93 void 94 x86_fatal_exception(iframe* frame) 95 { 96 char name[32]; 97 panic("Fatal exception \"%s\" occurred! Error code: 0x%lx\n", 98 exception_name(frame->vector, name, sizeof(name)), frame->error_code); 99 } 100 101 102 void 103 x86_unexpected_exception(iframe* frame) 104 { 105 debug_exception_type type; 106 uint32 signalNumber; 107 int32 signalCode; 108 addr_t signalAddress = 0; 109 int32 signalError = B_ERROR; 110 111 switch (frame->vector) { 112 case 0: // Divide Error Exception (#DE) 113 type = B_DIVIDE_ERROR; 114 signalNumber = SIGFPE; 115 signalCode = FPE_INTDIV; 116 signalAddress = frame->ip; 117 break; 118 119 case 4: // Overflow Exception (#OF) 120 type = B_OVERFLOW_EXCEPTION; 121 signalNumber = SIGFPE; 122 signalCode = FPE_INTOVF; 123 signalAddress = frame->ip; 124 break; 125 126 case 5: // BOUND Range Exceeded Exception (#BR) 127 type = B_BOUNDS_CHECK_EXCEPTION; 128 signalNumber = SIGTRAP; 129 signalCode = SI_USER; 130 break; 131 132 case 6: // Invalid Opcode Exception (#UD) 133 type = B_INVALID_OPCODE_EXCEPTION; 134 signalNumber = SIGILL; 135 signalCode = ILL_ILLOPC; 136 signalAddress = frame->ip; 137 break; 138 139 case 13: // General Protection Exception (#GP) 140 type = B_GENERAL_PROTECTION_FAULT; 141 signalNumber = SIGILL; 142 signalCode = ILL_PRVOPC; // or ILL_PRVREG 143 signalAddress = frame->ip; 144 break; 145 146 case 16: // x87 FPU Floating-Point Error (#MF) 147 type = B_FLOATING_POINT_EXCEPTION; 148 signalNumber = SIGFPE; 149 signalCode = FPE_FLTDIV; 150 // TODO: Determine the correct cause via the FPU status 151 // register! 152 signalAddress = frame->ip; 153 break; 154 155 case 17: // Alignment Check Exception (#AC) 156 type = B_ALIGNMENT_EXCEPTION; 157 signalNumber = SIGBUS; 158 signalCode = BUS_ADRALN; 159 // TODO: Also get the address (from where?). Since we don't enable 160 // alignment checking this exception should never happen, though. 161 signalError = EFAULT; 162 break; 163 164 case 19: // SIMD Floating-Point Exception (#XF) 165 type = B_FLOATING_POINT_EXCEPTION; 166 signalNumber = SIGFPE; 167 signalCode = FPE_FLTDIV; 168 // TODO: Determine the correct cause via the MXCSR register! 169 signalAddress = frame->ip; 170 break; 171 172 default: 173 x86_invalid_exception(frame); 174 return; 175 } 176 177 if (IFRAME_IS_USER(frame)) { 178 struct sigaction action; 179 Thread* thread = thread_get_current_thread(); 180 181 enable_interrupts(); 182 183 // If the thread has a signal handler for the signal, we simply send it 184 // the signal. Otherwise we notify the user debugger first. 185 if ((sigaction(signalNumber, NULL, &action) == 0 186 && action.sa_handler != SIG_DFL 187 && action.sa_handler != SIG_IGN) 188 || user_debug_exception_occurred(type, signalNumber)) { 189 Signal signal(signalNumber, signalCode, signalError, 190 thread->team->id); 191 signal.SetAddress((void*)signalAddress); 192 send_signal_to_thread(thread, signal, 0); 193 } 194 } else { 195 char name[32]; 196 panic("Unexpected exception \"%s\" occurred in kernel mode! " 197 "Error code: 0x%lx\n", 198 exception_name(frame->vector, name, sizeof(name)), 199 frame->error_code); 200 } 201 } 202 203 204 void 205 x86_hardware_interrupt(struct iframe* frame) 206 { 207 int32 vector = frame->vector - ARCH_INTERRUPT_BASE; 208 bool levelTriggered = false; 209 Thread* thread = thread_get_current_thread(); 210 211 if (sCurrentPIC->is_spurious_interrupt(vector)) { 212 TRACE(("got spurious interrupt at vector %ld\n", vector)); 213 return; 214 } 215 216 levelTriggered = sCurrentPIC->is_level_triggered_interrupt(vector); 217 218 if (!levelTriggered) { 219 // if it's not handled by the current pic then it's an apic generated 220 // interrupt like local interrupts, msi or ipi. 221 if (!sCurrentPIC->end_of_interrupt(vector)) 222 apic_end_of_interrupt(); 223 } 224 225 int_io_interrupt_handler(vector, levelTriggered); 226 227 if (levelTriggered) { 228 if (!sCurrentPIC->end_of_interrupt(vector)) 229 apic_end_of_interrupt(); 230 } 231 232 cpu_status state = disable_interrupts(); 233 if (thread->cpu->invoke_scheduler) { 234 SpinLocker schedulerLocker(gSchedulerLock); 235 scheduler_reschedule(); 236 schedulerLocker.Unlock(); 237 restore_interrupts(state); 238 } else if (thread->post_interrupt_callback != NULL) { 239 void (*callback)(void*) = thread->post_interrupt_callback; 240 void* data = thread->post_interrupt_data; 241 242 thread->post_interrupt_callback = NULL; 243 thread->post_interrupt_data = NULL; 244 245 restore_interrupts(state); 246 247 callback(data); 248 } 249 } 250 251 252 void 253 x86_page_fault_exception(struct iframe* frame) 254 { 255 Thread* thread = thread_get_current_thread(); 256 addr_t cr2 = x86_read_cr2(); 257 addr_t newip; 258 259 if (debug_debugger_running()) { 260 // If this CPU or this thread has a fault handler, we're allowed to be 261 // here. 262 if (thread != NULL) { 263 cpu_ent* cpu = &gCPU[smp_get_current_cpu()]; 264 if (cpu->fault_handler != 0) { 265 debug_set_page_fault_info(cr2, frame->ip, 266 (frame->error_code & 0x2) != 0 267 ? DEBUG_PAGE_FAULT_WRITE : 0); 268 frame->ip = cpu->fault_handler; 269 frame->bp = cpu->fault_handler_stack_pointer; 270 return; 271 } 272 273 if (thread->fault_handler != 0) { 274 kprintf("ERROR: thread::fault_handler used in kernel " 275 "debugger!\n"); 276 debug_set_page_fault_info(cr2, frame->ip, 277 (frame->error_code & 0x2) != 0 278 ? DEBUG_PAGE_FAULT_WRITE : 0); 279 frame->ip = thread->fault_handler; 280 return; 281 } 282 } 283 284 // otherwise, not really 285 panic("page fault in debugger without fault handler! Touching " 286 "address %p from ip %p\n", (void*)cr2, (void*)frame->ip); 287 return; 288 } else if ((frame->flags & 0x200) == 0) { 289 // interrupts disabled 290 291 // If a page fault handler is installed, we're allowed to be here. 292 // TODO: Now we are generally allowing user_memcpy() with interrupts 293 // disabled, which in most cases is a bug. We should add some thread 294 // flag allowing to explicitly indicate that this handling is desired. 295 if (thread && thread->fault_handler != 0) { 296 if (frame->ip != thread->fault_handler) { 297 frame->ip = thread->fault_handler; 298 return; 299 } 300 301 // The fault happened at the fault handler address. This is a 302 // certain infinite loop. 303 panic("page fault, interrupts disabled, fault handler loop. " 304 "Touching address %p from ip %p\n", (void*)cr2, 305 (void*)frame->ip); 306 } 307 308 // If we are not running the kernel startup the page fault was not 309 // allowed to happen and we must panic. 310 panic("page fault, but interrupts were disabled. Touching address " 311 "%p from ip %p\n", (void*)cr2, (void*)frame->ip); 312 return; 313 } else if (thread != NULL && thread->page_faults_allowed < 1) { 314 panic("page fault not allowed at this place. Touching address " 315 "%p from ip %p\n", (void*)cr2, (void*)frame->ip); 316 return; 317 } 318 319 enable_interrupts(); 320 321 vm_page_fault(cr2, frame->ip, 322 (frame->error_code & 0x2) != 0, // write access 323 (frame->error_code & 0x4) != 0, // userland 324 &newip); 325 if (newip != 0) { 326 // the page fault handler wants us to modify the iframe to set the 327 // IP the cpu will return to this ip 328 frame->ip = newip; 329 } 330 } 331 332 333 // #pragma mark - 334 335 336 void 337 arch_int_enable_io_interrupt(int irq) 338 { 339 sCurrentPIC->enable_io_interrupt(irq); 340 } 341 342 343 void 344 arch_int_disable_io_interrupt(int irq) 345 { 346 sCurrentPIC->disable_io_interrupt(irq); 347 } 348 349 350 void 351 arch_int_configure_io_interrupt(int irq, uint32 config) 352 { 353 sCurrentPIC->configure_io_interrupt(irq, config); 354 } 355 356 357 #undef arch_int_enable_interrupts 358 #undef arch_int_disable_interrupts 359 #undef arch_int_restore_interrupts 360 #undef arch_int_are_interrupts_enabled 361 362 363 void 364 arch_int_enable_interrupts(void) 365 { 366 arch_int_enable_interrupts_inline(); 367 } 368 369 370 int 371 arch_int_disable_interrupts(void) 372 { 373 return arch_int_disable_interrupts_inline(); 374 } 375 376 377 void 378 arch_int_restore_interrupts(int oldState) 379 { 380 arch_int_restore_interrupts_inline(oldState); 381 } 382 383 384 bool 385 arch_int_are_interrupts_enabled(void) 386 { 387 return arch_int_are_interrupts_enabled_inline(); 388 } 389 390 391 status_t 392 arch_int_init(kernel_args* args) 393 { 394 // setup the standard programmable interrupt controller 395 pic_init(); 396 return B_OK; 397 } 398 399 400 status_t 401 arch_int_init_post_vm(kernel_args* args) 402 { 403 // Always init the local apic as it can be used for timers even if we 404 // don't end up using the io apic 405 apic_init(args); 406 return B_OK; 407 } 408 409 410 status_t 411 arch_int_init_io(kernel_args* args) 412 { 413 msi_init(); 414 ioapic_init(args); 415 return B_OK; 416 } 417 418 419 status_t 420 arch_int_init_post_device_manager(kernel_args* args) 421 { 422 return B_OK; 423 } 424 425 426 void 427 arch_int_set_interrupt_controller(const interrupt_controller& controller) 428 { 429 sCurrentPIC = &controller; 430 } 431