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