xref: /haiku/src/system/kernel/arch/m68k/arch_int.cpp (revision 24df65921befcd0ad0c5c7866118f922da61cb96)
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