From: Simon Guo <wei.guo.simon@xxxxxxxxx> Currently guest kernel doesn't handle TAR fac unavailable and it always runs with TAR bit on. PR KVM will lazily enable TAR. TAR is not a frequent-use reg and it is not included in SVCPU struct. To make it work for transaction memory at PR KVM: 1). Flush/giveup TAR at kvmppc_save_tm_pr(). 2) If we are receiving a TAR fac unavail exception inside a transaction, the checkpointed TAR might be a TAR value from another process. So we need treclaim the transaction, then load the desired TAR value into reg, and perform trecheckpoint. 3) Load TAR facility at kvmppc_restore_tm_pr() when TM active. The reason we always loads TAR when restoring TM is that: If we don't do this way, when there is a TAR fac unavailable exception during TM active: case 1: it is the 1st TAR fac unavail exception after tbegin. vcpu->arch.tar should be reloaded as checkpoint tar val. case 2: it is the 2nd or later TAR fac unavail exception after tbegin. vcpu->arch.tar_tm should be reloaded as checkpoint tar val. There will be unnecessary difficulty to handle the above 2 cases. at the end of emulating treclaim., the correct TAR val need to be loaded into reg if FSCR_TAR bit is on. at the beginning of emulating trechkpt., TAR needs to be flushed so that the right tar val can be copy into tar_tm. Tested with: tools/testing/selftests/powerpc/tm/tm-tar tools/testing/selftests/powerpc/ptrace/ptrace-tm-tar (remove DSCR/PPR related testing). Signed-off-by: Simon Guo <wei.guo.simon@xxxxxxxxx> --- arch/powerpc/include/asm/kvm_book3s.h | 1 + arch/powerpc/kvm/book3s_emulate.c | 4 ++++ arch/powerpc/kvm/book3s_pr.c | 31 +++++++++++++++++++++++++++++-- arch/powerpc/kvm/tm.S | 16 ++++++++++++++-- 4 files changed, 48 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h index 8bd454c..6635506 100644 --- a/arch/powerpc/include/asm/kvm_book3s.h +++ b/arch/powerpc/include/asm/kvm_book3s.h @@ -259,6 +259,7 @@ extern void kvmppc_copy_from_svcpu(struct kvm_vcpu *vcpu, void kvmppc_restore_tm_pr(struct kvm_vcpu *vcpu); void kvmppc_restore_tm_sprs(struct kvm_vcpu *vcpu); void kvmppc_save_tm_sprs(struct kvm_vcpu *vcpu); +void kvmppc_giveup_fac(struct kvm_vcpu *vcpu, ulong fac); #endif extern int kvm_irq_bypass; diff --git a/arch/powerpc/kvm/book3s_emulate.c b/arch/powerpc/kvm/book3s_emulate.c index 11d76be..52ae307 100644 --- a/arch/powerpc/kvm/book3s_emulate.c +++ b/arch/powerpc/kvm/book3s_emulate.c @@ -167,6 +167,9 @@ static void kvmppc_emulate_treclaim(struct kvm_vcpu *vcpu, int ra_val) mtspr(SPRN_TFIAR, vcpu->arch.tfiar); tm_disable(); preempt_enable(); + + if (vcpu->arch.shadow_fscr & FSCR_TAR) + mtspr(SPRN_TAR, vcpu->arch.tar); } static void kvmppc_emulate_trchkpt(struct kvm_vcpu *vcpu) @@ -183,6 +186,7 @@ static void kvmppc_emulate_trchkpt(struct kvm_vcpu *vcpu) * copy. */ kvmppc_giveup_ext(vcpu, MSR_VSX); + kvmppc_giveup_fac(vcpu, FSCR_TAR_LG); kvmppc_copyto_vcpu_tm(vcpu); kvmppc_restore_tm_pr(vcpu); preempt_enable(); diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index cc568bc..9085524 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -56,7 +56,6 @@ static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr, ulong msr); static int kvmppc_load_ext(struct kvm_vcpu *vcpu, ulong msr); -static void kvmppc_giveup_fac(struct kvm_vcpu *vcpu, ulong fac); /* Some compatibility defines */ #ifdef CONFIG_PPC_BOOK3S_32 @@ -306,6 +305,7 @@ void kvmppc_save_tm_pr(struct kvm_vcpu *vcpu) vcpu->arch.save_msr_tm |= (vcpu->arch.guest_owned_ext & (MSR_FP | MSR_VEC | MSR_VSX)); + kvmppc_giveup_fac(vcpu, FSCR_TAR_LG); kvmppc_giveup_ext(vcpu, MSR_VSX); preempt_disable(); @@ -320,8 +320,20 @@ void kvmppc_restore_tm_pr(struct kvm_vcpu *vcpu) return; } + preempt_disable(); _kvmppc_restore_tm_pr(vcpu, vcpu->arch.save_msr_tm); + + if (!(vcpu->arch.shadow_fscr & FSCR_TAR)) { + /* always restore TAR in TM active state, since we don't + * want to be confused at fac unavailable while TM active: + * load vcpu->arch.tar or vcpu->arch.tar_tm as chkpt value? + */ + current->thread.tar = mfspr(SPRN_TAR); + mtspr(SPRN_TAR, vcpu->arch.tar); + vcpu->arch.shadow_fscr |= FSCR_TAR; + } + preempt_enable(); if (vcpu->arch.save_msr_tm & MSR_VSX) @@ -333,6 +345,7 @@ void kvmppc_restore_tm_pr(struct kvm_vcpu *vcpu) if (vcpu->arch.save_msr_tm & MSR_FP) kvmppc_load_ext(vcpu, MSR_FP); } + } #endif @@ -828,7 +841,7 @@ void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr) } /* Give up facility (TAR / EBB / DSCR) */ -static void kvmppc_giveup_fac(struct kvm_vcpu *vcpu, ulong fac) +void kvmppc_giveup_fac(struct kvm_vcpu *vcpu, ulong fac) { #ifdef CONFIG_PPC_BOOK3S_64 if (!(vcpu->arch.shadow_fscr & (1ULL << fac))) { @@ -1031,6 +1044,20 @@ static int kvmppc_handle_fac(struct kvm_vcpu *vcpu, ulong fac) switch (fac) { case FSCR_TAR_LG: + if (MSR_TM_ACTIVE(mfmsr())) { + /* When tbegin. was executed, the TAR in checkpoint + * state might be invalid. We need treclaim., then + * load correct TAR value, and perform trechkpt., + * so that valid TAR val can be checkpointed. + */ + preempt_disable(); + kvmppc_save_tm_pr(vcpu); + + vcpu->arch.tar_tm = vcpu->arch.tar; + + kvmppc_restore_tm_pr(vcpu); + preempt_enable(); + } /* TAR switching isn't lazy in Linux yet */ current->thread.tar = mfspr(SPRN_TAR); mtspr(SPRN_TAR, vcpu->arch.tar); diff --git a/arch/powerpc/kvm/tm.S b/arch/powerpc/kvm/tm.S index 5752bae..8b73af4 100644 --- a/arch/powerpc/kvm/tm.S +++ b/arch/powerpc/kvm/tm.S @@ -164,13 +164,16 @@ _GLOBAL(_kvmppc_save_tm_pr) mfmsr r5 SAVE_GPR(5, r1) - /* also save DSCR/CR so that it can be recovered later */ + /* also save DSCR/CR/TAR so that it can be recovered later */ mfspr r6, SPRN_DSCR SAVE_GPR(6, r1) mfcr r7 stw r7, _CCR(r1) + mfspr r8, SPRN_TAR + SAVE_GPR(8, r1) + /* allocate stack frame for __kvmppc_save_tm since * it will save LR into its stackframe and we don't * want to corrupt _kvmppc_save_tm_pr's. @@ -179,6 +182,9 @@ _GLOBAL(_kvmppc_save_tm_pr) bl __kvmppc_save_tm addi r1, r1, PPC_MIN_STKFRM + REST_GPR(8, r1) + mtspr SPRN_TAR, r8 + ld r7, _CCR(r1) mtcr r7 @@ -341,13 +347,16 @@ _GLOBAL(_kvmppc_restore_tm_pr) mfmsr r5 SAVE_GPR(5, r1) - /* also save DSCR/CR so that it can be recovered later */ + /* also save DSCR/CR/TAR so that it can be recovered later */ mfspr r6, SPRN_DSCR SAVE_GPR(6, r1) mfcr r7 stw r7, _CCR(r1) + mfspr r8, SPRN_TAR + SAVE_GPR(8, r1) + /* allocate stack frame for __kvmppc_restore_tm since * it will save LR into its own stackframe. */ @@ -356,6 +365,9 @@ _GLOBAL(_kvmppc_restore_tm_pr) bl __kvmppc_restore_tm addi r1, r1, PPC_MIN_STKFRM + REST_GPR(8, r1) + mtspr SPRN_TAR, r8 + ld r7, _CCR(r1) mtcr r7 -- 1.8.3.1 -- To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html