1 /* 2 * Copyright 2003-2006, 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 * Distributed under the terms of the MIT License. 10 * 11 * 12 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 13 * Distributed under the terms of the NewOS License. 14 */ 15 16 #include <int.h> 17 18 #include <arch_platform.h> 19 #include <arch/smp.h> 20 #include <boot/kernel_args.h> 21 #include <device_manager.h> 22 #include <kscheduler.h> 23 #include <interrupt_controller.h> 24 #include <smp.h> 25 #include <thread.h> 26 #include <timer.h> 27 #include <util/DoublyLinkedList.h> 28 #include <util/kernel_cpp.h> 29 #include <vm.h> 30 #include <vm_address_space.h> 31 #include <vm_priv.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 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 static bool 149 fault_was_write(struct iframe *iframe) 150 { 151 switch (iframe->cpu.type) { 152 case 0x7: 153 return !iframe->cpu.type_7.ssw.rw; 154 case 0xa: 155 return !iframe->cpu.type_a.ssw.rw; 156 case 0xb: 157 return !iframe->cpu.type_b.ssw.rw; 158 default: 159 panic("can't determine r/w from iframe type %d\n", 160 iframe->cpu.type); 161 return false; 162 } 163 } 164 165 extern "C" void m68k_exception_entry(struct iframe *iframe); 166 void 167 m68k_exception_entry(struct iframe *iframe) 168 { 169 int vector = iframe->cpu.vector >> 2; 170 int ret = B_HANDLED_INTERRUPT; 171 172 if (vector != -1) { 173 dprintf("m68k_exception_entry: time %lld vector 0x%x, iframe %p, " 174 "pc: %p\n", system_time(), vector, iframe, (void*)iframe->cpu.pc); 175 } 176 177 struct thread *thread = thread_get_current_thread(); 178 179 // push iframe 180 if (thread) 181 m68k_push_iframe(&thread->arch_info.iframes, iframe); 182 else 183 m68k_push_iframe(&gBootFrameStack, iframe); 184 185 switch (vector) { 186 case 0: // system reset 187 panic("system reset exception\n"); 188 break; 189 case 2: // bus error 190 case 3: // address error 191 { 192 bool kernelDebugger = debug_debugger_running(); 193 194 if (kernelDebugger) { 195 // if this thread has a fault handler, we're allowed to be here 196 struct thread *thread = thread_get_current_thread(); 197 if (thread && thread->fault_handler != 0) { 198 iframe->cpu.pc = thread->fault_handler; 199 break; 200 } 201 202 203 // otherwise, not really 204 panic("page fault in debugger without fault handler! Touching " 205 "address %p from ip %p\n", (void *)fault_address(iframe), 206 (void *)iframe->cpu.pc); 207 break; 208 } else if ((iframe->cpu.sr & SR_IP_MASK) != 0) { 209 // if the interrupts were disabled, and we are not running the 210 // kernel startup the page fault was not allowed to happen and 211 // we must panic 212 panic("page fault, but interrupts were disabled. Touching " 213 "address %p from ip %p\n", (void *)fault_address(iframe), 214 (void *)iframe->cpu.pc); 215 break; 216 } else if (thread != NULL && thread->page_faults_allowed < 1) { 217 panic("page fault not allowed at this place. Touching address " 218 "%p from ip %p\n", (void *)fault_address(iframe), 219 (void *)iframe->cpu.pc); 220 } 221 222 enable_interrupts(); 223 224 addr_t newip; 225 226 ret = vm_page_fault(fault_address(iframe), iframe->cpu.pc, 227 fault_was_write(iframe), // store or load 228 iframe->cpu.sr & SR_S, // was the system in user or supervisor 229 &newip); 230 if (newip != 0) { 231 // the page fault handler wants us to modify the iframe to set the 232 // IP the cpu will return to to be this ip 233 iframe->cpu.pc = newip; 234 } 235 break; 236 } 237 238 case 24: // spurious interrupt 239 dprintf("spurious interrupt\n"); 240 break; 241 case 25: // autovector interrupt 242 case 26: // autovector interrupt 243 case 27: // autovector interrupt 244 case 28: // autovector interrupt 245 case 29: // autovector interrupt 246 case 30: // autovector interrupt 247 case 31: // autovector interrupt 248 { 249 #if 0 250 if (!sPIC) { 251 panic("m68k_exception_entry(): external interrupt although we " 252 "don't have a PIC driver!"); 253 ret = B_HANDLED_INTERRUPT; 254 break; 255 } 256 #endif 257 M68KPlatform::Default()->AcknowledgeIOInterrupt(vector); 258 259 dprintf("handling I/O interrupts...\n"); 260 ret = int_io_interrupt_handler(vector, true); 261 #if 0 262 while ((irq = sPIC->acknowledge_io_interrupt(sPICCookie)) >= 0) { 263 // TODO: correctly pass level-triggered vs. edge-triggered to the handler! 264 ret = int_io_interrupt_handler(irq, true); 265 } 266 #endif 267 dprintf("handling I/O interrupts done\n"); 268 break; 269 } 270 271 case 9: // trace 272 default: 273 // vectors >= 64 are user defined vectors, used for IRQ 274 if (vector >= 64) { 275 if (M68KPlatform::Default()->AcknowledgeIOInterrupt(vector)) { 276 ret = int_io_interrupt_handler(vector, true); 277 break; 278 } 279 } 280 dprintf("unhandled exception type 0x%x\n", vector); 281 print_iframe(iframe); 282 panic("unhandled exception type\n"); 283 } 284 285 if (ret == B_INVOKE_SCHEDULER) { 286 int state = disable_interrupts(); 287 GRAB_THREAD_LOCK(); 288 scheduler_reschedule(); 289 RELEASE_THREAD_LOCK(); 290 restore_interrupts(state); 291 } 292 293 // pop iframe 294 if (thread) 295 m68k_pop_iframe(&thread->arch_info.iframes); 296 else 297 m68k_pop_iframe(&gBootFrameStack); 298 } 299 300 301 status_t 302 arch_int_init(kernel_args *args) 303 { 304 status_t err; 305 addr_t vbr; 306 int i; 307 308 gExceptionVectors = (m68k_exception_handler *)args->arch_args.vir_vbr; 309 310 /* fill in the vector table */ 311 for (i = 0; i < M68K_EXCEPTION_VECTOR_COUNT; i++) 312 gExceptionVectors[i] = &__m68k_exception_common; 313 314 vbr = args->arch_args.phys_vbr; 315 /* point VBR to the new table */ 316 asm volatile ("movec %0,%%vbr" : : "r"(vbr):); 317 return B_OK; 318 } 319 320 321 status_t 322 arch_int_init_post_vm(kernel_args *args) 323 { 324 return B_OK; 325 } 326 327 328 #if 0 /* PIC modules */ 329 template<typename ModuleInfo> 330 struct Module : DoublyLinkedListLinkImpl<Module<ModuleInfo> > { 331 Module(ModuleInfo *module) 332 : module(module) 333 { 334 } 335 336 ~Module() 337 { 338 if (module) 339 put_module(((module_info*)module)->name); 340 } 341 342 ModuleInfo *module; 343 }; 344 345 typedef Module<interrupt_controller_module_info> PICModule; 346 347 struct PICModuleList : DoublyLinkedList<PICModule> { 348 ~PICModuleList() 349 { 350 while (PICModule *module = First()) { 351 Remove(module); 352 delete module; 353 } 354 } 355 }; 356 357 358 class DeviceTreeIterator { 359 public: 360 DeviceTreeIterator(device_manager_info *deviceManager) 361 : fDeviceManager(deviceManager), 362 fNode(NULL), 363 fParent(NULL) 364 { 365 Rewind(); 366 } 367 368 ~DeviceTreeIterator() 369 { 370 if (fParent != NULL) 371 fDeviceManager->put_device_node(fParent); 372 if (fNode != NULL) 373 fDeviceManager->put_device_node(fNode); 374 } 375 376 void Rewind() 377 { 378 fNode = fDeviceManager->get_root(); 379 } 380 381 bool HasNext() const 382 { 383 return (fNode != NULL); 384 } 385 386 device_node_handle Next() 387 { 388 if (fNode == NULL) 389 return NULL; 390 391 device_node_handle foundNode = fNode; 392 393 // get first child 394 device_node_handle child = NULL; 395 if (fDeviceManager->get_next_child_device(fNode, &child, NULL) 396 == B_OK) { 397 // move to the child node 398 if (fParent != NULL) 399 fDeviceManager->put_device_node(fParent); 400 fParent = fNode; 401 fNode = child; 402 403 // no more children; backtrack to find the next sibling 404 } else { 405 while (fParent != NULL) { 406 if (fDeviceManager->get_next_child_device(fParent, &fNode, NULL) 407 == B_OK) { 408 // get_next_child_device() always puts the node 409 break; 410 } 411 fNode = fParent; 412 fParent = fDeviceManager->get_parent(fNode); 413 } 414 415 // if we hit the root node again, we're done 416 if (fParent == NULL) { 417 fDeviceManager->put_device_node(fNode); 418 fNode = NULL; 419 } 420 } 421 422 return foundNode; 423 } 424 425 private: 426 device_manager_info *fDeviceManager; 427 device_node_handle fNode; 428 device_node_handle fParent; 429 }; 430 431 432 static void 433 get_interrupt_controller_modules(PICModuleList &list) 434 { 435 const char *namePrefix = "interrupt_controllers/"; 436 size_t namePrefixLen = strlen(namePrefix); 437 438 char name[B_PATH_NAME_LENGTH]; 439 size_t length; 440 uint32 cookie = 0; 441 while (get_next_loaded_module_name(&cookie, name, &(length = sizeof(name))) 442 == B_OK) { 443 // an interrupt controller module? 444 if (length <= namePrefixLen 445 || strncmp(name, namePrefix, namePrefixLen) != 0) { 446 continue; 447 } 448 449 // get the module 450 interrupt_controller_module_info *moduleInfo; 451 if (get_module(name, (module_info**)&moduleInfo) != B_OK) 452 continue; 453 454 // add it to the list 455 PICModule *module = new(nothrow) PICModule(moduleInfo); 456 if (!module) { 457 put_module(((module_info*)moduleInfo)->name); 458 continue; 459 } 460 list.Add(module); 461 } 462 } 463 464 465 static bool 466 probe_pic_device(device_node_handle node, PICModuleList &picModules) 467 { 468 for (PICModule *module = picModules.Head(); 469 module; 470 module = picModules.GetNext(module)) { 471 bool noConnection; 472 if (module->module->info.supports_device(node, &noConnection) > 0) { 473 if (module->module->info.register_device(node) == B_OK) 474 return true; 475 } 476 } 477 478 return false; 479 } 480 #endif /* PIC modules */ 481 482 status_t 483 arch_int_init_post_device_manager(struct kernel_args *args) 484 { 485 status_t err; 486 err = M68KPlatform::Default()->InitPIC(args); 487 return err; 488 #if 0 /* PIC modules */ 489 // get the interrupt controller driver modules 490 PICModuleList picModules; 491 get_interrupt_controller_modules(picModules); 492 if (picModules.IsEmpty()) { 493 panic("arch_int_init_post_device_manager(): Found no PIC modules!"); 494 return B_ENTRY_NOT_FOUND; 495 } 496 497 // get the device manager module 498 device_manager_info *deviceManager; 499 status_t error = get_module(B_DEVICE_MANAGER_MODULE_NAME, 500 (module_info**)&deviceManager); 501 if (error != B_OK) { 502 panic("arch_int_init_post_device_manager(): Failed to get device " 503 "manager: %s", strerror(error)); 504 return error; 505 } 506 Module<device_manager_info> _deviceManager(deviceManager); // auto put 507 508 // iterate through the device tree and probe the interrupt controllers 509 DeviceTreeIterator iterator(deviceManager); 510 while (device_node_handle node = iterator.Next()) 511 probe_pic_device(node, picModules); 512 513 // iterate through the tree again and get an interrupt controller node 514 iterator.Rewind(); 515 while (device_node_handle node = iterator.Next()) { 516 char *deviceType; 517 if (deviceManager->get_attr_string(node, B_DRIVER_DEVICE_TYPE, 518 &deviceType, false) == B_OK) { 519 bool isPIC 520 = (strcmp(deviceType, B_INTERRUPT_CONTROLLER_DRIVER_TYPE) == 0); 521 free(deviceType); 522 523 if (isPIC) { 524 driver_module_info *driver; 525 void *driverCookie; 526 error = deviceManager->init_driver(node, NULL, &driver, 527 &driverCookie); 528 if (error == B_OK) { 529 sPIC = (interrupt_controller_module_info *)driver; 530 sPICCookie = driverCookie; 531 return B_OK; 532 } 533 } 534 } 535 } 536 537 #endif /* PIC modules */ 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 #if 0//PPC 547 // #pragma mark - 548 549 struct m68k_cpu_exception_context * 550 m68k_get_cpu_exception_context(int cpu) 551 { 552 return sCPUExceptionContexts + cpu; 553 } 554 555 556 void 557 m68k_set_current_cpu_exception_context(struct m68k_cpu_exception_context *context) 558 { 559 // translate to physical address 560 addr_t physicalPage; 561 addr_t inPageOffset = (addr_t)context & (B_PAGE_SIZE - 1); 562 status_t error = vm_get_page_mapping(vm_kernel_address_space_id(), 563 (addr_t)context - inPageOffset, &physicalPage); 564 if (error != B_OK) { 565 panic("m68k_set_current_cpu_exception_context(): Failed to get physical " 566 "address!"); 567 return; 568 } 569 570 asm volatile("mtsprg0 %0" : : "r"(physicalPage + inPageOffset)); 571 } 572 573 #endif 574