]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
riscv: Enable interrupt during exception handling
authorNam Cao <namcao@linutronix.de>
Wed, 25 Jun 2025 08:56:30 +0000 (10:56 +0200)
committerPalmer Dabbelt <palmer@dabbelt.com>
Wed, 16 Jul 2025 16:05:26 +0000 (09:05 -0700)
force_sig_fault() takes a spinlock, which is a sleeping lock with
CONFIG_PREEMPT_RT=y. However, exception handling calls force_sig_fault()
with interrupt disabled, causing a sleeping in atomic context warning.

This can be reproduced using userspace programs such as:
    int main() { asm ("ebreak"); }
or
    int main() { asm ("unimp"); }

There is no reason that interrupt must be disabled while handling
exceptions from userspace.

Enable interrupt while handling user exceptions. This also has the added
benefit of avoiding unnecessary delays in interrupt handling.

Fixes: f0bddf50586d ("riscv: entry: Convert to generic entry")
Suggested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Nam Cao <namcao@linutronix.de>
Reviewed-by: Alexandre Ghiti <alexghiti@rivosinc.com>
Link: https://lore.kernel.org/r/20250625085630.3649485-1-namcao@linutronix.de
Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
arch/riscv/kernel/traps.c

index 9c83848797a78b05e7f05a435dc4236f0a126948..80230de167def3c33db5bc190347ec5f87dbb6e3 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/cpu.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/irqflags.h>
 #include <linux/randomize_kstack.h>
 #include <linux/sched.h>
 #include <linux/sched/debug.h>
@@ -151,7 +152,9 @@ asmlinkage __visible __trap_section void name(struct pt_regs *regs)         \
 {                                                                              \
        if (user_mode(regs)) {                                                  \
                irqentry_enter_from_user_mode(regs);                            \
+               local_irq_enable();                                             \
                do_trap_error(regs, signo, code, regs->epc, "Oops - " str);     \
+               local_irq_disable();                                            \
                irqentry_exit_to_user_mode(regs);                               \
        } else {                                                                \
                irqentry_state_t state = irqentry_nmi_enter(regs);              \
@@ -173,17 +176,14 @@ asmlinkage __visible __trap_section void do_trap_insn_illegal(struct pt_regs *re
 
        if (user_mode(regs)) {
                irqentry_enter_from_user_mode(regs);
-
                local_irq_enable();
 
                handled = riscv_v_first_use_handler(regs);
-
-               local_irq_disable();
-
                if (!handled)
                        do_trap_error(regs, SIGILL, ILL_ILLOPC, regs->epc,
                                      "Oops - illegal instruction");
 
+               local_irq_disable();
                irqentry_exit_to_user_mode(regs);
        } else {
                irqentry_state_t state = irqentry_nmi_enter(regs);
@@ -308,9 +308,11 @@ asmlinkage __visible __trap_section void do_trap_break(struct pt_regs *regs)
 {
        if (user_mode(regs)) {
                irqentry_enter_from_user_mode(regs);
+               local_irq_enable();
 
                handle_break(regs);
 
+               local_irq_disable();
                irqentry_exit_to_user_mode(regs);
        } else {
                irqentry_state_t state = irqentry_nmi_enter(regs);