]> rtime.felk.cvut.cz Git - jailhouse.git/commitdiff
arm: better error reporting and panic dump
authorJean-Philippe Brucker <jean-philippe.brucker@arm.com>
Wed, 2 Jul 2014 11:44:43 +0000 (12:44 +0100)
committerJan Kiszka <jan.kiszka@siemens.com>
Fri, 19 Dec 2014 10:04:07 +0000 (11:04 +0100)
This patch adds exhaustive handling of hypervisor errors, and the
ability to stop and park CPUs after dumping their EL1 context, when they
encounter an unhandled trap.

Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
[Jan: Adjustments to recent control subsystem changes]
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
hypervisor/arch/arm/control.c
hypervisor/arch/arm/exception.S
hypervisor/arch/arm/include/asm/processor.h
hypervisor/arch/arm/include/asm/sysregs.h
hypervisor/arch/arm/setup.c
hypervisor/arch/arm/traps.c

index 27af483059413d5d7718f47256909a6c58032298..2bb1ae640f6b5fdae9ebaf81c487ccea8ca64aac 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <jailhouse/control.h>
 #include <jailhouse/printk.h>
+#include <jailhouse/processor.h>
 #include <jailhouse/string.h>
 #include <asm/control.h>
 #include <asm/irqchip.h>
@@ -139,6 +140,28 @@ static void arch_suspend_self(struct per_cpu *cpu_data)
                arch_cpu_tlb_flush(cpu_data);
 }
 
+static void arch_dump_exit(const char *reason)
+{
+       unsigned long pc;
+
+       arm_read_banked_reg(ELR_hyp, pc);
+       printk("Unhandled HYP %s exit at 0x%x\n", reason, pc);
+}
+
+static void arch_dump_abt(bool is_data)
+{
+       u32 hxfar;
+       u32 esr;
+
+       arm_read_sysreg(ESR_EL2, esr);
+       if (is_data)
+               arm_read_sysreg(HDFAR, hxfar);
+       else
+               arm_read_sysreg(HIFAR, hxfar);
+
+       printk("  paddr=0x%lx esr=0x%x\n", hxfar, esr);
+}
+
 struct registers* arch_handle_exit(struct per_cpu *cpu_data,
                                   struct registers *regs)
 {
@@ -149,10 +172,27 @@ struct registers* arch_handle_exit(struct per_cpu *cpu_data,
        case EXIT_REASON_TRAP:
                arch_handle_trap(cpu_data, regs);
                break;
+
+       case EXIT_REASON_UNDEF:
+               arch_dump_exit("undef");
+               panic_stop();
+       case EXIT_REASON_DABT:
+               arch_dump_exit("data abort");
+               arch_dump_abt(true);
+               panic_stop();
+       case EXIT_REASON_PABT:
+               arch_dump_exit("prefetch abort");
+               arch_dump_abt(false);
+               panic_stop();
+       case EXIT_REASON_HVC:
+               arch_dump_exit("hvc");
+               panic_stop();
+       case EXIT_REASON_FIQ:
+               arch_dump_exit("fiq");
+               panic_stop();
        default:
-               printk("Internal error: %d exit not implemented\n",
-                               regs->exit_reason);
-               while(1);
+               arch_dump_exit("unknown");
+               panic_stop();
        }
 
        return regs;
@@ -260,3 +300,19 @@ void arch_flush_cell_vcpu_caches(struct cell *cell)
 void arch_config_commit(struct cell *cell_added_removed)
 {
 }
+
+void arch_panic_stop(void)
+{
+       psci_cpu_off(this_cpu_data());
+       __builtin_unreachable();
+}
+
+void arch_panic_park(void)
+{
+       /* Won't return to panic_park */
+       if (phys_processor_id() == panic_cpu)
+               panic_in_progress = 0;
+
+       psci_cpu_off(this_cpu_data());
+       __builtin_unreachable();
+}
index 6190098753a233174037320b9284ad2a37aa8707..ede7a132a42522f26828270dfe527e783f4e8bb4 100644 (file)
        .align 5
 hyp_vectors:
        b       .
-       b       .
-       b       .
-       b       .
-       b       .
+       b       hyp_undef
+       b       hyp_hvc
+       b       hyp_pabt
+       b       hyp_dabt
        b       hyp_trap
        b       hyp_irq
-       b       .
+       b       hyp_fiq
 
 .macro handle_vmexit exit_reason
        /* Fill the struct registers. Should comply with NUM_USR_REGS */
@@ -34,8 +34,19 @@ hyp_vectors:
        b       vmexit_common
 .endm
 
+hyp_undef:
+       handle_vmexit EXIT_REASON_UNDEF
+hyp_hvc:
+       handle_vmexit EXIT_REASON_HVC
+hyp_pabt:
+       handle_vmexit EXIT_REASON_PABT
+hyp_dabt:
+       handle_vmexit EXIT_REASON_DABT
+
 hyp_irq:
        handle_vmexit EXIT_REASON_IRQ
+hyp_fiq:
+       handle_vmexit EXIT_REASON_FIQ
 hyp_trap:
        handle_vmexit EXIT_REASON_TRAP
 
index 0dbd4dfaa42a8c2984065333d16dd477f6200471..049a838a44f2b376d8e172f5c3b5db7c0471d25e 100644 (file)
 #define ESR_ICC_CV_BIT         (1 << 24)
 #define ESR_ICC_COND(icc)      ((icc) >> 20 & 0xf)
 
-#define EXIT_REASON_TRAP       0x1
-#define EXIT_REASON_IRQ                0x2
+#define EXIT_REASON_UNDEF      0x1
+#define EXIT_REASON_HVC                0x2
+#define EXIT_REASON_PABT       0x3
+#define EXIT_REASON_DABT       0x4
+#define EXIT_REASON_TRAP       0x5
+#define EXIT_REASON_IRQ                0x6
+#define EXIT_REASON_FIQ                0x7
 
 #define NUM_USR_REGS           14
 
index 1f9abeb4881771360c7028724d9976fe1079182c..47607561f84b2e807c16089a54a2d1d5aba51410 100644 (file)
@@ -69,6 +69,9 @@
 #define VBAR           SYSREG_32(0, c12, c0, 0)
 #define HCR            SYSREG_32(4, c1, c1, 0)
 #define HCR2           SYSREG_32(4, c1, c1, 4)
+#define HDFAR          SYSREG_32(4, c6, c0, 0)
+#define HIFAR          SYSREG_32(4, c6, c0, 2)
+#define HPFAR          SYSREG_32(4, c6, c0, 4)
 #define HMAIR0         SYSREG_32(4, c10, c2, 0)
 #define HMAIR1         SYSREG_32(4, c10, c2, 1)
 #define HVBAR          SYSREG_32(4, c12, c0, 0)
index ef408a8afbd9a5642a472dbf04a33260f1714e70..120d82f0547d41beb0d5906fc0ec20ab8c29a364 100644 (file)
@@ -121,5 +121,3 @@ void arch_cpu_restore(struct per_cpu *cpu_data)
 // catch missing symbols
 void arch_shutdown_cpu(unsigned int cpu_id) {}
 void arch_shutdown(void) {}
-void arch_panic_stop(void) {__builtin_unreachable();}
-void arch_panic_park(void) {}
index 8dc5ab57bbb445081fdda2d5429e60fda20acac0..6c8e788e82e7889011d11d45e276616121796120 100644 (file)
@@ -188,6 +188,22 @@ static void access_cell_reg(struct trap_context *ctx, u8 reg,
        }
 }
 
