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