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