From: Takuya Yoshikawa <[email protected]>

Instruction decoding can be split into separate parts, and this is the
first one which treats the instruction prefixes.

Signed-off-by: Takuya Yoshikawa <[email protected]>
Cc: Takuya Yoshikawa <[email protected]>
---
 arch/x86/kvm/emulate.c |   58 +++++++++++++++++++++++++++++++----------------
 1 files changed, 38 insertions(+), 20 deletions(-)

diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 5a49290..b22238b 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -3874,22 +3874,21 @@ done:
        return rc;
 }
 
-int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len)
+/**
+ * decode_prefixes - decode instruction prefixes
+ * @ctxt: emulation context
+ *
+ * Fetches instruction prefixes and sets some ctxt fields based on them.
+ * The byte next to the last prefix is also fetched into ctxt->b.
+ *
+ * Returns X86EMUL_CONTINUE on success.
+ */
+static int decode_prefixes(struct x86_emulate_ctxt *ctxt)
 {
        int rc = X86EMUL_CONTINUE;
-       int mode = ctxt->mode;
-       int def_op_bytes, def_ad_bytes, goffset, simd_prefix;
-       struct opcode opcode;
+       int def_op_bytes, def_ad_bytes;
 
-       ctxt->memop.type = OP_NONE;
-       ctxt->memopp = NULL;
-       ctxt->_eip = ctxt->eip;
-       ctxt->fetch.start = ctxt->_eip;
-       ctxt->fetch.end = ctxt->fetch.start + insn_len;
-       if (insn_len > 0)
-               memcpy(ctxt->fetch.data, insn, insn_len);
-
-       switch (mode) {
+       switch (ctxt->mode) {
        case X86EMUL_MODE_REAL:
        case X86EMUL_MODE_VM86:
        case X86EMUL_MODE_PROT16:
@@ -3905,7 +3904,7 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void 
*insn, int insn_len)
                break;
 #endif
        default:
-               return EMULATION_FAILED;
+               return X86EMUL_UNHANDLEABLE;
        }
 
        ctxt->op_bytes = def_op_bytes;
@@ -3920,7 +3919,7 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void 
*insn, int insn_len)
                        ctxt->op_bytes = def_op_bytes ^ 6;
                        break;
                case 0x67:      /* address-size override */
-                       if (mode == X86EMUL_MODE_PROT64)
+                       if (ctxt->mode == X86EMUL_MODE_PROT64)
                                /* switch between 4/8 bytes */
                                ctxt->ad_bytes = def_ad_bytes ^ 12;
                        else
@@ -3938,7 +3937,7 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void 
*insn, int insn_len)
                        set_seg_override(ctxt, ctxt->b & 7);
                        break;
                case 0x40 ... 0x4f: /* REX */
-                       if (mode != X86EMUL_MODE_PROT64)
+                       if (ctxt->mode != X86EMUL_MODE_PROT64)
                                goto done_prefixes;
                        ctxt->rex_prefix = ctxt->b;
                        continue;
@@ -3954,15 +3953,34 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void 
*insn, int insn_len)
                }
 
                /* Any legacy prefix after a REX prefix nullifies its effect. */
-
                ctxt->rex_prefix = 0;
        }
 
 done_prefixes:
-
        /* REX prefix. */
        if (ctxt->rex_prefix & 8)
                ctxt->op_bytes = 8;     /* REX.W */
+done:
+       return rc;
+}
+
+int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len)
+{
+       int rc = X86EMUL_CONTINUE;
+       int goffset, simd_prefix;
+       struct opcode opcode;
+
+       ctxt->memop.type = OP_NONE;
+       ctxt->memopp = NULL;
+       ctxt->_eip = ctxt->eip;
+       ctxt->fetch.start = ctxt->_eip;
+       ctxt->fetch.end = ctxt->fetch.start + insn_len;
+       if (insn_len > 0)
+               memcpy(ctxt->fetch.data, insn, insn_len);
+
+       rc = decode_prefixes(ctxt);
+       if (rc != X86EMUL_CONTINUE)
+               goto done;
 
        /* Opcode byte(s). */
        opcode = opcode_table[ctxt->b];
@@ -4025,11 +4043,11 @@ done_prefixes:
        if (!(ctxt->d & VendorSpecific) && ctxt->only_vendor_specific_insn)
                return EMULATION_FAILED;
 
-       if (mode == X86EMUL_MODE_PROT64 && (ctxt->d & Stack))
+       if (ctxt->mode == X86EMUL_MODE_PROT64 && (ctxt->d & Stack))
                ctxt->op_bytes = 8;
 
        if (ctxt->d & Op3264) {
-               if (mode == X86EMUL_MODE_PROT64)
+               if (ctxt->mode == X86EMUL_MODE_PROT64)
                        ctxt->op_bytes = 8;
                else
                        ctxt->op_bytes = 4;
-- 
1.7.5.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