KVM: PPC: Book3S PR: Add emulation for trechkpt.
authorSimon Guo <wei.guo.simon@gmail.com>
Wed, 23 May 2018 07:02:04 +0000 (15:02 +0800)
committerPaul Mackerras <paulus@ozlabs.org>
Fri, 1 Jun 2018 00:30:23 +0000 (10:30 +1000)
This patch adds host emulation when guest PR KVM executes "trechkpt.",
which is a privileged instruction and will trap into host.

We firstly copy vcpu ongoing content into vcpu tm checkpoint
content, then perform kvmppc_restore_tm_pr() to do trechkpt.
with updated vcpu tm checkpoint values.

Signed-off-by: Simon Guo <wei.guo.simon@gmail.com>
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
arch/powerpc/include/asm/kvm_book3s.h
arch/powerpc/kvm/book3s_emulate.c
arch/powerpc/kvm/book3s_pr.c

index c1cea8222d516647df975ce1df2167180a8e92af..2940de7bac0822b9b1d3b115c650e5b3f52f2d9a 100644 (file)
@@ -262,10 +262,12 @@ extern void kvmppc_copy_from_svcpu(struct kvm_vcpu *vcpu);
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
 void kvmppc_save_tm_pr(struct kvm_vcpu *vcpu);
 void kvmppc_restore_tm_pr(struct kvm_vcpu *vcpu);
+void kvmppc_save_tm_sprs(struct kvm_vcpu *vcpu);
 void kvmppc_restore_tm_sprs(struct kvm_vcpu *vcpu);
 #else
 static inline void kvmppc_save_tm_pr(struct kvm_vcpu *vcpu) {}
 static inline void kvmppc_restore_tm_pr(struct kvm_vcpu *vcpu) {}
+static inline void kvmppc_save_tm_sprs(struct kvm_vcpu *vcpu) {}
 static inline void kvmppc_restore_tm_sprs(struct kvm_vcpu *vcpu) {}
 #endif
 
index 04c29e01b391cec5413e7d6907916cc4fc22aaaf..b7530cf58834c87189ca1f86f5558462322d26a2 100644 (file)
@@ -52,6 +52,7 @@
 #define OP_31_XOP_TBEGIN       654
 
 #define OP_31_XOP_TRECLAIM     942
+#define OP_31_XOP_TRCHKPT      1006
 
 /* DCBZ is actually 1014, but we patch it to 1010 so we get a trap */
 #define OP_31_XOP_DCBZ         1010
@@ -172,6 +173,29 @@ static void kvmppc_emulate_treclaim(struct kvm_vcpu *vcpu, int ra_val)
        kvmppc_set_msr(vcpu, guest_msr);
        preempt_enable();
 }
+
+static void kvmppc_emulate_trchkpt(struct kvm_vcpu *vcpu)
+{
+       unsigned long guest_msr = kvmppc_get_msr(vcpu);
+
+       preempt_disable();
+       /*
+        * need flush FP/VEC/VSX to vcpu save area before
+        * copy.
+        */
+       kvmppc_giveup_ext(vcpu, MSR_VSX);
+       kvmppc_copyto_vcpu_tm(vcpu);
+       kvmppc_save_tm_sprs(vcpu);
+
+       /*
+        * as a result of trecheckpoint. set TS to suspended.
+        */
+       guest_msr &= ~(MSR_TS_MASK);
+       guest_msr |= MSR_TS_S;
+       kvmppc_set_msr(vcpu, guest_msr);
+       kvmppc_restore_tm_pr(vcpu);
+       preempt_enable();
+}
 #endif
 
 int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
@@ -478,6 +502,43 @@ int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
                        kvmppc_emulate_treclaim(vcpu, ra_val);
                        break;
                }
+               case OP_31_XOP_TRCHKPT:
+               {
+                       ulong guest_msr = kvmppc_get_msr(vcpu);
+                       unsigned long texasr;
+
+                       if (!cpu_has_feature(CPU_FTR_TM))
+                               break;
+
+                       if (!(kvmppc_get_msr(vcpu) & MSR_TM)) {
+                               kvmppc_trigger_fac_interrupt(vcpu, FSCR_TM_LG);
+                               emulated = EMULATE_AGAIN;
+                               break;
+                       }
+
+                       /* generate interrupt based on priorities */
+                       if (guest_msr & MSR_PR) {
+                               /* Privileged Instruction type Program Intr */
+                               kvmppc_core_queue_program(vcpu, SRR1_PROGPRIV);
+                               emulated = EMULATE_AGAIN;
+                               break;
+                       }
+
+                       tm_enable();
+                       texasr = mfspr(SPRN_TEXASR);
+                       tm_disable();
+
+                       if (MSR_TM_ACTIVE(guest_msr) ||
+                               !(texasr & (TEXASR_FS))) {
+                               /* TM bad thing interrupt */
+                               kvmppc_core_queue_program(vcpu, SRR1_PROGTM);
+                               emulated = EMULATE_AGAIN;
+                               break;
+                       }
+
+                       kvmppc_emulate_trchkpt(vcpu);
+                       break;
+               }
 #endif
                default:
                        emulated = EMULATE_FAIL;
index bb9209947db9563b9d2a5d5aebe0f37256019f74..a275f8b3a4a09ed018bf88f6df437078d7ca8b68 100644 (file)
@@ -299,7 +299,7 @@ out:
 }
 
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-static inline void kvmppc_save_tm_sprs(struct kvm_vcpu *vcpu)
+void kvmppc_save_tm_sprs(struct kvm_vcpu *vcpu)
 {
        tm_enable();
        vcpu->arch.tfhar = mfspr(SPRN_TFHAR);