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