2 * Copyright 2003-2011, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Axel Dörfler <axeld@pinc-software.de>
7 * Ingo Weinhold <bonefish@cs.tu-berlin.de>
8 * François Revol <revol@free.fr>
10 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
11 * Distributed under the terms of the NewOS License.
17 #include <arch_platform.h>
19 #include <boot/kernel_args.h>
20 #include <device_manager.h>
21 #include <kscheduler.h>
22 #include <interrupt_controller.h>
26 #include <util/AutoLock.h>
27 #include <util/DoublyLinkedList.h>
28 #include <util/kernel_cpp.h>
30 #include <vm/vm_priv.h>
31 #include <vm/VMAddressSpace.h>
34 #warning M68K: writeme!
37 //#define TRACE_ARCH_INT
39 # define TRACE(x) dprintf x
44 typedef void (*m68k_exception_handler
)(void);
45 #define M68K_EXCEPTION_VECTOR_COUNT 256
46 #warning M68K: align on 4 ?
47 //m68k_exception_handler gExceptionVectors[M68K_EXCEPTION_VECTOR_COUNT];
48 m68k_exception_handler
*gExceptionVectors
;
50 // defined in arch_exceptions.S
51 extern "C" void __m68k_exception_noop(void);
52 extern "C" void __m68k_exception_common(void);
54 extern int __irqvec_start
;
55 extern int __irqvec_end
;
57 extern"C" void m68k_exception_tail(void);
59 // current fault handler
62 // An iframe stack used in the early boot process when we don't have
64 struct iframe_stack gBootFrameStack
;
66 // interrupt controller interface (initialized
67 // in arch_int_init_post_device_manager())
68 //static struct interrupt_controller_module_info *sPIC;
69 //static void *sPICCookie;
73 arch_int_enable_io_interrupt(int irq
)
78 // TODO: I have no idea, what IRQ type is appropriate.
79 //sPIC->enable_io_interrupt(sPICCookie, irq, IRQ_TYPE_LEVEL);
80 M68KPlatform::Default()->EnableIOInterrupt(irq
);
85 arch_int_disable_io_interrupt(int irq
)
90 //sPIC->disable_io_interrupt(sPICCookie, irq);
91 M68KPlatform::Default()->DisableIOInterrupt(irq
);
95 /* arch_int_*_interrupts() and friends are in arch_asm.S */
99 arch_int_assign_to_cpu(int32 irq
, int32 cpu
)
101 // intentionally left blank; no SMP support (yet)
106 print_iframe(struct iframe
*frame
)
108 dprintf("iframe at %p:\n", frame
);
109 dprintf(" d0 0x%08lx d1 0x%08lx d2 0x%08lx d3 0x%08lx\n",
110 frame
->d
[0], frame
->d
[1], frame
->d
[2], frame
->d
[3]);
111 kprintf(" d4 0x%08lx d5 0x%08lx d6 0x%08lx d7 0x%08lx\n",
112 frame
->d
[4], frame
->d
[5], frame
->d
[6], frame
->d
[7]);
113 kprintf(" a0 0x%08lx a1 0x%08lx a2 0x%08lx a3 0x%08lx\n",
114 frame
->a
[0], frame
->a
[1], frame
->a
[2], frame
->a
[3]);
115 kprintf(" a4 0x%08lx a5 0x%08lx a6 0x%08lx "/*"a7 0x%08lx (sp)"*/"\n",
116 frame
->a
[4], frame
->a
[5], frame
->a
[6]/*, frame->a[7]*/);
118 /*kprintf(" pc 0x%08lx ccr 0x%02x\n",
119 frame->pc, frame->ccr);*/
120 kprintf(" pc 0x%08lx sr 0x%04x\n",
121 frame
->cpu
.pc
, frame
->cpu
.sr
);
123 dprintf("r0-r3: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame
->d0
, frame
->d1
, frame
->d2
, frame
->d3
);
124 dprintf("r4-r7: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame
->d4
, frame
->d5
, frame
->d6
, frame
->d7
);
125 dprintf("r8-r11: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame
->a0
, frame
->a1
, frame
->a2
, frame
->a3
);
126 dprintf("r12-r15: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame
->a4
, frame
->a5
, frame
->a6
, frame
->a7
);
127 dprintf(" pc 0x%08lx sr 0x%08lx\n", frame
->pc
, frame
->sr
);
133 fault_address(struct iframe
*iframe
)
135 switch (iframe
->cpu
.type
) {
140 return iframe
->cpu
.type_2
.instruction_address
;
142 return iframe
->cpu
.type_3
.effective_address
;
144 return iframe
->cpu
.type_7
.effective_address
;
146 return iframe
->cpu
.type_9
.instruction_address
;
148 return iframe
->cpu
.type_a
.fault_address
;
150 return iframe
->cpu
.type_b
.fault_address
;
158 fault_was_write(struct iframe
*iframe
)
160 switch (iframe
->cpu
.type
) {
162 return !iframe
->cpu
.type_7
.ssw
.rw
;
164 return !iframe
->cpu
.type_a
.ssw
.rw
;
166 return !iframe
->cpu
.type_b
.ssw
.rw
;
168 panic("can't determine r/w from iframe type %d\n",
175 extern "C" void m68k_exception_entry(struct iframe
*iframe
);
177 m68k_exception_entry(struct iframe
*iframe
)
179 int vector
= iframe
->cpu
.vector
>> 2;
180 bool hardwareInterrupt
= false;
183 dprintf("m68k_exception_entry: time %lld vector 0x%x, iframe %p, "
184 "pc: %p\n", system_time(), vector
, iframe
, (void*)iframe
->cpu
.pc
);
187 Thread
*thread
= thread_get_current_thread();
191 m68k_push_iframe(&thread
->arch_info
.iframes
, iframe
);
193 m68k_push_iframe(&gBootFrameStack
, iframe
);
196 case 0: // system reset
197 panic("system reset exception\n");
200 case 3: // address error
202 bool kernelDebugger
= debug_debugger_running();
204 if (kernelDebugger
) {
205 // if this thread has a fault handler, we're allowed to be here
206 if (thread
&& thread
->fault_handler
!= 0) {
207 iframe
->cpu
.pc
= reinterpret_cast<addr_t
>(thread
->fault_handler
);
212 // otherwise, not really
213 panic("page fault in debugger without fault handler! Touching "
214 "address %p from ip %p\n", (void *)fault_address(iframe
),
215 (void *)iframe
->cpu
.pc
);
217 } else if ((iframe
->cpu
.sr
& SR_IP_MASK
) != 0) {
218 // interrupts disabled
220 // If a page fault handler is installed, we're allowed to be here.
221 // TODO: Now we are generally allowing user_memcpy() with interrupts
222 // disabled, which in most cases is a bug. We should add some thread
223 // flag allowing to explicitly indicate that this handling is desired.
224 if (thread
&& thread
->fault_handler
!= 0) {
225 iframe
->cpu
.pc
= reinterpret_cast<addr_t
>(thread
->fault_handler
);
229 // if the interrupts were disabled, and we are not running the
230 // kernel startup the page fault was not allowed to happen and
232 panic("page fault, but interrupts were disabled. Touching "
233 "address %p from ip %p\n", (void *)fault_address(iframe
),
234 (void *)iframe
->cpu
.pc
);
236 } else if (thread
!= NULL
&& thread
->page_faults_allowed
< 1) {
237 panic("page fault not allowed at this place. Touching address "
238 "%p from ip %p\n", (void *)fault_address(iframe
),
239 (void *)iframe
->cpu
.pc
);
246 vm_page_fault(fault_address(iframe
), iframe
->cpu
.pc
,
247 fault_was_write(iframe
), // store or load
249 iframe
->cpu
.sr
& SR_S
, // was the system in user or supervisor
252 // the page fault handler wants us to modify the iframe to set the
253 // IP the cpu will return to to be this ip
254 iframe
->cpu
.pc
= newip
;
259 case 24: // spurious interrupt
260 dprintf("spurious interrupt\n");
262 case 25: // autovector interrupt
263 case 26: // autovector interrupt
264 case 27: // autovector interrupt
265 case 28: // autovector interrupt
266 case 29: // autovector interrupt
267 case 30: // autovector interrupt
268 case 31: // autovector interrupt
272 panic("m68k_exception_entry(): external interrupt although we "
273 "don't have a PIC driver!");
277 M68KPlatform::Default()->AcknowledgeIOInterrupt(vector
);
279 dprintf("handling I/O interrupts...\n");
280 int_io_interrupt_handler(vector
, true);
282 while ((irq
= sPIC
->acknowledge_io_interrupt(sPICCookie
)) >= 0) {
283 // TODO: correctly pass level-triggered vs. edge-triggered to the handler!
284 int_io_interrupt_handler(irq
, true);
287 dprintf("handling I/O interrupts done\n");
288 hardwareInterrupt
= true;
294 // vectors >= 64 are user defined vectors, used for IRQ
296 if (M68KPlatform::Default()->AcknowledgeIOInterrupt(vector
)) {
297 int_io_interrupt_handler(vector
, true);
301 dprintf("unhandled exception type 0x%x\n", vector
);
302 print_iframe(iframe
);
303 panic("unhandled exception type\n");
306 int state
= disable_interrupts();
307 if (thread
->cpu
->invoke_scheduler
) {
308 SpinLocker
schedulerLocker(thread
->scheduler_lock
);
309 scheduler_reschedule(B_THREAD_READY
);
310 schedulerLocker
.Unlock();
311 restore_interrupts(state
);
312 } else if (hardwareInterrupt
&& thread
->post_interrupt_callback
!= NULL
) {
313 void (*callback
)(void*) = thread
->post_interrupt_callback
;
314 void* data
= thread
->post_interrupt_data
;
316 thread
->post_interrupt_callback
= NULL
;
317 thread
->post_interrupt_data
= NULL
;
319 restore_interrupts(state
);
326 m68k_pop_iframe(&thread
->arch_info
.iframes
);
328 m68k_pop_iframe(&gBootFrameStack
);
333 arch_int_init(kernel_args
*args
)
339 gExceptionVectors
= (m68k_exception_handler
*)args
->arch_args
.vir_vbr
;
341 /* fill in the vector table */
342 for (i
= 0; i
< M68K_EXCEPTION_VECTOR_COUNT
; i
++)
343 gExceptionVectors
[i
] = &__m68k_exception_common
;
345 vbr
= args
->arch_args
.phys_vbr
;
346 /* point VBR to the new table */
347 asm volatile ("movec %0,%%vbr" : : "r"(vbr
):);
354 arch_int_init_post_vm(kernel_args
*args
)
357 err
= M68KPlatform::Default()->InitPIC(args
);
363 arch_int_init_io(kernel_args
* args
)
369 #if 0 /* PIC modules */
370 template<typename ModuleInfo
>
371 struct Module
: DoublyLinkedListLinkImpl
<Module
<ModuleInfo
> > {
372 Module(ModuleInfo
*module
)
380 put_module(((module_info
*)module
)->name
);
386 typedef Module
<interrupt_controller_module_info
> PICModule
;
388 struct PICModuleList
: DoublyLinkedList
<PICModule
> {
391 while (PICModule
*module
= First()) {
399 class DeviceTreeIterator
{
401 DeviceTreeIterator(device_manager_info
*deviceManager
)
402 : fDeviceManager(deviceManager
),
409 ~DeviceTreeIterator()
412 fDeviceManager
->put_device_node(fParent
);
414 fDeviceManager
->put_device_node(fNode
);
419 fNode
= fDeviceManager
->get_root();
424 return (fNode
!= NULL
);
427 device_node_handle
Next()
432 device_node_handle foundNode
= fNode
;
435 device_node_handle child
= NULL
;
436 if (fDeviceManager
->get_next_child_device(fNode
, &child
, NULL
)
438 // move to the child node
440 fDeviceManager
->put_device_node(fParent
);
444 // no more children; backtrack to find the next sibling
446 while (fParent
!= NULL
) {
447 if (fDeviceManager
->get_next_child_device(fParent
, &fNode
, NULL
)
449 // get_next_child_device() always puts the node
453 fParent
= fDeviceManager
->get_parent(fNode
);
456 // if we hit the root node again, we're done
457 if (fParent
== NULL
) {
458 fDeviceManager
->put_device_node(fNode
);
467 device_manager_info
*fDeviceManager
;
468 device_node_handle fNode
;
469 device_node_handle fParent
;
474 get_interrupt_controller_modules(PICModuleList
&list
)
476 const char *namePrefix
= "interrupt_controllers/";
477 size_t namePrefixLen
= strlen(namePrefix
);
479 char name
[B_PATH_NAME_LENGTH
];
482 while (get_next_loaded_module_name(&cookie
, name
, &(length
= sizeof(name
)))
484 // an interrupt controller module?
485 if (length
<= namePrefixLen
486 || strncmp(name
, namePrefix
, namePrefixLen
) != 0) {
491 interrupt_controller_module_info
*moduleInfo
;
492 if (get_module(name
, (module_info
**)&moduleInfo
) != B_OK
)
495 // add it to the list
496 PICModule
*module
= new(nothrow
) PICModule(moduleInfo
);
498 put_module(((module_info
*)moduleInfo
)->name
);
507 probe_pic_device(device_node_handle node
, PICModuleList
&picModules
)
509 for (PICModule
*module
= picModules
.Head();
511 module
= picModules
.GetNext(module
)) {
513 if (module
->module
->info
.supports_device(node
, &noConnection
) > 0) {
514 if (module
->module
->info
.register_device(node
) == B_OK
)
521 #endif /* PIC modules */
524 arch_int_init_post_device_manager(struct kernel_args
*args
)
526 #if 0 /* PIC modules */
527 // get the interrupt controller driver modules
528 PICModuleList picModules
;
529 get_interrupt_controller_modules(picModules
);
530 if (picModules
.IsEmpty()) {
531 panic("arch_int_init_post_device_manager(): Found no PIC modules!");
532 return B_ENTRY_NOT_FOUND
;
535 // get the device manager module
536 device_manager_info
*deviceManager
;
537 status_t error
= get_module(B_DEVICE_MANAGER_MODULE_NAME
,
538 (module_info
**)&deviceManager
);
540 panic("arch_int_init_post_device_manager(): Failed to get device "
541 "manager: %s", strerror(error
));
544 Module
<device_manager_info
> _deviceManager(deviceManager
); // auto put
546 // iterate through the device tree and probe the interrupt controllers
547 DeviceTreeIterator
iterator(deviceManager
);
548 while (device_node_handle node
= iterator
.Next())
549 probe_pic_device(node
, picModules
);
551 // iterate through the tree again and get an interrupt controller node
553 while (device_node_handle node
= iterator
.Next()) {
555 if (deviceManager
->get_attr_string(node
, B_DRIVER_DEVICE_TYPE
,
556 &deviceType
, false) == B_OK
) {
558 = (strcmp(deviceType
, B_INTERRUPT_CONTROLLER_DRIVER_TYPE
) == 0);
562 driver_module_info
*driver
;
564 error
= deviceManager
->init_driver(node
, NULL
, &driver
,
567 sPIC
= (interrupt_controller_module_info
*)driver
;
568 sPICCookie
= driverCookie
;
575 #endif /* PIC modules */
578 panic("arch_int_init_post_device_manager(): Found no supported PIC!");
580 return B_ENTRY_NOT_FOUND
;
587 struct m68k_cpu_exception_context
*
588 m68k_get_cpu_exception_context(int cpu
)
590 return sCPUExceptionContexts
+ cpu
;
595 m68k_set_current_cpu_exception_context(struct m68k_cpu_exception_context
*context
)
597 // translate to physical address
599 addr_t inPageOffset
= (addr_t
)context
& (B_PAGE_SIZE
- 1);
600 status_t error
= vm_get_page_mapping(VMAddressSpace::KernelID(),
601 (addr_t
)context
- inPageOffset
, &physicalPage
);
603 panic("m68k_set_current_cpu_exception_context(): Failed to get physical "
608 asm volatile("mtsprg0 %0" : : "r"(physicalPage
+ inPageOffset
));