Skip to content

Commit b871895

Browse files
npigginmpe
authored andcommitted
powerpc/64s: system call scv tabort fix for corrupt irq soft-mask state
If a system call is made with a transaction active, the kernel immediately aborts it and returns. scv system calls disable irqs even earlier in their interrupt handler, and tabort_syscall does not fix this up. This can result in irq soft-mask state being messed up on the next kernel entry, and crashing at BUG_ON(arch_irq_disabled_regs(regs)) in the kernel exit handlers, or possibly worse. This can't easily be fixed in asm because at this point an async irq may have hit, which is soft-masked and marked pending. The pending interrupt has to be replayed before returning to userspace. The fix is to move the tabort_syscall code to C in the main syscall handler, and just skip the system call but otherwise return as usual, which will take care of the pending irqs. This also does a bunch of other things including possible signal delivery to the process, but the doomed transaction should still be aborted when it is eventually returned to. The sc system call path is changed to use the new C function as well to reduce code and path differences. This slows down how quickly system calls are aborted when called while a transaction is active, which could potentially impact TM performance. But making any system call is already bad for performance, and TM is on the way out, so go with simpler over faster. Fixes: 7fa95f9 ("powerpc/64s: system call support for scv/rfscv instructions") Reported-by: Eirik Fuller <[email protected]> Signed-off-by: Nicholas Piggin <[email protected]> [mpe: Use #ifdef rather than IS_ENABLED() to fix build error on 32-bit] Signed-off-by: Michael Ellerman <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 6880fa6 commit b871895

File tree

2 files changed

+30
-41
lines changed

2 files changed

+30
-41
lines changed

arch/powerpc/kernel/interrupt.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <asm/switch_to.h>
1919
#include <asm/syscall.h>
2020
#include <asm/time.h>
21+
#include <asm/tm.h>
2122
#include <asm/unistd.h>
2223

2324
#if defined(CONFIG_PPC_ADV_DEBUG_REGS) && defined(CONFIG_PPC32)
@@ -136,6 +137,35 @@ notrace long system_call_exception(long r3, long r4, long r5,
136137
*/
137138
irq_soft_mask_regs_set_state(regs, IRQS_ENABLED);
138139

140+
/*
141+
* If the system call was made with a transaction active, doom it and
142+
* return without performing the system call. Unless it was an
143+
* unsupported scv vector, in which case it's treated like an illegal
144+
* instruction.
145+
*/
146+
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
147+
if (unlikely(MSR_TM_TRANSACTIONAL(regs->msr)) &&
148+
!trap_is_unsupported_scv(regs)) {
149+
/* Enable TM in the kernel, and disable EE (for scv) */
150+
hard_irq_disable();
151+
mtmsr(mfmsr() | MSR_TM);
152+
153+
/* tabort, this dooms the transaction, nothing else */
154+
asm volatile(".long 0x7c00071d | ((%0) << 16)"
155+
:: "r"(TM_CAUSE_SYSCALL|TM_CAUSE_PERSISTENT));
156+
157+
/*
158+
* Userspace will never see the return value. Execution will
159+
* resume after the tbegin. of the aborted transaction with the
160+
* checkpointed register state. A context switch could occur
161+
* or signal delivered to the process before resuming the
162+
* doomed transaction context, but that should all be handled
163+
* as expected.
164+
*/
165+
return -ENOSYS;
166+
}
167+
#endif // CONFIG_PPC_TRANSACTIONAL_MEM
168+
139169
local_irq_enable();
140170

141171
if (unlikely(current_thread_info()->flags & _TIF_SYSCALL_DOTRACE)) {

arch/powerpc/kernel/interrupt_64.S

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
#include <asm/mmu.h>
1313
#include <asm/ppc_asm.h>
1414
#include <asm/ptrace.h>
15-
#include <asm/tm.h>
1615

1716
.section ".toc","aw"
1817
SYS_CALL_TABLE:
@@ -55,12 +54,6 @@ COMPAT_SYS_CALL_TABLE:
5554
.globl system_call_vectored_\name
5655
system_call_vectored_\name:
5756
_ASM_NOKPROBE_SYMBOL(system_call_vectored_\name)
58-
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
59-
BEGIN_FTR_SECTION
60-
extrdi. r10, r12, 1, (63-MSR_TS_T_LG) /* transaction active? */
61-
bne tabort_syscall
62-
END_FTR_SECTION_IFSET(CPU_FTR_TM)
63-
#endif
6457
SCV_INTERRUPT_TO_KERNEL
6558
mr r10,r1
6659
ld r1,PACAKSAVE(r13)
@@ -247,12 +240,6 @@ _ASM_NOKPROBE_SYMBOL(system_call_common_real)
247240
.globl system_call_common
248241
system_call_common:
249242
_ASM_NOKPROBE_SYMBOL(system_call_common)
250-
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
251-
BEGIN_FTR_SECTION
252-
extrdi. r10, r12, 1, (63-MSR_TS_T_LG) /* transaction active? */
253-
bne tabort_syscall
254-
END_FTR_SECTION_IFSET(CPU_FTR_TM)
255-
#endif
256243
mr r10,r1
257244
ld r1,PACAKSAVE(r13)
258245
std r10,0(r1)
@@ -425,34 +412,6 @@ SOFT_MASK_TABLE(.Lsyscall_rst_start, 1b)
425412
RESTART_TABLE(.Lsyscall_rst_start, .Lsyscall_rst_end, syscall_restart)
426413
#endif
427414

428-
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
429-
tabort_syscall:
430-
_ASM_NOKPROBE_SYMBOL(tabort_syscall)
431-
/* Firstly we need to enable TM in the kernel */
432-
mfmsr r10
433-
li r9, 1
434-
rldimi r10, r9, MSR_TM_LG, 63-MSR_TM_LG
435-
mtmsrd r10, 0
436-
437-
/* tabort, this dooms the transaction, nothing else */
438-
li r9, (TM_CAUSE_SYSCALL|TM_CAUSE_PERSISTENT)
439-
TABORT(R9)
440-
441-
/*
442-
* Return directly to userspace. We have corrupted user register state,
443-
* but userspace will never see that register state. Execution will
444-
* resume after the tbegin of the aborted transaction with the
445-
* checkpointed register state.
446-
*/
447-
li r9, MSR_RI
448-
andc r10, r10, r9
449-
mtmsrd r10, 1
450-
mtspr SPRN_SRR0, r11
451-
mtspr SPRN_SRR1, r12
452-
RFI_TO_USER
453-
b . /* prevent speculative execution */
454-
#endif
455-
456415
/*
457416
* If MSR EE/RI was never enabled, IRQs not reconciled, NVGPRs not
458417
* touched, no exit work created, then this can be used.

0 commit comments

Comments
 (0)