After entering kgdb mode, 'stepi' may unexpectedly breaks the execution
somewhere in el1_irq.

This happens because a debug exception is always enabled in el1_irq
due to the following commit merged in v3.16:
  commit 2a2830703a23 ("arm64: debug: avoid accessing mdscr_el1 on fault
                        paths where possible")
A pending interrupt can be taken after kgdb has enabled a software step,
but before a debug exception is actually taken.

This patch enforces interrupts to be masked while single stepping.

Signed-off-by: AKASHI Takahiro <takahiro.aka...@linaro.org>
Cc: Catalin Marinas <catalin.mari...@arm.com>
Cc: Will Deacon <will.dea...@arm.com>
Cc: Jason Wessel <jason.wes...@windriver.com>
Cc: <sta...@vger.kernel.org> # 3.16-
---
 arch/arm64/kernel/kgdb.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/arm64/kernel/kgdb.c b/arch/arm64/kernel/kgdb.c
index 59c4aec..6732a27 100644
--- a/arch/arm64/kernel/kgdb.c
+++ b/arch/arm64/kernel/kgdb.c
@@ -26,6 +26,7 @@
 #include <linux/kgdb.h>
 #include <linux/kprobes.h>
 #include <linux/percpu.h>
+#include <asm/ptrace.h>
 #include <asm/traps.h>
 
 struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
@@ -109,6 +110,7 @@ struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
        { "fpcr", 4, -1 },
 };
 
+static DEFINE_PER_CPU(unsigned int, kgdb_pstate);
 static DEFINE_PER_CPU(struct irq_work, kgdb_irq_work);
 
 char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
@@ -198,6 +200,10 @@ int kgdb_arch_handle_exception(int exception_vector, int 
signo,
                err = 0;
                break;
        case 's':
+               /* mask interrupts while single stepping */
+               __this_cpu_write(kgdb_pstate, linux_regs->pstate);
+               linux_regs->pstate |= PSR_I_BIT;
+
                /*
                 * Update step address value with address passed
                 * with step packet.
@@ -239,9 +245,18 @@ NOKPROBE_SYMBOL(kgdb_compiled_brk_fn);
 
 static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned int esr)
 {
+       unsigned int pstate;
+
        kernel_disable_single_step();
        atomic_set(&kgdb_cpu_doing_single_step, -1);
 
+       /* restore interrupt mask status */
+       pstate = __this_cpu_read(kgdb_pstate);
+       if (pstate & PSR_I_BIT)
+               regs->pstate |= PSR_I_BIT;
+       else
+               regs->pstate &= ~PSR_I_BIT;
+
        kgdb_handle_exception(1, SIGTRAP, 0, regs);
        return 0;
 }
-- 
2.10.0


------------------------------------------------------------------------------
_______________________________________________
Kgdb-bugreport mailing list
Kgdb-bugreport@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kgdb-bugreport

Reply via email to