2 * Copyright (c) 2009-2013 ETH Zurich.
3 * Copyright (c) 2015, Hewlett Packard Enterprise Development LP.
6 * This file is distributed under the terms in the attached LICENSE file.
7 * If you do not find this file, copies can be found by writing to:
8 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
16 #include <exceptions.h>
22 #include <arch/arm/arm.h>
23 #include <arch/arm/gic.h>
24 #include <arch/arm/platform.h>
25 #include <dev/armv8_dev.h>
27 void handle_user_page_fault(lvaddr_t fault_address,
28 arch_registers_state_t* save_area,
29 union registers_aarch64 *resume_area)
32 struct dispatcher_shared_aarch64 *disp =
33 get_dispatcher_shared_aarch64(dcb_current->disp);
34 uintptr_t saved_pc = save_area->named.pc;
36 disp->d.disabled = dispatcher_is_disabled_ip(dcb_current->disp, saved_pc);
37 bool disabled = (disp->d.disabled != 0);
39 assert(dcb_current->disp_cte.cap.type == ObjType_Frame);
41 printk(LOG_WARN, "user page fault%s in '%.*s': addr %"PRIxLVADDR
43 disabled ? " WHILE DISABLED" : "", DISP_NAME_LEN,
44 disp->d.name, fault_address, saved_pc);
47 assert(save_area == &disp->trap_save_area);
48 handler = disp->d.dispatcher_pagefault_disabled;
49 dcb_current->faults_taken++;
52 assert(save_area == &disp->enabled_save_area);
53 handler = disp->d.dispatcher_pagefault;
56 if (dcb_current->faults_taken > 2) {
57 printk(LOG_WARN, "handle_user_page_fault: too many faults, "
58 "making domain unrunnable\n");
59 dcb_current->faults_taken = 0; // just in case it gets restarted
60 scheduler_remove(dcb_current);
65 // Upcall to dispatcher
67 // NB System might be cleaner with a prototype
68 // dispatch context that has R0-R3 to be overwritten
69 // plus initial stack, thread, and gic registers. Could do
70 // a faster resume_for_upcall().
73 struct dispatcher_shared_generic *disp_gen =
74 get_dispatcher_shared_generic(dcb_current->disp);
76 /* XXX - This code leaks the contents of the kernel stack to the
77 * user-level fault handler. */
79 resume_area->named.x0 = disp_gen->udisp;
80 resume_area->named.x1 = fault_address;
81 resume_area->named.x2 = 0;
82 resume_area->named.x3 = saved_pc;
83 /* Why does the kernel do this? */
84 resume_area->named.x10 = disp->got_base;
85 resume_area->named.pc = handler;
86 resume_area->named.spsr = CPSR_F_MASK | AARCH64_MODE_USR;
88 // SP is set by handler routine.
90 // Upcall user to save area
91 disp->d.disabled = true;
92 printk(LOG_WARN, "page fault at %p calling handler %p\n",
93 fault_address, handler);
97 void handle_user_undef(lvaddr_t fault_address, enum aarch64_exception_class cause,
98 arch_registers_state_t* save_area,
99 union registers_aarch64 *resume_area)
101 struct dispatcher_shared_aarch64 *disp =
102 get_dispatcher_shared_aarch64(dcb_current->disp);
105 dispatcher_is_disabled_ip(dcb_current->disp, save_area->named.pc);
106 disp->d.disabled = disabled;
108 assert(dcb_current->disp_cte.cap.type == ObjType_Frame);
110 // assert(save_area == &disp->trap_save_area);
113 assert(save_area == &disp->enabled_save_area);
116 printk(LOG_WARN, "user undef fault (0x%lx)%s in '%.*s': IP 0x%lx x29:%lx x30:%lx sp:%lx\n",
117 cause, disabled ? " WHILE DISABLED" : "", DISP_NAME_LEN,
118 disp->d.name, fault_address, save_area->named.x29, save_area->named.x30, save_area->named.stack);
120 struct dispatcher_shared_generic *disp_gen =
121 get_dispatcher_shared_generic(dcb_current->disp);
123 resume_area->named.x0 = disp_gen->udisp;
124 resume_area->named.x1 = AARCH64_EVECTOR_UNDEF;
125 resume_area->named.x2 = 0;
126 resume_area->named.x3 = fault_address;
127 /* Why does the kernel do this? */
128 resume_area->named.x10 = disp->got_base;
129 resume_area->named.pc = disp->d.dispatcher_trap;
130 resume_area->named.spsr = CPSR_F_MASK | AARCH64_MODE_USR;
132 // Upcall user to save area
133 disp->d.disabled = true;
136 void handle_user_fault(lvaddr_t fault_address, uintptr_t cause,
137 arch_registers_state_t* save_area)
139 union registers_aarch64 resume_area;
142 case aarch64_ec_unknown :
143 case aarch64_ec_wfi :
144 case aarch64_ec_mcr_cp15 :
145 case aarch64_ec_mcrr_cp15 :
146 case aarch64_ec_mcr_cp14 :
147 case aarch64_ec_ldc_cp14 :
148 case aarch64_ec_fpen :
149 case aarch64_ec_mcr_cp10 :
150 case aarch64_ec_mcrr_cp14 :
152 handle_user_undef(fault_address, cause, save_area, &resume_area);
154 case aarch64_ec_svc_aa32 :
155 case aarch64_ec_hvc_aa32 :
156 case aarch64_ec_smc_aa32 :
157 case aarch64_ec_svc_aa64 :
158 case aarch64_ec_hvc_aa64 :
159 case aarch64_ec_smc_aa64 :
160 panic("syscall ended up in exception handler ? Yuck.");
162 case aarch64_ec_mrs :
163 case aarch64_ec_impl :
164 handle_user_undef(fault_address, cause, save_area, &resume_area);
166 case aarch64_ec_iabt_low :
167 handle_user_page_fault(fault_address, save_area, &resume_area);
169 case aarch64_ec_iabt_high :
170 panic("pagefault while in kernel? Yuck.");
172 case aarch64_ec_pc_align :
173 handle_user_undef(fault_address, cause, save_area, &resume_area);
175 case aarch64_ec_dabt_low :
176 handle_user_page_fault(fault_address, save_area, &resume_area);
178 case aarch64_ec_dabt_high :
179 panic("pagefault while in kernel? Yuck.");
181 case aarch64_ec_sp_align :
182 case aarch64_ec_fpu_aa32 :
183 case aarch64_ec_fpu_aa64 :
184 case aarch64_ec_serror :
185 case aarch64_ec_bkpt_low :
186 case aarch64_ec_bkpt_high :
187 case aarch64_ec_step_low :
188 case aarch64_ec_step_high :
189 case aarch64_ec_wpt_low :
190 case aarch64_ec_wpt_high :
191 case aarch64_ec_bkpt_soft :
192 case aarch64_ec_bkpt_el2 :
193 case aarch64_ec_brk :
194 handle_user_undef(fault_address, cause, save_area, &resume_area);
197 panic("Unknown exception syndrome: %u", cause);
201 resume(&resume_area);
204 void handle_irq(arch_registers_state_t* save_area, uintptr_t fault_pc,
205 uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3)
209 /* Save the FPU registers */
211 " stp q0, q1, [%x0, #0]\n\t"
212 " stp q2, q3, [%x0, #0x20]\n\t"
213 " stp q4, q5, [%x0, #0x40]\n\t"
214 " stp q6, q7, [%x0, #0x60]\n\t"
215 " stp q8, q9, [%x0, #0x80]\n\t"
216 " stp q10, q11, [%x0, #0xa0]\n\t"
217 " stp q12, q13, [%x0, #0xc0]\n\t"
218 " stp q14, q15, [%x0, #0xe0]\n\t"
219 " stp q16, q17, [%x0, #0x100]\n\t"
220 " stp q18, q19, [%x0, #0x120]\n\t"
221 " stp q20, q21, [%x0, #0x140]\n\t"
222 " stp q22, q23, [%x0, #0x160]\n\t"
223 " stp q24, q25, [%x0, #0x180]\n\t"
224 " stp q26, q27, [%x0, #0x1a0]\n\t"
225 " stp q28, q29, [%x0, #0x1c0]\n\t"
226 " stp q30, q31, [%x0, #0x1e0]\n\t"
227 :: "r" (&save_area->named.v));
229 /* The assembly stub leaves the first 4 registers, the stack pointer,
230 * the exception PC, and the SPSR for us to save, as it's run out of room for
231 * the necessary instructions. */
232 save_area->named.x0 = x0;
233 save_area->named.x1 = x1;
234 save_area->named.x2 = x2;
235 save_area->named.x3 = x3;
236 save_area->named.stack = armv8_SP_EL0_rd(NULL);
237 save_area->named.spsr = armv8_SPSR_EL1_rd(NULL);
238 save_area->named.pc = fault_pc;
240 irq = platform_get_active_irq();
242 debug(SUBSYS_DISPATCH, "IRQ %"PRIu32" while %s\n", irq,
243 dcb_current ? (dcb_current->disabled ? "disabled": "enabled") :
246 if (dcb_current != NULL) {
247 dispatcher_handle_t handle = dcb_current->disp;
248 if (save_area == dispatcher_get_disabled_save_area(handle)) {
249 assert(dispatcher_is_disabled_ip(handle, fault_pc));
250 dcb_current->disabled = true;
252 /* debug(SUBSYS_DISPATCH,
253 "save_area=%p, dispatcher_get_enabled_save_are(handle)=%p\n",
254 save_area, dispatcher_get_enabled_save_area(handle));
257 assert(save_area == dispatcher_get_enabled_save_area(handle));
258 assert(!dispatcher_is_disabled_ip(handle, fault_pc));
259 dcb_current->disabled = false;
262 // Offer it to the timer
263 if (platform_is_timer_interrupt(irq)) {
264 platform_acknowledge_irq(irq);
265 wakeup_check(systime_now());
266 #ifndef CONFIG_ONESHOT_TIMER
268 systime_set_timer(kernel_timeslice);
270 dispatch(schedule());
272 printf("%s: %d\n", __func__, irq);
273 platform_acknowledge_irq(irq);
274 send_user_interrupt(irq);
275 panic("Unhandled IRQ %"PRIu32"\n", irq);
280 #define STACK_DUMP_LIMIT 32
282 /* For unhandled faults, we print a register dump and panic. */
283 void fatal_kernel_fault(lvaddr_t epc, uint64_t spsr, uint64_t esr,
284 uint64_t vector, arch_registers_state_t* save_area)
287 enum aarch64_exception_class exception_class = FIELD(26,6,esr);
288 /* int instruction_length = FIELD(25,1,esr); */
289 int iss = FIELD(0,25,esr);
291 /* Save the FPU registers */
293 " stp q0, q1, [%x0, #0]\n\t"
294 " stp q2, q3, [%x0, #0x20]\n\t"
295 " stp q4, q5, [%x0, #0x40]\n\t"
296 " stp q6, q7, [%x0, #0x60]\n\t"
297 " stp q8, q9, [%x0, #0x80]\n\t"
298 " stp q10, q11, [%x0, #0xa0]\n\t"
299 " stp q12, q13, [%x0, #0xc0]\n\t"
300 " stp q14, q15, [%x0, #0xe0]\n\t"
301 " stp q16, q17, [%x0, #0x100]\n\t"
302 " stp q18, q19, [%x0, #0x120]\n\t"
303 " stp q20, q21, [%x0, #0x140]\n\t"
304 " stp q22, q23, [%x0, #0x160]\n\t"
305 " stp q24, q25, [%x0, #0x180]\n\t"
306 " stp q26, q27, [%x0, #0x1a0]\n\t"
307 " stp q28, q29, [%x0, #0x1c0]\n\t"
308 " stp q30, q31, [%x0, #0x1e0]\n\t"
309 :: "r" (&save_area->named.v));
311 printk(LOG_PANIC, "Fatal (unexpected) fault at 0x%"PRIx64 " (%#" PRIx64 ")\n\n", epc, epc - (uintptr_t)&kernel_first_byte);
312 printk(LOG_PANIC, "Register context saved at: %p\n", save_area);
313 printk(LOG_PANIC, "Vector: ");
315 case AARCH64_EVECTOR_UNDEF:
316 printk(LOG_PANIC, "UNDEF\n");
318 case AARCH64_EVECTOR_EL0_SYNC:
319 printk(LOG_PANIC, "EL0_SYNC\n");
321 case AARCH64_EVECTOR_EL0_IRQ:
322 printk(LOG_PANIC, "EL0_IRQ\n");
324 case AARCH64_EVECTOR_EL0_FIQ:
325 printk(LOG_PANIC, "EL0_FIQ\n");
327 case AARCH64_EVECTOR_EL0_SERROR:
328 printk(LOG_PANIC, "EL0_SERROR\n");
330 case AARCH64_EVECTOR_EL1_SYNC:
331 printk(LOG_PANIC, "EL1_SYNC\n");
333 case AARCH64_EVECTOR_EL1_IRQ:
334 printk(LOG_PANIC, "EL1_IRQ\n");
336 case AARCH64_EVECTOR_EL1_FIQ:
337 printk(LOG_PANIC, "EL1_FIQ\n");
339 case AARCH64_EVECTOR_EL1_SERROR:
340 printk(LOG_PANIC, "EL1_SERROR\n");
342 case AARCH64_EVECTOR_EL2_SYNC:
343 printk(LOG_PANIC, "EL2_SYNC\n");
345 case AARCH64_EVECTOR_EL2_IRQ:
346 printk(LOG_PANIC, "EL2_IRQ\n");
348 case AARCH64_EVECTOR_EL2_FIQ:
349 printk(LOG_PANIC, "EL2_FIQ\n");
351 case AARCH64_EVECTOR_EL2_SERROR:
352 printk(LOG_PANIC, "EL2_SERROR\n");
354 case AARCH32_EVECTOR_EL0_SYNC:
355 printk(LOG_PANIC, "AARCH32_EL0_SYNC\n");
357 case AARCH32_EVECTOR_EL0_IRQ:
358 printk(LOG_PANIC, "AARCH32_EL0_IRQ\n");
360 case AARCH32_EVECTOR_EL0_FIQ:
361 printk(LOG_PANIC, "AARCH32_EL0_FIQ\n");
363 case AARCH32_EVECTOR_EL0_SERROR:
364 printk(LOG_PANIC, "AARCH32_EL0_SERROR\n");
368 for (i = 0; i < 31; i++) {
369 uint64_t reg = save_area->regs[i];
370 if (reg >= (uintptr_t)&kernel_first_byte && reg <= (uintptr_t)&kernel_text_final_byte) {
371 printk(LOG_PANIC, "x%d\t%"PRIx64" (%#" PRIx64 ")\n", i, reg, reg - (uintptr_t)&kernel_first_byte);
373 printk(LOG_PANIC, "x%d\t%"PRIx64"\n", i, reg);
377 printk(LOG_PANIC, "sp\t%"PRIx64"\n", save_area->regs[SP_REG]);
378 printk(LOG_PANIC, "pc\t%"PRIx64"\n", epc);
379 printk(LOG_PANIC, "spsr\t%"PRIx64"\n", spsr);
380 printk(LOG_PANIC, "instruction-specific syndrome\t%x\n", iss);
382 /* Skip the trap frame to dump the prior stack. */
383 uint64_t *kstack_base= (void *)save_area + (NUM_REGS * 8);
385 if((((uintptr_t)kstack_base) & MASK(3)) != 0) {
386 kstack_base= (uint64_t *)((uint64_t)kstack_base & ~MASK(3));
388 "Kernel stack is misaligned, dumping from %p\n",
392 uint64_t kstack_len =
393 (((uint64_t)kernel_stack + KERNEL_STACK_SIZE) -
394 (uint64_t)kstack_base) /
398 "Kernel stack (0x%p - 0x%p):\n",
400 (void *)kernel_stack + KERNEL_STACK_SIZE);
402 for(i= 0; i < kstack_len-2; i+=2) {
403 if(i > STACK_DUMP_LIMIT) {
404 printk(LOG_PANIC, "...\n");
409 "%016"PRIx64" %016"PRIx64" %016"PRIx64"\n",
410 (uint64_t)(kstack_base + i),
415 switch(exception_class) {
416 case aarch64_ec_unknown:
417 panic("Unknown reason/instruction.\n");
420 panic("Trapped WFI/WFI.\n");
422 case aarch64_ec_mcr_cp15:
423 case aarch64_ec_mcrr_cp15:
424 panic("CP15 abort.\n");
426 case aarch64_ec_mcr_cp14:
427 case aarch64_ec_ldc_cp14:
428 case aarch64_ec_mcrr_cp14:
429 panic("CP14 abort.\n");
431 case aarch64_ec_fpen:
432 case aarch64_ec_fpu_aa32:
433 case aarch64_ec_fpu_aa64:
434 panic("FPU abort.\n");
436 case aarch64_ec_mcr_cp10:
437 panic("CP10 abort.\n");
440 panic("PSTATE.IL == 1.\n");
442 case aarch64_ec_svc_aa32:
443 case aarch64_ec_hvc_aa32:
444 case aarch64_ec_svc_aa64:
445 case aarch64_ec_hvc_aa64:
446 case aarch64_ec_smc_aa64:
447 panic("Unhandled system/hypervisor/monitor call.\n");
450 panic("Exception caused by MSR/MRS.\n");
452 case aarch64_ec_impl:
453 panic("Implementation-specific exception.\n");
455 case aarch64_ec_iabt_low:
456 panic("Instruction abort at user level.\n");
458 case aarch64_ec_iabt_high:
459 panic("Instruction abort in the kernel.\n");
461 case aarch64_ec_pc_align:
462 panic("Misaligned PC @0x%"PRIx64".\n",
465 case aarch64_ec_dabt_low:
466 panic("Data abort at user level @0x%"PRIx64".\n",
469 case aarch64_ec_dabt_high:
471 "Data abort in the kernel @0x%"PRIx64".\n",
473 printk(LOG_PANIC, "Abort type: ");
475 case aarch64_dsfc_size_l0:
476 printk(LOG_PANIC, "address size fault, L0/TTBR\n");
478 case aarch64_dsfc_size_l1:
479 printk(LOG_PANIC, "address size fault, L1\n");
481 case aarch64_dsfc_size_l2:
482 printk(LOG_PANIC, "address size fault, L2\n");
484 case aarch64_dsfc_size_l3:
485 printk(LOG_PANIC, "address size fault, L3\n");
487 case aarch64_dsfc_trans_l0:
488 printk(LOG_PANIC, "translation fault, L0/TTBR\n");
490 case aarch64_dsfc_trans_l1:
491 printk(LOG_PANIC, "translation fault, L1\n");
493 case aarch64_dsfc_trans_l2:
494 printk(LOG_PANIC, "translation fault, L2\n");
496 case aarch64_dsfc_trans_l3:
497 printk(LOG_PANIC, "translation fault, L3\n");
499 case aarch64_dsfc_flag_l1:
500 printk(LOG_PANIC, "access flag fault, L1\n");
502 case aarch64_dsfc_flag_l2:
503 printk(LOG_PANIC, "access flag fault, L2\n");
505 case aarch64_dsfc_flag_l3:
506 printk(LOG_PANIC, "access flag fault, L3\n");
508 case aarch64_dsfc_perm_l1:
509 printk(LOG_PANIC, "permission fault, L1\n");
511 case aarch64_dsfc_perm_l2:
512 printk(LOG_PANIC, "permission fault, L2\n");
514 case aarch64_dsfc_perm_l3:
515 printk(LOG_PANIC, "permission fault, L3\n");
517 case aarch64_dsfc_external:
518 printk(LOG_PANIC, "external abort\n");
520 case aarch64_dsfc_external_l0:
521 printk(LOG_PANIC, "external abort on walk, L0/TTBR\n");
523 case aarch64_dsfc_external_l1:
524 printk(LOG_PANIC, "external abort on walk, L1\n");
526 case aarch64_dsfc_external_l2:
527 printk(LOG_PANIC, "external abort on walk, L2\n");
529 case aarch64_dsfc_external_l3:
530 printk(LOG_PANIC, "external abort on walk, L3\n");
532 case aarch64_dsfc_parity:
533 printk(LOG_PANIC, "parity error\n");
535 case aarch64_dsfc_parity_l0:
536 printk(LOG_PANIC, "parity error on walk, L0/TTBR\n");
538 case aarch64_dsfc_parity_l1:
539 printk(LOG_PANIC, "parity error on walk, L1\n");
541 case aarch64_dsfc_parity_l2:
542 printk(LOG_PANIC, "parity error on walk, L2\n");
544 case aarch64_dsfc_parity_l3:
545 printk(LOG_PANIC, "parity error on walk, L3\n");
547 case aarch64_dsfc_alighment:
548 printk(LOG_PANIC, "alignment fault\n");
550 case aarch64_dsfc_tlb_confl:
551 printk(LOG_PANIC, "TLB conflict\n");
553 case aarch64_dsfc_impl1:
554 printk(LOG_PANIC, "implementation-defined fault 1\n");
556 case aarch64_dsfc_impl2:
557 printk(LOG_PANIC, "implementation-defined fault 2\n");
559 case aarch64_dsfc_sect_dom:
560 printk(LOG_PANIC, "domain fault on section\n");
562 case aarch64_dsfc_page_dom:
563 printk(LOG_PANIC, "domain fault on page\n");
566 printk(LOG_PANIC, "unknown\n");
571 case aarch64_ec_sp_align:
572 panic("Misaligned SP.\n");
574 case aarch64_ec_serror:
575 panic("Delayed memory abort.\n");
577 case aarch64_ec_bkpt_low:
578 panic("HW Breakpoint in user code.\n");
580 case aarch64_ec_bkpt_high:
581 panic("HW Breakpoint in the kernel.\n");
583 case aarch64_ec_step_low:
584 panic("Single step in user code.\n");
586 case aarch64_ec_step_high:
587 panic("Single step in the kernel.\n");
589 case aarch64_ec_wpt_low:
590 panic("HW Watchpoint in user code @0x%"PRIx64".\n",
593 case aarch64_ec_wpt_high:
594 panic("HW Watchpoint in the kernel @0x%"PRIx64".\n",
597 case aarch64_ec_bkpt_soft:
598 panic("AArch32 soft breakpoint.\n");
600 case aarch64_ec_bkpt_el2:
601 panic("AArch32 Breakpoint trapped to EL2.\n");
604 panic("AArch64 soft breakpoint.\n");
607 panic("Unrecognised exception.\n");