1845a180fSFrançois Revol /* 2845a180fSFrançois Revol * Copyright 2003-2006, Haiku Inc. All rights reserved. 3845a180fSFrançois Revol * Distributed under the terms of the MIT License. 4845a180fSFrançois Revol * 5845a180fSFrançois Revol * Authors: 6845a180fSFrançois Revol * Axel Dörfler <axeld@pinc-software.de> 7845a180fSFrançois Revol * Ingo Weinhold <bonefish@cs.tu-berlin.de> 84e44040dSFrançois Revol * François Revol <revol@free.fr> 94e44040dSFrançois Revol * Distributed under the terms of the MIT License. 104e44040dSFrançois Revol * 11845a180fSFrançois Revol * 12845a180fSFrançois Revol * Copyright 2001, Travis Geiselbrecht. All rights reserved. 13845a180fSFrançois Revol * Distributed under the terms of the NewOS License. 14845a180fSFrançois Revol */ 15845a180fSFrançois Revol 16845a180fSFrançois Revol #include <int.h> 17845a180fSFrançois Revol 18845a180fSFrançois Revol #include <arch/smp.h> 19845a180fSFrançois Revol #include <boot/kernel_args.h> 20845a180fSFrançois Revol #include <device_manager.h> 21845a180fSFrançois Revol #include <kscheduler.h> 22845a180fSFrançois Revol #include <interrupt_controller.h> 23845a180fSFrançois Revol #include <smp.h> 24845a180fSFrançois Revol #include <thread.h> 25845a180fSFrançois Revol #include <timer.h> 26845a180fSFrançois Revol #include <util/DoublyLinkedList.h> 27845a180fSFrançois Revol #include <util/kernel_cpp.h> 28845a180fSFrançois Revol #include <vm.h> 29845a180fSFrançois Revol #include <vm_address_space.h> 30845a180fSFrançois Revol #include <vm_priv.h> 31845a180fSFrançois Revol #include <string.h> 32*35471ac5SFrançois Revol 334e44040dSFrançois Revol #warning M68K: writeme! 34845a180fSFrançois Revol 35*35471ac5SFrançois Revol 36*35471ac5SFrançois Revol //#define TRACE_ARCH_INT 37*35471ac5SFrançois Revol #ifdef TRACE_ARCH_INT 38*35471ac5SFrançois Revol # define TRACE(x) dprintf x 39*35471ac5SFrançois Revol #else 40*35471ac5SFrançois Revol # define TRACE(x) ; 41*35471ac5SFrançois Revol #endif 42*35471ac5SFrançois Revol 43*35471ac5SFrançois Revol typedef void (*m68k_exception_handler)(void); 44*35471ac5SFrançois Revol #define M68K_EXCEPTION_VECTOR_COUNT 256 45*35471ac5SFrançois Revol m68k_exception_handler gExceptionVectors[M68K_EXCEPTION_VECTOR_COUNT]; 46*35471ac5SFrançois Revol 47845a180fSFrançois Revol // defined in arch_exceptions.S 48*35471ac5SFrançois Revol extern "C" void __m68k_exception_noop(void); 49*35471ac5SFrançois Revol extern "C" void __m68k_exception_common(void); 50*35471ac5SFrançois Revol 51845a180fSFrançois Revol extern int __irqvec_start; 52845a180fSFrançois Revol extern int __irqvec_end; 53845a180fSFrançois Revol 54845a180fSFrançois Revol extern"C" void m68k_exception_tail(void); 55845a180fSFrançois Revol 56845a180fSFrançois Revol 57845a180fSFrançois Revol // An iframe stack used in the early boot process when we don't have 58845a180fSFrançois Revol // threads yet. 59845a180fSFrançois Revol struct iframe_stack gBootFrameStack; 60845a180fSFrançois Revol 61845a180fSFrançois Revol // interrupt controller interface (initialized 62845a180fSFrançois Revol // in arch_int_init_post_device_manager()) 63845a180fSFrançois Revol static struct interrupt_controller_module_info *sPIC; 64845a180fSFrançois Revol static void *sPICCookie; 65845a180fSFrançois Revol 66845a180fSFrançois Revol 67845a180fSFrançois Revol void 68845a180fSFrançois Revol arch_int_enable_io_interrupt(int irq) 69845a180fSFrançois Revol { 70845a180fSFrançois Revol if (!sPIC) 71845a180fSFrançois Revol return; 72845a180fSFrançois Revol 73845a180fSFrançois Revol // TODO: I have no idea, what IRQ type is appropriate. 74845a180fSFrançois Revol sPIC->enable_io_interrupt(sPICCookie, irq, IRQ_TYPE_LEVEL); 75845a180fSFrançois Revol } 76845a180fSFrançois Revol 77845a180fSFrançois Revol 78845a180fSFrançois Revol void 79845a180fSFrançois Revol arch_int_disable_io_interrupt(int irq) 80845a180fSFrançois Revol { 81845a180fSFrançois Revol if (!sPIC) 82845a180fSFrançois Revol return; 83845a180fSFrançois Revol 84845a180fSFrançois Revol sPIC->disable_io_interrupt(sPICCookie, irq); 85845a180fSFrançois Revol } 86845a180fSFrançois Revol 87845a180fSFrançois Revol 88845a180fSFrançois Revol /* arch_int_*_interrupts() and friends are in arch_asm.S */ 89845a180fSFrançois Revol 90845a180fSFrançois Revol 91845a180fSFrançois Revol static void 92845a180fSFrançois Revol print_iframe(struct iframe *frame) 93845a180fSFrançois Revol { 94845a180fSFrançois Revol dprintf("iframe at %p:\n", frame); 954e44040dSFrançois Revol dprintf(" d0 0x%08lx d1 0x%08lx d2 0x%08lx d3 0x%08lx\n", 9682610ec8SFrançois Revol frame->d[0], frame->d[1], frame->d[2], frame->d[3]); 974e44040dSFrançois Revol kprintf(" d4 0x%08lx d5 0x%08lx d6 0x%08lx d7 0x%08lx\n", 9882610ec8SFrançois Revol frame->d[4], frame->d[5], frame->d[6], frame->d[7]); 994e44040dSFrançois Revol kprintf(" a0 0x%08lx a1 0x%08lx a2 0x%08lx a3 0x%08lx\n", 10082610ec8SFrançois Revol frame->a[0], frame->a[1], frame->a[2], frame->a[3]); 10182610ec8SFrançois Revol kprintf(" a4 0x%08lx a5 0x%08lx a6 0x%08lx "/*"a7 0x%08lx (sp)"*/"\n", 10282610ec8SFrançois Revol frame->a[4], frame->a[5], frame->a[6]/*, frame->a[7]*/); 1034e44040dSFrançois Revol 1044e44040dSFrançois Revol /*kprintf(" pc 0x%08lx ccr 0x%02x\n", 1054e44040dSFrançois Revol frame->pc, frame->ccr);*/ 1064e44040dSFrançois Revol kprintf(" pc 0x%08lx sr 0x%04x\n", 1074e44040dSFrançois Revol frame->pc, frame->sr); 1089a507b45SFrançois Revol #if 0 1094e44040dSFrançois Revol dprintf("r0-r3: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->d0, frame->d1, frame->d2, frame->d3); 1104e44040dSFrançois Revol dprintf("r4-r7: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->d4, frame->d5, frame->d6, frame->d7); 1114e44040dSFrançois Revol dprintf("r8-r11: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->a0, frame->a1, frame->a2, frame->a3); 1124e44040dSFrançois Revol dprintf("r12-r15: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->a4, frame->a5, frame->a6, frame->a7); 1134e44040dSFrançois Revol dprintf(" pc 0x%08lx sr 0x%08lx\n", frame->pc, frame->sr); 1149a507b45SFrançois Revol #endif 115845a180fSFrançois Revol } 116845a180fSFrançois Revol 117845a180fSFrançois Revol 118*35471ac5SFrançois Revol extern "C" void m68k_exception_entry(struct iframe *iframe); 119845a180fSFrançois Revol void 120*35471ac5SFrançois Revol m68k_exception_entry(struct iframe *iframe) 121845a180fSFrançois Revol { 122*35471ac5SFrançois Revol int vector = iframe->cpu.vector >> 2; 123845a180fSFrançois Revol int ret = B_HANDLED_INTERRUPT; 124845a180fSFrançois Revol 125*35471ac5SFrançois Revol if (vector != -1) { 126845a180fSFrançois Revol dprintf("m68k_exception_entry: time %lld vector 0x%x, iframe %p, " 127*35471ac5SFrançois Revol "pc: %p\n", system_time(), vector, iframe, (void*)iframe->cpu.pc); 128845a180fSFrançois Revol } 129845a180fSFrançois Revol 130845a180fSFrançois Revol struct thread *thread = thread_get_current_thread(); 131845a180fSFrançois Revol 132845a180fSFrançois Revol // push iframe 133845a180fSFrançois Revol if (thread) 134845a180fSFrançois Revol m68k_push_iframe(&thread->arch_info.iframes, iframe); 135845a180fSFrançois Revol else 136845a180fSFrançois Revol m68k_push_iframe(&gBootFrameStack, iframe); 137845a180fSFrançois Revol 138845a180fSFrançois Revol switch (vector) { 139*35471ac5SFrançois Revol case 0: // system reset 140845a180fSFrançois Revol panic("system reset exception\n"); 141845a180fSFrançois Revol break; 142*35471ac5SFrançois Revol case 2: // bus error 143*35471ac5SFrançois Revol case 3: // address error 144845a180fSFrançois Revol { 145845a180fSFrançois Revol bool kernelDebugger = debug_debugger_running(); 146845a180fSFrançois Revol 147845a180fSFrançois Revol if (kernelDebugger) { 148845a180fSFrançois Revol // if this thread has a fault handler, we're allowed to be here 149845a180fSFrançois Revol struct thread *thread = thread_get_current_thread(); 150845a180fSFrançois Revol if (thread && thread->fault_handler != NULL) { 151845a180fSFrançois Revol iframe->srr0 = thread->fault_handler; 152845a180fSFrançois Revol break; 153845a180fSFrançois Revol } 154845a180fSFrançois Revol 155845a180fSFrançois Revol // otherwise, not really 156845a180fSFrançois Revol panic("page fault in debugger without fault handler! Touching " 157845a180fSFrançois Revol "address %p from ip %p\n", (void *)iframe->dar, 158845a180fSFrançois Revol (void *)iframe->srr0); 159845a180fSFrançois Revol break; 160845a180fSFrançois Revol } else if ((iframe->srr1 & MSR_EXCEPTIONS_ENABLED) == 0) { 161845a180fSFrançois Revol // if the interrupts were disabled, and we are not running the 162845a180fSFrançois Revol // kernel startup the page fault was not allowed to happen and 163845a180fSFrançois Revol // we must panic 164845a180fSFrançois Revol panic("page fault, but interrupts were disabled. Touching " 165845a180fSFrançois Revol "address %p from ip %p\n", (void *)iframe->dar, 166845a180fSFrançois Revol (void *)iframe->srr0); 167845a180fSFrançois Revol break; 168845a180fSFrançois Revol } else if (thread != NULL && thread->page_faults_allowed < 1) { 169845a180fSFrançois Revol panic("page fault not allowed at this place. Touching address " 170845a180fSFrançois Revol "%p from ip %p\n", (void *)iframe->dar, 171845a180fSFrançois Revol (void *)iframe->srr0); 172845a180fSFrançois Revol } 173845a180fSFrançois Revol 174845a180fSFrançois Revol enable_interrupts(); 175845a180fSFrançois Revol 176845a180fSFrançois Revol addr_t newip; 177845a180fSFrançois Revol 178845a180fSFrançois Revol ret = vm_page_fault(iframe->dar, iframe->srr0, 179845a180fSFrançois Revol iframe->dsisr & (1 << 25), // store or load 180845a180fSFrançois Revol iframe->srr1 & (1 << 14), // was the system in user or supervisor 181845a180fSFrançois Revol &newip); 182845a180fSFrançois Revol if (newip != 0) { 183845a180fSFrançois Revol // the page fault handler wants us to modify the iframe to set the 184845a180fSFrançois Revol // IP the cpu will return to to be this ip 185845a180fSFrançois Revol iframe->srr0 = newip; 186845a180fSFrançois Revol } 187845a180fSFrançois Revol break; 188845a180fSFrançois Revol } 189845a180fSFrançois Revol 190*35471ac5SFrançois Revol case 24: // spurious interrupt 191*35471ac5SFrançois Revol dprintf("spurious interrupt\n"); 192*35471ac5SFrançois Revol break; 193*35471ac5SFrançois Revol case 25: // autovector interrupt 194*35471ac5SFrançois Revol case 26: // autovector interrupt 195*35471ac5SFrançois Revol case 27: // autovector interrupt 196*35471ac5SFrançois Revol case 28: // autovector interrupt 197*35471ac5SFrançois Revol case 29: // autovector interrupt 198*35471ac5SFrançois Revol case 30: // autovector interrupt 199*35471ac5SFrançois Revol case 31: // autovector interrupt 200845a180fSFrançois Revol { 201845a180fSFrançois Revol if (!sPIC) { 202845a180fSFrançois Revol panic("m68k_exception_entry(): external interrupt although we " 203845a180fSFrançois Revol "don't have a PIC driver!"); 204845a180fSFrançois Revol ret = B_HANDLED_INTERRUPT; 205845a180fSFrançois Revol break; 206845a180fSFrançois Revol } 207845a180fSFrançois Revol 208845a180fSFrançois Revol dprintf("handling I/O interrupts...\n"); 209845a180fSFrançois Revol int irq; 210845a180fSFrançois Revol while ((irq = sPIC->acknowledge_io_interrupt(sPICCookie)) >= 0) { 211845a180fSFrançois Revol // TODO: correctly pass level-triggered vs. edge-triggered to the handler! 212845a180fSFrançois Revol ret = int_io_interrupt_handler(irq, true); 213845a180fSFrançois Revol } 214845a180fSFrançois Revol dprintf("handling I/O interrupts done\n"); 215845a180fSFrançois Revol break; 216845a180fSFrançois Revol } 217845a180fSFrançois Revol 218845a180fSFrançois Revol case 0x1700: // thermal management exception 219845a180fSFrançois Revol panic("thermal management exception: unimplemented\n"); 220845a180fSFrançois Revol break; 221*35471ac5SFrançois Revol case 9: // trace 222845a180fSFrançois Revol default: 223845a180fSFrançois Revol dprintf("unhandled exception type 0x%x\n", vector); 224845a180fSFrançois Revol print_iframe(iframe); 225845a180fSFrançois Revol panic("unhandled exception type\n"); 226845a180fSFrançois Revol } 227845a180fSFrançois Revol 228845a180fSFrançois Revol if (ret == B_INVOKE_SCHEDULER) { 229845a180fSFrançois Revol int state = disable_interrupts(); 230845a180fSFrançois Revol GRAB_THREAD_LOCK(); 231845a180fSFrançois Revol scheduler_reschedule(); 232845a180fSFrançois Revol RELEASE_THREAD_LOCK(); 233845a180fSFrançois Revol restore_interrupts(state); 234845a180fSFrançois Revol } 235845a180fSFrançois Revol 236845a180fSFrançois Revol // pop iframe 237845a180fSFrançois Revol if (thread) 238845a180fSFrançois Revol m68k_pop_iframe(&thread->arch_info.iframes); 239845a180fSFrançois Revol else 240845a180fSFrançois Revol m68k_pop_iframe(&gBootFrameStack); 241845a180fSFrançois Revol } 242845a180fSFrançois Revol 243845a180fSFrançois Revol 244845a180fSFrançois Revol status_t 245845a180fSFrançois Revol arch_int_init(kernel_args *args) 246845a180fSFrançois Revol { 247845a180fSFrançois Revol return B_OK; 248845a180fSFrançois Revol } 249845a180fSFrançois Revol 250845a180fSFrançois Revol 251845a180fSFrançois Revol status_t 252845a180fSFrançois Revol arch_int_init_post_vm(kernel_args *args) 253845a180fSFrançois Revol { 254845a180fSFrançois Revol void *handlers = (void *)args->arch_args.exception_handlers.start; 255845a180fSFrançois Revol 256845a180fSFrançois Revol // We may need to remap the exception handler area into the kernel address 257845a180fSFrançois Revol // space. 258845a180fSFrançois Revol if (!IS_KERNEL_ADDRESS(handlers)) { 259845a180fSFrançois Revol addr_t address = (addr_t)handlers; 260845a180fSFrançois Revol status_t error = m68k_remap_address_range(&address, 261845a180fSFrançois Revol args->arch_args.exception_handlers.size, true); 262845a180fSFrançois Revol if (error != B_OK) { 263845a180fSFrançois Revol panic("arch_int_init_post_vm(): Failed to remap the exception " 264845a180fSFrançois Revol "handler area!"); 265845a180fSFrançois Revol return error; 266845a180fSFrançois Revol } 267845a180fSFrançois Revol handlers = (void*)(address); 268845a180fSFrançois Revol } 269845a180fSFrançois Revol 270845a180fSFrançois Revol // create a region to map the irq vector code into (physical address 0x0) 271845a180fSFrançois Revol area_id exceptionArea = create_area("exception_handlers", 272845a180fSFrançois Revol &handlers, B_EXACT_ADDRESS, args->arch_args.exception_handlers.size, 273845a180fSFrançois Revol B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 274845a180fSFrançois Revol if (exceptionArea < B_OK) 275845a180fSFrançois Revol panic("arch_int_init2: could not create exception handler region\n"); 276845a180fSFrançois Revol 277845a180fSFrançois Revol dprintf("exception handlers at %p\n", handlers); 278845a180fSFrançois Revol 279845a180fSFrançois Revol // copy the handlers into this area 280845a180fSFrançois Revol memcpy(handlers, &__irqvec_start, args->arch_args.exception_handlers.size); 281845a180fSFrançois Revol arch_cpu_sync_icache(handlers, args->arch_args.exception_handlers.size); 282845a180fSFrançois Revol 283845a180fSFrançois Revol // init the CPU exception contexts 284845a180fSFrançois Revol int cpuCount = smp_get_num_cpus(); 285845a180fSFrançois Revol for (int i = 0; i < cpuCount; i++) { 286845a180fSFrançois Revol m68k_cpu_exception_context *context = m68k_get_cpu_exception_context(i); 287845a180fSFrançois Revol context->kernel_handle_exception = (void*)&m68k_exception_tail; 288845a180fSFrançois Revol context->exception_context = context; 289845a180fSFrançois Revol // kernel_stack is set when the current thread changes. At this point 290845a180fSFrançois Revol // we don't have threads yet. 291845a180fSFrançois Revol } 292845a180fSFrançois Revol 293845a180fSFrançois Revol // set the exception context for this CPU 294845a180fSFrançois Revol m68k_set_current_cpu_exception_context(m68k_get_cpu_exception_context(0)); 295845a180fSFrançois Revol 296845a180fSFrançois Revol return B_OK; 297845a180fSFrançois Revol } 298845a180fSFrançois Revol 299845a180fSFrançois Revol 300845a180fSFrançois Revol template<typename ModuleInfo> 301845a180fSFrançois Revol struct Module : DoublyLinkedListLinkImpl<Module<ModuleInfo> > { 302845a180fSFrançois Revol Module(ModuleInfo *module) 303845a180fSFrançois Revol : module(module) 304845a180fSFrançois Revol { 305845a180fSFrançois Revol } 306845a180fSFrançois Revol 307845a180fSFrançois Revol ~Module() 308845a180fSFrançois Revol { 309845a180fSFrançois Revol if (module) 310845a180fSFrançois Revol put_module(((module_info*)module)->name); 311845a180fSFrançois Revol } 312845a180fSFrançois Revol 313845a180fSFrançois Revol ModuleInfo *module; 314845a180fSFrançois Revol }; 315845a180fSFrançois Revol 316845a180fSFrançois Revol typedef Module<interrupt_controller_module_info> PICModule; 317845a180fSFrançois Revol 318845a180fSFrançois Revol struct PICModuleList : DoublyLinkedList<PICModule> { 319845a180fSFrançois Revol ~PICModuleList() 320845a180fSFrançois Revol { 321845a180fSFrançois Revol while (PICModule *module = First()) { 322845a180fSFrançois Revol Remove(module); 323845a180fSFrançois Revol delete module; 324845a180fSFrançois Revol } 325845a180fSFrançois Revol } 326845a180fSFrançois Revol }; 327845a180fSFrançois Revol 328845a180fSFrançois Revol 329845a180fSFrançois Revol class DeviceTreeIterator { 330845a180fSFrançois Revol public: 331845a180fSFrançois Revol DeviceTreeIterator(device_manager_info *deviceManager) 332845a180fSFrançois Revol : fDeviceManager(deviceManager), 333845a180fSFrançois Revol fNode(NULL), 334845a180fSFrançois Revol fParent(NULL) 335845a180fSFrançois Revol { 336845a180fSFrançois Revol Rewind(); 337845a180fSFrançois Revol } 338845a180fSFrançois Revol 339845a180fSFrançois Revol ~DeviceTreeIterator() 340845a180fSFrançois Revol { 341845a180fSFrançois Revol if (fParent != NULL) 342845a180fSFrançois Revol fDeviceManager->put_device_node(fParent); 343845a180fSFrançois Revol if (fNode != NULL) 344845a180fSFrançois Revol fDeviceManager->put_device_node(fNode); 345845a180fSFrançois Revol } 346845a180fSFrançois Revol 347845a180fSFrançois Revol void Rewind() 348845a180fSFrançois Revol { 349845a180fSFrançois Revol fNode = fDeviceManager->get_root(); 350845a180fSFrançois Revol } 351845a180fSFrançois Revol 352845a180fSFrançois Revol bool HasNext() const 353845a180fSFrançois Revol { 354845a180fSFrançois Revol return (fNode != NULL); 355845a180fSFrançois Revol } 356845a180fSFrançois Revol 357845a180fSFrançois Revol device_node_handle Next() 358845a180fSFrançois Revol { 359845a180fSFrançois Revol if (fNode == NULL) 360845a180fSFrançois Revol return NULL; 361845a180fSFrançois Revol 362845a180fSFrançois Revol device_node_handle foundNode = fNode; 363845a180fSFrançois Revol 364845a180fSFrançois Revol // get first child 365845a180fSFrançois Revol device_node_handle child = NULL; 366845a180fSFrançois Revol if (fDeviceManager->get_next_child_device(fNode, &child, NULL) 367845a180fSFrançois Revol == B_OK) { 368845a180fSFrançois Revol // move to the child node 369845a180fSFrançois Revol if (fParent != NULL) 370845a180fSFrançois Revol fDeviceManager->put_device_node(fParent); 371845a180fSFrançois Revol fParent = fNode; 372845a180fSFrançois Revol fNode = child; 373845a180fSFrançois Revol 374845a180fSFrançois Revol // no more children; backtrack to find the next sibling 375845a180fSFrançois Revol } else { 376845a180fSFrançois Revol while (fParent != NULL) { 377845a180fSFrançois Revol if (fDeviceManager->get_next_child_device(fParent, &fNode, NULL) 378845a180fSFrançois Revol == B_OK) { 379845a180fSFrançois Revol // get_next_child_device() always puts the node 380845a180fSFrançois Revol break; 381845a180fSFrançois Revol } 382845a180fSFrançois Revol fNode = fParent; 383845a180fSFrançois Revol fParent = fDeviceManager->get_parent(fNode); 384845a180fSFrançois Revol } 385845a180fSFrançois Revol 386845a180fSFrançois Revol // if we hit the root node again, we're done 387845a180fSFrançois Revol if (fParent == NULL) { 388845a180fSFrançois Revol fDeviceManager->put_device_node(fNode); 389845a180fSFrançois Revol fNode = NULL; 390845a180fSFrançois Revol } 391845a180fSFrançois Revol } 392845a180fSFrançois Revol 393845a180fSFrançois Revol return foundNode; 394845a180fSFrançois Revol } 395845a180fSFrançois Revol 396845a180fSFrançois Revol private: 397845a180fSFrançois Revol device_manager_info *fDeviceManager; 398845a180fSFrançois Revol device_node_handle fNode; 399845a180fSFrançois Revol device_node_handle fParent; 400845a180fSFrançois Revol }; 401845a180fSFrançois Revol 402845a180fSFrançois Revol 403845a180fSFrançois Revol static void 404845a180fSFrançois Revol get_interrupt_controller_modules(PICModuleList &list) 405845a180fSFrançois Revol { 406845a180fSFrançois Revol const char *namePrefix = "interrupt_controllers/"; 407845a180fSFrançois Revol size_t namePrefixLen = strlen(namePrefix); 408845a180fSFrançois Revol 409845a180fSFrançois Revol char name[B_PATH_NAME_LENGTH]; 410845a180fSFrançois Revol size_t length; 411845a180fSFrançois Revol uint32 cookie = 0; 412845a180fSFrançois Revol while (get_next_loaded_module_name(&cookie, name, &(length = sizeof(name))) 413845a180fSFrançois Revol == B_OK) { 414845a180fSFrançois Revol // an interrupt controller module? 415845a180fSFrançois Revol if (length <= namePrefixLen 416845a180fSFrançois Revol || strncmp(name, namePrefix, namePrefixLen) != 0) { 417845a180fSFrançois Revol continue; 418845a180fSFrançois Revol } 419845a180fSFrançois Revol 420845a180fSFrançois Revol // get the module 421845a180fSFrançois Revol interrupt_controller_module_info *moduleInfo; 422845a180fSFrançois Revol if (get_module(name, (module_info**)&moduleInfo) != B_OK) 423845a180fSFrançois Revol continue; 424845a180fSFrançois Revol 425845a180fSFrançois Revol // add it to the list 426845a180fSFrançois Revol PICModule *module = new(nothrow) PICModule(moduleInfo); 427845a180fSFrançois Revol if (!module) { 428845a180fSFrançois Revol put_module(((module_info*)moduleInfo)->name); 429845a180fSFrançois Revol continue; 430845a180fSFrançois Revol } 431845a180fSFrançois Revol list.Add(module); 432845a180fSFrançois Revol } 433845a180fSFrançois Revol } 434845a180fSFrançois Revol 435845a180fSFrançois Revol 436845a180fSFrançois Revol static bool 437845a180fSFrançois Revol probe_pic_device(device_node_handle node, PICModuleList &picModules) 438845a180fSFrançois Revol { 439845a180fSFrançois Revol for (PICModule *module = picModules.Head(); 440845a180fSFrançois Revol module; 441845a180fSFrançois Revol module = picModules.GetNext(module)) { 442845a180fSFrançois Revol bool noConnection; 443845a180fSFrançois Revol if (module->module->info.supports_device(node, &noConnection) > 0) { 444845a180fSFrançois Revol if (module->module->info.register_device(node) == B_OK) 445845a180fSFrançois Revol return true; 446845a180fSFrançois Revol } 447845a180fSFrançois Revol } 448845a180fSFrançois Revol 449845a180fSFrançois Revol return false; 450845a180fSFrançois Revol } 451845a180fSFrançois Revol 452845a180fSFrançois Revol 453845a180fSFrançois Revol status_t 454845a180fSFrançois Revol arch_int_init_post_device_manager(struct kernel_args *args) 455845a180fSFrançois Revol { 456845a180fSFrançois Revol // get the interrupt controller driver modules 457845a180fSFrançois Revol PICModuleList picModules; 458845a180fSFrançois Revol get_interrupt_controller_modules(picModules); 459845a180fSFrançois Revol if (picModules.IsEmpty()) { 460845a180fSFrançois Revol panic("arch_int_init_post_device_manager(): Found no PIC modules!"); 461845a180fSFrançois Revol return B_ENTRY_NOT_FOUND; 462845a180fSFrançois Revol } 463845a180fSFrançois Revol 464845a180fSFrançois Revol // get the device manager module 465845a180fSFrançois Revol device_manager_info *deviceManager; 466845a180fSFrançois Revol status_t error = get_module(B_DEVICE_MANAGER_MODULE_NAME, 467845a180fSFrançois Revol (module_info**)&deviceManager); 468845a180fSFrançois Revol if (error != B_OK) { 469845a180fSFrançois Revol panic("arch_int_init_post_device_manager(): Failed to get device " 470845a180fSFrançois Revol "manager: %s", strerror(error)); 471845a180fSFrançois Revol return error; 472845a180fSFrançois Revol } 473845a180fSFrançois Revol Module<device_manager_info> _deviceManager(deviceManager); // auto put 474845a180fSFrançois Revol 475845a180fSFrançois Revol // iterate through the device tree and probe the interrupt controllers 476845a180fSFrançois Revol DeviceTreeIterator iterator(deviceManager); 477845a180fSFrançois Revol while (device_node_handle node = iterator.Next()) 478845a180fSFrançois Revol probe_pic_device(node, picModules); 479845a180fSFrançois Revol 480845a180fSFrançois Revol // iterate through the tree again and get an interrupt controller node 481845a180fSFrançois Revol iterator.Rewind(); 482845a180fSFrançois Revol while (device_node_handle node = iterator.Next()) { 483845a180fSFrançois Revol char *deviceType; 484845a180fSFrançois Revol if (deviceManager->get_attr_string(node, B_DRIVER_DEVICE_TYPE, 485845a180fSFrançois Revol &deviceType, false) == B_OK) { 486845a180fSFrançois Revol bool isPIC 487845a180fSFrançois Revol = (strcmp(deviceType, B_INTERRUPT_CONTROLLER_DRIVER_TYPE) == 0); 488845a180fSFrançois Revol free(deviceType); 489845a180fSFrançois Revol 490845a180fSFrançois Revol if (isPIC) { 491845a180fSFrançois Revol driver_module_info *driver; 492845a180fSFrançois Revol void *driverCookie; 493845a180fSFrançois Revol error = deviceManager->init_driver(node, NULL, &driver, 494845a180fSFrançois Revol &driverCookie); 495845a180fSFrançois Revol if (error == B_OK) { 496845a180fSFrançois Revol sPIC = (interrupt_controller_module_info *)driver; 497845a180fSFrançois Revol sPICCookie = driverCookie; 498845a180fSFrançois Revol return B_OK; 499845a180fSFrançois Revol } 500845a180fSFrançois Revol } 501845a180fSFrançois Revol } 502845a180fSFrançois Revol } 503845a180fSFrançois Revol 504845a180fSFrançois Revol // no PIC found 505845a180fSFrançois Revol panic("arch_int_init_post_device_manager(): Found no supported PIC!"); 506845a180fSFrançois Revol 507845a180fSFrançois Revol return B_ENTRY_NOT_FOUND; 508845a180fSFrançois Revol } 509845a180fSFrançois Revol 510845a180fSFrançois Revol 511845a180fSFrançois Revol // #pragma mark - 512845a180fSFrançois Revol 513845a180fSFrançois Revol struct m68k_cpu_exception_context * 514845a180fSFrançois Revol m68k_get_cpu_exception_context(int cpu) 515845a180fSFrançois Revol { 516845a180fSFrançois Revol return sCPUExceptionContexts + cpu; 517845a180fSFrançois Revol } 518845a180fSFrançois Revol 519845a180fSFrançois Revol 520845a180fSFrançois Revol void 521845a180fSFrançois Revol m68k_set_current_cpu_exception_context(struct m68k_cpu_exception_context *context) 522845a180fSFrançois Revol { 523845a180fSFrançois Revol // translate to physical address 524845a180fSFrançois Revol addr_t physicalPage; 525845a180fSFrançois Revol addr_t inPageOffset = (addr_t)context & (B_PAGE_SIZE - 1); 526845a180fSFrançois Revol status_t error = vm_get_page_mapping(vm_kernel_address_space_id(), 527845a180fSFrançois Revol (addr_t)context - inPageOffset, &physicalPage); 528845a180fSFrançois Revol if (error != B_OK) { 529845a180fSFrançois Revol panic("m68k_set_current_cpu_exception_context(): Failed to get physical " 530845a180fSFrançois Revol "address!"); 531845a180fSFrançois Revol return; 532845a180fSFrançois Revol } 533845a180fSFrançois Revol 534845a180fSFrançois Revol asm volatile("mtsprg0 %0" : : "r"(physicalPage + inPageOffset)); 535845a180fSFrançois Revol } 536845a180fSFrançois Revol 537