Fix single step for traps
v2 cover Fix single step for traps
When single stepping a trapped/emulated instruction, the instruction not being actually executed, the PE ends up single stepping the instruction we return to after ERET-ing from the trap.
First patch is just to avoid raw values when using single stepping registers/bits.
Patches 2 fixes the issue for the kernel.
Changes since v1:
* Rename arm64_skip_trapped_instr to arm64_setup_next_instr
* Add defines for AARCH32 and Thumb instruction sizes
* Drop previous KVM patch, Alex Benn?e has a better approach
Cheers,
Julien Thierry
Julien Thierry (2):
arm64: Use existing defines for mdscr
arm64: Fix single stepping in kernel traps
arch/arm64/include/asm/assembler.h | 5 +++-- arch/arm64/include/asm/insn.h | 5 +++++ arch/arm64/include/asm/traps.h | 6 ++++++ arch/arm64/kernel/armv8_deprecated.c | 8 ++++---- arch/arm64/kernel/cpufeature.c | 2 +- arch/arm64/kernel/traps.c | 21 ++++++++++++++++----- 6 files changed, 35 insertions(+), 12 deletions(-)
--
1.9.1
PATCH v2 1/2 arm64: Use existing defines for mdscr
--- arch/arm64/include/asm/assembler.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
arch/arm64/include/asm/assembler.h +3 -2
@@ -30,6 +30,7 @@#include <asm/pgtable-hwdef.h> #include <asm/ptrace.h> #include <asm/thread_info.h> +#include <asm/debug-monitors.h> /* * Enable and disable interrupts.
@@ -65,7 +66,7 @@ .macro disable_step_tsk, flgs, tmp tbz \flgs, #TIF_SINGLESTEP, 9990f mrs \tmp, mdscr_el1 - bic \tmp, \tmp, #1 + bic \tmp, \tmp, #DBG_MDSCR_SS msr mdscr_el1, \tmp isb// Synchronise with enable_dbg 9990:
@@ -75,7 +76,7 @@ tbz \flgs, #TIF_SINGLESTEP, 9990fdisable_dbg mrs \tmp, mdscr_el1 - orr \tmp, \tmp, #1 + orr \tmp, \tmp, #DBG_MDSCR_SS msr mdscr_el1, \tmp 9990: .endm
--
1.9.1
Mark Rutland
reviewerPATCH v2 1/2 arm64: Use existing defines for mdscr
Hi,
Quoted 14 lines · Julien Thierry
Signed-off-by Julien Thierry <[email protected]>Reviewed-by Alex Benn?e <[email protected]>Cc Catalin Marinas <[email protected]>Cc Will Deacon <[email protected]>Cc Mark Rutland <[email protected]>--- arch/arm64/include/asm/assembler.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)arch/arm64/include/asm/assembler.h +0
-0
arch/arm64/include/asm/assembler.h line 33
Quoted 4 lines
arch/arm64/include/asm/assembler.h +1
-0@@ -30,6 +30,7 @@#include <asm/pgtable-hwdef.h> #include <asm/ptrace.h> #include <asm/thread_info.h> +#include <asm/debug-monitors.h>
Nit: please keep these ordered alphabetically.
Otherwise, this is much nicer! FWIW:
Thanks,
Mark.
Quoted 23 lines
arch/arm64/include/asm/assembler.h +2
-3/* * Enable and disable interrupts. @@ -65,7 +66,7 @@ .macro disable_step_tsk, flgs, tmp tbz \flgs, #TIF_SINGLESTEP, 9990f mrs \tmp, mdscr_el1 - bic \tmp, \tmp, #1 + bic \tmp, \tmp, #DBG_MDSCR_SS msr mdscr_el1, \tmp isb// Synchronise with enable_dbg 9990:@@ -75,7 +76,7 @@ tbz \flgs, #TIF_SINGLESTEP, 9990fdisable_dbg mrs \tmp, mdscr_el1 - orr \tmp, \tmp, #1 + orr \tmp, \tmp, #DBG_MDSCR_SS msr mdscr_el1, \tmp 9990: .endm --1.9.1
PATCH v2 2/2 arm64: Fix single stepping in kernel traps
In reply to Julien ThierrySoftware Step exception is missing after stepping a trapped instruction.
Ensure SPSR.SS gets set to 0 after emulating/skipping a trapped instruction before doing ERET.
--- arch/arm64/include/asm/insn.h | 5 +++++ arch/arm64/include/asm/traps.h | 6 ++++++ arch/arm64/kernel/armv8_deprecated.c | 8 ++++---- arch/arm64/kernel/cpufeature.c | 2 +- arch/arm64/kernel/traps.c | 21 ++++++++++++++++----- 5 files changed, 32 insertions(+), 10 deletions(-)
arch/arm64/include/asm/insn.h +5 -0
@@ -22,6 +22,11 @@/* A64 instructions are always 32 bits. */ #define AARCH64_INSN_SIZE 4 +#define AARCH32_INSN_SIZE 4 + +/* Thumb/Thumb2 instruction sizes */ +#define AARCH32_T32_INSN_SIZE 4 +#define AARCH32_T16_INSN_SIZE 2#ifndef __ASSEMBLY__/*
arch/arm64/include/asm/traps.h +6 -0
@@ -37,6 +37,12 @@ struct undef_hook {void arm64_notify_segfault (struct pt_regs *regs,unsigned long addr); +/* +* Move regs->pc to next instruction and do necessary setup before it +* is executed. +*/ +void arm64_setup_next_instr (struct pt_regs *regs,unsigned long size); +static inline int __in_irqentry_text (unsigned long ptr) { return ptr >= (unsigned long)&__irqentry_text_start &&
arch/arm64/kernel/armv8_deprecated.c +4 -4
@@ -431,7 +431,7 @@ static int swp_handler(struct pt_regs *regs, u32 instr)pr_warn_ratelimited ("\"%s\" (%ld) uses obsolete SWP{B} instruction at 0x%llx\n" , current->comm, (unsigned long )current->pid, regs->pc); - regs->pc +=4 ; +arm64_setup_next_instr (regs,AARCH32_INSN_SIZE );return 0 ; fault:
@@ -512,7 +512,7 @@ static int cp15barrier_handler(struct pt_regs *regs, u32 instr)pr_warn_ratelimited ("\"%s\" (%ld) uses deprecated CP15 Barrier instruction at 0x%llx\n" , current->comm, (unsigned long )current->pid, regs->pc); - regs->pc +=4 ; +arm64_setup_next_instr (regs,AARCH32_INSN_SIZE );return 0 ; }
@@ -586,14 +586,14 @@ static int compat_setend_handler(struct pt_regs *regs, u32 big_endian)static int a32_setend_handler (struct pt_regs *regs,u32 instr) {int rc =compat_setend_handler (regs, (instr >>9 ) &1 ); - regs->pc +=4 ; +arm64_setup_next_instr (regs,AARCH32_INSN_SIZE );return rc; }static int t16_setend_handler (struct pt_regs *regs,u32 instr) {int rc =compat_setend_handler (regs, (instr >>3 ) &1 ); - regs->pc +=2 ; +arm64_setup_next_instr (regs,AARCH32_T16_INSN_SIZE );return rc; }
arch/arm64/kernel/cpufeature.c +1 -1
@@ -1287,7 +1287,7 @@ static int emulate_mrs(struct pt_regs *regs, u32 insn)if (!rc) { dst =aarch64_insn_decode_register (AARCH64_INSN_REGTYPE_RT , insn);pt_regs_write_reg (regs, dst, val); - regs->pc +=4 ; +arm64_setup_next_instr (regs,AARCH64_INSN_SIZE ); }return rc;
arch/arm64/kernel/traps.c +16 -5
@@ -293,6 +293,17 @@ void arm64_notify_die(const char *str, struct pt_regs *regs, } } +void arm64_setup_next_instr (struct pt_regs *regs,unsigned long size) +{ + regs->pc += size; + +/* +* If we were single stepping, we want to get the step exception after +* we return from the trap. +*/ + regs->pstate &= ~DBG_SPSR_SS ; +} +static LIST_HEAD (undef_hook);static DEFINE_RAW_SPINLOCK (undef_lock);
@@ -480,7 +491,7 @@ static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs)if (ret)arm64_notify_segfault (regs, address);else - regs->pc +=4 ; +arm64_setup_next_instr (regs,AARCH64_INSN_SIZE ); }static void ctr_read_handler (unsigned int esr,struct pt_regs *regs)
@@ -490,7 +501,7 @@ static void ctr_read_handler(unsigned int esr, struct pt_regs *regs)pt_regs_write_reg (regs, rt, val); - regs->pc +=4 ; +arm64_setup_next_instr (regs,AARCH64_INSN_SIZE ); }static void cntvct_read_handler (unsigned int esr,struct pt_regs *regs)
@@ -498,7 +509,7 @@ static void cntvct_read_handler(unsigned int esr, struct pt_regs *regs)int rt = (esr & ESR_ELx_SYS64_ISS_RT_MASK) >> ESR_ELx_SYS64_ISS_RT_SHIFT;pt_regs_write_reg (regs, rt,arch_counter_get_cntvct ()); - regs->pc +=4 ; +arm64_setup_next_instr (regs,AARCH64_INSN_SIZE ); }static void cntfrq_read_handler (unsigned int esr,struct pt_regs *regs)
@@ -506,7 +517,7 @@ static void cntfrq_read_handler(unsigned int esr, struct pt_regs *regs)int rt = (esr & ESR_ELx_SYS64_ISS_RT_MASK) >> ESR_ELx_SYS64_ISS_RT_SHIFT;pt_regs_write_reg (regs, rt,arch_timer_get_rate ()); - regs->pc +=4 ; +arm64_setup_next_instr (regs,AARCH64_INSN_SIZE ); }struct sys64_hook {
@@ -761,7 +772,7 @@ static int bug_handler(struct pt_regs *regs, unsigned int esr) }/* If thread survives, skip over the BUG instruction and continue: */ - regs->pc +=AARCH64_INSN_SIZE ;/* skip BRK and resume */ +arm64_setup_next_instr (regs,AARCH64_INSN_SIZE );return DBG_HOOK_HANDLED ; }
--
1.9.1
PATCH v2 2/2 arm64: Fix single stepping in kernel traps
Quoted 18 lines · Julien Thierry
Software Step exception is missing after stepping a trapped instruction.
Ensure SPSR.SS gets set to 0 after emulating/skipping a trapped instruction before doing ERET.
Signed-off-by Julien Thierry <[email protected]>Reviewed-by Alex Benn?e <[email protected]>Cc Catalin Marinas <[email protected]>Cc Will Deacon <[email protected]>Cc Mark Rutland <[email protected]>--- arch/arm64/include/asm/insn.h | 5 +++++ arch/arm64/include/asm/traps.h | 6 ++++++ arch/arm64/kernel/armv8_deprecated.c | 8 ++++---- arch/arm64/kernel/cpufeature.c | 2 +- arch/arm64/kernel/traps.c | 21 ++++++++++++++++----- 5 files changed, 32 insertions(+), 10 deletions(-)
[...]
Quoted 7 lines
arch/arm64/kernel/traps.c +0
-0@@ -293,6 +293,17 @@ void arm64_notify_die(const char *str, struct pt_regs *regs, } }
arch/arm64/kernel/traps.c void arm64_notify_die(const char *str, struct pt_regs *regs, · line 304
Quoted 10 lines
arch/arm64/kernel/traps.c +9
-0+void arm64_setup_next_instr (struct pt_regs *regs,unsigned long size) +{ + regs->pc += size; + +/* +* If we were single stepping, we want to get the step exception after +* we return from the trap. +*/ + regs->pstate &= ~DBG_SPSR_SS ;
Can you use user_fastforward_single_step instead, like we do for the signal handling path?
Will
PATCH v2 2/2 arm64: Fix single stepping in kernel traps
Quoted 30 lines · Will Deacon
Quoted 18 lines · Julien Thierry
Software Step exception is missing after stepping a trapped instruction.
Ensure SPSR.SS gets set to 0 after emulating/skipping a trapped instruction before doing ERET.
Signed-off-by Julien Thierry <[email protected]>Reviewed-by Alex Benn?e <[email protected]>Cc Catalin Marinas <[email protected]>Cc Will Deacon <[email protected]>Cc Mark Rutland <[email protected]>--- arch/arm64/include/asm/insn.h | 5 +++++ arch/arm64/include/asm/traps.h | 6 ++++++ arch/arm64/kernel/armv8_deprecated.c | 8 ++++---- arch/arm64/kernel/cpufeature.c | 2 +- arch/arm64/kernel/traps.c | 21 ++++++++++++++++----- 5 files changed, 32 insertions(+), 10 deletions(-)[...]
Quoted 8 lines
arch/arm64/kernel/traps.c +0
-0@@ -293,6 +293,17 @@ void arm64_notify_die(const char *str, struct pt_regs *regs, } }
Quoted 12 lines
arch/arm64/kernel/traps.c void arm64_notify_die(const char *str, struct pt_regs *regs, · line 304
Quoted 9 lines
arch/arm64/kernel/traps.c +9
-0+void arm64_setup_next_instr (struct pt_regs *regs,unsigned long size) +{ + regs->pc += size; + +/* +* If we were single stepping, we want to get the step exception after +* we return from the trap. +*/ + regs->pstate &= ~DBG_SPSR_SS ;Can you use
user_fastforward_single_stepinstead, like we do for the signal handling path?
I guess we are always fast forwarding on the current task. So yes, I can use that.
Thanks,
Signature · 1 line
Julien Thierry