Commit 62453a46 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull powerpc fixes from Michael Ellerman:

 - Fix crashes when scv (System Call Vectored) is used to make a syscall
   when a transaction is active, on Power9 or later.

 - Fix bad interactions between rfscv (Return-from scv) and Power9
   fake-suspend mode.

 - Fix crashes when handling machine checks in LPARs using the Hash MMU.

 - Partly revert a recent change to our XICS interrupt controller code,
   which broke the recently added Microwatt support.

Thanks to Cédric Le Goater, Eirik Fuller, Ganesh Goudar, Gustavo Romero,
Joel Stanley, Nicholas Piggin.

* tag 'powerpc-5.15-2' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux:
  powerpc/xics: Set the IRQ chip data for the ICS native backend
  powerpc/mce: Fix access error in mce handler
  KVM: PPC: Book3S HV: Tolerate treclaim. in fake-suspend mode changing registers
  powerpc/64s: system call rfscv workaround for TM bugs
  selftests/powerpc: Add scv versions of the basic TM syscall tests
  powerpc/64s: system call scv tabort fix for corrupt irq soft-mask state
parents 2f629969 c006a065
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <asm/switch_to.h>
#include <asm/syscall.h>
#include <asm/time.h>
#include <asm/tm.h>
#include <asm/unistd.h>

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

	/*
	 * If system call is called with TM active, set _TIF_RESTOREALL to
	 * prevent RFSCV being used to return to userspace, because POWER9
	 * TM implementation has problems with this instruction returning to
	 * transactional state. Final register values are not relevant because
	 * the transaction will be aborted upon return anyway. Or in the case
	 * of unsupported_scv SIGILL fault, the return state does not much
	 * matter because it's an edge case.
	 */
	if (IS_ENABLED(CONFIG_PPC_TRANSACTIONAL_MEM) &&
			unlikely(MSR_TM_TRANSACTIONAL(regs->msr)))
		current_thread_info()->flags |= _TIF_RESTOREALL;

	/*
	 * If the system call was made with a transaction active, doom it and
	 * return without performing the system call. Unless it was an
	 * unsupported scv vector, in which case it's treated like an illegal
	 * instruction.
	 */
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
	if (unlikely(MSR_TM_TRANSACTIONAL(regs->msr)) &&
	    !trap_is_unsupported_scv(regs)) {
		/* Enable TM in the kernel, and disable EE (for scv) */
		hard_irq_disable();
		mtmsr(mfmsr() | MSR_TM);

		/* tabort, this dooms the transaction, nothing else */
		asm volatile(".long 0x7c00071d | ((%0) << 16)"
				:: "r"(TM_CAUSE_SYSCALL|TM_CAUSE_PERSISTENT));

		/*
		 * Userspace will never see the return value. Execution will
		 * resume after the tbegin. of the aborted transaction with the
		 * checkpointed register state. A context switch could occur
		 * or signal delivered to the process before resuming the
		 * doomed transaction context, but that should all be handled
		 * as expected.
		 */
		return -ENOSYS;
	}
#endif // CONFIG_PPC_TRANSACTIONAL_MEM

	local_irq_enable();

	if (unlikely(current_thread_info()->flags & _TIF_SYSCALL_DOTRACE)) {
+0 −41
Original line number Diff line number Diff line
@@ -12,7 +12,6 @@
#include <asm/mmu.h>
#include <asm/ppc_asm.h>
#include <asm/ptrace.h>
#include <asm/tm.h>

	.section	".toc","aw"
SYS_CALL_TABLE:
@@ -55,12 +54,6 @@ COMPAT_SYS_CALL_TABLE:
	.globl system_call_vectored_\name
system_call_vectored_\name:
_ASM_NOKPROBE_SYMBOL(system_call_vectored_\name)
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
BEGIN_FTR_SECTION
	extrdi.	r10, r12, 1, (63-MSR_TS_T_LG) /* transaction active? */
	bne	tabort_syscall
END_FTR_SECTION_IFSET(CPU_FTR_TM)
#endif
	SCV_INTERRUPT_TO_KERNEL
	mr	r10,r1
	ld	r1,PACAKSAVE(r13)
@@ -247,12 +240,6 @@ _ASM_NOKPROBE_SYMBOL(system_call_common_real)
	.globl system_call_common
system_call_common:
_ASM_NOKPROBE_SYMBOL(system_call_common)
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
BEGIN_FTR_SECTION
	extrdi.	r10, r12, 1, (63-MSR_TS_T_LG) /* transaction active? */
	bne	tabort_syscall
END_FTR_SECTION_IFSET(CPU_FTR_TM)
#endif
	mr	r10,r1
	ld	r1,PACAKSAVE(r13)
	std	r10,0(r1)
@@ -425,34 +412,6 @@ SOFT_MASK_TABLE(.Lsyscall_rst_start, 1b)
RESTART_TABLE(.Lsyscall_rst_start, .Lsyscall_rst_end, syscall_restart)
#endif

#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
tabort_syscall:
_ASM_NOKPROBE_SYMBOL(tabort_syscall)
	/* Firstly we need to enable TM in the kernel */
	mfmsr	r10
	li	r9, 1
	rldimi	r10, r9, MSR_TM_LG, 63-MSR_TM_LG
	mtmsrd	r10, 0

	/* tabort, this dooms the transaction, nothing else */
	li	r9, (TM_CAUSE_SYSCALL|TM_CAUSE_PERSISTENT)
	TABORT(R9)

	/*
	 * Return directly to userspace. We have corrupted user register state,
	 * but userspace will never see that register state. Execution will
	 * resume after the tbegin of the aborted transaction with the
	 * checkpointed register state.
	 */
	li	r9, MSR_RI
	andc	r10, r10, r9
	mtmsrd	r10, 1
	mtspr	SPRN_SRR0, r11
	mtspr	SPRN_SRR1, r12
	RFI_TO_USER
	b	.	/* prevent speculative execution */
#endif

	/*
	 * If MSR EE/RI was never enabled, IRQs not reconciled, NVGPRs not
	 * touched, no exit work created, then this can be used.
+15 −2
Original line number Diff line number Diff line
@@ -249,6 +249,7 @@ void machine_check_queue_event(void)
{
	int index;
	struct machine_check_event evt;
	unsigned long msr;

	if (!get_mce_event(&evt, MCE_EVENT_RELEASE))
		return;
@@ -262,8 +263,20 @@ void machine_check_queue_event(void)
	memcpy(&local_paca->mce_info->mce_event_queue[index],
	       &evt, sizeof(evt));

	/* Queue irq work to process this event later. */
	/*
	 * Queue irq work to process this event later. Before
	 * queuing the work enable translation for non radix LPAR,
	 * as irq_work_queue may try to access memory outside RMO
	 * region.
	 */
	if (!radix_enabled() && firmware_has_feature(FW_FEATURE_LPAR)) {
		msr = mfmsr();
		mtmsr(msr | MSR_IR | MSR_DR);
		irq_work_queue(&mce_event_process_work);
		mtmsr(msr);
	} else {
		irq_work_queue(&mce_event_process_work);
	}
}

