1845a180fSFrançois Revol /* 24535495dSIngo Weinhold * Copyright 2003-2011, 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> 9845a180fSFrançois Revol * 10845a180fSFrançois Revol * Copyright 2001, Travis Geiselbrecht. All rights reserved. 11845a180fSFrançois Revol * Distributed under the terms of the NewOS License. 12845a180fSFrançois Revol */ 13845a180fSFrançois Revol 149de17be6SAxel Dörfler 15845a180fSFrançois Revol #include <int.h> 16845a180fSFrançois Revol 1760b11851SFrançois Revol #include <arch_platform.h> 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> 26*24df6592SIngo Weinhold #include <util/AutoLock.h> 27845a180fSFrançois Revol #include <util/DoublyLinkedList.h> 28845a180fSFrançois Revol #include <util/kernel_cpp.h> 29e50cf876SIngo Weinhold #include <vm/vm.h> 30e50cf876SIngo Weinhold #include <vm/vm_priv.h> 31e50cf876SIngo Weinhold #include <vm/VMAddressSpace.h> 32845a180fSFrançois Revol #include <string.h> 3335471ac5SFrançois Revol 344e44040dSFrançois Revol #warning M68K: writeme! 35845a180fSFrançois Revol 3635471ac5SFrançois Revol 3735471ac5SFrançois Revol //#define TRACE_ARCH_INT 3835471ac5SFrançois Revol #ifdef TRACE_ARCH_INT 3935471ac5SFrançois Revol # define TRACE(x) dprintf x 4035471ac5SFrançois Revol #else 4135471ac5SFrançois Revol # define TRACE(x) ; 4235471ac5SFrançois Revol #endif 4335471ac5SFrançois Revol 4435471ac5SFrançois Revol typedef void (*m68k_exception_handler)(void); 4535471ac5SFrançois Revol #define M68K_EXCEPTION_VECTOR_COUNT 256 4630629f41SFrançois Revol #warning M68K: align on 4 ? 4736ee9f5cSFrançois Revol //m68k_exception_handler gExceptionVectors[M68K_EXCEPTION_VECTOR_COUNT]; 4836ee9f5cSFrançois Revol m68k_exception_handler *gExceptionVectors; 4935471ac5SFrançois Revol 50845a180fSFrançois Revol // defined in arch_exceptions.S 5135471ac5SFrançois Revol extern "C" void __m68k_exception_noop(void); 5235471ac5SFrançois Revol extern "C" void __m68k_exception_common(void); 5335471ac5SFrançois Revol 54845a180fSFrançois Revol extern int __irqvec_start; 55845a180fSFrançois Revol extern int __irqvec_end; 56845a180fSFrançois Revol 57845a180fSFrançois Revol extern"C" void m68k_exception_tail(void); 58845a180fSFrançois Revol 5930629f41SFrançois Revol // current fault handler 6030629f41SFrançois Revol addr_t gFaultHandler; 61845a180fSFrançois Revol 62845a180fSFrançois Revol // An iframe stack used in the early boot process when we don't have 63845a180fSFrançois Revol // threads yet. 64845a180fSFrançois Revol struct iframe_stack gBootFrameStack; 65845a180fSFrançois Revol 66845a180fSFrançois Revol // interrupt controller interface (initialized 67845a180fSFrançois Revol // in arch_int_init_post_device_manager()) 6860b11851SFrançois Revol //static struct interrupt_controller_module_info *sPIC; 6960b11851SFrançois Revol //static void *sPICCookie; 70845a180fSFrançois Revol 71845a180fSFrançois Revol 72845a180fSFrançois Revol void 73845a180fSFrançois Revol arch_int_enable_io_interrupt(int irq) 74845a180fSFrançois Revol { 7560b11851SFrançois Revol //if (!sPIC) 7660b11851SFrançois Revol // return; 77845a180fSFrançois Revol 78845a180fSFrançois Revol // TODO: I have no idea, what IRQ type is appropriate. 7960b11851SFrançois Revol //sPIC->enable_io_interrupt(sPICCookie, irq, IRQ_TYPE_LEVEL); 8060b11851SFrançois Revol M68KPlatform::Default()->EnableIOInterrupt(irq); 81845a180fSFrançois Revol } 82845a180fSFrançois Revol 83845a180fSFrançois Revol 84845a180fSFrançois Revol void 85845a180fSFrançois Revol arch_int_disable_io_interrupt(int irq) 86845a180fSFrançois Revol { 8760b11851SFrançois Revol //if (!sPIC) 8860b11851SFrançois Revol // return; 89845a180fSFrançois Revol 9060b11851SFrançois Revol //sPIC->disable_io_interrupt(sPICCookie, irq); 9160b11851SFrançois Revol M68KPlatform::Default()->DisableIOInterrupt(irq); 92845a180fSFrançois Revol } 93845a180fSFrançois Revol 94845a180fSFrançois Revol 95845a180fSFrançois Revol /* arch_int_*_interrupts() and friends are in arch_asm.S */ 96845a180fSFrançois Revol 97845a180fSFrançois Revol 98845a180fSFrançois Revol static void 99845a180fSFrançois Revol print_iframe(struct iframe *frame) 100845a180fSFrançois Revol { 101845a180fSFrançois Revol dprintf("iframe at %p:\n", frame); 1024e44040dSFrançois Revol dprintf(" d0 0x%08lx d1 0x%08lx d2 0x%08lx d3 0x%08lx\n", 10382610ec8SFrançois Revol frame->d[0], frame->d[1], frame->d[2], frame->d[3]); 1044e44040dSFrançois Revol kprintf(" d4 0x%08lx d5 0x%08lx d6 0x%08lx d7 0x%08lx\n", 10582610ec8SFrançois Revol frame->d[4], frame->d[5], frame->d[6], frame->d[7]); 1064e44040dSFrançois Revol kprintf(" a0 0x%08lx a1 0x%08lx a2 0x%08lx a3 0x%08lx\n", 10782610ec8SFrançois Revol frame->a[0], frame->a[1], frame->a[2], frame->a[3]); 10882610ec8SFrançois Revol kprintf(" a4 0x%08lx a5 0x%08lx a6 0x%08lx "/*"a7 0x%08lx (sp)"*/"\n", 10982610ec8SFrançois Revol frame->a[4], frame->a[5], frame->a[6]/*, frame->a[7]*/); 1104e44040dSFrançois Revol 1114e44040dSFrançois Revol /*kprintf(" pc 0x%08lx ccr 0x%02x\n", 1124e44040dSFrançois Revol frame->pc, frame->ccr);*/ 1134e44040dSFrançois Revol kprintf(" pc 0x%08lx sr 0x%04x\n", 11430629f41SFrançois Revol frame->cpu.pc, frame->cpu.sr); 1159a507b45SFrançois Revol #if 0 1164e44040dSFrançois Revol dprintf("r0-r3: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->d0, frame->d1, frame->d2, frame->d3); 1174e44040dSFrançois Revol dprintf("r4-r7: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->d4, frame->d5, frame->d6, frame->d7); 1184e44040dSFrançois Revol dprintf("r8-r11: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->a0, frame->a1, frame->a2, frame->a3); 1194e44040dSFrançois Revol dprintf("r12-r15: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->a4, frame->a5, frame->a6, frame->a7); 1204e44040dSFrançois Revol dprintf(" pc 0x%08lx sr 0x%08lx\n", frame->pc, frame->sr); 1219a507b45SFrançois Revol #endif 122845a180fSFrançois Revol } 123845a180fSFrançois Revol 1249de17be6SAxel Dörfler 12530629f41SFrançois Revol static addr_t 12630629f41SFrançois Revol fault_address(struct iframe *iframe) 12730629f41SFrançois Revol { 12830629f41SFrançois Revol switch (iframe->cpu.type) { 12930629f41SFrançois Revol case 0x0: 13030629f41SFrançois Revol case 0x1: 13130629f41SFrançois Revol return 0; 13230629f41SFrançois Revol case 0x2: 13330629f41SFrançois Revol return iframe->cpu.type_2.instruction_address; 13430629f41SFrançois Revol case 0x3: 13530629f41SFrançois Revol return iframe->cpu.type_3.effective_address; 13630629f41SFrançois Revol case 0x7: 13730629f41SFrançois Revol return iframe->cpu.type_7.effective_address; 13830629f41SFrançois Revol case 0x9: 13930629f41SFrançois Revol return iframe->cpu.type_9.instruction_address; 14030629f41SFrançois Revol case 0xa: 14130629f41SFrançois Revol return iframe->cpu.type_a.fault_address; 14230629f41SFrançois Revol case 0xb: 14330629f41SFrançois Revol return iframe->cpu.type_b.fault_address; 14430629f41SFrançois Revol default: 14530629f41SFrançois Revol return 0; 14630629f41SFrançois Revol } 14730629f41SFrançois Revol } 14830629f41SFrançois Revol 1499de17be6SAxel Dörfler 15030629f41SFrançois Revol static bool 15130629f41SFrançois Revol fault_was_write(struct iframe *iframe) 15230629f41SFrançois Revol { 15330629f41SFrançois Revol switch (iframe->cpu.type) { 15430629f41SFrançois Revol case 0x7: 15530629f41SFrançois Revol return !iframe->cpu.type_7.ssw.rw; 15630629f41SFrançois Revol case 0xa: 15730629f41SFrançois Revol return !iframe->cpu.type_a.ssw.rw; 15830629f41SFrançois Revol case 0xb: 15930629f41SFrançois Revol return !iframe->cpu.type_b.ssw.rw; 16030629f41SFrançois Revol default: 16130629f41SFrançois Revol panic("can't determine r/w from iframe type %d\n", 16230629f41SFrançois Revol iframe->cpu.type); 16330629f41SFrançois Revol return false; 16430629f41SFrançois Revol } 16530629f41SFrançois Revol } 166845a180fSFrançois Revol 1679de17be6SAxel Dörfler 16835471ac5SFrançois Revol extern "C" void m68k_exception_entry(struct iframe *iframe); 169845a180fSFrançois Revol void 17035471ac5SFrançois Revol m68k_exception_entry(struct iframe *iframe) 171845a180fSFrançois Revol { 17235471ac5SFrançois Revol int vector = iframe->cpu.vector >> 2; 1735222f12aSFrançois Revol bool hardwareInterrupt = false; 174845a180fSFrançois Revol 17535471ac5SFrançois Revol if (vector != -1) { 176845a180fSFrançois Revol dprintf("m68k_exception_entry: time %lld vector 0x%x, iframe %p, " 17735471ac5SFrançois Revol "pc: %p\n", system_time(), vector, iframe, (void*)iframe->cpu.pc); 178845a180fSFrançois Revol } 179845a180fSFrançois Revol 1804535495dSIngo Weinhold Thread *thread = thread_get_current_thread(); 181845a180fSFrançois Revol 182845a180fSFrançois Revol // push iframe 183845a180fSFrançois Revol if (thread) 184845a180fSFrançois Revol m68k_push_iframe(&thread->arch_info.iframes, iframe); 185845a180fSFrançois Revol else 186845a180fSFrançois Revol m68k_push_iframe(&gBootFrameStack, iframe); 187845a180fSFrançois Revol 188845a180fSFrançois Revol switch (vector) { 18935471ac5SFrançois Revol case 0: // system reset 190845a180fSFrançois Revol panic("system reset exception\n"); 191845a180fSFrançois Revol break; 19235471ac5SFrançois Revol case 2: // bus error 19335471ac5SFrançois Revol case 3: // address error 194845a180fSFrançois Revol { 195845a180fSFrançois Revol bool kernelDebugger = debug_debugger_running(); 196845a180fSFrançois Revol 197845a180fSFrançois Revol if (kernelDebugger) { 198845a180fSFrançois Revol // if this thread has a fault handler, we're allowed to be here 19930629f41SFrançois Revol if (thread && thread->fault_handler != 0) { 20030629f41SFrançois Revol iframe->cpu.pc = thread->fault_handler; 201845a180fSFrançois Revol break; 202845a180fSFrançois Revol } 203845a180fSFrançois Revol 20430629f41SFrançois Revol 205845a180fSFrançois Revol // otherwise, not really 206845a180fSFrançois Revol panic("page fault in debugger without fault handler! Touching " 20730629f41SFrançois Revol "address %p from ip %p\n", (void *)fault_address(iframe), 20830629f41SFrançois Revol (void *)iframe->cpu.pc); 209845a180fSFrançois Revol break; 21030629f41SFrançois Revol } else if ((iframe->cpu.sr & SR_IP_MASK) != 0) { 2115222f12aSFrançois Revol // interrupts disabled 2125222f12aSFrançois Revol 2135222f12aSFrançois Revol // If a page fault handler is installed, we're allowed to be here. 2145222f12aSFrançois Revol // TODO: Now we are generally allowing user_memcpy() with interrupts 2155222f12aSFrançois Revol // disabled, which in most cases is a bug. We should add some thread 2165222f12aSFrançois Revol // flag allowing to explicitly indicate that this handling is desired. 2175222f12aSFrançois Revol if (thread && thread->fault_handler != 0) { 2185222f12aSFrançois Revol iframe->cpu.pc = thread->fault_handler; 2195222f12aSFrançois Revol return; 2205222f12aSFrançois Revol } 2215222f12aSFrançois Revol 222845a180fSFrançois Revol // if the interrupts were disabled, and we are not running the 223845a180fSFrançois Revol // kernel startup the page fault was not allowed to happen and 224845a180fSFrançois Revol // we must panic 225845a180fSFrançois Revol panic("page fault, but interrupts were disabled. Touching " 22630629f41SFrançois Revol "address %p from ip %p\n", (void *)fault_address(iframe), 22730629f41SFrançois Revol (void *)iframe->cpu.pc); 228845a180fSFrançois Revol break; 229845a180fSFrançois Revol } else if (thread != NULL && thread->page_faults_allowed < 1) { 230845a180fSFrançois Revol panic("page fault not allowed at this place. Touching address " 23130629f41SFrançois Revol "%p from ip %p\n", (void *)fault_address(iframe), 23230629f41SFrançois Revol (void *)iframe->cpu.pc); 233845a180fSFrançois Revol } 234845a180fSFrançois Revol 235845a180fSFrançois Revol enable_interrupts(); 236845a180fSFrançois Revol 237845a180fSFrançois Revol addr_t newip; 238845a180fSFrançois Revol 2390338371fSIngo Weinhold vm_page_fault(fault_address(iframe), iframe->cpu.pc, 24030629f41SFrançois Revol fault_was_write(iframe), // store or load 24130629f41SFrançois Revol iframe->cpu.sr & SR_S, // was the system in user or supervisor 242845a180fSFrançois Revol &newip); 243845a180fSFrançois Revol if (newip != 0) { 244845a180fSFrançois Revol // the page fault handler wants us to modify the iframe to set the 245845a180fSFrançois Revol // IP the cpu will return to to be this ip 24630629f41SFrançois Revol iframe->cpu.pc = newip; 247845a180fSFrançois Revol } 248845a180fSFrançois Revol break; 249845a180fSFrançois Revol } 250845a180fSFrançois Revol 25135471ac5SFrançois Revol case 24: // spurious interrupt 25235471ac5SFrançois Revol dprintf("spurious interrupt\n"); 25335471ac5SFrançois Revol break; 25435471ac5SFrançois Revol case 25: // autovector interrupt 25535471ac5SFrançois Revol case 26: // autovector interrupt 25635471ac5SFrançois Revol case 27: // autovector interrupt 25735471ac5SFrançois Revol case 28: // autovector interrupt 25835471ac5SFrançois Revol case 29: // autovector interrupt 25935471ac5SFrançois Revol case 30: // autovector interrupt 26035471ac5SFrançois Revol case 31: // autovector interrupt 261845a180fSFrançois Revol { 26260b11851SFrançois Revol #if 0 263845a180fSFrançois Revol if (!sPIC) { 264845a180fSFrançois Revol panic("m68k_exception_entry(): external interrupt although we " 265845a180fSFrançois Revol "don't have a PIC driver!"); 266845a180fSFrançois Revol break; 267845a180fSFrançois Revol } 26860b11851SFrançois Revol #endif 26960b11851SFrançois Revol M68KPlatform::Default()->AcknowledgeIOInterrupt(vector); 270845a180fSFrançois Revol 271845a180fSFrançois Revol dprintf("handling I/O interrupts...\n"); 2720338371fSIngo Weinhold int_io_interrupt_handler(vector, true); 27360b11851SFrançois Revol #if 0 274845a180fSFrançois Revol while ((irq = sPIC->acknowledge_io_interrupt(sPICCookie)) >= 0) { 275845a180fSFrançois Revol // TODO: correctly pass level-triggered vs. edge-triggered to the handler! 2760338371fSIngo Weinhold int_io_interrupt_handler(irq, true); 277845a180fSFrançois Revol } 27860b11851SFrançois Revol #endif 279845a180fSFrançois Revol dprintf("handling I/O interrupts done\n"); 2805222f12aSFrançois Revol hardwareInterrupt = true; 281845a180fSFrançois Revol break; 282845a180fSFrançois Revol } 283845a180fSFrançois Revol 28435471ac5SFrançois Revol case 9: // trace 285845a180fSFrançois Revol default: 28660b11851SFrançois Revol // vectors >= 64 are user defined vectors, used for IRQ 28760b11851SFrançois Revol if (vector >= 64) { 2882fc21d4fSFrançois Revol if (M68KPlatform::Default()->AcknowledgeIOInterrupt(vector)) { 2890338371fSIngo Weinhold int_io_interrupt_handler(vector, true); 29060b11851SFrançois Revol break; 29160b11851SFrançois Revol } 2922fc21d4fSFrançois Revol } 293845a180fSFrançois Revol dprintf("unhandled exception type 0x%x\n", vector); 294845a180fSFrançois Revol print_iframe(iframe); 295845a180fSFrançois Revol panic("unhandled exception type\n"); 296845a180fSFrançois Revol } 297845a180fSFrançois Revol 298845a180fSFrançois Revol int state = disable_interrupts(); 2990338371fSIngo Weinhold if (thread->cpu->invoke_scheduler) { 300*24df6592SIngo Weinhold SpinLocker schedulerLocker(gSchedulerLock); 301845a180fSFrançois Revol scheduler_reschedule(); 302*24df6592SIngo Weinhold schedulerLocker.Unlock(); 303845a180fSFrançois Revol restore_interrupts(state); 3045222f12aSFrançois Revol } else if (hardwareInterrupt && thread->post_interrupt_callback != NULL) { 3055222f12aSFrançois Revol void (*callback)(void*) = thread->post_interrupt_callback; 3065222f12aSFrançois Revol void* data = thread->post_interrupt_data; 3075222f12aSFrançois Revol 3085222f12aSFrançois Revol thread->post_interrupt_callback = NULL; 3095222f12aSFrançois Revol thread->post_interrupt_data = NULL; 3105222f12aSFrançois Revol 311*24df6592SIngo Weinhold restore_interrupts(state); 312*24df6592SIngo Weinhold 3135222f12aSFrançois Revol callback(data); 314845a180fSFrançois Revol } 315845a180fSFrançois Revol 316845a180fSFrançois Revol // pop iframe 317845a180fSFrançois Revol if (thread) 318845a180fSFrançois Revol m68k_pop_iframe(&thread->arch_info.iframes); 319845a180fSFrançois Revol else 320845a180fSFrançois Revol m68k_pop_iframe(&gBootFrameStack); 321845a180fSFrançois Revol } 322845a180fSFrançois Revol 323845a180fSFrançois Revol 324845a180fSFrançois Revol status_t 325845a180fSFrançois Revol arch_int_init(kernel_args *args) 326845a180fSFrançois Revol { 32730629f41SFrançois Revol status_t err; 32830629f41SFrançois Revol addr_t vbr; 32930629f41SFrançois Revol int i; 33030629f41SFrançois Revol 33136ee9f5cSFrançois Revol gExceptionVectors = (m68k_exception_handler *)args->arch_args.vir_vbr; 33236ee9f5cSFrançois Revol 33330629f41SFrançois Revol /* fill in the vector table */ 33430629f41SFrançois Revol for (i = 0; i < M68K_EXCEPTION_VECTOR_COUNT; i++) 33530629f41SFrançois Revol gExceptionVectors[i] = &__m68k_exception_common; 33660b11851SFrançois Revol 33736ee9f5cSFrançois Revol vbr = args->arch_args.phys_vbr; 33830629f41SFrançois Revol /* point VBR to the new table */ 33936ee9f5cSFrançois Revol asm volatile ("movec %0,%%vbr" : : "r"(vbr):); 34094b1f001SFrançois Revol 341845a180fSFrançois Revol return B_OK; 342845a180fSFrançois Revol } 343845a180fSFrançois Revol 344845a180fSFrançois Revol 345845a180fSFrançois Revol status_t 346845a180fSFrançois Revol arch_int_init_post_vm(kernel_args *args) 347845a180fSFrançois Revol { 34894b1f001SFrançois Revol status_t err; 34994b1f001SFrançois Revol err = M68KPlatform::Default()->InitPIC(args); 35094b1f001SFrançois Revol return err; 351845a180fSFrançois Revol } 352845a180fSFrançois Revol 353845a180fSFrançois Revol 3549de17be6SAxel Dörfler status_t 3559de17be6SAxel Dörfler arch_int_init_io(kernel_args* args) 3569de17be6SAxel Dörfler { 3579de17be6SAxel Dörfler return B_OK; 3589de17be6SAxel Dörfler } 3599de17be6SAxel Dörfler 3609de17be6SAxel Dörfler 36130629f41SFrançois Revol #if 0 /* PIC modules */ 362845a180fSFrançois Revol template<typename ModuleInfo> 363845a180fSFrançois Revol struct Module : DoublyLinkedListLinkImpl<Module<ModuleInfo> > { 364845a180fSFrançois Revol Module(ModuleInfo *module) 365845a180fSFrançois Revol : module(module) 366845a180fSFrançois Revol { 367845a180fSFrançois Revol } 368845a180fSFrançois Revol 369845a180fSFrançois Revol ~Module() 370845a180fSFrançois Revol { 371845a180fSFrançois Revol if (module) 372845a180fSFrançois Revol put_module(((module_info*)module)->name); 373845a180fSFrançois Revol } 374845a180fSFrançois Revol 375845a180fSFrançois Revol ModuleInfo *module; 376845a180fSFrançois Revol }; 377845a180fSFrançois Revol 378845a180fSFrançois Revol typedef Module<interrupt_controller_module_info> PICModule; 379845a180fSFrançois Revol 380845a180fSFrançois Revol struct PICModuleList : DoublyLinkedList<PICModule> { 381845a180fSFrançois Revol ~PICModuleList() 382845a180fSFrançois Revol { 383845a180fSFrançois Revol while (PICModule *module = First()) { 384845a180fSFrançois Revol Remove(module); 385845a180fSFrançois Revol delete module; 386845a180fSFrançois Revol } 387845a180fSFrançois Revol } 388845a180fSFrançois Revol }; 389845a180fSFrançois Revol 390845a180fSFrançois Revol 391845a180fSFrançois Revol class DeviceTreeIterator { 392845a180fSFrançois Revol public: 393845a180fSFrançois Revol DeviceTreeIterator(device_manager_info *deviceManager) 394845a180fSFrançois Revol : fDeviceManager(deviceManager), 395845a180fSFrançois Revol fNode(NULL), 396845a180fSFrançois Revol fParent(NULL) 397845a180fSFrançois Revol { 398845a180fSFrançois Revol Rewind(); 399845a180fSFrançois Revol } 400845a180fSFrançois Revol 401845a180fSFrançois Revol ~DeviceTreeIterator() 402845a180fSFrançois Revol { 403845a180fSFrançois Revol if (fParent != NULL) 404845a180fSFrançois Revol fDeviceManager->put_device_node(fParent); 405845a180fSFrançois Revol if (fNode != NULL) 406845a180fSFrançois Revol fDeviceManager->put_device_node(fNode); 407845a180fSFrançois Revol } 408845a180fSFrançois Revol 409845a180fSFrançois Revol void Rewind() 410845a180fSFrançois Revol { 411845a180fSFrançois Revol fNode = fDeviceManager->get_root(); 412845a180fSFrançois Revol } 413845a180fSFrançois Revol 414845a180fSFrançois Revol bool HasNext() const 415845a180fSFrançois Revol { 416845a180fSFrançois Revol return (fNode != NULL); 417845a180fSFrançois Revol } 418845a180fSFrançois Revol 419845a180fSFrançois Revol device_node_handle Next() 420845a180fSFrançois Revol { 421845a180fSFrançois Revol if (fNode == NULL) 422845a180fSFrançois Revol return NULL; 423845a180fSFrançois Revol 424845a180fSFrançois Revol device_node_handle foundNode = fNode; 425845a180fSFrançois Revol 426845a180fSFrançois Revol // get first child 427845a180fSFrançois Revol device_node_handle child = NULL; 428845a180fSFrançois Revol if (fDeviceManager->get_next_child_device(fNode, &child, NULL) 429845a180fSFrançois Revol == B_OK) { 430845a180fSFrançois Revol // move to the child node 431845a180fSFrançois Revol if (fParent != NULL) 432845a180fSFrançois Revol fDeviceManager->put_device_node(fParent); 433845a180fSFrançois Revol fParent = fNode; 434845a180fSFrançois Revol fNode = child; 435845a180fSFrançois Revol 436845a180fSFrançois Revol // no more children; backtrack to find the next sibling 437845a180fSFrançois Revol } else { 438845a180fSFrançois Revol while (fParent != NULL) { 439845a180fSFrançois Revol if (fDeviceManager->get_next_child_device(fParent, &fNode, NULL) 440845a180fSFrançois Revol == B_OK) { 441845a180fSFrançois Revol // get_next_child_device() always puts the node 442845a180fSFrançois Revol break; 443845a180fSFrançois Revol } 444845a180fSFrançois Revol fNode = fParent; 445845a180fSFrançois Revol fParent = fDeviceManager->get_parent(fNode); 446845a180fSFrançois Revol } 447845a180fSFrançois Revol 448845a180fSFrançois Revol // if we hit the root node again, we're done 449845a180fSFrançois Revol if (fParent == NULL) { 450845a180fSFrançois Revol fDeviceManager->put_device_node(fNode); 451845a180fSFrançois Revol fNode = NULL; 452845a180fSFrançois Revol } 453845a180fSFrançois Revol } 454845a180fSFrançois Revol 455845a180fSFrançois Revol return foundNode; 456845a180fSFrançois Revol } 457845a180fSFrançois Revol 458845a180fSFrançois Revol private: 459845a180fSFrançois Revol device_manager_info *fDeviceManager; 460845a180fSFrançois Revol device_node_handle fNode; 461845a180fSFrançois Revol device_node_handle fParent; 462845a180fSFrançois Revol }; 463845a180fSFrançois Revol 464845a180fSFrançois Revol 465845a180fSFrançois Revol static void 466845a180fSFrançois Revol get_interrupt_controller_modules(PICModuleList &list) 467845a180fSFrançois Revol { 468845a180fSFrançois Revol const char *namePrefix = "interrupt_controllers/"; 469845a180fSFrançois Revol size_t namePrefixLen = strlen(namePrefix); 470845a180fSFrançois Revol 471845a180fSFrançois Revol char name[B_PATH_NAME_LENGTH]; 472845a180fSFrançois Revol size_t length; 473845a180fSFrançois Revol uint32 cookie = 0; 474845a180fSFrançois Revol while (get_next_loaded_module_name(&cookie, name, &(length = sizeof(name))) 475845a180fSFrançois Revol == B_OK) { 476845a180fSFrançois Revol // an interrupt controller module? 477845a180fSFrançois Revol if (length <= namePrefixLen 478845a180fSFrançois Revol || strncmp(name, namePrefix, namePrefixLen) != 0) { 479845a180fSFrançois Revol continue; 480845a180fSFrançois Revol } 481845a180fSFrançois Revol 482845a180fSFrançois Revol // get the module 483845a180fSFrançois Revol interrupt_controller_module_info *moduleInfo; 484845a180fSFrançois Revol if (get_module(name, (module_info**)&moduleInfo) != B_OK) 485845a180fSFrançois Revol continue; 486845a180fSFrançois Revol 487845a180fSFrançois Revol // add it to the list 488845a180fSFrançois Revol PICModule *module = new(nothrow) PICModule(moduleInfo); 489845a180fSFrançois Revol if (!module) { 490845a180fSFrançois Revol put_module(((module_info*)moduleInfo)->name); 491845a180fSFrançois Revol continue; 492845a180fSFrançois Revol } 493845a180fSFrançois Revol list.Add(module); 494845a180fSFrançois Revol } 495845a180fSFrançois Revol } 496845a180fSFrançois Revol 497845a180fSFrançois Revol 498845a180fSFrançois Revol static bool 499845a180fSFrançois Revol probe_pic_device(device_node_handle node, PICModuleList &picModules) 500845a180fSFrançois Revol { 501845a180fSFrançois Revol for (PICModule *module = picModules.Head(); 502845a180fSFrançois Revol module; 503845a180fSFrançois Revol module = picModules.GetNext(module)) { 504845a180fSFrançois Revol bool noConnection; 505845a180fSFrançois Revol if (module->module->info.supports_device(node, &noConnection) > 0) { 506845a180fSFrançois Revol if (module->module->info.register_device(node) == B_OK) 507845a180fSFrançois Revol return true; 508845a180fSFrançois Revol } 509845a180fSFrançois Revol } 510845a180fSFrançois Revol 511845a180fSFrançois Revol return false; 512845a180fSFrançois Revol } 51330629f41SFrançois Revol #endif /* PIC modules */ 514845a180fSFrançois Revol 515845a180fSFrançois Revol status_t 516845a180fSFrançois Revol arch_int_init_post_device_manager(struct kernel_args *args) 517845a180fSFrançois Revol { 51830629f41SFrançois Revol #if 0 /* PIC modules */ 519845a180fSFrançois Revol // get the interrupt controller driver modules 520845a180fSFrançois Revol PICModuleList picModules; 521845a180fSFrançois Revol get_interrupt_controller_modules(picModules); 522845a180fSFrançois Revol if (picModules.IsEmpty()) { 523845a180fSFrançois Revol panic("arch_int_init_post_device_manager(): Found no PIC modules!"); 524845a180fSFrançois Revol return B_ENTRY_NOT_FOUND; 525845a180fSFrançois Revol } 526845a180fSFrançois Revol 527845a180fSFrançois Revol // get the device manager module 528845a180fSFrançois Revol device_manager_info *deviceManager; 529845a180fSFrançois Revol status_t error = get_module(B_DEVICE_MANAGER_MODULE_NAME, 530845a180fSFrançois Revol (module_info**)&deviceManager); 531845a180fSFrançois Revol if (error != B_OK) { 532845a180fSFrançois Revol panic("arch_int_init_post_device_manager(): Failed to get device " 533845a180fSFrançois Revol "manager: %s", strerror(error)); 534845a180fSFrançois Revol return error; 535845a180fSFrançois Revol } 536845a180fSFrançois Revol Module<device_manager_info> _deviceManager(deviceManager); // auto put 537845a180fSFrançois Revol 538845a180fSFrançois Revol // iterate through the device tree and probe the interrupt controllers 539845a180fSFrançois Revol DeviceTreeIterator iterator(deviceManager); 540845a180fSFrançois Revol while (device_node_handle node = iterator.Next()) 541845a180fSFrançois Revol probe_pic_device(node, picModules); 542845a180fSFrançois Revol 543845a180fSFrançois Revol // iterate through the tree again and get an interrupt controller node 544845a180fSFrançois Revol iterator.Rewind(); 545845a180fSFrançois Revol while (device_node_handle node = iterator.Next()) { 546845a180fSFrançois Revol char *deviceType; 547845a180fSFrançois Revol if (deviceManager->get_attr_string(node, B_DRIVER_DEVICE_TYPE, 548845a180fSFrançois Revol &deviceType, false) == B_OK) { 549845a180fSFrançois Revol bool isPIC 550845a180fSFrançois Revol = (strcmp(deviceType, B_INTERRUPT_CONTROLLER_DRIVER_TYPE) == 0); 551845a180fSFrançois Revol free(deviceType); 552845a180fSFrançois Revol 553845a180fSFrançois Revol if (isPIC) { 554845a180fSFrançois Revol driver_module_info *driver; 555845a180fSFrançois Revol void *driverCookie; 556845a180fSFrançois Revol error = deviceManager->init_driver(node, NULL, &driver, 557845a180fSFrançois Revol &driverCookie); 558845a180fSFrançois Revol if (error == B_OK) { 559845a180fSFrançois Revol sPIC = (interrupt_controller_module_info *)driver; 560845a180fSFrançois Revol sPICCookie = driverCookie; 561845a180fSFrançois Revol return B_OK; 562845a180fSFrançois Revol } 563845a180fSFrançois Revol } 564845a180fSFrançois Revol } 565845a180fSFrançois Revol } 566845a180fSFrançois Revol 56730629f41SFrançois Revol #endif /* PIC modules */ 56830629f41SFrançois Revol 569845a180fSFrançois Revol // no PIC found 570845a180fSFrançois Revol panic("arch_int_init_post_device_manager(): Found no supported PIC!"); 571845a180fSFrançois Revol 572845a180fSFrançois Revol return B_ENTRY_NOT_FOUND; 573845a180fSFrançois Revol } 574845a180fSFrançois Revol 575845a180fSFrançois Revol 57660b11851SFrançois Revol #if 0//PPC 577845a180fSFrançois Revol // #pragma mark - 578845a180fSFrançois Revol 579845a180fSFrançois Revol struct m68k_cpu_exception_context * 580845a180fSFrançois Revol m68k_get_cpu_exception_context(int cpu) 581845a180fSFrançois Revol { 582845a180fSFrançois Revol return sCPUExceptionContexts + cpu; 583845a180fSFrançois Revol } 584845a180fSFrançois Revol 585845a180fSFrançois Revol 586845a180fSFrançois Revol void 587845a180fSFrançois Revol m68k_set_current_cpu_exception_context(struct m68k_cpu_exception_context *context) 588845a180fSFrançois Revol { 589845a180fSFrançois Revol // translate to physical address 590845a180fSFrançois Revol addr_t physicalPage; 591845a180fSFrançois Revol addr_t inPageOffset = (addr_t)context & (B_PAGE_SIZE - 1); 59290d870c1SIngo Weinhold status_t error = vm_get_page_mapping(VMAddressSpace::KernelID(), 593845a180fSFrançois Revol (addr_t)context - inPageOffset, &physicalPage); 594845a180fSFrançois Revol if (error != B_OK) { 595845a180fSFrançois Revol panic("m68k_set_current_cpu_exception_context(): Failed to get physical " 596845a180fSFrançois Revol "address!"); 597845a180fSFrançois Revol return; 598845a180fSFrançois Revol } 599845a180fSFrançois Revol 600845a180fSFrançois Revol asm volatile("mtsprg0 %0" : : "r"(physicalPage + inPageOffset)); 601845a180fSFrançois Revol } 602845a180fSFrançois Revol 60330629f41SFrançois Revol #endif 604