powerpc fixes for 5.15 #2
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. -----BEGIN PGP SIGNATURE----- iQJHBAABCAAxFiEEJFGtCPCthwEv2Y/bUevqPMjhpYAFAmFHDfsTHG1wZUBlbGxl cm1hbi5pZC5hdQAKCRBR6+o8yOGlgNlAD/oC/14jV2fCv54vH5Al1XAz2WuPhhEu UsN+MLlx7JshXfLeGzzEogvvakfLFuVkpIxsv+g8a9H6jejjCj/A4wjUy34Im0hS nhsMsa1vZPZY/Vz9v3WzdYmqjHVZDKo6ZdUmn0z4OjPnv7wQaEEbaXmoe0+CaXXQ jIY2TjVQxbgXeUI1QcPUWh36hiSaYn4O8fAD4VdjxdStl2z6q8zbo/5nzQ8dkBpP lldC0T/HRCKLe1ODUExFfbBFqFuLVdbALq0RIuh0GXd+dAqpK1iOkNsxUWChU6Q7 gu0PrmhRydX3bmL9jmOsZfUk/hIR0fEgwSGITQAb8v0LCvZI0JRn+yvkl7uVZ9Ce OWY7B8HZQldvoQqA4/f7YCpAIS2ag7ugDrcAfuDVkDl2o/qJHoTi58IU24wI6+LL lwJZjNJoxZ8n1tl1l+gtCNp4E4YYOfuKZi0zH0oJoLiSWeK6PYOvwEGuEC2iQ9cJ BEdyYVXqSBuc2anCQ4k+y8gu/zJwP1MCpDNMPMU4P/JcaG9lnrLUhvctf4GKtOSy UiktHSTL52J5ldMxSMicpw9qCVgePsQX78Sk3UTHRilRmix6TtWOWYslm4mL+zeD u3wpnK+NKkju72LRS/AB1U6cWvModW+WBANPws9j6caoOorh397xsDGEYiKWvp0Z xSG/dzXzi2oscQ== =yC9U -----END PGP SIGNATURE----- Merge tag 'powerpc-5.15-2' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux 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
This commit is contained in:
commit
62453a460a
|
@ -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)) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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. */
|
||||
irq_work_queue(&mce_event_process_work);
|
||||
/*
|
||||
* 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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#include <ppc-asm.h>
|
||||
#include <basic_asm.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
.text
|
||||
|
@ -26,3 +26,38 @@ FUNC_START(getppid_tm_suspended)
|
|||
1:
|
||||
li r3, -1
|
||||
blr
|
||||
|
||||
|
||||
.macro scv level
|
||||
.long (0x44000001 | (\level) << 5)
|
||||
.endm
|
||||
|
||||
FUNC_START(getppid_scv_tm_active)
|
||||
PUSH_BASIC_STACK(0)
|
||||
tbegin.
|
||||
beq 1f
|
||||
li r0, __NR_getppid
|
||||
scv 0
|
||||
tend.
|
||||
POP_BASIC_STACK(0)
|
||||
blr
|
||||
1:
|
||||
li r3, -1
|
||||
POP_BASIC_STACK(0)
|
||||
blr
|
||||
|
||||
FUNC_START(getppid_scv_tm_suspended)
|
||||
PUSH_BASIC_STACK(0)
|
||||
tbegin.
|
||||
beq 1f
|
||||
li r0, __NR_getppid
|
||||
tsuspend.
|
||||
scv 0
|
||||
tresume.
|
||||
tend.
|
||||
POP_BASIC_STACK(0)
|
||||
blr
|
||||
1:
|
||||
li r3, -1
|
||||
POP_BASIC_STACK(0)
|
||||
blr
|
||||
|
|
|
@ -19,23 +19,36 @@
|
|||
#include "utils.h"
|
||||
#include "tm.h"
|
||||
|
||||
#ifndef PPC_FEATURE2_SCV
|
||||
#define PPC_FEATURE2_SCV 0x00100000 /* scv syscall */
|
||||
#endif
|
||||
|
||||
extern int getppid_tm_active(void);
|
||||
extern int getppid_tm_suspended(void);
|
||||
extern int getppid_scv_tm_active(void);
|
||||
extern int getppid_scv_tm_suspended(void);
|
||||
|
||||
unsigned retries = 0;
|
||||
|
||||
#define TEST_DURATION 10 /* seconds */
|
||||
|
||||
pid_t getppid_tm(bool suspend)
|
||||
pid_t getppid_tm(bool scv, bool suspend)
|
||||
{
|
||||
int i;
|
||||
pid_t pid;
|
||||
|
||||
for (i = 0; i < TM_RETRIES; i++) {
|
||||
if (suspend)
|
||||
pid = getppid_tm_suspended();
|
||||
else
|
||||
pid = getppid_tm_active();
|
||||
if (suspend) {
|
||||
if (scv)
|
||||
pid = getppid_scv_tm_suspended();
|
||||
else
|
||||
pid = getppid_tm_suspended();
|
||||
} else {
|
||||
if (scv)
|
||||
pid = getppid_scv_tm_active();
|
||||
else
|
||||
pid = getppid_tm_active();
|
||||
}
|
||||
|
||||
if (pid >= 0)
|
||||
return pid;
|
||||
|
@ -82,15 +95,24 @@ int tm_syscall(void)
|
|||
* Test a syscall within a suspended transaction and verify
|
||||
* that it succeeds.
|
||||
*/
|
||||
FAIL_IF(getppid_tm(true) == -1); /* Should succeed. */
|
||||
FAIL_IF(getppid_tm(false, true) == -1); /* Should succeed. */
|
||||
|
||||
/*
|
||||
* Test a syscall within an active transaction and verify that
|
||||
* it fails with the correct failure code.
|
||||
*/
|
||||
FAIL_IF(getppid_tm(false) != -1); /* Should fail... */
|
||||
FAIL_IF(getppid_tm(false, false) != -1); /* Should fail... */
|
||||
FAIL_IF(!failure_is_persistent()); /* ...persistently... */
|
||||
FAIL_IF(!failure_is_syscall()); /* ...with code syscall. */
|
||||
|
||||
/* Now do it all again with scv if it is available. */
|
||||
if (have_hwcap2(PPC_FEATURE2_SCV)) {
|
||||
FAIL_IF(getppid_tm(true, true) == -1); /* Should succeed. */
|
||||
FAIL_IF(getppid_tm(true, false) != -1); /* Should fail... */
|
||||
FAIL_IF(!failure_is_persistent()); /* ...persistently... */
|
||||
FAIL_IF(!failure_is_syscall()); /* ...with code syscall. */
|
||||
}
|
||||
|
||||
gettimeofday(&now, 0);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue