Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: 7fa95f9adaee7 ("powerpc/64s: system call support for scv/rfscv instructions")
Reported-by: Eirik Fuller <efuller@redhat.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
[mpe: Use #ifdef rather than IS_ENABLED() to fix build error on 32-bit]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20210903125707.1601269-1-npiggin@gmail.com

authored by

Nicholas Piggin and committed by
Michael Ellerman
b871895b 6880fa6c

+30 -41
+30
arch/powerpc/kernel/interrupt.c
··· 18 18 #include <asm/switch_to.h> 19 19 #include <asm/syscall.h> 20 20 #include <asm/time.h> 21 + #include <asm/tm.h> 21 22 #include <asm/unistd.h> 22 23 23 24 #if defined(CONFIG_PPC_ADV_DEBUG_REGS) && defined(CONFIG_PPC32) ··· 136 135 * returns to user with IRQS_ENABLED, this store could be avoided! 137 136 */ 138 137 irq_soft_mask_regs_set_state(regs, IRQS_ENABLED); 138 + 139 + /* 140 + * If the system call was made with a transaction active, doom it and 141 + * return without performing the system call. Unless it was an 142 + * unsupported scv vector, in which case it's treated like an illegal 143 + * instruction. 144 + */ 145 + #ifdef CONFIG_PPC_TRANSACTIONAL_MEM 146 + if (unlikely(MSR_TM_TRANSACTIONAL(regs->msr)) && 147 + !trap_is_unsupported_scv(regs)) { 148 + /* Enable TM in the kernel, and disable EE (for scv) */ 149 + hard_irq_disable(); 150 + mtmsr(mfmsr() | MSR_TM); 151 + 152 + /* tabort, this dooms the transaction, nothing else */ 153 + asm volatile(".long 0x7c00071d | ((%0) << 16)" 154 + :: "r"(TM_CAUSE_SYSCALL|TM_CAUSE_PERSISTENT)); 155 + 156 + /* 157 + * Userspace will never see the return value. Execution will 158 + * resume after the tbegin. of the aborted transaction with the 159 + * checkpointed register state. A context switch could occur 160 + * or signal delivered to the process before resuming the 161 + * doomed transaction context, but that should all be handled 162 + * as expected. 163 + */ 164 + return -ENOSYS; 165 + } 166 + #endif // CONFIG_PPC_TRANSACTIONAL_MEM 139 167 140 168 local_irq_enable(); 141 169
-41
arch/powerpc/kernel/interrupt_64.S
··· 12 12 #include <asm/mmu.h> 13 13 #include <asm/ppc_asm.h> 14 14 #include <asm/ptrace.h> 15 - #include <asm/tm.h> 16 15 17 16 .section ".toc","aw" 18 17 SYS_CALL_TABLE: ··· 54 55 .globl system_call_vectored_\name 55 56 system_call_vectored_\name: 56 57 _ASM_NOKPROBE_SYMBOL(system_call_vectored_\name) 57 - #ifdef CONFIG_PPC_TRANSACTIONAL_MEM 58 - BEGIN_FTR_SECTION 59 - extrdi. r10, r12, 1, (63-MSR_TS_T_LG) /* transaction active? */ 60 - bne tabort_syscall 61 - END_FTR_SECTION_IFSET(CPU_FTR_TM) 62 - #endif 63 58 SCV_INTERRUPT_TO_KERNEL 64 59 mr r10,r1 65 60 ld r1,PACAKSAVE(r13) ··· 240 247 .globl system_call_common 241 248 system_call_common: 242 249 _ASM_NOKPROBE_SYMBOL(system_call_common) 243 - #ifdef CONFIG_PPC_TRANSACTIONAL_MEM 244 - BEGIN_FTR_SECTION 245 - extrdi. r10, r12, 1, (63-MSR_TS_T_LG) /* transaction active? */ 246 - bne tabort_syscall 247 - END_FTR_SECTION_IFSET(CPU_FTR_TM) 248 - #endif 249 250 mr r10,r1 250 251 ld r1,PACAKSAVE(r13) 251 252 std r10,0(r1) ··· 410 423 411 424 SOFT_MASK_TABLE(.Lsyscall_rst_start, 1b) 412 425 RESTART_TABLE(.Lsyscall_rst_start, .Lsyscall_rst_end, syscall_restart) 413 - #endif 414 - 415 - #ifdef CONFIG_PPC_TRANSACTIONAL_MEM 416 - tabort_syscall: 417 - _ASM_NOKPROBE_SYMBOL(tabort_syscall) 418 - /* Firstly we need to enable TM in the kernel */ 419 - mfmsr r10 420 - li r9, 1 421 - rldimi r10, r9, MSR_TM_LG, 63-MSR_TM_LG 422 - mtmsrd r10, 0 423 - 424 - /* tabort, this dooms the transaction, nothing else */ 425 - li r9, (TM_CAUSE_SYSCALL|TM_CAUSE_PERSISTENT) 426 - TABORT(R9) 427 - 428 - /* 429 - * Return directly to userspace. We have corrupted user register state, 430 - * but userspace will never see that register state. Execution will 431 - * resume after the tbegin of the aborted transaction with the 432 - * checkpointed register state. 433 - */ 434 - li r9, MSR_RI 435 - andc r10, r10, r9 436 - mtmsrd r10, 1 437 - mtspr SPRN_SRR0, r11 438 - mtspr SPRN_SRR1, r12 439 - RFI_TO_USER 440 - b . /* prevent speculative execution */ 441 426 #endif 442 427 443 428 /*