btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / system / kernel / arch / arm / arch_int.cpp
blobd7184dc6f904297f00e7477dae8d96f8fa75a3d5
1 /*
2 * Copyright 2003-2012, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
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.
16 #include <int.h>
18 #include <arch/smp.h>
19 #include <boot/kernel_args.h>
20 #include <device_manager.h>
21 #include <kscheduler.h>
22 #include <interrupt_controller.h>
23 #include <smp.h>
24 #include <thread.h>
25 #include <timer.h>
26 #include <util/DoublyLinkedList.h>
27 #include <util/kernel_cpp.h>
28 #include <vm/vm.h>
29 #include <vm/vm_priv.h>
30 #include <vm/VMAddressSpace.h>
31 #include <string.h>
33 #include <drivers/bus/FDT.h>
34 #include "soc.h"
36 #include "soc_pxa.h"
37 #include "soc_omap3.h"
39 #define TRACE_ARCH_INT
40 #ifdef TRACE_ARCH_INT
41 # define TRACE(x) dprintf x
42 #else
43 # define TRACE(x) ;
44 #endif
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
60 // threads yet.
61 struct iframe_stack gBootFrameStack;
64 void
65 arch_int_enable_io_interrupt(int irq)
67 TRACE(("arch_int_enable_io_interrupt(%d)\n", irq));
68 InterruptController *ic = InterruptController::Get();
69 if (ic != NULL)
70 ic->EnableInterrupt(irq);
74 void
75 arch_int_disable_io_interrupt(int irq)
77 TRACE(("arch_int_disable_io_interrupt(%d)\n", irq));
78 InterruptController *ic = InterruptController::Get();
79 if (ic != NULL)
80 ic->DisableInterrupt(irq);
84 /* arch_int_*_interrupts() and friends are in arch_asm.S */
86 void
87 arch_int_assign_to_cpu(int32 irq, int32 cpu)
89 // intentionally left blank; no SMP support (yet)
92 static void
93 print_iframe(const char *event, struct iframe *frame)
95 if (event)
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);
109 status_t
110 arch_int_init(kernel_args *args)
112 return B_OK;
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,
123 }, {
124 .compatible = "ti,omap3-intc",
125 .init = OMAP3InterruptController::Init,
128 static int intc_count = sizeof(intc_table) / sizeof(struct fdt_device_info);
131 status_t
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);
154 arm_vector_init();
156 // see if high vectors are enabled
157 if ((mmu_read_c1() & (1 << 13)) != 0)
158 dprintf("High vectors already enabled\n");
159 else {
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");
164 else
165 dprintf("Enabled high vectors\n");
168 status_t rc = get_module(B_FDT_MODULE_NAME, (module_info**)&sFdtModule);
169 if (rc != B_OK)
170 panic("Unable to get FDT module: %08lx!\n", rc);
172 rc = sFdtModule->setup_devices(intc_table, intc_count, NULL);
173 if (rc != B_OK)
174 panic("No interrupt controllers found!\n");
176 return B_OK;
180 status_t
181 arch_int_init_io(kernel_args* args)
183 return B_OK;
187 status_t
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.
196 class IFrameScope {
197 public:
198 IFrameScope(struct iframe *iframe) {
199 fThread = thread_get_current_thread();
200 if (fThread)
201 arm_push_iframe(&fThread->arch_info.iframes, iframe);
202 else
203 arm_push_iframe(&gBootFrameStack, iframe);
206 virtual ~IFrameScope() {
207 // pop iframe
208 if (fThread)
209 arm_pop_iframe(&fThread->arch_info.iframes);
210 else
211 arm_pop_iframe(&gBootFrameStack);
213 private:
214 Thread* fThread;
218 extern "C" void
219 arch_arm_undefined(struct iframe *iframe)
221 print_iframe("Undefined Instruction", iframe);
222 IFrameScope scope(iframe); // push/pop iframe
224 panic("not handled!");
228 extern "C" void
229 arch_arm_syscall(struct iframe *iframe)
231 print_iframe("Software interrupt", iframe);
232 IFrameScope scope(iframe); // push/pop iframe
236 extern "C" void
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();
242 bool isWrite = true;
243 addr_t newip = 0;
245 #ifdef TRACE_ARCH_INT
246 print_iframe("Data Abort", frame);
247 dprintf("FAR: %08lx, thread: %s\n", far, thread->name);
248 #endif
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
254 // here.
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;
263 return;
266 if (thread->fault_handler != 0) {
267 kprintf("ERROR: thread::fault_handler used in kernel "
268 "debugger!\n");
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);
272 return;
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);
279 return;
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) {
290 frame->pc = handler;
291 return;
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,
298 (void*)frame->pc);
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);
305 return;
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);
309 return;
312 enable_interrupts();
314 vm_page_fault(far, frame->pc, isWrite, false, isUser, &newip);
316 if (newip != 0) {
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
319 frame->pc = newip;
324 extern "C" void
325 arch_arm_prefetch_abort(struct iframe *iframe)
327 print_iframe("Prefetch Abort", iframe);
328 IFrameScope scope(iframe);
330 panic("not handled!");
334 extern "C" void
335 arch_arm_irq(struct iframe *iframe)
337 IFrameScope scope(iframe);
339 InterruptController *ic = InterruptController::Get();
340 if (ic != NULL)
341 ic->HandleInterrupt();
345 extern "C" void
346 arch_arm_fiq(struct iframe *iframe)
348 IFrameScope scope(iframe);
350 panic("FIQ not implemented yet!");