+static void dump_guest_regs(struct per_cpu *cpu_data, struct trap_context *ctx)
+{
+       u8 reg;
+       unsigned long reg_val;
+
+       panic_printk("pc=0x%08x cpsr=0x%08x esr=0x%08x\n", ctx->pc, ctx->cpsr,
+                       ctx->esr);
+       for (reg = 0; reg < 15; reg++) {
+               access_cell_reg(ctx, reg, &reg_val, true);
+               panic_printk("r%d=0x%08x ", reg, reg_val);
+               if ((reg + 1) % 4 == 0)
+                       panic_printk("\n");
+       }
+       panic_printk("\n");
+}
+
 static int arch_handle_hvc(struct per_cpu *cpu_data, struct trap_context *ctx)
 {
        unsigned long *regs = ctx->regs;
@@ -257,10 +273,14 @@ void arch_handle_trap(struct per_cpu *cpu_data, struct registers *guest_regs)
        if (trap_handlers[exception_class])
                ret = trap_handlers[exception_class](cpu_data, &ctx);
 
-       if (ret != TRAP_HANDLED) {
-               panic_printk("CPU%d: Unhandled HYP trap, syndrome 0x%x\n",
-                               cpu_data->cpu_id, ctx.esr);
-               while(1);
+       switch (ret) {
+       case TRAP_UNHANDLED:
+       case TRAP_FORBIDDEN:
+               panic_printk("FATAL: %s on CPU%d\n", (ret == TRAP_UNHANDLED ?
+                               "unhandled trap" : "forbidden access"),
+                               cpu_data->cpu_id);
+               dump_guest_regs(cpu_data, &ctx);
+               panic_park();
        }
 
 restore_context: