Skip to content

Commit cc73cc6

Browse files
seehearfeelchenhuacai
authored andcommitted
LoongArch: Make do_xyz() exception handlers more robust
Currently, interrupts need to be disabled before single-step mode is set, it requires that CSR_PRMD_PIE be cleared in save_local_irqflag() which is called by setup_singlestep(), this is reasonable. But in the first kprobe breakpoint exception, if the irq is enabled at the beginning of do_bp(), it will not be disabled at the end of do_bp() due to the CSR_PRMD_PIE has been cleared in save_local_irqflag(). So for this case, it may corrupt exception context when restoring the exception after do_bp() in handle_bp(), this is not reasonable. In order to restore exception safely in handle_bp(), it needs to ensure the irq is disabled at the end of do_bp(), so just add a local variable to record the original interrupt status in the parent context, then use it as the check condition to enable and disable irq in do_bp(). While at it, do the similar thing for other do_xyz() exception handlers to make them more robust. Fixes: 6d4cc40 ("LoongArch: Add kprobes support") Suggested-by: Jinyang He <hejinyang@loongson.cn> Suggested-by: Huacai Chen <chenhuacai@loongson.cn> Co-developed-by: Tianyang Zhang <zhangtianyang@loongson.cn> Signed-off-by: Tianyang Zhang <zhangtianyang@loongson.cn> Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn> Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
1 parent bb0511d commit cc73cc6

File tree

1 file changed

+12
-8
lines changed

1 file changed

+12
-8
lines changed

arch/loongarch/kernel/traps.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -553,9 +553,10 @@ asmlinkage void noinstr do_ale(struct pt_regs *regs)
553553
die_if_kernel("Kernel ale access", regs);
554554
force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)regs->csr_badvaddr);
555555
#else
556+
bool pie = regs_irqs_disabled(regs);
556557
unsigned int *pc;
557558

558-
if (regs->csr_prmd & CSR_PRMD_PIE)
559+
if (!pie)
559560
local_irq_enable();
560561

561562
perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, regs->csr_badvaddr);
@@ -582,7 +583,7 @@ asmlinkage void noinstr do_ale(struct pt_regs *regs)
582583
die_if_kernel("Kernel ale access", regs);
583584
force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)regs->csr_badvaddr);
584585
out:
585-
if (regs->csr_prmd & CSR_PRMD_PIE)
586+
if (!pie)
586587
local_irq_disable();
587588
#endif
588589
irqentry_exit(regs, state);
@@ -621,12 +622,13 @@ static void bug_handler(struct pt_regs *regs)
621622
asmlinkage void noinstr do_bce(struct pt_regs *regs)
622623
{
623624
bool user = user_mode(regs);
625+
bool pie = regs_irqs_disabled(regs);
624626
unsigned long era = exception_era(regs);
625627
u64 badv = 0, lower = 0, upper = ULONG_MAX;
626628
union loongarch_instruction insn;
627629
irqentry_state_t state = irqentry_enter(regs);
628630

629-
if (regs->csr_prmd & CSR_PRMD_PIE)
631+
if (!pie)
630632
local_irq_enable();
631633

632634
current->thread.trap_nr = read_csr_excode();
@@ -692,7 +694,7 @@ asmlinkage void noinstr do_bce(struct pt_regs *regs)
692694
force_sig_bnderr((void __user *)badv, (void __user *)lower, (void __user *)upper);
693695

694696
out:
695-
if (regs->csr_prmd & CSR_PRMD_PIE)
697+
if (!pie)
696698
local_irq_disable();
697699

698700
irqentry_exit(regs, state);
@@ -710,11 +712,12 @@ asmlinkage void noinstr do_bce(struct pt_regs *regs)
710712
asmlinkage void noinstr do_bp(struct pt_regs *regs)
711713
{
712714
bool user = user_mode(regs);
715+
bool pie = regs_irqs_disabled(regs);
713716
unsigned int opcode, bcode;
714717
unsigned long era = exception_era(regs);
715718
irqentry_state_t state = irqentry_enter(regs);
716719

717-
if (regs->csr_prmd & CSR_PRMD_PIE)
720+
if (!pie)
718721
local_irq_enable();
719722

720723
if (__get_inst(&opcode, (u32 *)era, user))
@@ -780,7 +783,7 @@ asmlinkage void noinstr do_bp(struct pt_regs *regs)
780783
}
781784

782785
out:
783-
if (regs->csr_prmd & CSR_PRMD_PIE)
786+
if (!pie)
784787
local_irq_disable();
785788

786789
irqentry_exit(regs, state);
@@ -1015,6 +1018,7 @@ static void init_restore_lbt(void)
10151018

10161019
asmlinkage void noinstr do_lbt(struct pt_regs *regs)
10171020
{
1021+
bool pie = regs_irqs_disabled(regs);
10181022
irqentry_state_t state = irqentry_enter(regs);
10191023

10201024
/*
@@ -1024,7 +1028,7 @@ asmlinkage void noinstr do_lbt(struct pt_regs *regs)
10241028
* (including the user using 'MOVGR2GCSR' to turn on TM, which
10251029
* will not trigger the BTE), we need to check PRMD first.
10261030
*/
1027-
if (regs->csr_prmd & CSR_PRMD_PIE)
1031+
if (!pie)
10281032
local_irq_enable();
10291033

10301034
if (!cpu_has_lbt) {
@@ -1038,7 +1042,7 @@ asmlinkage void noinstr do_lbt(struct pt_regs *regs)
10381042
preempt_enable();
10391043

10401044
out:
1041-
if (regs->csr_prmd & CSR_PRMD_PIE)
1045+
if (!pie)
10421046
local_irq_disable();
10431047

10441048
irqentry_exit(regs, state);

0 commit comments

Comments
 (0)