1 /* 2 * Copyright 2003-2010, Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler <axeld@pinc-software.de> 7 * Ingo Weinhold <bonefish@cs.tu-berlin.de> 8 * 9 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 10 * Distributed under the terms of the NewOS License. 11 */ 12 13 14 #include <int.h> 15 16 #include <arch/smp.h> 17 #include <boot/kernel_args.h> 18 #include <device_manager.h> 19 #include <kscheduler.h> 20 #include <interrupt_controller.h> 21 #include <smp.h> 22 #include <thread.h> 23 #include <timer.h> 24 #include <util/DoublyLinkedList.h> 25 #include <util/kernel_cpp.h> 26 #include <vm/vm.h> 27 #include <vm/vm_priv.h> 28 #include <vm/VMAddressSpace.h> 29 30 #include <string.h> 31 32 33 // defined in arch_exceptions.S 34 extern int __irqvec_start; 35 extern int __irqvec_end; 36 37 extern"C" void ppc_exception_tail(void); 38 39 40 // the exception contexts for all CPUs 41 static ppc_cpu_exception_context sCPUExceptionContexts[SMP_MAX_CPUS]; 42 43 44 // An iframe stack used in the early boot process when we don't have 45 // threads yet. 46 struct iframe_stack gBootFrameStack; 47 48 // interrupt controller interface (initialized 49 // in arch_int_init_post_device_manager()) 50 static struct interrupt_controller_module_info *sPIC; 51 static void *sPICCookie; 52 53 54 void 55 arch_int_enable_io_interrupt(int irq) 56 { 57 if (!sPIC) 58 return; 59 60 // TODO: I have no idea, what IRQ type is appropriate. 61 sPIC->enable_io_interrupt(sPICCookie, irq, IRQ_TYPE_LEVEL); 62 } 63 64 65 void 66 arch_int_disable_io_interrupt(int irq) 67 { 68 if (!sPIC) 69 return; 70 71 sPIC->disable_io_interrupt(sPICCookie, irq); 72 } 73 74 75 /* arch_int_*_interrupts() and friends are in arch_asm.S */ 76 77 78 static void 79 print_iframe(struct iframe *frame) 80 { 81 dprintf("iframe at %p:\n", frame); 82 dprintf("r0-r3: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->r0, frame->r1, frame->r2, frame->r3); 83 dprintf("r4-r7: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->r4, frame->r5, frame->r6, frame->r7); 84 dprintf("r8-r11: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->r8, frame->r9, frame->r10, frame->r11); 85 dprintf("r12-r15: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->r12, frame->r13, frame->r14, frame->r15); 86 dprintf("r16-r19: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->r16, frame->r17, frame->r18, frame->r19); 87 dprintf("r20-r23: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->r20, frame->r21, frame->r22, frame->r23); 88 dprintf("r24-r27: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->r24, frame->r25, frame->r26, frame->r27); 89 dprintf("r28-r31: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->r28, frame->r29, frame->r30, frame->r31); 90 dprintf(" ctr 0x%08lx xer 0x%08lx\n", frame->ctr, frame->xer); 91 dprintf(" cr 0x%08lx lr 0x%08lx\n", frame->cr, frame->lr); 92 dprintf(" dsisr 0x%08lx dar 0x%08lx\n", frame->dsisr, frame->dar); 93 dprintf(" srr1 0x%08lx srr0 0x%08lx\n", frame->srr1, frame->srr0); 94 } 95 96 97 extern "C" void ppc_exception_entry(int vector, struct iframe *iframe); 98 void 99 ppc_exception_entry(int vector, struct iframe *iframe) 100 { 101 if (vector != 0x900) { 102 dprintf("ppc_exception_entry: time %lld vector 0x%x, iframe %p, " 103 "srr0: %p\n", system_time(), vector, iframe, (void*)iframe->srr0); 104 } 105 106 struct thread *thread = thread_get_current_thread(); 107 108 // push iframe 109 if (thread) 110 ppc_push_iframe(&thread->arch_info.iframes, iframe); 111 else 112 ppc_push_iframe(&gBootFrameStack, iframe); 113 114 switch (vector) { 115 case 0x100: // system reset 116 panic("system reset exception\n"); 117 break; 118 case 0x200: // machine check 119 panic("machine check exception\n"); 120 break; 121 case 0x300: // DSI 122 case 0x400: // ISI 123 { 124 bool kernelDebugger = debug_debugger_running(); 125 126 if (kernelDebugger) { 127 // if this CPU or this thread has a fault handler, 128 // we're allowed to be here 129 cpu_ent* cpu = &gCPU[smp_get_current_cpu()]; 130 if (cpu->fault_handler != 0) { 131 iframe->srr0 = cpu->fault_handler; 132 iframe->r1 = cpu->fault_handler_stack_pointer; 133 break; 134 } 135 struct thread *thread = thread_get_current_thread(); 136 if (thread && thread->fault_handler != 0) { 137 iframe->srr0 = thread->fault_handler; 138 break; 139 } 140 141 // otherwise, not really 142 panic("page fault in debugger without fault handler! Touching " 143 "address %p from ip %p\n", (void *)iframe->dar, 144 (void *)iframe->srr0); 145 break; 146 } else if ((iframe->srr1 & MSR_EXCEPTIONS_ENABLED) == 0) { 147 // if the interrupts were disabled, and we are not running the 148 // kernel startup the page fault was not allowed to happen and 149 // we must panic 150 panic("page fault, but interrupts were disabled. Touching " 151 "address %p from ip %p\n", (void *)iframe->dar, 152 (void *)iframe->srr0); 153 break; 154 } else if (thread != NULL && thread->page_faults_allowed < 1) { 155 panic("page fault not allowed at this place. Touching address " 156 "%p from ip %p\n", (void *)iframe->dar, 157 (void *)iframe->srr0); 158 } 159 160 enable_interrupts(); 161 162 addr_t newip; 163 164 vm_page_fault(iframe->dar, iframe->srr0, 165 iframe->dsisr & (1 << 25), // store or load 166 iframe->srr1 & (1 << 14), // was the system in user or supervisor 167 &newip); 168 if (newip != 0) { 169 // the page fault handler wants us to modify the iframe to set the 170 // IP the cpu will return to to be this ip 171 iframe->srr0 = newip; 172 } 173 break; 174 } 175 176 case 0x500: // external interrupt 177 { 178 if (!sPIC) { 179 panic("ppc_exception_entry(): external interrupt although we " 180 "don't have a PIC driver!"); 181 break; 182 } 183 184 dprintf("handling I/O interrupts...\n"); 185 int irq; 186 while ((irq = sPIC->acknowledge_io_interrupt(sPICCookie)) >= 0) { 187 // TODO: correctly pass level-triggered vs. edge-triggered to the handler! 188 int_io_interrupt_handler(irq, true); 189 } 190 dprintf("handling I/O interrupts done\n"); 191 break; 192 } 193 194 case 0x600: // alignment exception 195 panic("alignment exception: unimplemented\n"); 196 break; 197 case 0x700: // program exception 198 panic("program exception: unimplemented\n"); 199 break; 200 case 0x800: // FP unavailable exception 201 panic("FP unavailable exception: unimplemented\n"); 202 break; 203 case 0x900: // decrementer exception 204 timer_interrupt(); 205 break; 206 case 0xc00: // system call 207 panic("system call exception: unimplemented\n"); 208 break; 209 case 0xd00: // trace exception 210 panic("trace exception: unimplemented\n"); 211 break; 212 case 0xe00: // FP assist exception 213 panic("FP assist exception: unimplemented\n"); 214 break; 215 case 0xf00: // performance monitor exception 216 panic("performance monitor exception: unimplemented\n"); 217 break; 218 case 0xf20: // altivec unavailable exception 219 panic("alitivec unavailable exception: unimplemented\n"); 220 break; 221 case 0x1000: 222 case 0x1100: 223 case 0x1200: 224 panic("TLB miss exception: unimplemented\n"); 225 break; 226 case 0x1300: // instruction address exception 227 panic("instruction address exception: unimplemented\n"); 228 break; 229 case 0x1400: // system management exception 230 panic("system management exception: unimplemented\n"); 231 break; 232 case 0x1600: // altivec assist exception 233 panic("altivec assist exception: unimplemented\n"); 234 break; 235 case 0x1700: // thermal management exception 236 panic("thermal management exception: unimplemented\n"); 237 break; 238 default: 239 dprintf("unhandled exception type 0x%x\n", vector); 240 print_iframe(iframe); 241 panic("unhandled exception type\n"); 242 } 243 244 cpu_status state = disable_interrupts(); 245 if (thread->cpu->invoke_scheduler) { 246 GRAB_THREAD_LOCK(); 247 scheduler_reschedule(); 248 RELEASE_THREAD_LOCK(); 249 restore_interrupts(state); 250 } else if (thread->post_interrupt_callback != NULL) { 251 restore_interrupts(state); 252 void (*callback)(void*) = thread->post_interrupt_callback; 253 void* data = thread->post_interrupt_data; 254 255 thread->post_interrupt_callback = NULL; 256 thread->post_interrupt_data = NULL; 257 258 callback(data); 259 } 260 261 // pop iframe 262 if (thread) 263 ppc_pop_iframe(&thread->arch_info.iframes); 264 else 265 ppc_pop_iframe(&gBootFrameStack); 266 } 267 268 269 status_t 270 arch_int_init(kernel_args *args) 271 { 272 return B_OK; 273 } 274 275 276 status_t 277 arch_int_init_post_vm(kernel_args *args) 278 { 279 void *handlers = (void *)args->arch_args.exception_handlers.start; 280 281 // We may need to remap the exception handler area into the kernel address 282 // space. 283 if (!IS_KERNEL_ADDRESS(handlers)) { 284 addr_t address = (addr_t)handlers; 285 status_t error = ppc_remap_address_range(&address, 286 args->arch_args.exception_handlers.size, true); 287 if (error != B_OK) { 288 panic("arch_int_init_post_vm(): Failed to remap the exception " 289 "handler area!"); 290 return error; 291 } 292 handlers = (void*)(address); 293 } 294 295 // create a region to map the irq vector code into (physical address 0x0) 296 area_id exceptionArea = create_area("exception_handlers", 297 &handlers, B_EXACT_ADDRESS, args->arch_args.exception_handlers.size, 298 B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 299 if (exceptionArea < B_OK) 300 panic("arch_int_init2: could not create exception handler region\n"); 301 302 dprintf("exception handlers at %p\n", handlers); 303 304 // copy the handlers into this area 305 memcpy(handlers, &__irqvec_start, args->arch_args.exception_handlers.size); 306 arch_cpu_sync_icache(handlers, args->arch_args.exception_handlers.size); 307 308 // init the CPU exception contexts 309 int cpuCount = smp_get_num_cpus(); 310 for (int i = 0; i < cpuCount; i++) { 311 ppc_cpu_exception_context *context = ppc_get_cpu_exception_context(i); 312 context->kernel_handle_exception = (void*)&ppc_exception_tail; 313 context->exception_context = context; 314 // kernel_stack is set when the current thread changes. At this point 315 // we don't have threads yet. 316 } 317 318 // set the exception context for this CPU 319 ppc_set_current_cpu_exception_context(ppc_get_cpu_exception_context(0)); 320 321 return B_OK; 322 } 323 324 325 status_t 326 arch_int_init_io(kernel_args* args) 327 { 328 return B_OK; 329 } 330 331 332 template<typename ModuleInfo> 333 struct Module : DoublyLinkedListLinkImpl<Module<ModuleInfo> > { 334 Module(ModuleInfo *module) 335 : module(module) 336 { 337 } 338 339 ~Module() 340 { 341 if (module) 342 put_module(((module_info*)module)->name); 343 } 344 345 ModuleInfo *module; 346 }; 347 348 typedef Module<interrupt_controller_module_info> PICModule; 349 350 struct PICModuleList : DoublyLinkedList<PICModule> { 351 ~PICModuleList() 352 { 353 while (PICModule *module = First()) { 354 Remove(module); 355 delete module; 356 } 357 } 358 }; 359 360 361 class DeviceTreeIterator { 362 public: 363 DeviceTreeIterator(device_manager_info *deviceManager) 364 : fDeviceManager(deviceManager), 365 fNode(NULL), 366 fParent(NULL) 367 { 368 Rewind(); 369 } 370 371 ~DeviceTreeIterator() 372 { 373 if (fParent != NULL) 374 fDeviceManager->put_node(fParent); 375 if (fNode != NULL) 376 fDeviceManager->put_node(fNode); 377 } 378 379 void Rewind() 380 { 381 fNode = fDeviceManager->get_root_node(); 382 } 383 384 bool HasNext() const 385 { 386 return (fNode != NULL); 387 } 388 389 device_node *Next() 390 { 391 if (fNode == NULL) 392 return NULL; 393 394 device_node *foundNode = fNode; 395 396 // get first child 397 device_node *child = NULL; 398 if (fDeviceManager->get_next_child_node(fNode, NULL, &child) 399 == B_OK) { 400 // move to the child node 401 if (fParent != NULL) 402 fDeviceManager->put_node(fParent); 403 fParent = fNode; 404 fNode = child; 405 406 // no more children; backtrack to find the next sibling 407 } else { 408 while (fParent != NULL) { 409 if (fDeviceManager->get_next_child_node(fParent, NULL, &fNode) 410 == B_OK) { 411 // get_next_child_node() always puts the node 412 break; 413 } 414 fNode = fParent; 415 fParent = fDeviceManager->get_parent_node(fNode); 416 } 417 418 // if we hit the root node again, we're done 419 if (fParent == NULL) { 420 fDeviceManager->put_node(fNode); 421 fNode = NULL; 422 } 423 } 424 425 return foundNode; 426 } 427 428 private: 429 device_manager_info *fDeviceManager; 430 device_node *fNode; 431 device_node *fParent; 432 }; 433 434 435 static void 436 get_interrupt_controller_modules(PICModuleList &list) 437 { 438 const char *namePrefix = "interrupt_controllers/"; 439 size_t namePrefixLen = strlen(namePrefix); 440 441 char name[B_PATH_NAME_LENGTH]; 442 size_t length; 443 uint32 cookie = 0; 444 while (get_next_loaded_module_name(&cookie, name, &(length = sizeof(name))) 445 == B_OK) { 446 // an interrupt controller module? 447 if (length <= namePrefixLen 448 || strncmp(name, namePrefix, namePrefixLen) != 0) { 449 continue; 450 } 451 452 // get the module 453 interrupt_controller_module_info *moduleInfo; 454 if (get_module(name, (module_info**)&moduleInfo) != B_OK) 455 continue; 456 457 // add it to the list 458 PICModule *module = new(nothrow) PICModule(moduleInfo); 459 if (!module) { 460 put_module(((module_info*)moduleInfo)->name); 461 continue; 462 } 463 list.Add(module); 464 } 465 } 466 467 468 static bool 469 probe_pic_device(device_node *node, PICModuleList &picModules) 470 { 471 for (PICModule *module = picModules.Head(); 472 module; 473 module = picModules.GetNext(module)) { 474 //bool noConnection; 475 if (module->module->info.supports_device(node) > 0) { 476 if (module->module->info.register_device(node) == B_OK) 477 return true; 478 } 479 } 480 481 return false; 482 } 483 484 485 status_t 486 arch_int_init_post_device_manager(struct kernel_args *args) 487 { 488 // get the interrupt controller driver modules 489 PICModuleList picModules; 490 get_interrupt_controller_modules(picModules); 491 if (picModules.IsEmpty()) { 492 panic("arch_int_init_post_device_manager(): Found no PIC modules!"); 493 return B_ENTRY_NOT_FOUND; 494 } 495 496 // get the device manager module 497 device_manager_info *deviceManager; 498 status_t error = get_module(B_DEVICE_MANAGER_MODULE_NAME, 499 (module_info**)&deviceManager); 500 if (error != B_OK) { 501 panic("arch_int_init_post_device_manager(): Failed to get device " 502 "manager: %s", strerror(error)); 503 return error; 504 } 505 Module<device_manager_info> _deviceManager(deviceManager); // auto put 506 507 // iterate through the device tree and probe the interrupt controllers 508 DeviceTreeIterator iterator(deviceManager); 509 while (device_node *node = iterator.Next()) 510 probe_pic_device(node, picModules); 511 512 // iterate through the tree again and get an interrupt controller node 513 iterator.Rewind(); 514 while (device_node *node = iterator.Next()) { 515 const char *deviceType; 516 if (deviceManager->get_attr_string(node, B_DEVICE_TYPE, 517 &deviceType, false) == B_OK) { 518 bool isPIC = false; 519 520 /* 521 bool isPIC 522 = (strcmp(deviceType, B_INTERRUPT_CONTROLLER_DRIVER_TYPE) == 0); 523 free(deviceType); 524 */ 525 526 if (isPIC) { 527 driver_module_info *driver; 528 void *driverCookie; 529 530 deviceManager->get_driver(node, (driver_module_info **)&driver, (void **)&driverCookie); 531 532 sPIC = (interrupt_controller_module_info *)driver; 533 sPICCookie = driverCookie; 534 return B_OK; 535 } 536 } 537 } 538 539 // no PIC found 540 panic("arch_int_init_post_device_manager(): Found no supported PIC!"); 541 542 return B_ENTRY_NOT_FOUND; 543 } 544 545 546 // #pragma mark - 547 548 struct ppc_cpu_exception_context * 549 ppc_get_cpu_exception_context(int cpu) 550 { 551 return sCPUExceptionContexts + cpu; 552 } 553 554 555 void 556 ppc_set_current_cpu_exception_context(struct ppc_cpu_exception_context *context) 557 { 558 // translate to physical address 559 phys_addr_t physicalPage; 560 addr_t inPageOffset = (addr_t)context & (B_PAGE_SIZE - 1); 561 status_t error = vm_get_page_mapping(VMAddressSpace::KernelID(), 562 (addr_t)context - inPageOffset, &physicalPage); 563 if (error != B_OK) { 564 panic("ppc_set_current_cpu_exception_context(): Failed to get physical " 565 "address!"); 566 return; 567 } 568 569 asm volatile("mtsprg0 %0" : : "r"(physicalPage + inPageOffset)); 570 } 571 572