1 /* 2 * Copyright 2003-2011, 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 * François Revol <revol@free.fr> 9 * 10 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 11 * Distributed under the terms of the NewOS License. 12 */ 13 14 15 #include <int.h> 16 17 #include <arch_platform.h> 18 #include <arch/smp.h> 19 #include <boot/kernel_args.h> 20 #include <device_manager.h> 21 #include <kscheduler.h> 22 #include <interrupt_controller.h> 23 #include <smp.h> 24 #include <thread.h> 25 #include <timer.h> 26 #include <util/AutoLock.h> 27 #include <util/DoublyLinkedList.h> 28 #include <util/kernel_cpp.h> 29 #include <vm/vm.h> 30 #include <vm/vm_priv.h> 31 #include <vm/VMAddressSpace.h> 32 #include <string.h> 33 34 #warning M68K: writeme! 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 typedef void (*m68k_exception_handler)(void); 45 #define M68K_EXCEPTION_VECTOR_COUNT 256 46 #warning M68K: align on 4 ? 47 //m68k_exception_handler gExceptionVectors[M68K_EXCEPTION_VECTOR_COUNT]; 48 m68k_exception_handler *gExceptionVectors; 49 50 // defined in arch_exceptions.S 51 extern "C" void __m68k_exception_noop(void); 52 extern "C" void __m68k_exception_common(void); 53 54 extern int __irqvec_start; 55 extern int __irqvec_end; 56 57 extern"C" void m68k_exception_tail(void); 58 59 // current fault handler 60 addr_t gFaultHandler; 61 62 // An iframe stack used in the early boot process when we don't have 63 // threads yet. 64 struct iframe_stack gBootFrameStack; 65 66 // interrupt controller interface (initialized 67 // in arch_int_init_post_device_manager()) 68 //static struct interrupt_controller_module_info *sPIC; 69 //static void *sPICCookie; 70 71 72 void 73 arch_int_enable_io_interrupt(int32 irq) 74 { 75 //if (!sPIC) 76 // return; 77 78 // TODO: I have no idea, what IRQ type is appropriate. 79 //sPIC->enable_io_interrupt(sPICCookie, irq, IRQ_TYPE_LEVEL); 80 M68KPlatform::Default()->EnableIOInterrupt(irq); 81 } 82 83 84 void 85 arch_int_disable_io_interrupt(int32 irq) 86 { 87 //if (!sPIC) 88 // return; 89 90 //sPIC->disable_io_interrupt(sPICCookie, irq); 91 M68KPlatform::Default()->DisableIOInterrupt(irq); 92 } 93 94 95 /* arch_int_*_interrupts() and friends are in arch_asm.S */ 96 97 98 int32 99 arch_int_assign_to_cpu(int32 irq, int32 cpu) 100 { 101 // Not yet supported. 102 return 0; 103 } 104 105 106 static void 107 print_iframe(struct iframe *frame) 108 { 109 dprintf("iframe at %p:\n", frame); 110 dprintf(" d0 0x%08lx d1 0x%08lx d2 0x%08lx d3 0x%08lx\n", 111 frame->d[0], frame->d[1], frame->d[2], frame->d[3]); 112 kprintf(" d4 0x%08lx d5 0x%08lx d6 0x%08lx d7 0x%08lx\n", 113 frame->d[4], frame->d[5], frame->d[6], frame->d[7]); 114 kprintf(" a0 0x%08lx a1 0x%08lx a2 0x%08lx a3 0x%08lx\n", 115 frame->a[0], frame->a[1], frame->a[2], frame->a[3]); 116 kprintf(" a4 0x%08lx a5 0x%08lx a6 0x%08lx "/*"a7 0x%08lx (sp)"*/"\n", 117 frame->a[4], frame->a[5], frame->a[6]/*, frame->a[7]*/); 118 119 /*kprintf(" pc 0x%08lx ccr 0x%02x\n", 120 frame->pc, frame->ccr);*/ 121 kprintf(" pc 0x%08lx sr 0x%04x\n", 122 frame->cpu.pc, frame->cpu.sr); 123 #if 0 124 dprintf("r0-r3: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->d0, frame->d1, frame->d2, frame->d3); 125 dprintf("r4-r7: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->d4, frame->d5, frame->d6, frame->d7); 126 dprintf("r8-r11: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->a0, frame->a1, frame->a2, frame->a3); 127 dprintf("r12-r15: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->a4, frame->a5, frame->a6, frame->a7); 128 dprintf(" pc 0x%08lx sr 0x%08lx\n", frame->pc, frame->sr); 129 #endif 130 } 131 132 133 static addr_t 134 fault_address(struct iframe *iframe) 135 { 136 switch (iframe->cpu.type) { 137 case 0x0: 138 case 0x1: 139 return 0; 140 case 0x2: 141 return iframe->cpu.type_2.instruction_address; 142 case 0x3: 143 return iframe->cpu.type_3.effective_address; 144 case 0x7: 145 return iframe->cpu.type_7.effective_address; 146 case 0x9: 147 return iframe->cpu.type_9.instruction_address; 148 case 0xa: 149 return iframe->cpu.type_a.fault_address; 150 case 0xb: 151 return iframe->cpu.type_b.fault_address; 152 default: 153 return 0; 154 } 155 } 156 157 158 static bool 159 fault_was_write(struct iframe *iframe) 160 { 161 switch (iframe->cpu.type) { 162 case 0x7: 163 return !iframe->cpu.type_7.ssw.rw; 164 case 0xa: 165 return !iframe->cpu.type_a.ssw.rw; 166 case 0xb: 167 return !iframe->cpu.type_b.ssw.rw; 168 default: 169 panic("can't determine r/w from iframe type %d\n", 170 iframe->cpu.type); 171 return false; 172 } 173 } 174 175 176 extern "C" void m68k_exception_entry(struct iframe *iframe); 177 void 178 m68k_exception_entry(struct iframe *iframe) 179 { 180 int vector = iframe->cpu.vector >> 2; 181 bool hardwareInterrupt = false; 182 183 if (vector != -1) { 184 dprintf("m68k_exception_entry: time %lld vector 0x%x, iframe %p, " 185 "pc: %p\n", system_time(), vector, iframe, (void*)iframe->cpu.pc); 186 } 187 188 Thread *thread = thread_get_current_thread(); 189 190 // push iframe 191 if (thread) 192 m68k_push_iframe(&thread->arch_info.iframes, iframe); 193 else 194 m68k_push_iframe(&gBootFrameStack, iframe); 195 196 switch (vector) { 197 case 0: // system reset 198 panic("system reset exception\n"); 199 break; 200 case 2: // bus error 201 case 3: // address error 202 { 203 bool kernelDebugger = debug_debugger_running(); 204 205 if (kernelDebugger) { 206 // if this thread has a fault handler, we're allowed to be here 207 if (thread && thread->fault_handler != 0) { 208 iframe->cpu.pc = reinterpret_cast<addr_t>(thread->fault_handler); 209 break; 210 } 211 212 213 // otherwise, not really 214 panic("page fault in debugger without fault handler! Touching " 215 "address %p from ip %p\n", (void *)fault_address(iframe), 216 (void *)iframe->cpu.pc); 217 break; 218 } else if ((iframe->cpu.sr & SR_IP_MASK) != 0) { 219 // interrupts disabled 220 221 // If a page fault handler is installed, we're allowed to be here. 222 // TODO: Now we are generally allowing user_memcpy() with interrupts 223 // disabled, which in most cases is a bug. We should add some thread 224 // flag allowing to explicitly indicate that this handling is desired. 225 if (thread && thread->fault_handler != 0) { 226 iframe->cpu.pc = reinterpret_cast<addr_t>(thread->fault_handler); 227 return; 228 } 229 230 // if the interrupts were disabled, and we are not running the 231 // kernel startup the page fault was not allowed to happen and 232 // we must panic 233 panic("page fault, but interrupts were disabled. Touching " 234 "address %p from ip %p\n", (void *)fault_address(iframe), 235 (void *)iframe->cpu.pc); 236 break; 237 } else if (thread != NULL && thread->page_faults_allowed < 1) { 238 panic("page fault not allowed at this place. Touching address " 239 "%p from ip %p\n", (void *)fault_address(iframe), 240 (void *)iframe->cpu.pc); 241 } 242 243 enable_interrupts(); 244 245 addr_t newip; 246 247 vm_page_fault(fault_address(iframe), iframe->cpu.pc, 248 fault_was_write(iframe), // store or load 249 false, 250 iframe->cpu.sr & SR_S, // was the system in user or supervisor 251 &newip); 252 if (newip != 0) { 253 // the page fault handler wants us to modify the iframe to set the 254 // IP the cpu will return to to be this ip 255 iframe->cpu.pc = newip; 256 } 257 break; 258 } 259 260 case 24: // spurious interrupt 261 dprintf("spurious interrupt\n"); 262 break; 263 case 25: // autovector interrupt 264 case 26: // autovector interrupt 265 case 27: // autovector interrupt 266 case 28: // autovector interrupt 267 case 29: // autovector interrupt 268 case 30: // autovector interrupt 269 case 31: // autovector interrupt 270 { 271 #if 0 272 if (!sPIC) { 273 panic("m68k_exception_entry(): external interrupt although we " 274 "don't have a PIC driver!"); 275 break; 276 } 277 #endif 278 M68KPlatform::Default()->AcknowledgeIOInterrupt(vector); 279 280 dprintf("handling I/O interrupts...\n"); 281 int_io_interrupt_handler(vector, true); 282 #if 0 283 while ((irq = sPIC->acknowledge_io_interrupt(sPICCookie)) >= 0) { 284 // TODO: correctly pass level-triggered vs. edge-triggered to the handler! 285 int_io_interrupt_handler(irq, true); 286 } 287 #endif 288 dprintf("handling I/O interrupts done\n"); 289 hardwareInterrupt = true; 290 break; 291 } 292 293 case 9: // trace 294 default: 295 // vectors >= 64 are user defined vectors, used for IRQ 296 if (vector >= 64) { 297 if (M68KPlatform::Default()->AcknowledgeIOInterrupt(vector)) { 298 int_io_interrupt_handler(vector, true); 299 break; 300 } 301 } 302 dprintf("unhandled exception type 0x%x\n", vector); 303 print_iframe(iframe); 304 panic("unhandled exception type\n"); 305 } 306 307 int state = disable_interrupts(); 308 if (hardwareInterrupt && thread->post_interrupt_callback != NULL) { 309 void (*callback)(void*) = thread->post_interrupt_callback; 310 void* data = thread->post_interrupt_data; 311 312 thread->post_interrupt_callback = NULL; 313 thread->post_interrupt_data = NULL; 314 315 restore_interrupts(state); 316 317 callback(data); 318 } else if (thread->cpu->invoke_scheduler) { 319 SpinLocker schedulerLocker(thread->scheduler_lock); 320 scheduler_reschedule(B_THREAD_READY); 321 schedulerLocker.Unlock(); 322 restore_interrupts(state); 323 } 324 325 // pop iframe 326 if (thread) 327 m68k_pop_iframe(&thread->arch_info.iframes); 328 else 329 m68k_pop_iframe(&gBootFrameStack); 330 } 331 332 333 status_t 334 arch_int_init(kernel_args *args) 335 { 336 status_t err; 337 addr_t vbr; 338 int i; 339 340 gExceptionVectors = (m68k_exception_handler *)args->arch_args.vir_vbr; 341 342 /* fill in the vector table */ 343 for (i = 0; i < M68K_EXCEPTION_VECTOR_COUNT; i++) 344 gExceptionVectors[i] = &__m68k_exception_common; 345 346 vbr = args->arch_args.phys_vbr; 347 /* point VBR to the new table */ 348 asm volatile ("movec %0,%%vbr" : : "r"(vbr):); 349 350 return B_OK; 351 } 352 353 354 status_t 355 arch_int_init_post_vm(kernel_args *args) 356 { 357 status_t err; 358 err = M68KPlatform::Default()->InitPIC(args); 359 return err; 360 } 361 362 363 status_t 364 arch_int_init_io(kernel_args* args) 365 { 366 return B_OK; 367 } 368 369 370 #if 0 /* PIC modules */ 371 template<typename ModuleInfo> 372 struct Module : DoublyLinkedListLinkImpl<Module<ModuleInfo> > { 373 Module(ModuleInfo *module) 374 : module(module) 375 { 376 } 377 378 ~Module() 379 { 380 if (module) 381 put_module(((module_info*)module)->name); 382 } 383 384 ModuleInfo *module; 385 }; 386 387 typedef Module<interrupt_controller_module_info> PICModule; 388 389 struct PICModuleList : DoublyLinkedList<PICModule> { 390 ~PICModuleList() 391 { 392 while (PICModule *module = First()) { 393 Remove(module); 394 delete module; 395 } 396 } 397 }; 398 399 400 class DeviceTreeIterator { 401 public: 402 DeviceTreeIterator(device_manager_info *deviceManager) 403 : fDeviceManager(deviceManager), 404 fNode(NULL), 405 fParent(NULL) 406 { 407 Rewind(); 408 } 409 410 ~DeviceTreeIterator() 411 { 412 if (fParent != NULL) 413 fDeviceManager->put_device_node(fParent); 414 if (fNode != NULL) 415 fDeviceManager->put_device_node(fNode); 416 } 417 418 void Rewind() 419 { 420 fNode = fDeviceManager->get_root(); 421 } 422 423 bool HasNext() const 424 { 425 return (fNode != NULL); 426 } 427 428 device_node_handle Next() 429 { 430 if (fNode == NULL) 431 return NULL; 432 433 device_node_handle foundNode = fNode; 434 435 // get first child 436 device_node_handle child = NULL; 437 if (fDeviceManager->get_next_child_device(fNode, &child, NULL) 438 == B_OK) { 439 // move to the child node 440 if (fParent != NULL) 441 fDeviceManager->put_device_node(fParent); 442 fParent = fNode; 443 fNode = child; 444 445 // no more children; backtrack to find the next sibling 446 } else { 447 while (fParent != NULL) { 448 if (fDeviceManager->get_next_child_device(fParent, &fNode, NULL) 449 == B_OK) { 450 // get_next_child_device() always puts the node 451 break; 452 } 453 fNode = fParent; 454 fParent = fDeviceManager->get_parent(fNode); 455 } 456 457 // if we hit the root node again, we're done 458 if (fParent == NULL) { 459 fDeviceManager->put_device_node(fNode); 460 fNode = NULL; 461 } 462 } 463 464 return foundNode; 465 } 466 467 private: 468 device_manager_info *fDeviceManager; 469 device_node_handle fNode; 470 device_node_handle fParent; 471 }; 472 473 474 static void 475 get_interrupt_controller_modules(PICModuleList &list) 476 { 477 const char *namePrefix = "interrupt_controllers/"; 478 size_t namePrefixLen = strlen(namePrefix); 479 480 char name[B_PATH_NAME_LENGTH]; 481 size_t length; 482 uint32 cookie = 0; 483 while (get_next_loaded_module_name(&cookie, name, &(length = sizeof(name))) 484 == B_OK) { 485 // an interrupt controller module? 486 if (length <= namePrefixLen 487 || strncmp(name, namePrefix, namePrefixLen) != 0) { 488 continue; 489 } 490 491 // get the module 492 interrupt_controller_module_info *moduleInfo; 493 if (get_module(name, (module_info**)&moduleInfo) != B_OK) 494 continue; 495 496 // add it to the list 497 PICModule *module = new(nothrow) PICModule(moduleInfo); 498 if (!module) { 499 put_module(((module_info*)moduleInfo)->name); 500 continue; 501 } 502 list.Add(module); 503 } 504 } 505 506 507 static bool 508 probe_pic_device(device_node_handle node, PICModuleList &picModules) 509 { 510 for (PICModule *module = picModules.Head(); 511 module; 512 module = picModules.GetNext(module)) { 513 bool noConnection; 514 if (module->module->info.supports_device(node, &noConnection) > 0) { 515 if (module->module->info.register_device(node) == B_OK) 516 return true; 517 } 518 } 519 520 return false; 521 } 522 #endif /* PIC modules */ 523 524 status_t 525 arch_int_init_post_device_manager(struct kernel_args *args) 526 { 527 #if 0 /* PIC modules */ 528 // get the interrupt controller driver modules 529 PICModuleList picModules; 530 get_interrupt_controller_modules(picModules); 531 if (picModules.IsEmpty()) { 532 panic("arch_int_init_post_device_manager(): Found no PIC modules!"); 533 return B_ENTRY_NOT_FOUND; 534 } 535 536 // get the device manager module 537 device_manager_info *deviceManager; 538 status_t error = get_module(B_DEVICE_MANAGER_MODULE_NAME, 539 (module_info**)&deviceManager); 540 if (error != B_OK) { 541 panic("arch_int_init_post_device_manager(): Failed to get device " 542 "manager: %s", strerror(error)); 543 return error; 544 } 545 Module<device_manager_info> _deviceManager(deviceManager); // auto put 546 547 // iterate through the device tree and probe the interrupt controllers 548 DeviceTreeIterator iterator(deviceManager); 549 while (device_node_handle node = iterator.Next()) 550 probe_pic_device(node, picModules); 551 552 // iterate through the tree again and get an interrupt controller node 553 iterator.Rewind(); 554 while (device_node_handle node = iterator.Next()) { 555 char *deviceType; 556 if (deviceManager->get_attr_string(node, B_DRIVER_DEVICE_TYPE, 557 &deviceType, false) == B_OK) { 558 bool isPIC 559 = (strcmp(deviceType, B_INTERRUPT_CONTROLLER_DRIVER_TYPE) == 0); 560 free(deviceType); 561 562 if (isPIC) { 563 driver_module_info *driver; 564 void *driverCookie; 565 error = deviceManager->init_driver(node, NULL, &driver, 566 &driverCookie); 567 if (error == B_OK) { 568 sPIC = (interrupt_controller_module_info *)driver; 569 sPICCookie = driverCookie; 570 return B_OK; 571 } 572 } 573 } 574 } 575 576 #endif /* PIC modules */ 577 578 // no PIC found 579 panic("arch_int_init_post_device_manager(): Found no supported PIC!"); 580 581 return B_ENTRY_NOT_FOUND; 582 } 583 584 585 #if 0//PPC 586 // #pragma mark - 587 588 struct m68k_cpu_exception_context * 589 m68k_get_cpu_exception_context(int cpu) 590 { 591 return sCPUExceptionContexts + cpu; 592 } 593 594 595 void 596 m68k_set_current_cpu_exception_context(struct m68k_cpu_exception_context *context) 597 { 598 // translate to physical address 599 addr_t physicalPage; 600 addr_t inPageOffset = (addr_t)context & (B_PAGE_SIZE - 1); 601 status_t error = vm_get_page_mapping(VMAddressSpace::KernelID(), 602 (addr_t)context - inPageOffset, &physicalPage); 603 if (error != B_OK) { 604 panic("m68k_set_current_cpu_exception_context(): Failed to get physical " 605 "address!"); 606 return; 607 } 608 609 asm volatile("mtsprg0 %0" : : "r"(physicalPage + inPageOffset)); 610 } 611 612 #endif 613