From: Simon Guo <wei.guo.si...@gmail.com>

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.si...@gmail.com>
---
 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

Reply via email to