aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/emulate.c
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2011-03-29 05:34:38 -0400
committerAvi Kivity <avi@redhat.com>2011-05-11 07:56:59 -0400
commit0d7cdee83ad1582eecbf3b4a220e82dcb5ad561c (patch)
tree928983175d0e149e9957884524218ffc257a98ed /arch/x86/kvm/emulate.c
parent5037f6f324cdcc6c9071dc774aba992f96c7e5ff (diff)
KVM: x86 emulator: Specialize decoding for insns with 66/f2/f3 prefixes
Most SIMD instructions use the 66/f2/f3 prefixes to distinguish between different variants of the same instruction. Usually the encoding is quite regular, but in some cases (including non-SIMD instructions) the prefixes generate very different instructions. Examples include XCHG/PAUSE, MOVQ/MOVDQA/MOVDQU, and MOVBE/CRC32. Allow the emulator to handle these special cases by splitting such opcodes into groups, with different decode flags and execution functions for different prefixes. Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm/emulate.c')
-rw-r--r--arch/x86/kvm/emulate.c26
1 files changed, 25 insertions, 1 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 075bb6fc73ae..fcce7aeacc84 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -75,6 +75,7 @@
75#define Stack (1<<13) /* Stack instruction (push/pop) */ 75#define Stack (1<<13) /* Stack instruction (push/pop) */
76#define Group (1<<14) /* Bits 3:5 of modrm byte extend opcode */ 76#define Group (1<<14) /* Bits 3:5 of modrm byte extend opcode */
77#define GroupDual (1<<15) /* Alternate decoding of mod == 3 */ 77#define GroupDual (1<<15) /* Alternate decoding of mod == 3 */
78#define Prefix (1<<16) /* Instruction varies with 66/f2/f3 prefix */
78/* Misc flags */ 79/* Misc flags */
79#define VendorSpecific (1<<22) /* Vendor specific instruction */ 80#define VendorSpecific (1<<22) /* Vendor specific instruction */
80#define NoAccess (1<<23) /* Don't access memory (lea/invlpg/verr etc) */ 81#define NoAccess (1<<23) /* Don't access memory (lea/invlpg/verr etc) */
@@ -106,6 +107,7 @@ struct opcode {
106 int (*execute)(struct x86_emulate_ctxt *ctxt); 107 int (*execute)(struct x86_emulate_ctxt *ctxt);
107 struct opcode *group; 108 struct opcode *group;
108 struct group_dual *gdual; 109 struct group_dual *gdual;
110 struct gprefix *gprefix;
109 } u; 111 } u;
110}; 112};
111 113
@@ -114,6 +116,13 @@ struct group_dual {
114 struct opcode mod3[8]; 116 struct opcode mod3[8];
115}; 117};
116 118
119struct gprefix {
120 struct opcode pfx_no;
121 struct opcode pfx_66;
122 struct opcode pfx_f2;
123 struct opcode pfx_f3;
124};
125
117/* EFLAGS bit definitions. */ 126/* EFLAGS bit definitions. */
118#define EFLG_ID (1<<21) 127#define EFLG_ID (1<<21)
119#define EFLG_VIP (1<<20) 128#define EFLG_VIP (1<<20)
@@ -2625,7 +2634,8 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len)
2625 struct decode_cache *c = &ctxt->decode; 2634 struct decode_cache *c = &ctxt->decode;
2626 int rc = X86EMUL_CONTINUE; 2635 int rc = X86EMUL_CONTINUE;
2627 int mode = ctxt->mode; 2636 int mode = ctxt->mode;
2628 int def_op_bytes, def_ad_bytes, dual, goffset; 2637 int def_op_bytes, def_ad_bytes, dual, goffset, simd_prefix;
2638 bool op_prefix = false;
2629 struct opcode opcode, *g_mod012, *g_mod3; 2639 struct opcode opcode, *g_mod012, *g_mod3;
2630 struct operand memop = { .type = OP_NONE }; 2640 struct operand memop = { .type = OP_NONE };
2631 2641
@@ -2662,6 +2672,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len)
2662 for (;;) { 2672 for (;;) {
2663 switch (c->b = insn_fetch(u8, 1, c->eip)) { 2673 switch (c->b = insn_fetch(u8, 1, c->eip)) {
2664 case 0x66: /* operand-size override */ 2674 case 0x66: /* operand-size override */
2675 op_prefix = true;
2665 /* switch between 2/4 bytes */ 2676 /* switch between 2/4 bytes */
2666 c->op_bytes = def_op_bytes ^ 6; 2677 c->op_bytes = def_op_bytes ^ 6;
2667 break; 2678 break;
@@ -2742,6 +2753,19 @@ done_prefixes:
2742 c->d |= opcode.flags; 2753 c->d |= opcode.flags;
2743 } 2754 }
2744 2755
2756 if (c->d & Prefix) {
2757 if (c->rep_prefix && op_prefix)
2758 return X86EMUL_UNHANDLEABLE;
2759 simd_prefix = op_prefix ? 0x66 : c->rep_prefix;
2760 switch (simd_prefix) {
2761 case 0x00: opcode = opcode.u.gprefix->pfx_no; break;
2762 case 0x66: opcode = opcode.u.gprefix->pfx_66; break;
2763 case 0xf2: opcode = opcode.u.gprefix->pfx_f2; break;
2764 case 0xf3: opcode = opcode.u.gprefix->pfx_f3; break;
2765 }
2766 c->d |= opcode.flags;
2767 }
2768
2745 c->execute = opcode.u.execute; 2769 c->execute = opcode.u.execute;
2746 2770
2747 /* Unrecognised? */ 2771 /* Unrecognised? */