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