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