From: Rusty Russell <[email protected]>

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 <[email protected]>
---
 arch/arm/kvm/emulate.c |   80 ++++++++++++++++++++++++++----------------------
 1 file changed, 43 insertions(+), 37 deletions(-)

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;
-- 
1.7.10.4

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

Reply via email to