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>
2624df6592SIngo 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
arch_int_enable_io_interrupt(int32 irq)7302463fb4SX512 arch_int_enable_io_interrupt(int32 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
arch_int_disable_io_interrupt(int32 irq)8502463fb4SX512 arch_int_disable_io_interrupt(int32 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
983c259739SAugustin Cavalier int32
arch_int_assign_to_cpu(int32 irq,int32 cpu)99169349c9SFrançois Revol arch_int_assign_to_cpu(int32 irq, int32 cpu)
100169349c9SFrançois Revol {
1013c259739SAugustin Cavalier // Not yet supported.
1023c259739SAugustin Cavalier return 0;
103169349c9SFrançois Revol }
104169349c9SFrançois Revol
105169349c9SFrançois Revol
106845a180fSFrançois Revol static void
print_iframe(struct iframe * frame)107845a180fSFrançois Revol print_iframe(struct iframe *frame)
108845a180fSFrançois Revol {
109845a180fSFrançois Revol dprintf("iframe at %p:\n", frame);
1104e44040dSFrançois Revol dprintf(" d0 0x%08lx d1 0x%08lx d2 0x%08lx d3 0x%08lx\n",
11182610ec8SFrançois Revol frame->d[0], frame->d[1], frame->d[2], frame->d[3]);
1124e44040dSFrançois Revol kprintf(" d4 0x%08lx d5 0x%08lx d6 0x%08lx d7 0x%08lx\n",
11382610ec8SFrançois Revol frame->d[4], frame->d[5], frame->d[6], frame->d[7]);
1144e44040dSFrançois Revol kprintf(" a0 0x%08lx a1 0x%08lx a2 0x%08lx a3 0x%08lx\n",
11582610ec8SFrançois Revol frame->a[0], frame->a[1], frame->a[2], frame->a[3]);
11682610ec8SFrançois Revol kprintf(" a4 0x%08lx a5 0x%08lx a6 0x%08lx "/*"a7 0x%08lx (sp)"*/"\n",
11782610ec8SFrançois Revol frame->a[4], frame->a[5], frame->a[6]/*, frame->a[7]*/);
1184e44040dSFrançois Revol
1194e44040dSFrançois Revol /*kprintf(" pc 0x%08lx ccr 0x%02x\n",
1204e44040dSFrançois Revol frame->pc, frame->ccr);*/
1214e44040dSFrançois Revol kprintf(" pc 0x%08lx sr 0x%04x\n",
12230629f41SFrançois Revol frame->cpu.pc, frame->cpu.sr);
1239a507b45SFrançois Revol #if 0
1244e44040dSFrançois Revol dprintf("r0-r3: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->d0, frame->d1, frame->d2, frame->d3);
1254e44040dSFrançois Revol dprintf("r4-r7: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->d4, frame->d5, frame->d6, frame->d7);
1264e44040dSFrançois Revol dprintf("r8-r11: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->a0, frame->a1, frame->a2, frame->a3);
1274e44040dSFrançois Revol dprintf("r12-r15: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->a4, frame->a5, frame->a6, frame->a7);
1284e44040dSFrançois Revol dprintf(" pc 0x%08lx sr 0x%08lx\n", frame->pc, frame->sr);
1299a507b45SFrançois Revol #endif
130845a180fSFrançois Revol }
131845a180fSFrançois Revol
1329de17be6SAxel Dörfler
13330629f41SFrançois Revol static addr_t
fault_address(struct iframe * iframe)13430629f41SFrançois Revol fault_address(struct iframe *iframe)
13530629f41SFrançois Revol {
13630629f41SFrançois Revol switch (iframe->cpu.type) {
13730629f41SFrançois Revol case 0x0:
13830629f41SFrançois Revol case 0x1:
13930629f41SFrançois Revol return 0;
14030629f41SFrançois Revol case 0x2:
14130629f41SFrançois Revol return iframe->cpu.type_2.instruction_address;
14230629f41SFrançois Revol case 0x3:
14330629f41SFrançois Revol return iframe->cpu.type_3.effective_address;
14430629f41SFrançois Revol case 0x7:
14530629f41SFrançois Revol return iframe->cpu.type_7.effective_address;
14630629f41SFrançois Revol case 0x9:
14730629f41SFrançois Revol return iframe->cpu.type_9.instruction_address;
14830629f41SFrançois Revol case 0xa:
14930629f41SFrançois Revol return iframe->cpu.type_a.fault_address;
15030629f41SFrançois Revol case 0xb:
15130629f41SFrançois Revol return iframe->cpu.type_b.fault_address;
15230629f41SFrançois Revol default:
15330629f41SFrançois Revol return 0;
15430629f41SFrançois Revol }
15530629f41SFrançois Revol }
15630629f41SFrançois Revol
1579de17be6SAxel Dörfler
15830629f41SFrançois Revol static bool
fault_was_write(struct iframe * iframe)15930629f41SFrançois Revol fault_was_write(struct iframe *iframe)
16030629f41SFrançois Revol {
16130629f41SFrançois Revol switch (iframe->cpu.type) {
16230629f41SFrançois Revol case 0x7:
16330629f41SFrançois Revol return !iframe->cpu.type_7.ssw.rw;
16430629f41SFrançois Revol case 0xa:
16530629f41SFrançois Revol return !iframe->cpu.type_a.ssw.rw;
16630629f41SFrançois Revol case 0xb:
16730629f41SFrançois Revol return !iframe->cpu.type_b.ssw.rw;
16830629f41SFrançois Revol default:
16930629f41SFrançois Revol panic("can't determine r/w from iframe type %d\n",
17030629f41SFrançois Revol iframe->cpu.type);
17130629f41SFrançois Revol return false;
17230629f41SFrançois Revol }
17330629f41SFrançois Revol }
174845a180fSFrançois Revol
1759de17be6SAxel Dörfler
17635471ac5SFrançois Revol extern "C" void m68k_exception_entry(struct iframe *iframe);
177845a180fSFrançois Revol void
m68k_exception_entry(struct iframe * iframe)17835471ac5SFrançois Revol m68k_exception_entry(struct iframe *iframe)
179845a180fSFrançois Revol {
18035471ac5SFrançois Revol int vector = iframe->cpu.vector >> 2;
1815222f12aSFrançois Revol bool hardwareInterrupt = false;
182845a180fSFrançois Revol
18335471ac5SFrançois Revol if (vector != -1) {
184845a180fSFrançois Revol dprintf("m68k_exception_entry: time %lld vector 0x%x, iframe %p, "
18535471ac5SFrançois Revol "pc: %p\n", system_time(), vector, iframe, (void*)iframe->cpu.pc);
186845a180fSFrançois Revol }
187845a180fSFrançois Revol
1884535495dSIngo Weinhold Thread *thread = thread_get_current_thread();
189845a180fSFrançois Revol
190845a180fSFrançois Revol // push iframe
191845a180fSFrançois Revol if (thread)
192845a180fSFrançois Revol m68k_push_iframe(&thread->arch_info.iframes, iframe);
193845a180fSFrançois Revol else
194845a180fSFrançois Revol m68k_push_iframe(&gBootFrameStack, iframe);
195845a180fSFrançois Revol
196845a180fSFrançois Revol switch (vector) {
19735471ac5SFrançois Revol case 0: // system reset
198845a180fSFrançois Revol panic("system reset exception\n");
199845a180fSFrançois Revol break;
20035471ac5SFrançois Revol case 2: // bus error
20135471ac5SFrançois Revol case 3: // address error
202845a180fSFrançois Revol {
203845a180fSFrançois Revol bool kernelDebugger = debug_debugger_running();
204845a180fSFrançois Revol
205845a180fSFrançois Revol if (kernelDebugger) {
206845a180fSFrançois Revol // if this thread has a fault handler, we're allowed to be here
20730629f41SFrançois Revol if (thread && thread->fault_handler != 0) {
2087cd7ba75SFrançois Revol iframe->cpu.pc = reinterpret_cast<addr_t>(thread->fault_handler);
209845a180fSFrançois Revol break;
210845a180fSFrançois Revol }
211845a180fSFrançois Revol
21230629f41SFrançois Revol
213845a180fSFrançois Revol // otherwise, not really
214845a180fSFrançois Revol panic("page fault in debugger without fault handler! Touching "
21530629f41SFrançois Revol "address %p from ip %p\n", (void *)fault_address(iframe),
21630629f41SFrançois Revol (void *)iframe->cpu.pc);
217845a180fSFrançois Revol break;
21830629f41SFrançois Revol } else if ((iframe->cpu.sr & SR_IP_MASK) != 0) {
2195222f12aSFrançois Revol // interrupts disabled
2205222f12aSFrançois Revol
2215222f12aSFrançois Revol // If a page fault handler is installed, we're allowed to be here.
2225222f12aSFrançois Revol // TODO: Now we are generally allowing user_memcpy() with interrupts
2235222f12aSFrançois Revol // disabled, which in most cases is a bug. We should add some thread
2245222f12aSFrançois Revol // flag allowing to explicitly indicate that this handling is desired.
2255222f12aSFrançois Revol if (thread && thread->fault_handler != 0) {
2267cd7ba75SFrançois Revol iframe->cpu.pc = reinterpret_cast<addr_t>(thread->fault_handler);
2275222f12aSFrançois Revol return;
2285222f12aSFrançois Revol }
2295222f12aSFrançois Revol
230845a180fSFrançois Revol // if the interrupts were disabled, and we are not running the
231845a180fSFrançois Revol // kernel startup the page fault was not allowed to happen and
232845a180fSFrançois Revol // we must panic
233845a180fSFrançois Revol panic("page fault, but interrupts were disabled. Touching "
23430629f41SFrançois Revol "address %p from ip %p\n", (void *)fault_address(iframe),
23530629f41SFrançois Revol (void *)iframe->cpu.pc);
236845a180fSFrançois Revol break;
237845a180fSFrançois Revol } else if (thread != NULL && thread->page_faults_allowed < 1) {
238845a180fSFrançois Revol panic("page fault not allowed at this place. Touching address "
23930629f41SFrançois Revol "%p from ip %p\n", (void *)fault_address(iframe),
24030629f41SFrançois Revol (void *)iframe->cpu.pc);
241845a180fSFrançois Revol }
242845a180fSFrançois Revol
243845a180fSFrançois Revol enable_interrupts();
244845a180fSFrançois Revol
245845a180fSFrançois Revol addr_t newip;
246845a180fSFrançois Revol
2470338371fSIngo Weinhold vm_page_fault(fault_address(iframe), iframe->cpu.pc,
24830629f41SFrançois Revol fault_was_write(iframe), // store or load
249966f2076SPawel Dziepak false,
25030629f41SFrançois Revol iframe->cpu.sr & SR_S, // was the system in user or supervisor
251845a180fSFrançois Revol &newip);
252845a180fSFrançois Revol if (newip != 0) {
253845a180fSFrançois Revol // the page fault handler wants us to modify the iframe to set the
254845a180fSFrançois Revol // IP the cpu will return to to be this ip
25530629f41SFrançois Revol iframe->cpu.pc = newip;
256845a180fSFrançois Revol }
257845a180fSFrançois Revol break;
258845a180fSFrançois Revol }
259845a180fSFrançois Revol
26035471ac5SFrançois Revol case 24: // spurious interrupt
26135471ac5SFrançois Revol dprintf("spurious interrupt\n");
26235471ac5SFrançois Revol break;
26335471ac5SFrançois Revol case 25: // autovector interrupt
26435471ac5SFrançois Revol case 26: // autovector interrupt
26535471ac5SFrançois Revol case 27: // autovector interrupt
26635471ac5SFrançois Revol case 28: // autovector interrupt
26735471ac5SFrançois Revol case 29: // autovector interrupt
26835471ac5SFrançois Revol case 30: // autovector interrupt
26935471ac5SFrançois Revol case 31: // autovector interrupt
270845a180fSFrançois Revol {
27160b11851SFrançois Revol #if 0
272845a180fSFrançois Revol if (!sPIC) {
273845a180fSFrançois Revol panic("m68k_exception_entry(): external interrupt although we "
274845a180fSFrançois Revol "don't have a PIC driver!");
275845a180fSFrançois Revol break;
276845a180fSFrançois Revol }
27760b11851SFrançois Revol #endif
27860b11851SFrançois Revol M68KPlatform::Default()->AcknowledgeIOInterrupt(vector);
279845a180fSFrançois Revol
280845a180fSFrançois Revol dprintf("handling I/O interrupts...\n");
2810338371fSIngo Weinhold int_io_interrupt_handler(vector, true);
28260b11851SFrançois Revol #if 0
283845a180fSFrançois Revol while ((irq = sPIC->acknowledge_io_interrupt(sPICCookie)) >= 0) {
284845a180fSFrançois Revol // TODO: correctly pass level-triggered vs. edge-triggered to the handler!
2850338371fSIngo Weinhold int_io_interrupt_handler(irq, true);
286845a180fSFrançois Revol }
28760b11851SFrançois Revol #endif
288845a180fSFrançois Revol dprintf("handling I/O interrupts done\n");
2895222f12aSFrançois Revol hardwareInterrupt = true;
290845a180fSFrançois Revol break;
291845a180fSFrançois Revol }
292845a180fSFrançois Revol
29335471ac5SFrançois Revol case 9: // trace
294845a180fSFrançois Revol default:
29560b11851SFrançois Revol // vectors >= 64 are user defined vectors, used for IRQ
29660b11851SFrançois Revol if (vector >= 64) {
2972fc21d4fSFrançois Revol if (M68KPlatform::Default()->AcknowledgeIOInterrupt(vector)) {
2980338371fSIngo Weinhold int_io_interrupt_handler(vector, true);
29960b11851SFrançois Revol break;
30060b11851SFrançois Revol }
3012fc21d4fSFrançois Revol }
302845a180fSFrançois Revol dprintf("unhandled exception type 0x%x\n", vector);
303845a180fSFrançois Revol print_iframe(iframe);
304845a180fSFrançois Revol panic("unhandled exception type\n");
305845a180fSFrançois Revol }
306845a180fSFrançois Revol
307845a180fSFrançois Revol int state = disable_interrupts();
308*d75f6109SAugustin Cavalier if (hardwareInterrupt && thread->post_interrupt_callback != NULL) {
3095222f12aSFrançois Revol void (*callback)(void*) = thread->post_interrupt_callback;
3105222f12aSFrançois Revol void* data = thread->post_interrupt_data;
3115222f12aSFrançois Revol
3125222f12aSFrançois Revol thread->post_interrupt_callback = NULL;
3135222f12aSFrançois Revol thread->post_interrupt_data = NULL;
3145222f12aSFrançois Revol
31524df6592SIngo Weinhold restore_interrupts(state);
31624df6592SIngo Weinhold
3175222f12aSFrançois Revol callback(data);
318*d75f6109SAugustin Cavalier } else if (thread->cpu->invoke_scheduler) {
319*d75f6109SAugustin Cavalier SpinLocker schedulerLocker(thread->scheduler_lock);
320*d75f6109SAugustin Cavalier scheduler_reschedule(B_THREAD_READY);
321*d75f6109SAugustin Cavalier schedulerLocker.Unlock();
322*d75f6109SAugustin Cavalier restore_interrupts(state);
323845a180fSFrançois Revol }
324845a180fSFrançois Revol
325845a180fSFrançois Revol // pop iframe
326845a180fSFrançois Revol if (thread)
327845a180fSFrançois Revol m68k_pop_iframe(&thread->arch_info.iframes);
328845a180fSFrançois Revol else
329845a180fSFrançois Revol m68k_pop_iframe(&gBootFrameStack);
330845a180fSFrançois Revol }
331845a180fSFrançois Revol
332845a180fSFrançois Revol
333845a180fSFrançois Revol status_t
arch_int_init(kernel_args * args)334845a180fSFrançois Revol arch_int_init(kernel_args *args)
335845a180fSFrançois Revol {
33630629f41SFrançois Revol status_t err;
33730629f41SFrançois Revol addr_t vbr;
33830629f41SFrançois Revol int i;
33930629f41SFrançois Revol
34036ee9f5cSFrançois Revol gExceptionVectors = (m68k_exception_handler *)args->arch_args.vir_vbr;
34136ee9f5cSFrançois Revol
34230629f41SFrançois Revol /* fill in the vector table */
34330629f41SFrançois Revol for (i = 0; i < M68K_EXCEPTION_VECTOR_COUNT; i++)
34430629f41SFrançois Revol gExceptionVectors[i] = &__m68k_exception_common;
34560b11851SFrançois Revol
34636ee9f5cSFrançois Revol vbr = args->arch_args.phys_vbr;
34730629f41SFrançois Revol /* point VBR to the new table */
34836ee9f5cSFrançois Revol asm volatile ("movec %0,%%vbr" : : "r"(vbr):);
34994b1f001SFrançois Revol
350845a180fSFrançois Revol return B_OK;
351845a180fSFrançois Revol }
352845a180fSFrançois Revol
353845a180fSFrançois Revol
354845a180fSFrançois Revol status_t
arch_int_init_post_vm(kernel_args * args)355845a180fSFrançois Revol arch_int_init_post_vm(kernel_args *args)
356845a180fSFrançois Revol {
35794b1f001SFrançois Revol status_t err;
35894b1f001SFrançois Revol err = M68KPlatform::Default()->InitPIC(args);
35994b1f001SFrançois Revol return err;
360845a180fSFrançois Revol }
361845a180fSFrançois Revol
362845a180fSFrançois Revol
3639de17be6SAxel Dörfler status_t
arch_int_init_io(kernel_args * args)3649de17be6SAxel Dörfler arch_int_init_io(kernel_args* args)
3659de17be6SAxel Dörfler {
3669de17be6SAxel Dörfler return B_OK;
3679de17be6SAxel Dörfler }
3689de17be6SAxel Dörfler
3699de17be6SAxel Dörfler
37030629f41SFrançois Revol #if 0 /* PIC modules */
371845a180fSFrançois Revol template<typename ModuleInfo>
372845a180fSFrançois Revol struct Module : DoublyLinkedListLinkImpl<Module<ModuleInfo> > {
373845a180fSFrançois Revol Module(ModuleInfo *module)
374845a180fSFrançois Revol : module(module)
375845a180fSFrançois Revol {
376845a180fSFrançois Revol }
377845a180fSFrançois Revol
378845a180fSFrançois Revol ~Module()
379845a180fSFrançois Revol {
380845a180fSFrançois Revol if (module)
381845a180fSFrançois Revol put_module(((module_info*)module)->name);
382845a180fSFrançois Revol }
383845a180fSFrançois Revol
384845a180fSFrançois Revol ModuleInfo *module;
385845a180fSFrançois Revol };
386845a180fSFrançois Revol
387845a180fSFrançois Revol typedef Module<interrupt_controller_module_info> PICModule;
388845a180fSFrançois Revol
389845a180fSFrançois Revol struct PICModuleList : DoublyLinkedList<PICModule> {
390845a180fSFrançois Revol ~PICModuleList()
391845a180fSFrançois Revol {
392845a180fSFrançois Revol while (PICModule *module = First()) {
393845a180fSFrançois Revol Remove(module);
394845a180fSFrançois Revol delete module;
395845a180fSFrançois Revol }
396845a180fSFrançois Revol }
397845a180fSFrançois Revol };
398845a180fSFrançois Revol
399845a180fSFrançois Revol
400845a180fSFrançois Revol class DeviceTreeIterator {
401845a180fSFrançois Revol public:
402845a180fSFrançois Revol DeviceTreeIterator(device_manager_info *deviceManager)
403845a180fSFrançois Revol : fDeviceManager(deviceManager),
404845a180fSFrançois Revol fNode(NULL),
405845a180fSFrançois Revol fParent(NULL)
406845a180fSFrançois Revol {
407845a180fSFrançois Revol Rewind();
408845a180fSFrançois Revol }
409845a180fSFrançois Revol
410845a180fSFrançois Revol ~DeviceTreeIterator()
411845a180fSFrançois Revol {
412845a180fSFrançois Revol if (fParent != NULL)
413845a180fSFrançois Revol fDeviceManager->put_device_node(fParent);
414845a180fSFrançois Revol if (fNode != NULL)
415845a180fSFrançois Revol fDeviceManager->put_device_node(fNode);
416845a180fSFrançois Revol }
417845a180fSFrançois Revol
418845a180fSFrançois Revol void Rewind()
419845a180fSFrançois Revol {
420845a180fSFrançois Revol fNode = fDeviceManager->get_root();
421845a180fSFrançois Revol }
422845a180fSFrançois Revol
423845a180fSFrançois Revol bool HasNext() const
424845a180fSFrançois Revol {
425845a180fSFrançois Revol return (fNode != NULL);
426845a180fSFrançois Revol }
427845a180fSFrançois Revol
428845a180fSFrançois Revol device_node_handle Next()
429845a180fSFrançois Revol {
430845a180fSFrançois Revol if (fNode == NULL)
431845a180fSFrançois Revol return NULL;
432845a180fSFrançois Revol
433845a180fSFrançois Revol device_node_handle foundNode = fNode;
434845a180fSFrançois Revol
435845a180fSFrançois Revol // get first child
436845a180fSFrançois Revol device_node_handle child = NULL;
437845a180fSFrançois Revol if (fDeviceManager->get_next_child_device(fNode, &child, NULL)
438845a180fSFrançois Revol == B_OK) {
439845a180fSFrançois Revol // move to the child node
440845a180fSFrançois Revol if (fParent != NULL)
441845a180fSFrançois Revol fDeviceManager->put_device_node(fParent);
442845a180fSFrançois Revol fParent = fNode;
443845a180fSFrançois Revol fNode = child;
444845a180fSFrançois Revol
445845a180fSFrançois Revol // no more children; backtrack to find the next sibling
446845a180fSFrançois Revol } else {
447845a180fSFrançois Revol while (fParent != NULL) {
448845a180fSFrançois Revol if (fDeviceManager->get_next_child_device(fParent, &fNode, NULL)
449845a180fSFrançois Revol == B_OK) {
450845a180fSFrançois Revol // get_next_child_device() always puts the node
451845a180fSFrançois Revol break;
452845a180fSFrançois Revol }
453845a180fSFrançois Revol fNode = fParent;
454845a180fSFrançois Revol fParent = fDeviceManager->get_parent(fNode);
455845a180fSFrançois Revol }
456845a180fSFrançois Revol
457845a180fSFrançois Revol // if we hit the root node again, we're done
458845a180fSFrançois Revol if (fParent == NULL) {
459845a180fSFrançois Revol fDeviceManager->put_device_node(fNode);
460845a180fSFrançois Revol fNode = NULL;
461845a180fSFrançois Revol }
462845a180fSFrançois Revol }
463845a180fSFrançois Revol
464845a180fSFrançois Revol return foundNode;
465845a180fSFrançois Revol }
466845a180fSFrançois Revol
467845a180fSFrançois Revol private:
468845a180fSFrançois Revol device_manager_info *fDeviceManager;
469845a180fSFrançois Revol device_node_handle fNode;
470845a180fSFrançois Revol device_node_handle fParent;
471845a180fSFrançois Revol };
472845a180fSFrançois Revol
473845a180fSFrançois Revol
474845a180fSFrançois Revol static void
475845a180fSFrançois Revol get_interrupt_controller_modules(PICModuleList &list)
476845a180fSFrançois Revol {
477845a180fSFrançois Revol const char *namePrefix = "interrupt_controllers/";
478845a180fSFrançois Revol size_t namePrefixLen = strlen(namePrefix);
479845a180fSFrançois Revol
480845a180fSFrançois Revol char name[B_PATH_NAME_LENGTH];
481845a180fSFrançois Revol size_t length;
482845a180fSFrançois Revol uint32 cookie = 0;
483845a180fSFrançois Revol while (get_next_loaded_module_name(&cookie, name, &(length = sizeof(name)))
484845a180fSFrançois Revol == B_OK) {
485845a180fSFrançois Revol // an interrupt controller module?
486845a180fSFrançois Revol if (length <= namePrefixLen
487845a180fSFrançois Revol || strncmp(name, namePrefix, namePrefixLen) != 0) {
488845a180fSFrançois Revol continue;
489845a180fSFrançois Revol }
490845a180fSFrançois Revol
491845a180fSFrançois Revol // get the module
492845a180fSFrançois Revol interrupt_controller_module_info *moduleInfo;
493845a180fSFrançois Revol if (get_module(name, (module_info**)&moduleInfo) != B_OK)
494845a180fSFrançois Revol continue;
495845a180fSFrançois Revol
496845a180fSFrançois Revol // add it to the list
497845a180fSFrançois Revol PICModule *module = new(nothrow) PICModule(moduleInfo);
498845a180fSFrançois Revol if (!module) {
499845a180fSFrançois Revol put_module(((module_info*)moduleInfo)->name);
500845a180fSFrançois Revol continue;
501845a180fSFrançois Revol }
502845a180fSFrançois Revol list.Add(module);
503845a180fSFrançois Revol }
504845a180fSFrançois Revol }
505845a180fSFrançois Revol
506845a180fSFrançois Revol
507845a180fSFrançois Revol static bool
508845a180fSFrançois Revol probe_pic_device(device_node_handle node, PICModuleList &picModules)
509845a180fSFrançois Revol {
510845a180fSFrançois Revol for (PICModule *module = picModules.Head();
511845a180fSFrançois Revol module;
512845a180fSFrançois Revol module = picModules.GetNext(module)) {
513845a180fSFrançois Revol bool noConnection;
514845a180fSFrançois Revol if (module->module->info.supports_device(node, &noConnection) > 0) {
515845a180fSFrançois Revol if (module->module->info.register_device(node) == B_OK)
516845a180fSFrançois Revol return true;
517845a180fSFrançois Revol }
518845a180fSFrançois Revol }
519845a180fSFrançois Revol
520845a180fSFrançois Revol return false;
521845a180fSFrançois Revol }
52230629f41SFrançois Revol #endif /* PIC modules */
523845a180fSFrançois Revol
524845a180fSFrançois Revol status_t
arch_int_init_post_device_manager(struct kernel_args * args)525845a180fSFrançois Revol arch_int_init_post_device_manager(struct kernel_args *args)
526845a180fSFrançois Revol {
52730629f41SFrançois Revol #if 0 /* PIC modules */
528845a180fSFrançois Revol // get the interrupt controller driver modules
529845a180fSFrançois Revol PICModuleList picModules;
530845a180fSFrançois Revol get_interrupt_controller_modules(picModules);
531845a180fSFrançois Revol if (picModules.IsEmpty()) {
532845a180fSFrançois Revol panic("arch_int_init_post_device_manager(): Found no PIC modules!");
533845a180fSFrançois Revol return B_ENTRY_NOT_FOUND;
534845a180fSFrançois Revol }
535845a180fSFrançois Revol
536845a180fSFrançois Revol // get the device manager module
537845a180fSFrançois Revol device_manager_info *deviceManager;
538845a180fSFrançois Revol status_t error = get_module(B_DEVICE_MANAGER_MODULE_NAME,
539845a180fSFrançois Revol (module_info**)&deviceManager);
540845a180fSFrançois Revol if (error != B_OK) {
541845a180fSFrançois Revol panic("arch_int_init_post_device_manager(): Failed to get device "
542845a180fSFrançois Revol "manager: %s", strerror(error));
543845a180fSFrançois Revol return error;
544845a180fSFrançois Revol }
545845a180fSFrançois Revol Module<device_manager_info> _deviceManager(deviceManager); // auto put
546845a180fSFrançois Revol
547845a180fSFrançois Revol // iterate through the device tree and probe the interrupt controllers
548845a180fSFrançois Revol DeviceTreeIterator iterator(deviceManager);
549845a180fSFrançois Revol while (device_node_handle node = iterator.Next())
550845a180fSFrançois Revol probe_pic_device(node, picModules);
551845a180fSFrançois Revol
552845a180fSFrançois Revol // iterate through the tree again and get an interrupt controller node
553845a180fSFrançois Revol iterator.Rewind();
554845a180fSFrançois Revol while (device_node_handle node = iterator.Next()) {
555845a180fSFrançois Revol char *deviceType;
556845a180fSFrançois Revol if (deviceManager->get_attr_string(node, B_DRIVER_DEVICE_TYPE,
557845a180fSFrançois Revol &deviceType, false) == B_OK) {
558845a180fSFrançois Revol bool isPIC
559845a180fSFrançois Revol = (strcmp(deviceType, B_INTERRUPT_CONTROLLER_DRIVER_TYPE) == 0);
560845a180fSFrançois Revol free(deviceType);
561845a180fSFrançois Revol
562845a180fSFrançois Revol if (isPIC) {
563845a180fSFrançois Revol driver_module_info *driver;
564845a180fSFrançois Revol void *driverCookie;
565845a180fSFrançois Revol error = deviceManager->init_driver(node, NULL, &driver,
566845a180fSFrançois Revol &driverCookie);
567845a180fSFrançois Revol if (error == B_OK) {
568845a180fSFrançois Revol sPIC = (interrupt_controller_module_info *)driver;
569845a180fSFrançois Revol sPICCookie = driverCookie;
570845a180fSFrançois Revol return B_OK;
571845a180fSFrançois Revol }
572845a180fSFrançois Revol }
573845a180fSFrançois Revol }
574845a180fSFrançois Revol }
575845a180fSFrançois Revol
57630629f41SFrançois Revol #endif /* PIC modules */
57730629f41SFrançois Revol
578845a180fSFrançois Revol // no PIC found
579845a180fSFrançois Revol panic("arch_int_init_post_device_manager(): Found no supported PIC!");
580845a180fSFrançois Revol
581845a180fSFrançois Revol return B_ENTRY_NOT_FOUND;
582845a180fSFrançois Revol }
583845a180fSFrançois Revol
584845a180fSFrançois Revol
58560b11851SFrançois Revol #if 0//PPC
586845a180fSFrançois Revol // #pragma mark -
587845a180fSFrançois Revol
588845a180fSFrançois Revol struct m68k_cpu_exception_context *
589845a180fSFrançois Revol m68k_get_cpu_exception_context(int cpu)
590845a180fSFrançois Revol {
591845a180fSFrançois Revol return sCPUExceptionContexts + cpu;
592845a180fSFrançois Revol }
593845a180fSFrançois Revol
594845a180fSFrançois Revol
595845a180fSFrançois Revol void
596845a180fSFrançois Revol m68k_set_current_cpu_exception_context(struct m68k_cpu_exception_context *context)
597845a180fSFrançois Revol {
598845a180fSFrançois Revol // translate to physical address
599845a180fSFrançois Revol addr_t physicalPage;
600845a180fSFrançois Revol addr_t inPageOffset = (addr_t)context & (B_PAGE_SIZE - 1);
60190d870c1SIngo Weinhold status_t error = vm_get_page_mapping(VMAddressSpace::KernelID(),
602845a180fSFrançois Revol (addr_t)context - inPageOffset, &physicalPage);
603845a180fSFrançois Revol if (error != B_OK) {
604845a180fSFrançois Revol panic("m68k_set_current_cpu_exception_context(): Failed to get physical "
605845a180fSFrançois Revol "address!");
606845a180fSFrançois Revol return;
607845a180fSFrançois Revol }
608845a180fSFrançois Revol
609845a180fSFrançois Revol asm volatile("mtsprg0 %0" : : "r"(physicalPage + inPageOffset));
610845a180fSFrançois Revol }
611845a180fSFrançois Revol
61230629f41SFrançois Revol #endif
613