diff options
author | Avi Kivity <avi@redhat.com> | 2011-03-29 05:34:38 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2011-05-11 07:56:59 -0400 |
commit | 0d7cdee83ad1582eecbf3b4a220e82dcb5ad561c (patch) | |
tree | 928983175d0e149e9957884524218ffc257a98ed /arch/x86/kvm/emulate.c | |
parent | 5037f6f324cdcc6c9071dc774aba992f96c7e5ff (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.c | 26 |
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 | ||
119 | struct 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? */ |