2 * Copyright 2003-2012, 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>
9 * Ithamar R. Adema <ithamar@upgrade-android.com>
11 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
12 * Distributed under the terms of the NewOS License.
19 #include <boot/kernel_args.h>
20 #include <device_manager.h>
21 #include <kscheduler.h>
22 #include <interrupt_controller.h>
26 #include <util/DoublyLinkedList.h>
27 #include <util/kernel_cpp.h>
29 #include <vm/vm_priv.h>
30 #include <vm/VMAddressSpace.h>
33 #include <drivers/bus/FDT.h>
37 #include "soc_omap3.h"
39 #define TRACE_ARCH_INT
41 # define TRACE(x) dprintf x
46 #define VECTORPAGE_SIZE 64
47 #define USER_VECTOR_ADDR_LOW 0x00000000
48 #define USER_VECTOR_ADDR_HIGH 0xffff0000
50 extern int _vectors_start
;
51 extern int _vectors_end
;
53 static area_id sVectorPageArea
;
54 static void *sVectorPageAddress
;
55 static area_id sUserVectorPageArea
;
56 static void *sUserVectorPageAddress
;
57 static fdt_module_info
*sFdtModule
;
59 // An iframe stack used in the early boot process when we don't have
61 struct iframe_stack gBootFrameStack
;
65 arch_int_enable_io_interrupt(int irq
)
67 TRACE(("arch_int_enable_io_interrupt(%d)\n", irq
));
68 InterruptController
*ic
= InterruptController::Get();
70 ic
->EnableInterrupt(irq
);
75 arch_int_disable_io_interrupt(int irq
)
77 TRACE(("arch_int_disable_io_interrupt(%d)\n", irq
));
78 InterruptController
*ic
= InterruptController::Get();
80 ic
->DisableInterrupt(irq
);
84 /* arch_int_*_interrupts() and friends are in arch_asm.S */
87 arch_int_assign_to_cpu(int32 irq
, int32 cpu
)
89 // intentionally left blank; no SMP support (yet)
93 print_iframe(const char *event
, struct iframe
*frame
)
96 dprintf("Exception: %s\n", event
);
98 dprintf("R00=%08lx R01=%08lx R02=%08lx R03=%08lx\n"
99 "R04=%08lx R05=%08lx R06=%08lx R07=%08lx\n",
100 frame
->r0
, frame
->r1
, frame
->r2
, frame
->r3
,
101 frame
->r4
, frame
->r5
, frame
->r6
, frame
->r7
);
102 dprintf("R08=%08lx R09=%08lx R10=%08lx R11=%08lx\n"
103 "R12=%08lx SP=%08lx LR=%08lx PC=%08lx CPSR=%08lx\n",
104 frame
->r8
, frame
->r9
, frame
->r10
, frame
->r11
,
105 frame
->r12
, frame
->svc_sp
, frame
->svc_lr
, frame
->pc
, frame
->spsr
);
110 arch_int_init(kernel_args
*args
)
116 extern "C" void arm_vector_init(void);
119 static struct fdt_device_info intc_table
[] = {
121 .compatible
= "marvell,pxa-intc",
122 .init
= PXAInterruptController::Init
,
124 .compatible
= "ti,omap3-intc",
125 .init
= OMAP3InterruptController::Init
,
128 static int intc_count
= sizeof(intc_table
) / sizeof(struct fdt_device_info
);
132 arch_int_init_post_vm(kernel_args
*args
)
134 // create a read/write kernel area
135 sVectorPageArea
= create_area("vectorpage", (void **)&sVectorPageAddress
,
136 B_ANY_ADDRESS
, VECTORPAGE_SIZE
, B_FULL_LOCK
,
137 B_KERNEL_WRITE_AREA
| B_KERNEL_READ_AREA
);
138 if (sVectorPageArea
< 0)
139 panic("vector page could not be created!");
141 // clone it at a fixed address with user read/only permissions
142 sUserVectorPageAddress
= (addr_t
*)USER_VECTOR_ADDR_HIGH
;
143 sUserVectorPageArea
= clone_area("user_vectorpage",
144 (void **)&sUserVectorPageAddress
, B_EXACT_ADDRESS
,
145 B_READ_AREA
| B_EXECUTE_AREA
, sVectorPageArea
);
147 if (sUserVectorPageArea
< 0)
148 panic("user vector page @ %p could not be created (%lx)!",
149 sVectorPageAddress
, sUserVectorPageArea
);
151 // copy vectors into the newly created area
152 memcpy(sVectorPageAddress
, &_vectors_start
, VECTORPAGE_SIZE
);
156 // see if high vectors are enabled
157 if ((mmu_read_c1() & (1 << 13)) != 0)
158 dprintf("High vectors already enabled\n");
160 mmu_write_c1(mmu_read_c1() | (1 << 13));
162 if ((mmu_read_c1() & (1 << 13)) == 0)
163 dprintf("Unable to enable high vectors!\n");
165 dprintf("Enabled high vectors\n");
168 status_t rc
= get_module(B_FDT_MODULE_NAME
, (module_info
**)&sFdtModule
);
170 panic("Unable to get FDT module: %08lx!\n", rc
);
172 rc
= sFdtModule
->setup_devices(intc_table
, intc_count
, NULL
);
174 panic("No interrupt controllers found!\n");
181 arch_int_init_io(kernel_args
* args
)
188 arch_int_init_post_device_manager(struct kernel_args
*args
)
190 return B_ENTRY_NOT_FOUND
;
194 // Little helper class for handling the
195 // iframe stack as used by KDL.
198 IFrameScope(struct iframe
*iframe
) {
199 fThread
= thread_get_current_thread();
201 arm_push_iframe(&fThread
->arch_info
.iframes
, iframe
);
203 arm_push_iframe(&gBootFrameStack
, iframe
);
206 virtual ~IFrameScope() {
209 arm_pop_iframe(&fThread
->arch_info
.iframes
);
211 arm_pop_iframe(&gBootFrameStack
);
219 arch_arm_undefined(struct iframe
*iframe
)
221 print_iframe("Undefined Instruction", iframe
);
222 IFrameScope
scope(iframe
); // push/pop iframe
224 panic("not handled!");
229 arch_arm_syscall(struct iframe
*iframe
)
231 print_iframe("Software interrupt", iframe
);
232 IFrameScope
scope(iframe
); // push/pop iframe
237 arch_arm_data_abort(struct iframe
*frame
)
239 Thread
*thread
= thread_get_current_thread();
240 bool isUser
= (frame
->spsr
& 0x1f) == 0x10;
241 addr_t far
= arm_get_far();
245 #ifdef TRACE_ARCH_INT
246 print_iframe("Data Abort", frame
);
247 dprintf("FAR: %08lx, thread: %s\n", far
, thread
->name
);
250 IFrameScope
scope(frame
);
252 if (debug_debugger_running()) {
253 // If this CPU or this thread has a fault handler, we're allowed to be
255 if (thread
!= NULL
) {
256 cpu_ent
* cpu
= &gCPU
[smp_get_current_cpu()];
258 if (cpu
->fault_handler
!= 0) {
259 debug_set_page_fault_info(far
, frame
->pc
,
260 isWrite
? DEBUG_PAGE_FAULT_WRITE
: 0);
261 frame
->svc_sp
= cpu
->fault_handler_stack_pointer
;
262 frame
->pc
= cpu
->fault_handler
;
266 if (thread
->fault_handler
!= 0) {
267 kprintf("ERROR: thread::fault_handler used in kernel "
269 debug_set_page_fault_info(far
, frame
->pc
,
270 isWrite
? DEBUG_PAGE_FAULT_WRITE
: 0);
271 frame
->pc
= reinterpret_cast<uintptr_t>(thread
->fault_handler
);
276 // otherwise, not really
277 panic("page fault in debugger without fault handler! Touching "
278 "address %p from pc %p\n", (void *)far
, (void *)frame
->pc
);
280 } else if ((frame
->spsr
& (1 << 7)) != 0) {
281 // interrupts disabled
283 // If a page fault handler is installed, we're allowed to be here.
284 // TODO: Now we are generally allowing user_memcpy() with interrupts
285 // disabled, which in most cases is a bug. We should add some thread
286 // flag allowing to explicitly indicate that this handling is desired.
287 uintptr_t handler
= reinterpret_cast<uintptr_t>(thread
->fault_handler
);
288 if (thread
&& thread
->fault_handler
!= 0) {
289 if (frame
->pc
!= handler
) {
294 // The fault happened at the fault handler address. This is a
295 // certain infinite loop.
296 panic("page fault, interrupts disabled, fault handler loop. "
297 "Touching address %p from pc %p\n", (void*)far
,
301 // If we are not running the kernel startup the page fault was not
302 // allowed to happen and we must panic.
303 panic("page fault, but interrupts were disabled. Touching address "
304 "%p from pc %p\n", (void *)far
, (void *)frame
->pc
);
306 } else if (thread
!= NULL
&& thread
->page_faults_allowed
< 1) {
307 panic("page fault not allowed at this place. Touching address "
308 "%p from pc %p\n", (void *)far
, (void *)frame
->pc
);
314 vm_page_fault(far
, frame
->pc
, isWrite
, false, isUser
, &newip
);
317 // the page fault handler wants us to modify the iframe to set the
318 // IP the cpu will return to to be this ip
325 arch_arm_prefetch_abort(struct iframe
*iframe
)
327 print_iframe("Prefetch Abort", iframe
);
328 IFrameScope
scope(iframe
);
330 panic("not handled!");
335 arch_arm_irq(struct iframe
*iframe
)
337 IFrameScope
scope(iframe
);
339 InterruptController
*ic
= InterruptController::Get();
341 ic
->HandleInterrupt();
346 arch_arm_fiq(struct iframe
*iframe
)
348 IFrameScope
scope(iframe
);
350 panic("FIQ not implemented yet!");