powerpc/64s: system call rfscv workaround for TM bugs
Subsystems (2)
Nicholas Piggin
reviewerPATCH 1/2 powerpc/64s: system call rfscv workaround for TM bugs
The rfscv instruction does not work correctly with the fake-suspend mode in POWER9, which can end up with the hypervisor restoring an incorrect checkpoint.
Work around this by setting the _TIF_RESTOREALL flag if a system call returns to a transaction active state, causing rfid to be used instead of rfscv to return, which will do the right thing. The contents of the registers are irrelevant because they will be overwritten in this case anyway.
--- arch/powerpc/kernel/interrupt.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
arch/powerpc/kernel/interrupt.c +13 -0
@@ -139,6 +139,19 @@ 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
Signature · 1 line
2.23.0
Nicholas Piggin
reviewerPATCH 2/2 KVM: PPC: Book3S HV: Tolerate treclaim. in fake-suspend mode changing registers
POWER9 DD2.2 and 2.3 hardware implements a "fake-suspend" mode where certain TM instructions executed in HV=0 mode cause softpatch interrupts so the hypervisor can emulate them and prevent problematic processor conditions. In this fake-suspend mode, the treclaim. instruction does not modify registers.
Unfortunately the rfscv instruction executed by the guest do not generate softpatch interrupts, which can cause the hypervisor to lose track of the fake-suspend mode, and it can execute this treclaim. while not in fake-suspend mode. This modifies GPRs and crashes the hypervisor.
It's not trivial to disable scv in the guest with HFSCR now, because they assume a POWER9 has scv available. So this fix saves and restores checkpointed registers across the treclaim.
--- arch/powerpc/kvm/book3s_hv_rmhandlers.S | 36 +++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-)
arch/powerpc/kvm/book3s_hv_rmhandlers.S +34 -2
@@ -2578,7 +2578,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
@@ -2593,10 +2593,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
@@ -2624,7 +2656,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
Signature · 1 line
2.23.0
Quoted 3 lines · Nicholas Piggin
The rfscv instruction does not work correctly with the fake-suspend mode in POWER9, which can end up with the hypervisor restoring an incorrect checkpoint.
If I understand correctly from commit 4bb3c7a0208f ("KVM: PPC: Book3S
HV: Work around transactional memory bugs in POWER9"), this is because rfscv does not cause a soft-patch interrupt in the way that rfid etc do. So we need to avoid calling rfscv if we are in fake-suspend state - instead we must call something that does indeed get soft-patched - like rfid.
Quoted 5 lines
Work around this by setting the
_TIF_RESTOREALLflag if a system call returns to a transaction active state, causing rfid to be used instead of rfscv to return, which will do the right thing. The contents of the registers are irrelevant because they will be overwritten in this case anyway.
I can follow that this will indeed cause syscall_exit_prepare to return non-zero and therefore we should take the syscall_vectored_*_restore_regs path which does an RFID_TO_USER rather than a RFSCV_TO_USER. My only question/concern is:
.Lsyscall_vectored_\name\()_exit:
addi r4,r1,STACK_FRAME_OVERHEAD li r5,1 /* scv */ bl syscall_exit_prepare <-------- we get r3 != 0 here std r1,PACA_EXIT_SAVE_R1(r13) /* save r1 for restart */ .Lsyscall_vectored_\name\()_rst_start: lbz r11,PACAIRQHAPPENED(r13) andi. r11,r11,(~PACA_IRQ_HARD_DIS)@l bne- syscall_vectored_\name\()_restart <-- can we end up taking this branch?
Are there any circumstances that would take us down the _restart path, and if so, will we still go through the correct RFID_TO_USER branch rather than the RFSCV_TO_USER branch?
Apart from that this looks good to me, although with the heavy disclaimer that I only learned about fake suspend for the first time while reviewing the patch.
Kind regards,
Daniel
Quoted 34 lines
Reported-by Eirik Fuller <[email protected]>Fixes 7fa95f9adaee7 ("powerpc/64s: system call support for scv/rfscv instructions")Signed-off-by Nicholas Piggin <[email protected]>--- arch/powerpc/kernel/interrupt.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)arch/powerpc/kernel/interrupt.c +13
-0@@ -139,6 +139,19 @@ 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 Signature · 1 line
2.23.0
Michael Ellerman
AppliedQuoted 11 lines · Nicholas Piggin
The rfscv instruction does not work correctly with the fake-suspend mode in POWER9, which can end up with the hypervisor restoring an incorrect checkpoint.
Work around this by setting the
_TIF_RESTOREALLflag if a system call returns to a transaction active state, causing rfid to be used instead of rfscv to return, which will do the right thing. The contents of the registers are irrelevant because they will be overwritten in this case anyway.[...]
Applied to powerpc/fixes.
[1/2] powerpc/64s: system call rfscv workaround for TM bugs
https://git.kernel.org/powerpc/c/ae7aaecc3f2f78b76ab3a8d6178610f55aadfa56 [2/2] KVM: PPC: Book3S HV: Tolerate treclaim. in fake-suspend mode changing registers https://git.kernel.org/powerpc/c/267cdfa21385d78c794768233678756e32b39ead
cheers