diff mbox

[02/10] kvm: split out instruction decode from emulation.

Message ID 1351077923-17977-3-git-send-email-rusty@rustcorp.com.au (mailing list archive)
State New, archived
Headers show

Commit Message

Rusty Russell Oct. 24, 2012, 11:25 a.m. UTC
From: Rusty Russell <rusty.russell@linaro.org>

This adds more fields which we need to store in the struct arm_insn,
so execute() knows what to do.

Signed-off-by: Rusty Russell <rusty.russell@linaro.org>
---
 arch/arm/kvm/emulate.c |   80 ++++++++++++++++++++++++++----------------------
 1 file changed, 43 insertions(+), 37 deletions(-)
diff mbox

Patch

diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c
index e4fc12b..05b534f 100644
--- a/arch/arm/kvm/emulate.c
+++ b/arch/arm/kvm/emulate.c
@@ -303,11 +303,12 @@  struct arm_insn {
 	u8 type;
 	u8 Rt, Rn, Rm;
 	u8 shift_n;
+	u32 offset_addr;
 
 	/* Common decoding */
 	u8 len;
 	bool sign_extend;
-	bool w;
+	bool w, W, U, P;
 };
 
 struct arm_decode {
@@ -315,7 +316,7 @@  struct arm_decode {
 	u32 opc;
 	u32 opc_mask;
 
-	bool (*decode)(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
+	bool (*decode)(struct kvm_vcpu *vcpu,
 		       unsigned long instr, struct arm_insn *ai);
 
 	struct arm_insn template;
@@ -385,31 +386,24 @@  u32 shift(u32 value, u8 N, enum SRType type, u8 amount, bool carry_in)
 	return value & mask;
 }
 
-static bool decode_arm_wb(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
-			  unsigned long instr, const struct arm_insn *ai)
+static bool decode_arm_wb(struct kvm_vcpu *vcpu, unsigned long instr,
+			  struct arm_insn *ai)
 {
-	u8 Rt = (instr >> 12) & 0xf;
-	u8 Rn = (instr >> 16) & 0xf;
-	u8 W = (instr >> 21) & 1;
-	u8 U = (instr >> 23) & 1;
-	u8 P = (instr >> 24) & 1;
-	u32 base_addr = *vcpu_reg(vcpu, Rn);
-	u32 offset_addr, offset;
+	u32 base_addr, offset;
 
-	/*
-	 * Technically this is allowed in certain circumstances,
-	 * but we don't support it.
-	 */
-	if (Rt == 15 || Rn == 15)
-		return false;
+	ai->Rt = (instr >> 12) & 0xf;
+	ai->Rn = (instr >> 16) & 0xf;
+	ai->W = (instr >> 21) & 1;
+	ai->U = (instr >> 23) & 1;
+	ai->P = (instr >> 24) & 1;
+
+	base_addr = *vcpu_reg(vcpu, ai->Rn);
 
-	if (P && !W) {
+	if (ai->P && !ai->W) {
 		kvm_err("Decoding operation with valid ISV?\n");
 		return false;
 	}
 
-	vcpu->arch.mmio.rd = Rt;
-
 	if (ai->register_form) {
 		/* Register operation */
 		enum SRType s_type;
@@ -425,46 +419,56 @@  static bool decode_arm_wb(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
 	}
 
 	/* Handle Writeback */
-	if (U)
-		offset_addr = base_addr + offset;
+	if (ai->U)
+		ai->offset_addr = base_addr + offset;
 	else
-		offset_addr = base_addr - offset;
-	*vcpu_reg(vcpu, Rn) = offset_addr;
+		ai->offset_addr = base_addr - offset;
 	return true;
 }
 
-static bool decode_arm_ls(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
+static bool decode_arm_ls(struct kvm_vcpu *vcpu,
 			  unsigned long instr, struct arm_insn *ai)
 {
 	u8 A = (instr >> 25) & 1;
 
-	mmio->is_write = ai->w;
-	mmio->len = ai->len;
-	vcpu->arch.mmio.sign_extend = false;
-
 	ai->register_form = A;
 	ai->imm = instr & 0xfff;
 	ai->Rm = instr & 0xf;
 	ai->type = (instr >> 5) & 0x3;
 	ai->shift_n = (instr >> 7) & 0x1f;
 
-	return decode_arm_wb(vcpu, mmio, instr, ai);
+	return decode_arm_wb(vcpu, instr, ai);
 }
 
-static bool decode_arm_extra(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
+static bool decode_arm_extra(struct kvm_vcpu *vcpu,
 			     unsigned long instr, struct arm_insn *ai)
 {
-	mmio->is_write = ai->w;
-	mmio->len = ai->len;
-	vcpu->arch.mmio.sign_extend = ai->sign_extend;
-
 	ai->register_form = !((instr >> 22) & 1);
 	ai->imm = ((instr >> 4) & 0xf0) | (instr & 0xf);
 	ai->Rm = instr & 0xf;
 	ai->type = 0; /* SRType_LSL */
 	ai->shift_n = 0;
 
-	return decode_arm_wb(vcpu, mmio, instr, ai);
+	return decode_arm_wb(vcpu, instr, ai);
+}
+
+static bool execute(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
+		    const struct arm_insn *ai)
+{
+	/*
+	 * Technically this is allowed in certain circumstances,
+	 * but we don't support it.
+	 */
+	if (ai->Rt == 15 || ai->Rn == 15)
+		return false;
+
+	mmio->is_write = ai->w;
+	mmio->len = ai->len;
+	vcpu->arch.mmio.sign_extend = ai->sign_extend;
+
+	vcpu->arch.mmio.rd = ai->Rt;
+	*vcpu_reg(vcpu, ai->Rn) = ai->offset_addr;
+	return true;
 }
 
 /*
@@ -553,7 +557,9 @@  static bool kvm_decode_arm_ls(struct kvm_vcpu *vcpu, unsigned long instr,
 		const struct arm_decode *d = &arm_decode[i];
 		if ((instr & d->opc_mask) == d->opc) {
 			struct arm_insn ai = d->template;
-			return d->decode(vcpu, mmio, instr, &ai);
+			if (!d->decode(vcpu, instr, &ai))
+				return false;
+			return execute(vcpu, mmio, &ai);
 		}
 	}
 	return false;