[PATCH 08/33] KVM: PPC: Introduce emulation for unprivileged instructions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



We want to be able to emulate instructions during phases where we can't
run the guest in guest context, such as the "critical section" phase
in our magic page helpers.

Add an emulation helper for that case that allows us to emulate both
privileged and unprivileged instructions.

Signed-off-by: Alexander Graf <agraf@xxxxxxx>
---
 arch/powerpc/include/asm/kvm_ppc.h |  1 +
 arch/powerpc/kvm/emulate.c         | 55 +++++++++++++++++++++++++++++++++++---
 2 files changed, 52 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index ad8a1d7..b141eae 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -78,6 +78,7 @@ extern int kvmppc_st(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr,
 		     bool data);
 extern int kvmppc_emulate_instruction(struct kvm_run *run,
                                       struct kvm_vcpu *vcpu);
+extern int kvmppc_emulate_any_instruction(struct kvm_vcpu *vcpu);
 extern int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu);
 extern int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu);
 extern void kvmppc_emulate_dec(struct kvm_vcpu *vcpu);
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
index c92476e..7bf247e0 100644
--- a/arch/powerpc/kvm/emulate.c
+++ b/arch/powerpc/kvm/emulate.c
@@ -209,14 +209,13 @@ static int kvmppc_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
 
 /* XXX Should probably auto-generate instruction decoding for a particular core
  * from opcode tables in the future. */
-int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
+static int kvmppc_emulate_priv_instruction(struct kvm_vcpu *vcpu, int *advance)
 {
 	u32 inst = kvmppc_get_last_inst(vcpu);
 	int rs = get_rs(inst);
 	int rt = get_rt(inst);
 	int sprn = get_sprn(inst);
 	enum emulation_result emulated = EMULATE_DONE;
-	int advance = 1;
 
 	/* this default type might be overwritten by subcategories */
 	kvmppc_set_exit_type(vcpu, EMULATED_INST_EXITS);
@@ -232,7 +231,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
 		kvmppc_core_queue_program(vcpu,
 					  vcpu->arch.shared->esr | ESR_PTR);
 #endif
-		advance = 0;
+		*advance = 0;
 		break;
 
 	case 31:
@@ -248,7 +247,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
 			kvmppc_core_queue_program(vcpu,
 					vcpu->arch.shared->esr | ESR_PTR);
 #endif
-			advance = 0;
+			*advance = 0;
 			break;
 
 		case OP_31_XOP_MFSPR:
@@ -272,6 +271,17 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
 		emulated = EMULATE_FAIL;
 	}
 
+	return emulated;
+}
+
+/* Emulates privileged instructions only */
+int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
+{
+	u32 inst = kvmppc_get_last_inst(vcpu);
+	enum emulation_result emulated;
+	int advance = 1;
+
+	emulated = kvmppc_emulate_priv_instruction(vcpu, &advance);
 	if (emulated == EMULATE_FAIL) {
 		emulated = vcpu->kvm->arch.kvm_ops->emulate_op(run, vcpu, inst,
 							       &advance);
@@ -294,3 +304,40 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
 	return emulated;
 }
 EXPORT_SYMBOL_GPL(kvmppc_emulate_instruction);
+
+/* Emulates privileged and non-privileged instructions */
+int kvmppc_emulate_any_instruction(struct kvm_vcpu *vcpu)
+{
+	u32 inst = kvmppc_get_last_inst(vcpu);
+	enum emulation_result emulated = EMULATE_DONE;
+	int advance = 1;
+
+	kvmppc_set_exit_type(vcpu, EMULATED_INST_EXITS);
+
+	/* Try non-privileged instructions */
+	switch (get_op(inst)) {
+	default:
+		emulated = EMULATE_FAIL;
+	}
+
+	/* Try privileged instructions */
+	if (emulated == EMULATE_FAIL)
+		emulated = kvmppc_emulate_priv_instruction(vcpu, &advance);
+
+	if (emulated == EMULATE_AGAIN) {
+		advance = 0;
+	} else if (emulated == EMULATE_FAIL) {
+		advance = 0;
+		printk(KERN_ERR "Couldn't emulate instruction 0x%08x "
+		       "(op %d xop %d)\n", inst, get_op(inst), get_xop(inst));
+		kvmppc_core_queue_program(vcpu, 0);
+	}
+
+	trace_kvm_ppc_instr(inst, kvmppc_get_pc(vcpu), emulated);
+
+	/* Advance past emulated instruction. */
+	if (advance)
+		kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) + 4);
+
+	return emulated;
+}
-- 
1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux