From: Rusty Russell <rusty.russ...@linaro.org>

We add some callbacks and use them instead of using struct kvm_vcpu or
vcpu_reg() directly.  We also remove the kvm_ prefixes, and call the
top-level function decode_insn() instead of kvm_decode().

Signed-off-by: Rusty Russell <rusty.russ...@linaro.org>
---
 arch/arm/include/asm/opcodes.h |   38 ++++
 arch/arm/kernel/opcodes.c      |  438 +++++++++++++++++++++++++++++++++++++
 arch/arm/kvm/emulate.c         |  473 +---------------------------------------
 3 files changed, 484 insertions(+), 465 deletions(-)

diff --git a/arch/arm/include/asm/opcodes.h b/arch/arm/include/asm/opcodes.h
index 74e211a..7ceb7fb 100644
--- a/arch/arm/include/asm/opcodes.h
+++ b/arch/arm/include/asm/opcodes.h
@@ -11,6 +11,44 @@
 
 #ifndef __ASSEMBLY__
 extern asmlinkage unsigned int arm_check_condition(u32 opcode, u32 psr);
+
+struct arm_insn {
+       /* Encoded instruction. */
+       u32 instr;
+
+       /* Decoding for the register write back */
+       bool register_form;
+       u32 imm;
+       u8 type;
+       u8 Rt, Rn, Rm, Rd;
+       u8 shift_n;
+       u32 offset_addr;
+
+       /* Common decoding */
+       u8 len;
+       bool sign_extend;
+       bool w, W, U, P;
+
+       /* Thumb encoding */
+       bool is_thumb, is_thumb32;
+       union {
+               struct {
+                       u8 opcode;
+                       u8 mask;
+               } t16;
+
+               struct {
+                       u8 op1;
+                       u8 op2;
+                       u8 op2_mask;
+               } t32;
+       };
+};
+
+int decode_insn(struct arm_insn *ai, unsigned long pc, u32 psr,
+               int (*copy_from)(void *dst, unsigned long addr, size_t, void *),
+               u32 (*get_regval)(int reg, void *),
+               void *priv);
 #endif
 
 #define ARM_OPCODE_CONDTEST_FAIL   0
diff --git a/arch/arm/kernel/opcodes.c b/arch/arm/kernel/opcodes.c
index f8179c6..b6c7940 100644
--- a/arch/arm/kernel/opcodes.c
+++ b/arch/arm/kernel/opcodes.c
@@ -70,3 +70,441 @@ asmlinkage unsigned int arm_check_condition(u32 opcode, u32 
psr)
        return ret;
 }
 EXPORT_SYMBOL_GPL(arm_check_condition);
+
+/******************************************************************************
+ * Load-Store instruction emulation
+ *****************************************************************************/
+enum SRType {
+       SRType_LSL,
+       SRType_LSR,
+       SRType_ASR,
+       SRType_ROR,
+       SRType_RRX
+};
+
+struct arm_decode {
+       /* Instruction decoding */
+       u32 opc;
+       u32 opc_mask;
+
+       bool (*decode)(struct arm_insn *ai, u32 psr,
+                      u32 (*get_regval)(int reg, void *priv), void *priv);
+
+       struct arm_insn template;
+};
+
+/* Modelled after DecodeImmShift() in the ARM ARM */
+enum SRType decode_imm_shift(u8 type, u8 imm5, u8 *amount)
+{
+       switch (type) {
+       case 0x0:
+               *amount = imm5;
+               return SRType_LSL;
+       case 0x1:
+               *amount = (imm5 == 0) ? 32 : imm5;
+               return SRType_LSR;
+       case 0x2:
+               *amount = (imm5 == 0) ? 32 : imm5;
+               return SRType_ASR; 
+       case 0x3:
+               if (imm5 == 0) {
+                       *amount = 1;
+                       return SRType_RRX;
+               } else {
+                       *amount = imm5;
+                       return SRType_ROR;
+               }
+       }
+
+       return SRType_LSL;
+}
+
+/* Modelled after Shift() in the ARM ARM */
+u32 shift(u32 value, u8 N, enum SRType type, u8 amount, bool carry_in)
+{
+       u32 mask = (1 << N) - 1;
+       s32 svalue = (s32)value;
+
+       BUG_ON(N > 32);
+       BUG_ON(type == SRType_RRX && amount != 1);
+       BUG_ON(amount > N);
+
+       if (amount == 0)
+               return value;
+
+       switch (type) {
+       case SRType_LSL:
+               value <<= amount;
+               break;
+       case SRType_LSR:
+                value >>= amount;
+               break;
+       case SRType_ASR:
+               if (value & (1 << (N - 1)))
+                       svalue |= ((-1UL) << N);
+               value = svalue >> amount;
+               break;
+       case SRType_ROR:
+               value = (value >> amount) | (value << (N - amount));
+               break;
+       case SRType_RRX: {
+               u32 C = (carry_in) ? 1 : 0;
+               value = (value >> 1) | (C << (N - 1));
+               break;
+       }
+       }
+
+       return value & mask;
+}
+
+static bool decode_arm_wb(struct arm_insn *ai, u32 psr,
+                         u32 (*get_regval)(int reg, void *priv), void *priv)
+{
+       u32 base_addr, offset;
+
+       ai->Rt = (ai->instr >> 12) & 0xf;
+       ai->Rn = (ai->instr >> 16) & 0xf;
+       ai->W = (ai->instr >> 21) & 1;
+       ai->U = (ai->instr >> 23) & 1;
+       ai->P = (ai->instr >> 24) & 1;
+
+       base_addr = get_regval(ai->Rn, priv);
+
+       if (ai->P && !ai->W) {
+               pr_err("Decoding operation with valid ISV?\n");
+               return false;
+       }
+
+       if (ai->register_form) {
+               /* Register operation */
+               enum SRType s_type;
+               u8 shift_n;
+               bool c_bit = psr & PSR_C_BIT;
+               u32 s_reg = get_regval(ai->Rm, priv);
+
+               s_type = decode_imm_shift(ai->type, ai->shift_n, &shift_n);
+               offset = shift(s_reg, 5, s_type, shift_n, c_bit);
+       } else {
+               /* Immediate operation */
+               offset = ai->imm;
+       }
+
+       /* Handle Writeback */
+       if (ai->U)
+               ai->offset_addr = base_addr + offset;
+       else
+               ai->offset_addr = base_addr - offset;
+       return true;
+}
+
+static bool decode_arm_ls(struct arm_insn *ai, u32 psr,
+                         u32 (*get_regval)(int reg, void *priv), void *priv)
+{
+       u8 A = (ai->instr >> 25) & 1;
+
+       ai->register_form = A;
+       ai->imm = ai->instr & 0xfff;
+       ai->Rm = ai->instr & 0xf;
+       ai->type = (ai->instr >> 5) & 0x3;
+       ai->shift_n = (ai->instr >> 7) & 0x1f;
+
+       return decode_arm_wb(ai, psr, get_regval, priv);
+}
+
+static bool decode_arm_extra(struct arm_insn *ai, u32 psr,
+                            u32 (*get_regval)(int reg, void *priv), void *priv)
+{
+       ai->register_form = !((ai->instr >> 22) & 1);
+       ai->imm = ((ai->instr >> 4) & 0xf0) | (ai->instr & 0xf);
+       ai->Rm = ai->instr & 0xf;
+       ai->type = 0; /* SRType_LSL */
+       ai->shift_n = 0;
+
+       return decode_arm_wb(ai, psr, get_regval, priv);
+}
+
+/*
+ * The encodings in this table assumes that a fault was generated where the
+ * ISV field in the HSR was clear, and the decoding information was invalid,
+ * which means that a register write-back occurred, the PC was used as the
+ * destination or a load/store multiple operation was used. Since the latter
+ * two cases are crazy for MMIO on the guest side, we simply inject a fault
+ * when this happens and support the common case.
+ *
+ * We treat unpriviledged loads and stores of words and bytes like all other
+ * loads and stores as their encodings mandate the W bit set and the P bit
+ * clear.
+ */
+static const struct arm_decode arm_decode[] = {
+       /**************** Load/Store Word and Byte **********************/
+       /* Store word with writeback */
+       { .opc = 0x04000000, .opc_mask = 0x0c500000,
+         .decode = decode_arm_ls,
+         .template =  { .len = 4, .w = true, .sign_extend = false, }, },
+       /* Store byte with writeback */
+       { .opc = 0x04400000, .opc_mask = 0x0c500000,
+         .decode = decode_arm_ls,
+         .template = {  .len = 1, .w = true, .sign_extend = false, }, },
+       /* Load word with writeback */
+       { .opc = 0x04100000, .opc_mask = 0x0c500000,
+         .decode = decode_arm_ls,
+         .template = {  .len = 4, .w = false, .sign_extend = false, }, },
+       /* Load byte with writeback */
+       { .opc = 0x04500000, .opc_mask = 0x0c500000,
+         .decode = decode_arm_ls,
+         .template = { .len = 1, .w = false, .sign_extend = false, }, },
+
+       /*************** Extra load/store instructions ******************/
+
+       /* Store halfword with writeback */
+       { .opc = 0x000000b0, .opc_mask = 0x0c1000f0,
+         .decode = decode_arm_extra,
+         .template = { .len = 2, .w = true, .sign_extend = false, }, },
+       /* Load halfword with writeback */
+       { .opc = 0x001000b0, .opc_mask = 0x0c1000f0, 
+         .decode = decode_arm_extra,
+         .template = { .len = 2, .w = false, .sign_extend = false, }, },
+       /* Load dual with writeback */
+       { .opc = 0x000000d0, .opc_mask = 0x0c1000f0,
+         .decode = decode_arm_extra,
+         .template = { .len = 8, .w = false, .sign_extend = false, }, },
+       /* Load signed byte with writeback */
+       { .opc = 0x001000d0, .opc_mask = 0x0c1000f0,
+         .decode = decode_arm_extra,
+         .template = { .len = 1, .w = false, .sign_extend = true, }, },
+
+       /* Store dual with writeback */
+       { .opc = 0x000000f0, .opc_mask = 0x0c1000f0,
+         .decode = decode_arm_extra,
+         .template = { .len = 8, .w = true, .sign_extend = false, }, },
+       /* Load signed halfword with writeback */
+       { .opc = 0x001000f0, .opc_mask = 0x0c1000f0,
+         .decode = decode_arm_extra,
+         .template = { .len = 2, .w = false, .sign_extend = true, }, },
+
+       /* Store halfword unprivileged */
+       { .opc = 0x002000b0, .opc_mask = 0x0f3000f0,
+         .decode = decode_arm_extra,
+         .template = { .len = 2, .w = true, .sign_extend = false, }, },
+       /* Load halfword unprivileged */
+       { .opc = 0x003000b0, .opc_mask = 0x0f3000f0,
+         .decode = decode_arm_extra,
+         .template = { .len = 2, .w = false, .sign_extend = false, }, },
+       /* Load signed byte unprivileged */
+       { .opc = 0x003000d0, .opc_mask = 0x0f3000f0,
+         .decode = decode_arm_extra,
+         .template = { .len = 1, .w = false, .sign_extend = true, }, },
+       /* Load signed halfword unprivileged */
+       { .opc = 0x003000d0, .opc_mask = 0x0f3000f0,
+         .decode = decode_arm_extra,
+         .template = { .len = 2, .w = false, .sign_extend = true, }, },
+};
+
+static bool decode_arm(struct arm_insn *ai, u32 psr,
+                      u32 (*get_regval)(int reg, void *), void *priv)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(arm_decode); i++) {
+               const struct arm_decode *d = &arm_decode[i];
+               if ((ai->instr & d->opc_mask) == d->opc) {
+                       ai->len = d->template.len;
+                       ai->w = d->template.w;
+                       ai->sign_extend = d->template.sign_extend;
+                       return d->decode(ai, psr, get_regval, priv);
+               }
+       }
+       return false;
+}
+
+struct thumb_decode {
+       bool is32;
+
+       union {
+               struct {
+                       u8 opcode;
+                       u8 mask;
+               } t16;
+
+               struct {
+                       u8 op1;
+                       u8 op2;
+                       u8 op2_mask;
+               } t32;
+       };
+
+       bool (*decode)(struct arm_insn *ti);
+};
+
+static bool decode_thumb_wb(struct arm_insn *ti)
+{
+       u8 imm8 = ti->instr & 0xff;
+
+       ti->P = (ti->instr >> 10) & 1;
+       ti->U = (ti->instr >> 9) & 1;
+       ti->Rn = (ti->instr >> 16) & 0xf;
+       ti->Rd = (ti->instr >> 12) & 0xf;
+
+       /* Handle Writeback: offset_addr relative to fault address. */
+       if (!ti->P && ti->U)
+               ti->offset_addr = imm8;
+       else if (!ti->P && !ti->U)
+               ti->offset_addr = -imm8;
+       return true;
+}
+
+static bool decode_thumb_str(struct arm_insn *ti)
+{
+       u8 op1 = (ti->instr >> (16 + 5)) & 0x7;
+       u8 op2 = (ti->instr >> 6) & 0x3f;
+
+       ti->W = true;
+       ti->sign_extend = false;
+
+       switch (op1) {
+       case 0x0: ti->len = 1; break;
+       case 0x1: ti->len = 2; break;
+       case 0x2: ti->len = 4; break;
+       default:
+                 return false; /* Only register write-back versions! */
+       }
+
+       if ((op2 & 0x24) == 0x24) {
+               /* STRB (immediate, thumb, W=1) */
+               return decode_thumb_wb(ti);
+       }
+
+       return false;
+}
+
+static bool decode_thumb_ldr(struct arm_insn *ti)
+{
+       u8 op1 = (ti->instr >> (16 + 7)) & 0x3;
+       u8 op2 = (ti->instr >> 6) & 0x3f;
+
+       ti->W = false;
+
+       switch (ti->t32.op2 & 0x7) {
+       case 0x1: ti->len = 1; break;
+       case 0x3: ti->len = 2; break;
+       case 0x5: ti->len = 4; break;
+       }
+
+       if (op1 == 0x0)
+               ti->sign_extend = false;
+       else if (op1 == 0x2 && (ti->t32.op2 & 0x7) != 0x5)
+               ti->sign_extend = true;
+       else
+               return false; /* Only register write-back versions! */
+
+       if ((op2 & 0x24) == 0x24) {
+               /* LDR{S}X (immediate, thumb, W=1) */
+               return decode_thumb_wb(ti);
+       }
+
+       return false;
+}
+
+/*
+ * We only support instruction decoding for valid reasonable MMIO operations
+ * where trapping them do not provide sufficient information in the HSR (no
+ * 16-bit Thumb instructions provide register writeback that we care about).
+ *
+ * The following instruciton types are NOT supported for MMIO operations
+ * despite the HSR not containing decode info:
+ *  - any Load/Store multiple
+ *  - any load/store exclusive
+ *  - any load/store dual
+ *  - anything with the PC as the dest register
+ */
+static const struct thumb_decode thumb_decode[] = {
+       /**************** 32-bit Thumb instructions **********************/
+       /* Store single data item:      Op1 == 11, Op2 == 000xxx0 */
+       { .is32 = true,  .t32 = { 3, 0x00, 0x71}, decode_thumb_str      },
+       /* Load byte:                   Op1 == 11, Op2 == 00xx001 */
+       { .is32 = true,  .t32 = { 3, 0x01, 0x67}, decode_thumb_ldr      },
+       /* Load halfword:               Op1 == 11, Op2 == 00xx011 */
+       { .is32 = true,  .t32 = { 3, 0x03, 0x67}, decode_thumb_ldr      },
+       /* Load word:                   Op1 == 11, Op2 == 00xx101 */
+       { .is32 = true,  .t32 = { 3, 0x05, 0x67}, decode_thumb_ldr      },
+};
+
+
+static bool decode_thumb(struct arm_insn *ti)
+{
+       bool is16;
+       int i;
+
+       is16 = !ti->is_thumb32;
+       if (is16) {
+               ti->t16.opcode = (ti->instr >> 10) & 0x3f;
+       } else {
+               ti->t32.op1 = (ti->instr >> (16 + 11)) & 0x3;
+               ti->t32.op2 = (ti->instr >> (16 + 4)) & 0x7f;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(thumb_decode); i++) {
+               const struct thumb_decode *td = &thumb_decode[i];
+               if (td->is32 != ti->is_thumb32)
+                       continue;
+
+               if (is16) {
+                       if ((ti->t16.opcode & td->t16.mask) != td->t16.opcode)
+                               continue;
+               } else {
+                       if (td->t32.op1 != ti->t32.op1)
+                               continue;
+                       if ((td->t32.op2_mask & ti->t32.op2) != td->t32.op2)
+                               continue;
+               }
+
+               return td->decode(ti);
+       }
+
+       return false;
+}
+
+int decode_insn(struct arm_insn *ai, unsigned long pc, u32 psr,
+               int (*copy_from)(void *dst, unsigned long addr, size_t, void *),
+               u32 (*get_regval)(int reg, void *),
+               void *priv)
+{
+       int err;
+       unsigned int instr_len;
+
+       memset(&ai, 0, sizeof(ai));
+
+       ai->is_thumb = psr & PSR_T_BIT;
+       instr_len = ai->is_thumb ? 2 : 4;
+
+       BUG_ON(!ai->is_thumb && (pc & 0x3));
+
+       /* Zero out high bits for thumb case, and so it's set on error. */
+       ai->instr = 0;
+
+       /* Now guest isn't running, we can va->pa map and copy atomically. */
+       err = copy_from(&ai->instr, pc, instr_len, priv);
+       if (err)
+               return err;
+
+       if (ai->is_thumb) {
+               /*
+                * Is it a 32 bit thumb instruction?  Can't get it all
+                * in 1 go, since it can actually go over a page
+                * boundary.
+                */
+               ai->is_thumb32 = is_wide_instruction(ai->instr);
+
+               if (ai->is_thumb32) {
+                       ai->instr = ai->instr << 16;
+                       err = copy_from(&ai->instr, pc + instr_len, instr_len,
+                                       priv);
+                       if (err)
+                               return err;
+               }
+               return decode_thumb(ai);
+       }
+
+       return decode_arm(ai, psr, get_regval, priv);
+}
+EXPORT_SYMBOL_GPL(decode_insn);
diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c
index c0014e1..eeebd33 100644
--- a/arch/arm/kvm/emulate.c
+++ b/arch/arm/kvm/emulate.c
@@ -20,6 +20,7 @@
 #include <linux/kvm_host.h>
 #include <asm/kvm_arm.h>
 #include <asm/kvm_emulate.h>
