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/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.h> 29 #include <vm_address_space.h> 30 #include <vm_priv.h> 31 32 #include <string.h> 33 #warning M68K: writeme! 34 35 // defined in arch_exceptions.S 36 extern int __irqvec_start; 37 extern int __irqvec_end; 38 39 extern"C" void m68k_exception_tail(void); 40 41 42 // the exception contexts for all CPUs 43 static m68k_cpu_exception_context sCPUExceptionContexts[SMP_MAX_CPUS]; 44 45 46 // An iframe stack used in the early boot process when we don't have 47 // threads yet. 48 struct iframe_stack gBootFrameStack; 49 50 // interrupt controller interface (initialized 51 // in arch_int_init_post_device_manager()) 52 static struct interrupt_controller_module_info *sPIC; 53 static void *sPICCookie; 54 55 56 void 57 arch_int_enable_io_interrupt(int irq) 58 { 59 if (!sPIC) 60 return; 61 62 // TODO: I have no idea, what IRQ type is appropriate. 63 sPIC->enable_io_interrupt(sPICCookie, irq, IRQ_TYPE_LEVEL); 64 } 65 66 67 void 68 arch_int_disable_io_interrupt(int irq) 69 { 70 if (!sPIC) 71 return; 72 73 sPIC->disable_io_interrupt(sPICCookie, irq); 74 } 75 76 77 /* arch_int_*_interrupts() and friends are in arch_asm.S */ 78 79 80 static void 81 print_iframe(struct iframe *frame) 82 { 83 dprintf("iframe at %p:\n", frame); 84 dprintf(" d0 0x%08lx d1 0x%08lx d2 0x%08lx d3 0x%08lx\n", 85 frame->d0, frame->d1, frame->d2, frame->d3); 86 kprintf(" d4 0x%08lx d5 0x%08lx d6 0x%08lx d7 0x%08lx\n", 87 frame->d4, frame->d5, frame->d6, frame->d7); 88 kprintf(" a0 0x%08lx a1 0x%08lx a2 0x%08lx a3 0x%08lx\n", 89 frame->a0, frame->a1, frame->a2, frame->a3); 90 kprintf(" a4 0x%08lx a5 0x%08lx a6 0x%08lx a7 0x%08lx (sp)\n", 91 frame->d4, frame->d5, frame->d6, frame->d7); 92 93 /*kprintf(" pc 0x%08lx ccr 0x%02x\n", 94 frame->pc, frame->ccr);*/ 95 kprintf(" pc 0x%08lx sr 0x%04x\n", 96 frame->pc, frame->sr); 97 dprintf("r0-r3: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->d0, frame->d1, frame->d2, frame->d3); 98 dprintf("r4-r7: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->d4, frame->d5, frame->d6, frame->d7); 99 dprintf("r8-r11: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->a0, frame->a1, frame->a2, frame->a3); 100 dprintf("r12-r15: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->a4, frame->a5, frame->a6, frame->a7); 101 dprintf(" pc 0x%08lx sr 0x%08lx\n", frame->pc, frame->sr); 102 } 103 104 105 extern "C" void m68k_exception_entry(int vector, struct iframe *iframe); 106 void 107 m68k_exception_entry(int vector, struct iframe *iframe) 108 { 109 int ret = B_HANDLED_INTERRUPT; 110 111 if (vector != 0x900) { 112 dprintf("m68k_exception_entry: time %lld vector 0x%x, iframe %p, " 113 "srr0: %p\n", system_time(), vector, iframe, (void*)iframe->srr0); 114 } 115 116 struct thread *thread = thread_get_current_thread(); 117 118 // push iframe 119 if (thread) 120 m68k_push_iframe(&thread->arch_info.iframes, iframe); 121 else 122 m68k_push_iframe(&gBootFrameStack, iframe); 123 124 switch (vector) { 125 case 0x100: // system reset 126 panic("system reset exception\n"); 127 break; 128 case 0x200: // machine check 129 panic("machine check exception\n"); 130 break; 131 case 0x300: // DSI 132 case 0x400: // ISI 133 { 134 bool kernelDebugger = debug_debugger_running(); 135 136 if (kernelDebugger) { 137 // if this thread has a fault handler, we're allowed to be here 138 struct thread *thread = thread_get_current_thread(); 139 if (thread && thread->fault_handler != NULL) { 140 iframe->srr0 = thread->fault_handler; 141 break; 142 } 143 144 // otherwise, not really 145 panic("page fault in debugger without fault handler! Touching " 146 "address %p from ip %p\n", (void *)iframe->dar, 147 (void *)iframe->srr0); 148 break; 149 } else if ((iframe->srr1 & MSR_EXCEPTIONS_ENABLED) == 0) { 150 // if the interrupts were disabled, and we are not running the 151 // kernel startup the page fault was not allowed to happen and 152 // we must panic 153 panic("page fault, but interrupts were disabled. Touching " 154 "address %p from ip %p\n", (void *)iframe->dar, 155 (void *)iframe->srr0); 156 break; 157 } else if (thread != NULL && thread->page_faults_allowed < 1) { 158 panic("page fault not allowed at this place. Touching address " 159 "%p from ip %p\n", (void *)iframe->dar, 160 (void *)iframe->srr0); 161 } 162 163 enable_interrupts(); 164 165 addr_t newip; 166 167 ret = vm_page_fault(iframe->dar, iframe->srr0, 168 iframe->dsisr & (1 << 25), // store or load 169 iframe->srr1 & (1 << 14), // was the system in user or supervisor 170 &newip); 171 if (newip != 0) { 172 // the page fault handler wants us to modify the iframe to set the 173 // IP the cpu will return to to be this ip 174 iframe->srr0 = newip; 175 } 176 break; 177 } 178 179 case 0x500: // external interrupt 180 { 181 if (!sPIC) { 182 panic("m68k_exception_entry(): external interrupt although we " 183 "don't have a PIC driver!"); 184 ret = B_HANDLED_INTERRUPT; 185 break; 186 } 187 188 dprintf("handling I/O interrupts...\n"); 189 int irq; 190 while ((irq = sPIC->acknowledge_io_interrupt(sPICCookie)) >= 0) { 191 // TODO: correctly pass level-triggered vs. edge-triggered to the handler! 192 ret = int_io_interrupt_handler(irq, true); 193 } 194 dprintf("handling I/O interrupts done\n"); 195 break; 196 } 197 198 case 0x600: // alignment exception 199 panic("alignment exception: unimplemented\n"); 200 break; 201 case 0x700: // program exception 202 panic("program exception: unimplemented\n"); 203 break; 204 case 0x800: // FP unavailable exception 205 panic("FP unavailable exception: unimplemented\n"); 206 break; 207 case 0x900: // decrementer exception 208 ret = timer_interrupt(); 209 break; 210 case 0xc00: // system call 211 panic("system call exception: unimplemented\n"); 212 break; 213 case 0xd00: // trace exception 214 panic("trace exception: unimplemented\n"); 215 break; 216 case 0xe00: // FP assist exception 217 panic("FP assist exception: unimplemented\n"); 218 break; 219 case 0xf00: // performance monitor exception 220 panic("performance monitor exception: unimplemented\n"); 221 break; 222 case 0xf20: // altivec unavailable exception 223 panic("alitivec unavailable exception: unimplemented\n"); 224 break; 225 case 0x1000: 226 case 0x1100: 227 case 0x1200: 228 panic("TLB miss exception: unimplemented\n"); 229 break; 230 case 0x1300: // instruction address exception 231 panic("instruction address exception: unimplemented\n"); 232 break; 233 case 0x1400: // system management exception 234 panic("system management exception: unimplemented\n"); 235 break; 236 case 0x1600: // altivec assist exception 237 panic("altivec assist exception: unimplemented\n"); 238 break; 239 case 0x1700: // thermal management exception 240 panic("thermal management exception: unimplemented\n"); 241 break; 242 default: 243 dprintf("unhandled exception type 0x%x\n", vector); 244 print_iframe(iframe); 245 panic("unhandled exception type\n"); 246 } 247 248 if (ret == B_INVOKE_SCHEDULER) { 249 int state = disable_interrupts(); 250 GRAB_THREAD_LOCK(); 251 scheduler_reschedule(); 252 RELEASE_THREAD_LOCK(); 253 restore_interrupts(state); 254 } 255 256 // pop iframe 257 if (thread) 258 m68k_pop_iframe(&thread->arch_info.iframes); 259 else 260 m68k_pop_iframe(&gBootFrameStack); 261 } 262 263 264 status_t 265 arch_int_init(kernel_args *args) 266 { 267 return B_OK; 268 } 269 270 271 status_t 272 arch_int_init_post_vm(kernel_args *args) 273 { 274 void *handlers = (void *)args->arch_args.exception_handlers.start; 275 276 // We may need to remap the exception handler area into the kernel address 277 // space. 278 if (!IS_KERNEL_ADDRESS(handlers)) { 279 addr_t address = (addr_t)handlers; 280 status_t error = m68k_remap_address_range(&address, 281 args->arch_args.exception_handlers.size, true); 282 if (error != B_OK) { 283 panic("arch_int_init_post_vm(): Failed to remap the exception " 284 "handler area!"); 285 return error; 286 } 287 handlers = (void*)(address); 288 } 289 290 // create a region to map the irq vector code into (physical address 0x0) 291 area_id exceptionArea = create_area("exception_handlers", 292 &handlers, B_EXACT_ADDRESS, args->arch_args.exception_handlers.size, 293 B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 294 if (exceptionArea < B_OK) 295 panic("arch_int_init2: could not create exception handler region\n"); 296 297 dprintf("exception handlers at %p\n", handlers); 298 299 // copy the handlers into this area 300 memcpy(handlers, &__irqvec_start, args->arch_args.exception_handlers.size); 301 arch_cpu_sync_icache(handlers, args->arch_args.exception_handlers.size); 302 303 // init the CPU exception contexts 304 int cpuCount = smp_get_num_cpus(); 305 for (int i = 0; i < cpuCount; i++) { 306 m68k_cpu_exception_context *context = m68k_get_cpu_exception_context(i); 307 context->kernel_handle_exception = (void*)&m68k_exception_tail; 308 context->exception_context = context; 309 // kernel_stack is set when the current thread changes. At this point 310 // we don't have threads yet. 311 } 312 313 // set the exception context for this CPU 314 m68k_set_current_cpu_exception_context(m68k_get_cpu_exception_context(0)); 315 316 return B_OK; 317 } 318 319 320 template<typename ModuleInfo> 321 struct Module : DoublyLinkedListLinkImpl<Module<ModuleInfo> > { 322 Module(ModuleInfo *module) 323 : module(module) 324 { 325 } 326 327 ~Module() 328 { 329 if (module) 330 put_module(((module_info*)module)->name); 331 } 332 333 ModuleInfo *module; 334 }; 335 336 typedef Module<interrupt_controller_module_info> PICModule; 337 338 struct PICModuleList : DoublyLinkedList<PICModule> { 339 ~PICModuleList() 340 { 341 while (PICModule *module = First()) { 342 Remove(module); 343 delete module; 344 } 345 } 346 }; 347 348 349 class DeviceTreeIterator { 350 public: 351 DeviceTreeIterator(device_manager_info *deviceManager) 352 : fDeviceManager(deviceManager), 353 fNode(NULL), 354 fParent(NULL) 355 { 356 Rewind(); 357 } 358 359 ~DeviceTreeIterator() 360 { 361 if (fParent != NULL) 362 fDeviceManager->put_device_node(fParent); 363 if (fNode != NULL) 364 fDeviceManager->put_device_node(fNode); 365 } 366 367 void Rewind() 368 { 369 fNode = fDeviceManager->get_root(); 370 } 371 372 bool HasNext() const 373 { 374 return (fNode != NULL); 375 } 376 377 device_node_handle Next() 378 { 379 if (fNode == NULL) 380 return NULL; 381 382 device_node_handle foundNode = fNode; 383 384 // get first child 385 device_node_handle child = NULL; 386 if (fDeviceManager->get_next_child_device(fNode, &child, NULL) 387 == B_OK) { 388 // move to the child node 389 if (fParent != NULL) 390 fDeviceManager->put_device_node(fParent); 391 fParent = fNode; 392 fNode = child; 393 394 // no more children; backtrack to find the next sibling 395 } else { 396 while (fParent != NULL) { 397 if (fDeviceManager->get_next_child_device(fParent, &fNode, NULL) 398 == B_OK) { 399 // get_next_child_device() always puts the node 400 break; 401 } 402 fNode = fParent; 403 fParent = fDeviceManager->get_parent(fNode); 404 } 405 406 // if we hit the root node again, we're done 407 if (fParent == NULL) { 408 fDeviceManager->put_device_node(fNode); 409 fNode = NULL; 410 } 411 } 412 413 return foundNode; 414 } 415 416 private: 417 device_manager_info *fDeviceManager; 418 device_node_handle fNode; 419 device_node_handle fParent; 420 }; 421 422 423 static void 424 get_interrupt_controller_modules(PICModuleList &list) 425 { 426 const char *namePrefix = "interrupt_controllers/"; 427 size_t namePrefixLen = strlen(namePrefix); 428 429 char name[B_PATH_NAME_LENGTH]; 430 size_t length; 431 uint32 cookie = 0; 432 while (get_next_loaded_module_name(&cookie, name, &(length = sizeof(name))) 433 == B_OK) { 434 // an interrupt controller module? 435 if (length <= namePrefixLen 436 || strncmp(name, namePrefix, namePrefixLen) != 0) { 437 continue; 438 } 439 440 // get the module 441 interrupt_controller_module_info *moduleInfo; 442 if (get_module(name, (module_info**)&moduleInfo) != B_OK) 443 continue; 444 445 // add it to the list 446 PICModule *module = new(nothrow) PICModule(moduleInfo); 447 if (!module) { 448 put_module(((module_info*)moduleInfo)->name); 449 continue; 450 } 451 list.Add(module); 452 } 453 } 454 455 456 static bool 457 probe_pic_device(device_node_handle node, PICModuleList &picModules) 458 { 459 for (PICModule *module = picModules.Head(); 460 module; 461 module = picModules.GetNext(module)) { 462 bool noConnection; 463 if (module->module->info.supports_device(node, &noConnection) > 0) { 464 if (module->module->info.register_device(node) == B_OK) 465 return true; 466 } 467 } 468 469 return false; 470 } 471 472 473 status_t 474 arch_int_init_post_device_manager(struct kernel_args *args) 475 { 476 // get the interrupt controller driver modules 477 PICModuleList picModules; 478 get_interrupt_controller_modules(picModules); 479 if (picModules.IsEmpty()) { 480 panic("arch_int_init_post_device_manager(): Found no PIC modules!"); 481 return B_ENTRY_NOT_FOUND; 482 } 483 484 // get the device manager module 485 device_manager_info *deviceManager; 486 status_t error = get_module(B_DEVICE_MANAGER_MODULE_NAME, 487 (module_info**)&deviceManager); 488 if (error != B_OK) { 489 panic("arch_int_init_post_device_manager(): Failed to get device " 490 "manager: %s", strerror(error)); 491 return error; 492 } 493 Module<device_manager_info> _deviceManager(deviceManager); // auto put 494 495 // iterate through the device tree and probe the interrupt controllers 496 DeviceTreeIterator iterator(deviceManager); 497 while (device_node_handle node = iterator.Next()) 498 probe_pic_device(node, picModules); 499 500 // iterate through the tree again and get an interrupt controller node 501 iterator.Rewind(); 502 while (device_node_handle node = iterator.Next()) { 503 char *deviceType; 504 if (deviceManager->get_attr_string(node, B_DRIVER_DEVICE_TYPE, 505 &deviceType, false) == B_OK) { 506 bool isPIC 507 = (strcmp(deviceType, B_INTERRUPT_CONTROLLER_DRIVER_TYPE) == 0); 508 free(deviceType); 509 510 if (isPIC) { 511 driver_module_info *driver; 512 void *driverCookie; 513 error = deviceManager->init_driver(node, NULL, &driver, 514 &driverCookie); 515 if (error == B_OK) { 516 sPIC = (interrupt_controller_module_info *)driver; 517 sPICCookie = driverCookie; 518 return B_OK; 519 } 520 } 521 } 522 } 523 524 // no PIC found 525 panic("arch_int_init_post_device_manager(): Found no supported PIC!"); 526 527 return B_ENTRY_NOT_FOUND; 528 } 529 530 531 // #pragma mark - 532 533 struct m68k_cpu_exception_context * 534 m68k_get_cpu_exception_context(int cpu) 535 { 536 return sCPUExceptionContexts + cpu; 537 } 538 539 540 void 541 m68k_set_current_cpu_exception_context(struct m68k_cpu_exception_context *context) 542 { 543 // translate to physical address 544 addr_t physicalPage; 545 addr_t inPageOffset = (addr_t)context & (B_PAGE_SIZE - 1); 546 status_t error = vm_get_page_mapping(vm_kernel_address_space_id(), 547 (addr_t)context - inPageOffset, &physicalPage); 548 if (error != B_OK) { 549 panic("m68k_set_current_cpu_exception_context(): Failed to get physical " 550 "address!"); 551 return; 552 } 553 554 asm volatile("mtsprg0 %0" : : "r"(physicalPage + inPageOffset)); 555 } 556 557