@@ -231,11 +231,15 @@ DEFINE_STATIC_KEY_TRUE(sk_dynamic_irqentry_exit_cond_resched);
#define need_irq_preemption() (IS_ENABLED(CONFIG_PREEMPTION))
#endif
-static void __sched arm64_preempt_schedule_irq(void)
+static void __sched arm64_preempt_schedule_irq(struct pt_regs *regs)
{
if (!need_irq_preemption())
return;
+ /* Don't reschedule in case we are single stepping */
+ if (regs->pstate & DBG_SPSR_SS)
+ return;
+
/*
* Note: thread_info::preempt_count includes both thread_info::count
* and thread_info::need_resched, and is not equivalent to
@@ -471,19 +475,33 @@ static __always_inline void __el1_irq(struct pt_regs *regs,
do_interrupt_handler(regs, handler);
irq_exit_rcu();
- arm64_preempt_schedule_irq();
+ arm64_preempt_schedule_irq(regs);
exit_to_kernel_mode(regs);
}
+
static void noinstr el1_interrupt(struct pt_regs *regs,
void (*handler)(struct pt_regs *))
{
+ unsigned long mdscr;
+
+ /* Disable single stepping within interrupt handler */
+ if (regs->pstate & DBG_SPSR_SS) {
+ mdscr = read_sysreg(mdscr_el1);
+ write_sysreg(mdscr & ~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(mdscr, mdscr_el1);
+ }
}
asmlinkage void noinstr el1h_64_irq_handler(struct pt_regs *regs)