+#include <asm/opcodes.h>
 #include <trace/events/kvm.h>
 
 #include "trace.h"
@@ -231,11 +232,10 @@ static void do_nothing(void *info)
  * Fortunately this is so rare (we don't usually need the instruction), we
  * can go very slowly and noone will mind.
  */
-static int copy_from_guest(struct kvm_vcpu *vcpu,
-                          void *dest,
-                          unsigned long gva,
-                          size_t len)
+static int copy_from_guest(void *dest, unsigned long gva, size_t len,
+                          void *_vcpu)
 {
+       struct kvm_vcpu *vcpu = _vcpu;
        int i;
        bool ret;
        struct kvm_vcpu *v;
@@ -269,467 +269,9 @@ static int copy_from_guest(struct kvm_vcpu *vcpu,
        return ret ? 0 : -EFAULT;
 }
 
-/******************************************************************************
- * Load-Store instruction emulation
- *****************************************************************************/
-enum SRType {
-       SRType_LSL,
-       SRType_LSR,
-       SRType_ASR,
-       SRType_ROR,
-       SRType_RRX
-};
-
-struct arm_insn {
-       /* Encoded instruction. */
-       u32 instr;
-
-       /* Decoding for the register write back */
-       bool register_form;
-       u32 imm;
-       u8 type;
-       u8 Rt, Rn, Rm, Rd;
-       u8 shift_n;
-       u32 offset_addr;
-
-       /* Common decoding */
-       u8 len;
-       bool sign_extend;
-       bool w, W, U, P;
-
-       /* Thumb encoding */
-       bool is_thumb, is_thumb32;
-       union {
-               struct {
-                       u8 opcode;
-                       u8 mask;
-               } t16;
-
-               struct {
-                       u8 op1;
-                       u8 op2;
-                       u8 op2_mask;
-               } t32;
-       };
-};
-
-struct arm_decode {
-       /* Instruction decoding */
-       u32 opc;
-       u32 opc_mask;
-
-       bool (*decode)(struct kvm_vcpu *vcpu, struct arm_insn *ai, u32 psr);
-
-       struct arm_insn template;
-};
-
-/* Modelled after DecodeImmShift() in the ARM ARM */
-enum SRType decode_imm_shift(u8 type, u8 imm5, u8 *amount)
-{
-       switch (type) {
-       case 0x0:
-               *amount = imm5;
-               return SRType_LSL;
-       case 0x1:
-               *amount = (imm5 == 0) ? 32 : imm5;
-               return SRType_LSR;
-       case 0x2:
-               *amount = (imm5 == 0) ? 32 : imm5;
-               return SRType_ASR; 
-       case 0x3:
-               if (imm5 == 0) {
-                       *amount = 1;
-                       return SRType_RRX;
-               } else {
-                       *amount = imm5;
-                       return SRType_ROR;
-               }
-       }
-
-       return SRType_LSL;
-}
-
-/* Modelled after Shift() in the ARM ARM */
-u32 shift(u32 value, u8 N, enum SRType type, u8 amount, bool carry_in)
+static u32 get_guest_reg(int reg, void *_vcpu)
 {
-       u32 mask = (1 << N) - 1;
-       s32 svalue = (s32)value;
-
-       BUG_ON(N > 32);
-       BUG_ON(type == SRType_RRX && amount != 1);
-       BUG_ON(amount > N);
-
-       if (amount == 0)
-               return value;
-
-       switch (type) {
-       case SRType_LSL:
-               value <<= amount;
-               break;
-       case SRType_LSR:
-                value >>= amount;
-               break;
-       case SRType_ASR:
-               if (value & (1 << (N - 1)))
-                       svalue |= ((-1UL) << N);
-               value = svalue >> amount;
-               break;
-       case SRType_ROR:
-               value = (value >> amount) | (value << (N - amount));
-               break;
-       case SRType_RRX: {
-               u32 C = (carry_in) ? 1 : 0;
-               value = (value >> 1) | (C << (N - 1));
-               break;
-       }
-       }
-
-       return value & mask;
-}
-
-static bool decode_arm_wb(struct kvm_vcpu *vcpu, struct arm_insn *ai, u32 psr)
-{
-       u32 base_addr, offset;
-
-       ai->Rt = (ai->instr >> 12) & 0xf;
-       ai->Rn = (ai->instr >> 16) & 0xf;
-       ai->W = (ai->instr >> 21) & 1;
-       ai->U = (ai->instr >> 23) & 1;
-       ai->P = (ai->instr >> 24) & 1;
-
-       base_addr = *vcpu_reg(vcpu, ai->Rn);
-
-       if (ai->P && !ai->W) {
-               kvm_err("Decoding operation with valid ISV?\n");
-               return false;
-       }
-
-       if (ai->register_form) {
-               /* Register operation */
-               enum SRType s_type;
-               u8 shift_n;
-               bool c_bit = psr & PSR_C_BIT;
-               u32 s_reg = *vcpu_reg(vcpu, ai->Rm);
-
-               s_type = decode_imm_shift(ai->type, ai->shift_n, &shift_n);
-               offset = shift(s_reg, 5, s_type, shift_n, c_bit);
-       } else {
-               /* Immediate operation */
-               offset = ai->imm;
-       }
-
-       /* Handle Writeback */
-       if (ai->U)
-               ai->offset_addr = base_addr + offset;
-       else
-               ai->offset_addr = base_addr - offset;
-       return true;
-}
-
-static bool decode_arm_ls(struct kvm_vcpu *vcpu, struct arm_insn *ai, u32 psr)
-{
-       u8 A = (ai->instr >> 25) & 1;
-
-       ai->register_form = A;
-       ai->imm = ai->instr & 0xfff;
-       ai->Rm = ai->instr & 0xf;
-       ai->type = (ai->instr >> 5) & 0x3;
-       ai->shift_n = (ai->instr >> 7) & 0x1f;
-
-       return decode_arm_wb(vcpu, ai, psr);
-}
-
-static bool decode_arm_extra(struct kvm_vcpu *vcpu, struct arm_insn *ai,
-                            u32 psr)
-{
-       ai->register_form = !((ai->instr >> 22) & 1);
-       ai->imm = ((ai->instr >> 4) & 0xf0) | (ai->instr & 0xf);
-       ai->Rm = ai->instr & 0xf;
-       ai->type = 0; /* SRType_LSL */
-       ai->shift_n = 0;
-
-       return decode_arm_wb(vcpu, ai, psr);
-}
-
-/*
- * The encodings in this table assumes that a fault was generated where the
- * ISV field in the HSR was clear, and the decoding information was invalid,
- * which means that a register write-back occurred, the PC was used as the
- * destination or a load/store multiple operation was used. Since the latter
- * two cases are crazy for MMIO on the guest side, we simply inject a fault
- * when this happens and support the common case.
- *
- * We treat unpriviledged loads and stores of words and bytes like all other
- * loads and stores as their encodings mandate the W bit set and the P bit
- * clear.
- */
-static const struct arm_decode arm_decode[] = {
-       /**************** Load/Store Word and Byte **********************/
-       /* Store word with writeback */
-       { .opc = 0x04000000, .opc_mask = 0x0c500000,
-         .decode = decode_arm_ls,
-         .template =  { .len = 4, .w = true, .sign_extend = false, }, },
-       /* Store byte with writeback */
-       { .opc = 0x04400000, .opc_mask = 0x0c500000,
-         .decode = decode_arm_ls,
-         .template = {  .len = 1, .w = true, .sign_extend = false, }, },
-       /* Load word with writeback */
-       { .opc = 0x04100000, .opc_mask = 0x0c500000,
-         .decode = decode_arm_ls,
-         .template = {  .len = 4, .w = false, .sign_extend = false, }, },
-       /* Load byte with writeback */
-       { .opc = 0x04500000, .opc_mask = 0x0c500000,
-         .decode = decode_arm_ls,
-         .template = { .len = 1, .w = false, .sign_extend = false, }, },
-
-       /*************** Extra load/store instructions ******************/
-
-       /* Store halfword with writeback */
-       { .opc = 0x000000b0, .opc_mask = 0x0c1000f0,
-         .decode = decode_arm_extra,
-         .template = { .len = 2, .w = true, .sign_extend = false, }, },
-       /* Load halfword with writeback */
-       { .opc = 0x001000b0, .opc_mask = 0x0c1000f0, 
-         .decode = decode_arm_extra,
-         .template = { .len = 2, .w = false, .sign_extend = false, }, },
-       /* Load dual with writeback */
-       { .opc = 0x000000d0, .opc_mask = 0x0c1000f0,
-         .decode = decode_arm_extra,
-         .template = { .len = 8, .w = false, .sign_extend = false, }, },
-       /* Load signed byte with writeback */
-       { .opc = 0x001000d0, .opc_mask = 0x0c1000f0,
-         .decode = decode_arm_extra,
-         .template = { .len = 1, .w = false, .sign_extend = true, }, },
-
-       /* Store dual with writeback */
-       { .opc = 0x000000f0, .opc_mask = 0x0c1000f0,
-         .decode = decode_arm_extra,
-         .template = { .len = 8, .w = true, .sign_extend = false, }, },
-       /* Load signed halfword with writeback */
-       { .opc = 0x001000f0, .opc_mask = 0x0c1000f0,
-         .decode = decode_arm_extra,
-         .template = { .len = 2, .w = false, .sign_extend = true, }, },
-
-       /* Store halfword unprivileged */
-       { .opc = 0x002000b0, .opc_mask = 0x0f3000f0,
-         .decode = decode_arm_extra,
-         .template = { .len = 2, .w = true, .sign_extend = false, }, },
-       /* Load halfword unprivileged */
-       { .opc = 0x003000b0, .opc_mask = 0x0f3000f0,
-         .decode = decode_arm_extra,
-         .template = { .len = 2, .w = false, .sign_extend = false, }, },
-       /* Load signed byte unprivileged */
-       { .opc = 0x003000d0, .opc_mask = 0x0f3000f0,
-         .decode = decode_arm_extra,
-         .template = { .len = 1, .w = false, .sign_extend = true, }, },
-       /* Load signed halfword unprivileged */
-       { .opc = 0x003000d0, .opc_mask = 0x0f3000f0,
-         .decode = decode_arm_extra,
-         .template = { .len = 2, .w = false, .sign_extend = true, }, },
-};
-
-static bool kvm_decode_arm_ls(struct kvm_vcpu *vcpu, struct arm_insn *ai,
-                             u32 psr)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(arm_decode); i++) {
-               const struct arm_decode *d = &arm_decode[i];
-               if ((ai->instr & d->opc_mask) == d->opc) {
-                       ai->len = d->template.len;
-                       ai->w = d->template.w;
-                       ai->sign_extend = d->template.sign_extend;
-                       return d->decode(vcpu, ai, psr);
-               }
-       }
-       return false;
-}
-
-struct thumb_decode {
-       bool is32;
-
-       union {
-               struct {
-                       u8 opcode;
-                       u8 mask;
-               } t16;
-
-               struct {
-                       u8 op1;
-                       u8 op2;
-                       u8 op2_mask;
-               } t32;
-       };
-
-       bool (*decode)(struct kvm_vcpu *vcpu, struct arm_insn *ti);
-};
-
-static bool decode_thumb_wb(struct kvm_vcpu *vcpu, struct arm_insn *ti)
-{
-       u8 imm8 = ti->instr & 0xff;
-
-       ti->P = (ti->instr >> 10) & 1;
-       ti->U = (ti->instr >> 9) & 1;
-       ti->Rn = (ti->instr >> 16) & 0xf;
-       ti->Rd = (ti->instr >> 12) & 0xf;
-
-       /* Handle Writeback: offset_addr relative to fault address. */
-       if (!ti->P && ti->U)
-               ti->offset_addr = imm8;
-       else if (!ti->P && !ti->U)
-               ti->offset_addr = -imm8;
-       return true;
-}
-
-static bool decode_thumb_str(struct kvm_vcpu *vcpu, struct arm_insn *ti)
-{
-       u8 op1 = (ti->instr >> (16 + 5)) & 0x7;
-       u8 op2 = (ti->instr >> 6) & 0x3f;
-
-       ti->W = true;
-       ti->sign_extend = false;
-
-       switch (op1) {
-       case 0x0: ti->len = 1; break;
-       case 0x1: ti->len = 2; break;
-       case 0x2: ti->len = 4; break;
-       default:
-                 return false; /* Only register write-back versions! */
-       }
-
-       if ((op2 & 0x24) == 0x24) {
-               /* STRB (immediate, thumb, W=1) */
-               return decode_thumb_wb(vcpu, ti);
-       }
-
-       return false;
-}
-
-static bool decode_thumb_ldr(struct kvm_vcpu *vcpu, struct arm_insn *ti)
-{
-       u8 op1 = (ti->instr >> (16 + 7)) & 0x3;
-       u8 op2 = (ti->instr >> 6) & 0x3f;
-
-       ti->W = false;
-
-       switch (ti->t32.op2 & 0x7) {
-       case 0x1: ti->len = 1; break;
-       case 0x3: ti->len = 2; break;
-       case 0x5: ti->len = 4; break;
-       }
-
-       if (op1 == 0x0)
-               ti->sign_extend = false;
-       else if (op1 == 0x2 && (ti->t32.op2 & 0x7) != 0x5)
-               ti->sign_extend = true;
-       else
-               return false; /* Only register write-back versions! */
-
-       if ((op2 & 0x24) == 0x24) {
-               /* LDR{S}X (immediate, thumb, W=1) */
-               return decode_thumb_wb(vcpu, ti);
-       }
-
-       return false;
-}
-
-/*
- * We only support instruction decoding for valid reasonable MMIO operations
- * where trapping them do not provide sufficient information in the HSR (no
- * 16-bit Thumb instructions provide register writeback that we care about).
- *
- * The following instruciton types are NOT supported for MMIO operations
- * despite the HSR not containing decode info:
- *  - any Load/Store multiple
- *  - any load/store exclusive
- *  - any load/store dual
- *  - anything with the PC as the dest register
- */
-static const struct thumb_decode thumb_decode[] = {
-       /**************** 32-bit Thumb instructions **********************/
-       /* Store single data item:      Op1 == 11, Op2 == 000xxx0 */
-       { .is32 = true,  .t32 = { 3, 0x00, 0x71}, decode_thumb_str      },
-       /* Load byte:                   Op1 == 11, Op2 == 00xx001 */
-       { .is32 = true,  .t32 = { 3, 0x01, 0x67}, decode_thumb_ldr      },
-       /* Load halfword:               Op1 == 11, Op2 == 00xx011 */
-       { .is32 = true,  .t32 = { 3, 0x03, 0x67}, decode_thumb_ldr      },
-       /* Load word:                   Op1 == 11, Op2 == 00xx101 */
-       { .is32 = true,  .t32 = { 3, 0x05, 0x67}, decode_thumb_ldr      },
-};
-
-
-static bool kvm_decode_thumb_ls(struct kvm_vcpu *vcpu, struct arm_insn *ti)
-{
-       bool is16;
-       int i;
-
-       is16 = !ti->is_thumb32;
-       if (is16) {
-               ti->t16.opcode = (ti->instr >> 10) & 0x3f;
-       } else {
-               ti->t32.op1 = (ti->instr >> (16 + 11)) & 0x3;
-               ti->t32.op2 = (ti->instr >> (16 + 4)) & 0x7f;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(thumb_decode); i++) {
-               const struct thumb_decode *td = &thumb_decode[i];
-               if (td->is32 != ti->is_thumb32)
-                       continue;
-
-               if (is16) {
-                       if ((ti->t16.opcode & td->t16.mask) != td->t16.opcode)
-                               continue;
-               } else {
-                       if (td->t32.op1 != ti->t32.op1)
-                               continue;
-                       if ((td->t32.op2_mask & ti->t32.op2) != td->t32.op2)
-                               continue;
-               }
-
-               return td->decode(vcpu, ti);
-       }
-
-       return false;
-}
-
-static int kvm_decode(struct kvm_vcpu *vcpu, unsigned long pc, u32 psr,
-                     struct arm_insn *ai)
-{
-       int err;
-       unsigned int instr_len;
-
-       ai->is_thumb = psr & PSR_T_BIT;
-       instr_len = ai->is_thumb ? 2 : 4;
-
-       BUG_ON(!ai->is_thumb && (pc & 0x3));
-
-       /* Zero out high bits for thumb case, and so it's set on error. */
-       ai->instr = 0;
-
-       /* Now guest isn't running, we can va->pa map and copy atomically. */
-       err = copy_from_guest(vcpu, &ai->instr, pc, instr_len);
-       if (err)
-               return err;
-
-       if (ai->is_thumb) {
-               /*
-                * Is it a 32 bit thumb instruction?  Can't get it all
-                * in 1 go, since it can actually go over a page
-                * boundary.
-                */
-               ai->is_thumb32 = is_wide_instruction(ai->instr);
-
-               if (ai->is_thumb32) {
-                       ai->instr = ai->instr << 16;
-                       err = copy_from_guest(vcpu, &ai->instr,
-                                             pc + instr_len, instr_len);
-                       if (err)
-                               return err;
-               }
-               return kvm_decode_thumb_ls(vcpu, ai);
-       }
-
-       return kvm_decode_arm_ls(vcpu, ai, psr);
+       return *vcpu_reg(_vcpu, reg);
 }
 
 static bool execute(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
@@ -788,7 +330,8 @@ int kvm_emulate_mmio_ls(struct kvm_vcpu *vcpu, phys_addr_t 
fault_ipa,
 
        mmio->phys_addr = fault_ipa;
 
-       err = kvm_decode(vcpu, *vcpu_pc(vcpu), *vcpu_cpsr(vcpu), &insn);
+       err = decode_insn(&insn, *vcpu_pc(vcpu), *vcpu_cpsr(vcpu),
+                         copy_from_guest, get_guest_reg, vcpu);
        if (err) {
                kvm_debug("Unable to decode inst: %#08x (cpsr: %#08x (T=%i)"
                          "pc: %#08x) - %i\n",
-- 
1.7.10.4

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

Reply via email to