void mce_common_process_ue(struct pt_regs *regs,
+34 −2
Original line number Diff line number Diff line
@@ -2536,7 +2536,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_P9_TM_HV_ASSIST)
	/* The following code handles the fake_suspend = 1 case */
	mflr	r0
	std	r0, PPC_LR_STKOFF(r1)
	stdu	r1, -PPC_MIN_STKFRM(r1)
	stdu	r1, -TM_FRAME_SIZE(r1)

	/* Turn on TM. */
	mfmsr	r8
@@ -2551,10 +2551,42 @@ BEGIN_FTR_SECTION
END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_XER_SO_BUG)
	nop

	/*
	 * It's possible that treclaim. may modify registers, if we have lost
	 * track of fake-suspend state in the guest due to it using rfscv.
	 * Save and restore registers in case this occurs.
	 */
	mfspr	r3, SPRN_DSCR
	mfspr	r4, SPRN_XER
	mfspr	r5, SPRN_AMR
	/* SPRN_TAR would need to be saved here if the kernel ever used it */
	mfcr	r12
	SAVE_NVGPRS(r1)
	SAVE_GPR(2, r1)
	SAVE_GPR(3, r1)
	SAVE_GPR(4, r1)
	SAVE_GPR(5, r1)
	stw	r12, 8(r1)
	std	r1, HSTATE_HOST_R1(r13)

	/* We have to treclaim here because that's the only way to do S->N */
	li	r3, TM_CAUSE_KVM_RESCHED
	TRECLAIM(R3)

	GET_PACA(r13)
	ld	r1, HSTATE_HOST_R1(r13)
	REST_GPR(2, r1)
	REST_GPR(3, r1)
	REST_GPR(4, r1)
	REST_GPR(5, r1)
	lwz	r12, 8(r1)
	REST_NVGPRS(r1)
	mtspr	SPRN_DSCR, r3
	mtspr	SPRN_XER, r4
	mtspr	SPRN_AMR, r5
	mtcr	r12
	HMT_MEDIUM

	/*
	 * We were in fake suspend, so we are not going to save the
	 * register state as the guest checkpointed state (since
@@ -2582,7 +2614,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_XER_SO_BUG)
	std	r5, VCPU_TFHAR(r9)
	std	r6, VCPU_TFIAR(r9)

	addi	r1, r1, PPC_MIN_STKFRM
	addi	r1, r1, TM_FRAME_SIZE
	ld	r0, PPC_LR_STKOFF(r1)
	mtlr	r0
	blr
+2 −2
Original line number Diff line number Diff line
@@ -348,9 +348,9 @@ static int xics_host_map(struct irq_domain *domain, unsigned int virq,
	if (xics_ics->check(xics_ics, hwirq))
		return -EINVAL;

	/* No chip data for the XICS domain */
	/* Let the ICS be the chip data for the XICS domain. For ICS native */
	irq_domain_set_info(domain, virq, hwirq, xics_ics->chip,
			    NULL, handle_fasteoi_irq, NULL, NULL);
			    xics_ics, handle_fasteoi_irq, NULL, NULL);

	return 0;
}
Loading