summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorSimon Guo <wei.guo.simon@gmail.com>2018-05-23 15:02:00 +0800
committerPaul Mackerras <paulus@ozlabs.org>2018-06-01 10:30:05 +1000
commit533082ae86e2f1ff6cb9eca7a25202a81fc0567e (patch)
tree73670cd71af29f9ead14ab83432eb64fbf3ca7c5 /arch
parent13989b65ebb74c05c577dbbcc111e1fdd7da763a (diff)
downloadlinux-533082ae86e2f1ff6cb9eca7a25202a81fc0567e.tar.bz2
KVM: PPC: Book3S PR: Emulate mtspr/mfspr using active TM SPRs
The mfspr/mtspr on TM SPRs(TEXASR/TFIAR/TFHAR) are non-privileged instructions and can be executed by PR KVM guest in problem state without trapping into the host. We only emulate mtspr/mfspr texasr/tfiar/tfhar in guest PR=0 state. When we are emulating mtspr tm sprs in guest PR=0 state, the emulation result needs to be visible to guest PR=1 state. That is, the actual TM SPR val should be loaded into actual registers. We already flush TM SPRs into vcpu when switching out of CPU, and load TM SPRs when switching back. This patch corrects mfspr()/mtspr() emulation for TM SPRs to make the actual source/dest be the actual TM SPRs. Signed-off-by: Simon Guo <wei.guo.simon@gmail.com> Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/include/asm/kvm_book3s.h1
-rw-r--r--arch/powerpc/kvm/book3s_emulate.c58
-rw-r--r--arch/powerpc/kvm/book3s_pr.c2
3 files changed, 50 insertions, 11 deletions
diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h
index fc15ad9dfc3b..43e8bb18c2d7 100644
--- a/arch/powerpc/include/asm/kvm_book3s.h
+++ b/arch/powerpc/include/asm/kvm_book3s.h
@@ -210,6 +210,7 @@ extern void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec)
extern void kvmppc_book3s_dequeue_irqprio(struct kvm_vcpu *vcpu,
unsigned int vec);
extern void kvmppc_inject_interrupt(struct kvm_vcpu *vcpu, int vec, u64 flags);
+extern void kvmppc_trigger_fac_interrupt(struct kvm_vcpu *vcpu, ulong fac);
extern void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat,
bool upper, u32 val);
extern void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr);
diff --git a/arch/powerpc/kvm/book3s_emulate.c b/arch/powerpc/kvm/book3s_emulate.c
index f81a921e0865..c4e3ec63f253 100644
--- a/arch/powerpc/kvm/book3s_emulate.c
+++ b/arch/powerpc/kvm/book3s_emulate.c
@@ -24,6 +24,7 @@
#include <asm/switch_to.h>
#include <asm/time.h>
#include "book3s.h"
+#include <asm/asm-prototypes.h>
#define OP_19_XOP_RFID 18
#define OP_19_XOP_RFI 50
@@ -523,13 +524,38 @@ int kvmppc_core_emulate_mtspr_pr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
break;
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
case SPRN_TFHAR:
- vcpu->arch.tfhar = spr_val;
- break;
case SPRN_TEXASR:
- vcpu->arch.texasr = spr_val;
- break;
case SPRN_TFIAR:
- vcpu->arch.tfiar = spr_val;
+ 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;
+ }
+
+ if (MSR_TM_ACTIVE(kvmppc_get_msr(vcpu)) &&
+ !((MSR_TM_SUSPENDED(kvmppc_get_msr(vcpu))) &&
+ (sprn == SPRN_TFHAR))) {
+ /* it is illegal to mtspr() TM regs in
+ * other than non-transactional state, with
+ * the exception of TFHAR in suspend state.
+ */
+ kvmppc_core_queue_program(vcpu, SRR1_PROGTM);
+ emulated = EMULATE_AGAIN;
+ break;
+ }
+
+ tm_enable();
+ if (sprn == SPRN_TFHAR)
+ mtspr(SPRN_TFHAR, spr_val);
+ else if (sprn == SPRN_TEXASR)
+ mtspr(SPRN_TEXASR, spr_val);
+ else
+ mtspr(SPRN_TFIAR, spr_val);
+ tm_disable();
+
break;
#endif
#endif
@@ -676,13 +702,25 @@ int kvmppc_core_emulate_mfspr_pr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val
break;
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
case SPRN_TFHAR:
- *spr_val = vcpu->arch.tfhar;
- break;
case SPRN_TEXASR:
- *spr_val = vcpu->arch.texasr;
- break;
case SPRN_TFIAR:
- *spr_val = vcpu->arch.tfiar;
+ 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;
+ }
+
+ tm_enable();
+ if (sprn == SPRN_TFHAR)
+ *spr_val = mfspr(SPRN_TFHAR);
+ else if (sprn == SPRN_TEXASR)
+ *spr_val = mfspr(SPRN_TEXASR);
+ else if (sprn == SPRN_TFIAR)
+ *spr_val = mfspr(SPRN_TFIAR);
+ tm_disable();
break;
#endif
#endif
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index dcb577fde9cd..c0f45c83f683 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -918,7 +918,7 @@ static void kvmppc_handle_lost_ext(struct kvm_vcpu *vcpu)
#ifdef CONFIG_PPC_BOOK3S_64
-static void kvmppc_trigger_fac_interrupt(struct kvm_vcpu *vcpu, ulong fac)
+void kvmppc_trigger_fac_interrupt(struct kvm_vcpu *vcpu, ulong fac)
{
/* Inject the Interrupt Cause field and trigger a guest interrupt */
vcpu->arch.fscr &= ~(0xffULL << 56);