* [PATCH v4 0/2] arm64: Fix pending single-step debugging issues @ 2022-12-15 14:29 Sumit Garg 2022-12-15 14:29 ` [PATCH v4 1/2] arm64: entry: Skip single stepping into interrupt handlers Sumit Garg 2022-12-15 14:29 ` [PATCH v4 2/2] arm64: kgdb: Set PSTATE.SS to 1 to re-enable single-step Sumit Garg 0 siblings, 2 replies; 5+ messages in thread From: Sumit Garg @ 2022-12-15 14:29 UTC (permalink / raw) To: will, catalin.marinas, daniel.thompson, dianders Cc: liwei391, mark.rutland, mhiramat, maz, linux-arm-kernel, linux-kernel, Sumit Garg This patch-set reworks pending fixes from Wei's series [1] to make single-step debugging via kgdb/kdb on arm64 work as expected. There was a prior discussion on ML [2] regarding if we should keep the interrupts enabled during single-stepping. So patch #1 follows suggestion from Will [3] to not disable interrupts during single stepping but rather skip single stepping within interrupt handler. [1] https://lore.kernel.org/all/20200509214159.19680-1-liwei391@huawei.com/ [2] https://lore.kernel.org/all/CAD=FV=Voyfq3Qz0T3RY+aYWYJ0utdH=P_AweB=13rcV8GDBeyQ@mail.gmail.com/ [3] https://lore.kernel.org/all/20200626095551.GA9312@willie-the-truck/ Changes in v4: - Rebased to the tip of mainline. - Picked up Doug's Tested-by tag. Changes in v3: - Reword commit descriptions as per Daniel's suggestions. Changes in v2: - Replace patch #1 to rather follow Will's suggestion. Sumit Garg (2): arm64: entry: Skip single stepping into interrupt handlers arm64: kgdb: Set PSTATE.SS to 1 to re-enable single-step arch/arm64/include/asm/debug-monitors.h | 1 + arch/arm64/kernel/debug-monitors.c | 5 +++++ arch/arm64/kernel/entry-common.c | 18 +++++++++++++++++- arch/arm64/kernel/kgdb.c | 2 ++ 4 files changed, 25 insertions(+), 1 deletion(-) -- 2.34.1 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v4 1/2] arm64: entry: Skip single stepping into interrupt handlers 2022-12-15 14:29 [PATCH v4 0/2] arm64: Fix pending single-step debugging issues Sumit Garg @ 2022-12-15 14:29 ` Sumit Garg 2022-12-16 16:44 ` Mark Rutland 2022-12-15 14:29 ` [PATCH v4 2/2] arm64: kgdb: Set PSTATE.SS to 1 to re-enable single-step Sumit Garg 1 sibling, 1 reply; 5+ messages in thread From: Sumit Garg @ 2022-12-15 14:29 UTC (permalink / raw) To: will, catalin.marinas, daniel.thompson, dianders Cc: liwei391, mark.rutland, mhiramat, maz, linux-arm-kernel, linux-kernel, Sumit Garg Currently on systems where the timer interrupt (or any other fast-at-human-scale periodic interrupt) is active then it is impossible to step any code with interrupts unlocked because we will always end up stepping into the timer interrupt instead of stepping the user code. The common user's goal while single stepping is that when they step then the system will stop at PC+4 or PC+I for a branch that gets taken relative to the instruction they are stepping. So, fix broken single step implementation via skipping single stepping into interrupt handlers. The methodology is when we receive an interrupt from EL1, check if we are single stepping (pstate.SS). If yes then we save MDSCR_EL1.SS and clear the register bit if it was set. Then unmask only D and leave I set. On return from the interrupt, set D and restore MDSCR_EL1.SS. Along with this skip reschedule if we were stepping. Suggested-by: Will Deacon <will@kernel.org> Signed-off-by: Sumit Garg <sumit.garg@linaro.org> Tested-by: Douglas Anderson <dianders@chromium.org> --- arch/arm64/kernel/entry-common.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c index cce1167199e3..53bcb1902f2f 100644 --- a/arch/arm64/kernel/entry-common.c +++ b/arch/arm64/kernel/entry-common.c @@ -471,19 +471,35 @@ static __always_inline void __el1_irq(struct pt_regs *regs, do_interrupt_handler(regs, handler); irq_exit_rcu(); - arm64_preempt_schedule_irq(); + /* Don't reschedule in case we are single stepping */ + if (!(regs->pstate & DBG_SPSR_SS)) + arm64_preempt_schedule_irq(); exit_to_kernel_mode(regs); } + static void noinstr el1_interrupt(struct pt_regs *regs, void (*handler)(struct pt_regs *)) { + unsigned long reg; + + /* Disable single stepping within interrupt handler */ + if (regs->pstate & DBG_SPSR_SS) { + reg = read_sysreg(mdscr_el1); + write_sysreg(reg & ~DBG_MDSCR_SS, mdscr_el1); + } + write_sysreg(DAIF_PROCCTX_NOIRQ, daif); if (IS_ENABLED(CONFIG_ARM64_PSEUDO_NMI) && !interrupts_enabled(regs)) __el1_pnmi(regs, handler); else __el1_irq(regs, handler); + + if (regs->pstate & DBG_SPSR_SS) { + write_sysreg(DAIF_PROCCTX_NOIRQ | PSR_D_BIT, daif); + write_sysreg(reg, mdscr_el1); + } } asmlinkage void noinstr el1h_64_irq_handler(struct pt_regs *regs) -- 2.34.1 ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v4 1/2] arm64: entry: Skip single stepping into interrupt handlers 2022-12-15 14:29 ` [PATCH v4 1/2] arm64: entry: Skip single stepping into interrupt handlers Sumit Garg @ 2022-12-16 16:44 ` Mark Rutland 2022-12-19 6:23 ` Sumit Garg 0 siblings, 1 reply; 5+ messages in thread From: Mark Rutland @ 2022-12-16 16:44 UTC (permalink / raw) To: Sumit Garg Cc: will, catalin.marinas, daniel.thompson, dianders, liwei391, mhiramat, maz, linux-arm-kernel, linux-kernel On Thu, Dec 15, 2022 at 07:59:02PM +0530, Sumit Garg wrote: > Currently on systems where the timer interrupt (or any other > fast-at-human-scale periodic interrupt) is active then it is impossible > to step any code with interrupts unlocked because we will always end up > stepping into the timer interrupt instead of stepping the user code. > > The common user's goal while single stepping is that when they step then > the system will stop at PC+4 or PC+I for a branch that gets taken > relative to the instruction they are stepping. So, fix broken single step > implementation via skipping single stepping into interrupt handlers. > > The methodology is when we receive an interrupt from EL1, check if we > are single stepping (pstate.SS). If yes then we save MDSCR_EL1.SS and > clear the register bit if it was set. Then unmask only D and leave I set. > On return from the interrupt, set D and restore MDSCR_EL1.SS. Along with > this skip reschedule if we were stepping. > > Suggested-by: Will Deacon <will@kernel.org> > Signed-off-by: Sumit Garg <sumit.garg@linaro.org> > Tested-by: Douglas Anderson <dianders@chromium.org> FWIW, this looks reasonable to me; I have a couple of minor style/structure comments below. > --- > arch/arm64/kernel/entry-common.c | 18 +++++++++++++++++- > 1 file changed, 17 insertions(+), 1 deletion(-) > > diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c > index cce1167199e3..53bcb1902f2f 100644 > --- a/arch/arm64/kernel/entry-common.c > +++ b/arch/arm64/kernel/entry-common.c > @@ -471,19 +471,35 @@ static __always_inline void __el1_irq(struct pt_regs *regs, > do_interrupt_handler(regs, handler); > irq_exit_rcu(); > > - arm64_preempt_schedule_irq(); > + /* Don't reschedule in case we are single stepping */ > + if (!(regs->pstate & DBG_SPSR_SS)) > + arm64_preempt_schedule_irq(); Please change arm64_preempt_schedule_irq() to take the regs as an argument, and put this test inside arm64_preempt_schedule_irq(). That way all the decision-making about whether to preempt is in one place. That can go immediately after the need_irq_preemption() test. > > exit_to_kernel_mode(regs); > } > + > static void noinstr el1_interrupt(struct pt_regs *regs, > void (*handler)(struct pt_regs *)) > { > + unsigned long reg; Please s/reg/mdscr/. That way it's harder to confuse with 'regs', it's clearer that it's the MDSCR_ELx value, and if we have to save/restore any other registers in future it'll be obvious how to name things. Thanks, Mark. > + > + /* Disable single stepping within interrupt handler */ > + if (regs->pstate & DBG_SPSR_SS) { > + reg = read_sysreg(mdscr_el1); > + write_sysreg(reg & ~DBG_MDSCR_SS, mdscr_el1); > + } > + > write_sysreg(DAIF_PROCCTX_NOIRQ, daif); > > if (IS_ENABLED(CONFIG_ARM64_PSEUDO_NMI) && !interrupts_enabled(regs)) > __el1_pnmi(regs, handler); > else > __el1_irq(regs, handler); > + > + if (regs->pstate & DBG_SPSR_SS) { > + write_sysreg(DAIF_PROCCTX_NOIRQ | PSR_D_BIT, daif); > + write_sysreg(reg, mdscr_el1); > + } > } > > asmlinkage void noinstr el1h_64_irq_handler(struct pt_regs *regs) > -- > 2.34.1 > ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v4 1/2] arm64: entry: Skip single stepping into interrupt handlers 2022-12-16 16:44 ` Mark Rutland @ 2022-12-19 6:23 ` Sumit Garg 0 siblings, 0 replies; 5+ messages in thread From: Sumit Garg @ 2022-12-19 6:23 UTC (permalink / raw) To: Mark Rutland Cc: will, catalin.marinas, daniel.thompson, dianders, liwei391, mhiramat, maz, linux-arm-kernel, linux-kernel On Fri, 16 Dec 2022 at 22:14, Mark Rutland <mark.rutland@arm.com> wrote: > > On Thu, Dec 15, 2022 at 07:59:02PM +0530, Sumit Garg wrote: > > Currently on systems where the timer interrupt (or any other > > fast-at-human-scale periodic interrupt) is active then it is impossible > > to step any code with interrupts unlocked because we will always end up > > stepping into the timer interrupt instead of stepping the user code. > > > > The common user's goal while single stepping is that when they step then > > the system will stop at PC+4 or PC+I for a branch that gets taken > > relative to the instruction they are stepping. So, fix broken single step > > implementation via skipping single stepping into interrupt handlers. > > > > The methodology is when we receive an interrupt from EL1, check if we > > are single stepping (pstate.SS). If yes then we save MDSCR_EL1.SS and > > clear the register bit if it was set. Then unmask only D and leave I set. > > On return from the interrupt, set D and restore MDSCR_EL1.SS. Along with > > this skip reschedule if we were stepping. > > > > Suggested-by: Will Deacon <will@kernel.org> > > Signed-off-by: Sumit Garg <sumit.garg@linaro.org> > > Tested-by: Douglas Anderson <dianders@chromium.org> > > FWIW, this looks reasonable to me; I have a couple of minor style/structure > comments below. Thanks Mark for your review. > > > --- > > arch/arm64/kernel/entry-common.c | 18 +++++++++++++++++- > > 1 file changed, 17 insertions(+), 1 deletion(-) > > > > diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c > > index cce1167199e3..53bcb1902f2f 100644 > > --- a/arch/arm64/kernel/entry-common.c > > +++ b/arch/arm64/kernel/entry-common.c > > @@ -471,19 +471,35 @@ static __always_inline void __el1_irq(struct pt_regs *regs, > > do_interrupt_handler(regs, handler); > > irq_exit_rcu(); > > > > - arm64_preempt_schedule_irq(); > > + /* Don't reschedule in case we are single stepping */ > > + if (!(regs->pstate & DBG_SPSR_SS)) > > + arm64_preempt_schedule_irq(); > > Please change arm64_preempt_schedule_irq() to take the regs as an argument, and > put this test inside arm64_preempt_schedule_irq(). That way all the > decision-making about whether to preempt is in one place. > > That can go immediately after the need_irq_preemption() test. Okay, I will change arm64_preempt_schedule_irq() accordingly. > > > > > exit_to_kernel_mode(regs); > > } > > + > > static void noinstr el1_interrupt(struct pt_regs *regs, > > void (*handler)(struct pt_regs *)) > > { > > + unsigned long reg; > > Please s/reg/mdscr/. That way it's harder to confuse with 'regs', it's clearer > that it's the MDSCR_ELx value, and if we have to save/restore any other > registers in future it'll be obvious how to name things. > Ack. -Sumit > Thanks, > Mark. > > > + > > + /* Disable single stepping within interrupt handler */ > > + if (regs->pstate & DBG_SPSR_SS) { > > + reg = read_sysreg(mdscr_el1); > > + write_sysreg(reg & ~DBG_MDSCR_SS, mdscr_el1); > > + } > > + > > write_sysreg(DAIF_PROCCTX_NOIRQ, daif); > > > > if (IS_ENABLED(CONFIG_ARM64_PSEUDO_NMI) && !interrupts_enabled(regs)) > > __el1_pnmi(regs, handler); > > else > > __el1_irq(regs, handler); > > + > > + if (regs->pstate & DBG_SPSR_SS) { > > + write_sysreg(DAIF_PROCCTX_NOIRQ | PSR_D_BIT, daif); > > + write_sysreg(reg, mdscr_el1); > > + } > > } > > > > asmlinkage void noinstr el1h_64_irq_handler(struct pt_regs *regs) > > -- > > 2.34.1 > > ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v4 2/2] arm64: kgdb: Set PSTATE.SS to 1 to re-enable single-step 2022-12-15 14:29 [PATCH v4 0/2] arm64: Fix pending single-step debugging issues Sumit Garg 2022-12-15 14:29 ` [PATCH v4 1/2] arm64: entry: Skip single stepping into interrupt handlers Sumit Garg @ 2022-12-15 14:29 ` Sumit Garg 1 sibling, 0 replies; 5+ messages in thread From: Sumit Garg @ 2022-12-15 14:29 UTC (permalink / raw) To: will, catalin.marinas, daniel.thompson, dianders Cc: liwei391, mark.rutland, mhiramat, maz, linux-arm-kernel, linux-kernel, Sumit Garg Currently only the first attempt to single-step has any effect. After that all further stepping remains "stuck" at the same program counter value. Refer to the ARM Architecture Reference Manual (ARM DDI 0487E.a) D2.12, PSTATE.SS=1 should be set at each step before transferring the PE to the 'Active-not-pending' state. The problem here is PSTATE.SS=1 is not set since the second single-step. After the first single-step, the PE transferes to the 'Inactive' state, with PSTATE.SS=0 and MDSCR.SS=1, thus PSTATE.SS won't be set to 1 due to kernel_active_single_step()=true. Then the PE transferes to the 'Active-pending' state when ERET and returns to the debugger by step exception. Before this patch: ================== Entering kdb (current=0xffff3376039f0000, pid 1) on processor 0 due to Keyboard Entry [0]kdb> [0]kdb> [0]kdb> bp write_sysrq_trigger Instruction(i) BP #0 at 0xffffa45c13d09290 (write_sysrq_trigger) is enabled addr at ffffa45c13d09290, hardtype=0 installed=0 [0]kdb> go $ echo h > /proc/sysrq-trigger Entering kdb (current=0xffff4f7e453f8000, pid 175) on processor 1 due to Breakpoint @ 0xffffad651a309290 [1]kdb> ss Entering kdb (current=0xffff4f7e453f8000, pid 175) on processor 1 due to SS trap @ 0xffffad651a309294 [1]kdb> ss Entering kdb (current=0xffff4f7e453f8000, pid 175) on processor 1 due to SS trap @ 0xffffad651a309294 [1]kdb> After this patch: ================= Entering kdb (current=0xffff6851c39f0000, pid 1) on processor 0 due to Keyboard Entry [0]kdb> bp write_sysrq_trigger Instruction(i) BP #0 at 0xffffc02d2dd09290 (write_sysrq_trigger) is enabled addr at ffffc02d2dd09290, hardtype=0 installed=0 [0]kdb> go $ echo h > /proc/sysrq-trigger Entering kdb (current=0xffff6851c53c1840, pid 174) on processor 1 due to Breakpoint @ 0xffffc02d2dd09290 [1]kdb> ss Entering kdb (current=0xffff6851c53c1840, pid 174) on processor 1 due to SS trap @ 0xffffc02d2dd09294 [1]kdb> ss Entering kdb (current=0xffff6851c53c1840, pid 174) on processor 1 due to SS trap @ 0xffffc02d2dd09298 [1]kdb> ss Entering kdb (current=0xffff6851c53c1840, pid 174) on processor 1 due to SS trap @ 0xffffc02d2dd0929c [1]kdb> Fixes: 44679a4f142b ("arm64: KGDB: Add step debugging support") Co-developed-by: Wei Li <liwei391@huawei.com> Signed-off-by: Wei Li <liwei391@huawei.com> Signed-off-by: Sumit Garg <sumit.garg@linaro.org> Tested-by: Douglas Anderson <dianders@chromium.org> --- arch/arm64/include/asm/debug-monitors.h | 1 + arch/arm64/kernel/debug-monitors.c | 5 +++++ arch/arm64/kernel/kgdb.c | 2 ++ 3 files changed, 8 insertions(+) diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h index 7b7e05c02691..ce3875ad5cd3 100644 --- a/arch/arm64/include/asm/debug-monitors.h +++ b/arch/arm64/include/asm/debug-monitors.h @@ -104,6 +104,7 @@ void user_regs_reset_single_step(struct user_pt_regs *regs, void kernel_enable_single_step(struct pt_regs *regs); void kernel_disable_single_step(void); int kernel_active_single_step(void); +void kernel_regs_reset_single_step(struct pt_regs *regs); #ifdef CONFIG_HAVE_HW_BREAKPOINT int reinstall_suspended_bps(struct pt_regs *regs); diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c index 3da09778267e..9af898b22ed4 100644 --- a/arch/arm64/kernel/debug-monitors.c +++ b/arch/arm64/kernel/debug-monitors.c @@ -438,6 +438,11 @@ int kernel_active_single_step(void) } NOKPROBE_SYMBOL(kernel_active_single_step); +void kernel_regs_reset_single_step(struct pt_regs *regs) +{ + set_regs_spsr_ss(regs); +} + /* ptrace API */ void user_enable_single_step(struct task_struct *task) { diff --git a/arch/arm64/kernel/kgdb.c b/arch/arm64/kernel/kgdb.c index cda9c1e9864f..51f204bbcf87 100644 --- a/arch/arm64/kernel/kgdb.c +++ b/arch/arm64/kernel/kgdb.c @@ -224,6 +224,8 @@ int kgdb_arch_handle_exception(int exception_vector, int signo, */ if (!kernel_active_single_step()) kernel_enable_single_step(linux_regs); + else + kernel_regs_reset_single_step(linux_regs); err = 0; break; default: -- 2.34.1 ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2022-12-19 6:24 UTC | newest] Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2022-12-15 14:29 [PATCH v4 0/2] arm64: Fix pending single-step debugging issues Sumit Garg 2022-12-15 14:29 ` [PATCH v4 1/2] arm64: entry: Skip single stepping into interrupt handlers Sumit Garg 2022-12-16 16:44 ` Mark Rutland 2022-12-19 6:23 ` Sumit Garg 2022-12-15 14:29 ` [PATCH v4 2/2] arm64: kgdb: Set PSTATE.SS to 1 to re-enable single-step Sumit Garg
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®