From e32c53d1cf0022af180548474f4c29c189d37d93 Mon Sep 17 00:00:00 2001 From: Simon Guo Date: Wed, 23 May 2018 15:02:04 +0800 Subject: KVM: PPC: Book3S PR: Add emulation for trechkpt. 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 Signed-off-by: Paul Mackerras --- arch/powerpc/kvm/book3s_emulate.c | 61 +++++++++++++++++++++++++++++++++++++++ arch/powerpc/kvm/book3s_pr.c | 2 +- 2 files changed, 62 insertions(+), 1 deletion(-) (limited to 'arch/powerpc/kvm') diff --git a/arch/powerpc/kvm/book3s_emulate.c b/arch/powerpc/kvm/book3s_emulate.c index 04c29e01b391..b7530cf58834 100644 --- a/arch/powerpc/kvm/book3s_emulate.c +++ b/arch/powerpc/kvm/book3s_emulate.c @@ -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; diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index bb9209947db9..a275f8b3a4a0 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -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); -- cgit v1.2.3