2 * Copyright (c) 2009-2013 ETH Zurich.
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
14 /* XXX - not AArch64-compatible. */
16 #include <exceptions.h>
23 void handle_user_page_fault(lvaddr_t fault_address,
24 arch_registers_state_t* save_area)
27 struct dispatcher_shared_arm *disp = get_dispatcher_shared_arm(dcb_current->disp);
28 uintptr_t saved_pc = save_area->named.pc;
30 disp->d.disabled = dispatcher_is_disabled_ip(dcb_current->disp, saved_pc);
31 bool disabled = (disp->d.disabled != 0);
33 assert(dcb_current->disp_cte.cap.type == ObjType_Frame);
35 printk(LOG_WARN, "user page fault%s in '%.*s': addr %"PRIxLVADDR
37 disabled ? " WHILE DISABLED" : "", DISP_NAME_LEN,
38 disp->d.name, fault_address, saved_pc);
41 assert(save_area == &disp->trap_save_area);
42 handler = disp->d.dispatcher_pagefault_disabled;
43 dcb_current->faults_taken++;
46 assert(save_area == &disp->enabled_save_area);
47 handler = disp->d.dispatcher_pagefault;
50 if (dcb_current->faults_taken > 2) {
51 printk(LOG_WARN, "handle_user_page_fault: too many faults, "
52 "making domain unrunnable\n");
53 dcb_current->faults_taken = 0; // just in case it gets restarted
54 scheduler_remove(dcb_current);
59 // Upcall to dispatcher
61 // NB System might be cleaner with a prototype
62 // dispatch context that has R0-R3 to be overwritten
63 // plus initial stack, thread, and gic registers. Could do
64 // a faster resume_for_upcall().
67 struct dispatcher_shared_generic *disp_gen =
68 get_dispatcher_shared_generic(dcb_current->disp);
70 union registers_arm resume_area;
72 resume_area.named.cpsr = CPSR_F_MASK | ARM_MODE_USR;
73 resume_area.named.pc = handler;
74 resume_area.named.r0 = disp_gen->udisp;
75 resume_area.named.r1 = fault_address;
76 resume_area.named.r2 = 0;
77 resume_area.named.r3 = saved_pc;
78 resume_area.named.rtls = disp_gen->udisp;
79 resume_area.named.r10 = disp->got_base;
81 // SP is set by handler routine.
83 // Upcall user to save area
84 disp->d.disabled = true;
89 void handle_user_undef(lvaddr_t fault_address,
90 arch_registers_state_t* save_area)
92 union registers_arm resume_area;
94 struct dispatcher_shared_arm *disp = get_dispatcher_shared_arm(dcb_current->disp);
96 bool disabled = dispatcher_is_disabled_ip(dcb_current->disp, save_area->named.pc);
97 disp->d.disabled = disabled;
99 assert(dcb_current->disp_cte.cap.type == ObjType_Frame);
101 // assert(save_area == &disp->trap_save_area);
104 assert(save_area == &disp->enabled_save_area);
107 printk(LOG_WARN, "user undef fault%s in '%.*s': IP %" PRIuPTR "\n",
108 disabled ? " WHILE DISABLED" : "", DISP_NAME_LEN,
109 disp->d.name, fault_address);
111 struct dispatcher_shared_generic *disp_gen =
112 get_dispatcher_shared_generic(dcb_current->disp);
114 resume_area.named.cpsr = CPSR_F_MASK | ARM_MODE_USR;
115 resume_area.named.pc = disp->d.dispatcher_trap;
116 resume_area.named.r0 = disp_gen->udisp;
117 resume_area.named.r1 = ARM_EVECTOR_UNDEF;
118 resume_area.named.r2 = 0;
119 resume_area.named.r3 = fault_address;
120 resume_area.named.rtls = disp_gen->udisp;
121 resume_area.named.r10 = disp->got_base;
123 // Upcall user to save area
124 disp->d.disabled = true;
125 resume(&resume_area);
128 /* XXX - not 64-bit clean, not AArch64-compatible. */
129 static int32_t bkpt_decode(lvaddr_t fault_address)
131 int32_t bkpt_id = -1;
132 if ((fault_address & 3) == 0 && fault_address >= KERNEL_OFFSET) {
133 const uint32_t bkpt_mask = 0xfff000f0;
134 const uint32_t bkpt_isn = 0xe1200070;
136 uintptr_t isn = *((uintptr_t*)fault_address);
137 if ((isn & bkpt_mask) == bkpt_isn) {
138 bkpt_id = (int32_t)((isn & 0xf) | ((isn & 0xfff00) >> 4));
144 /* XXX - not 64-bit clean, not AArch64-compatible. */
145 void fatal_kernel_fault(uint32_t evector, lvaddr_t address, arch_registers_state_t* save_area
149 printk(LOG_PANIC, "Kernel fault at %08"PRIxLVADDR
150 " vector %08"PRIx32"\n\n", address, evector);
151 printk(LOG_PANIC, "Processor save_area at: %p\n", save_area);
153 for (i = 0; i < 16; i++) {
154 const char *extrainfo = "";
158 extrainfo = "\t(sp)";
162 extrainfo = "\t(lr)";
168 snprintf(str, 128, "\t(pc)\t%08lx",
169 save_area->regs[R0_REG + i] -
170 (uint32_t)&kernel_first_byte +
177 printk(LOG_PANIC, "r%d\t%08"PRIx32"%s\n", i, save_area->regs[R0_REG + i], extrainfo);
179 printk(LOG_PANIC, "cpsr\t%08"PRIx32"\n", save_area->regs[CPSR_REG]);
180 printk(LOG_PANIC, "called from: %#lx\n",
181 (lvaddr_t)__builtin_return_address(0) -
182 (lvaddr_t)&kernel_first_byte + 0x100000);
185 case ARM_EVECTOR_UNDEF:
186 panic("Undefined instruction.\n");
189 case ARM_EVECTOR_PABT: {
190 int ifsr = cp15_read_ifsr();
192 int bkpt = bkpt_decode(address);
194 panic("Breakpoint: %4x\n", bkpt);
197 panic("Prefetch abort: ifsr %08x\n", ifsr);
201 case ARM_EVECTOR_DABT:
203 uint32_t dfsr = cp15_read_dfsr();
207 if((dfsr >> 11) & 1) {
208 printf("On write access\n");
210 printf("On read access\n");
213 switch((dfsr & 0xf) | (dfsr & 0x400)) {
215 printf("Alignment fault\n");
219 printf("Instruction cache-maintenance fault\n");
223 printf("Translation fault on section\n");
227 printf("Translation fault on page\n");
231 printf("Synchronous external abort\n");
235 printf("Unknown fault\n");
239 panic("Data abort: dfsr %08"PRIx32"\n", dfsr);
243 panic("Caused by evector: %02"PRIx32, evector);
248 void handle_irq(arch_registers_state_t* save_area, uintptr_t fault_pc)
251 /* XXX - not revision-independent. */
252 #if defined(__ARM_ARCH_7A__)
253 irq = gic_get_active_irq();
255 // this is for ARMv5, -SG
256 irq = pic_get_active_irq();
259 /* XXX - not 64-bit clean */
260 debug(SUBSYS_DISPATCH, "IRQ %"PRIu32" while %s\n", irq,
261 dcb_current ? (dcb_current->disabled ? "disabled": "enabled") : "in kernel");
263 if (dcb_current != NULL) {
264 dispatcher_handle_t handle = dcb_current->disp;
265 if (save_area == dispatcher_get_disabled_save_area(handle)) {
266 assert(dispatcher_is_disabled_ip(handle, fault_pc));
267 dcb_current->disabled = true;
269 /* debug(SUBSYS_DISPATCH,
270 "save_area=%p, dispatcher_get_enabled_save_are(handle)=%p\n",
271 save_area, dispatcher_get_enabled_save_area(handle));
274 assert(save_area == dispatcher_get_enabled_save_area(handle));
275 assert(!dispatcher_is_disabled_ip(handle, fault_pc));
276 dcb_current->disabled = false;
280 if (pit_handle_irq(irq)) {
281 // Timer interrupt, pit_handle_irq acks it at the timer.
282 assert(kernel_ticks_enabled);
283 kernel_now += kernel_timeslice;
284 wakeup_check(kernel_now);
285 dispatch(schedule());
287 // this is the (still) unacknowledged startup interrupt sent by the BSP
288 // we just acknowledge it here
291 /* XXX - not revision-independent. */
292 #if defined(__ARM_ARCH_7A__)
295 // this is for ARMv5, -SG
298 dispatch(schedule());
301 /* XXX - not revision-independent. */
302 #if defined(__ARM_ARCH_7A__)
304 send_user_interrupt(irq);
305 panic("Unhandled IRQ %"PRIu32"\n", irq);
307 // SK: No support for user-level interrupts on ARMv5 and XScale
308 panic("Unhandled IRQ %"PRIu32". User-level IRQs only supported on ARMv7!\n", irq);