diff options
author | Avi Kivity <avi@redhat.com> | 2010-07-29 08:11:39 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2010-10-24 04:50:10 -0400 |
commit | 120df8902dbe91cc1b3b7886481e350fae7334fe (patch) | |
tree | f2cc9a26d9783e550698b5e3618e028b9dc4b465 /arch/x86/kvm/emulate.c | |
parent | 793d5a8d6baad9062b0a03e034944b31e50dfe5c (diff) |
KVM: x86 emulator: allow specifying group directly in opcode
Instead of having a group number, store the group table pointer directly in
the opcode.
Signed-off-by: Avi Kivity <avi@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86/kvm/emulate.c')
-rw-r--r-- | arch/x86/kvm/emulate.c | 47 |
1 files changed, 38 insertions, 9 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 5e496127a01c..f3b984427d10 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -110,10 +110,21 @@ enum { | |||
110 | 110 | ||
111 | struct opcode { | 111 | struct opcode { |
112 | u32 flags; | 112 | u32 flags; |
113 | union { | ||
114 | struct opcode *group; | ||
115 | struct group_dual *gdual; | ||
116 | } u; | ||
117 | }; | ||
118 | |||
119 | struct group_dual { | ||
120 | struct opcode mod012[8]; | ||
121 | struct opcode mod3[8]; | ||
113 | }; | 122 | }; |
114 | 123 | ||
115 | #define D(_y) { .flags = (_y) } | 124 | #define D(_y) { .flags = (_y) } |
116 | #define N D(0) | 125 | #define N D(0) |
126 | #define G(_f, _g) { .flags = ((_f) | Group), .u.group = (_g) } | ||
127 | #define GD(_f, _g) { .flags = ((_f) | Group | GroupDual), .u.gdual = (_g) } | ||
117 | 128 | ||
118 | static struct opcode group_table[] = { | 129 | static struct opcode group_table[] = { |
119 | [Group1*8] = | 130 | [Group1*8] = |
@@ -331,6 +342,8 @@ static struct opcode twobyte_table[256] = { | |||
331 | 342 | ||
332 | #undef D | 343 | #undef D |
333 | #undef N | 344 | #undef N |
345 | #undef G | ||
346 | #undef GD | ||
334 | 347 | ||
335 | /* EFLAGS bit definitions. */ | 348 | /* EFLAGS bit definitions. */ |
336 | #define EFLG_ID (1<<21) | 349 | #define EFLG_ID (1<<21) |
@@ -930,8 +943,8 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) | |||
930 | struct decode_cache *c = &ctxt->decode; | 943 | struct decode_cache *c = &ctxt->decode; |
931 | int rc = X86EMUL_CONTINUE; | 944 | int rc = X86EMUL_CONTINUE; |
932 | int mode = ctxt->mode; | 945 | int mode = ctxt->mode; |
933 | int def_op_bytes, def_ad_bytes, group, dual; | 946 | int def_op_bytes, def_ad_bytes, group, dual, goffset; |
934 | 947 | struct opcode opcode, *g_mod012, *g_mod3; | |
935 | 948 | ||
936 | /* we cannot decode insn before we complete previous rep insn */ | 949 | /* we cannot decode insn before we complete previous rep insn */ |
937 | WARN_ON(ctxt->restart); | 950 | WARN_ON(ctxt->restart); |
@@ -1018,15 +1031,16 @@ done_prefixes: | |||
1018 | c->op_bytes = 8; /* REX.W */ | 1031 | c->op_bytes = 8; /* REX.W */ |
1019 | 1032 | ||
1020 | /* Opcode byte(s). */ | 1033 | /* Opcode byte(s). */ |
1021 | c->d = opcode_table[c->b].flags; | 1034 | opcode = opcode_table[c->b]; |
1022 | if (c->d == 0) { | 1035 | if (opcode.flags == 0) { |
1023 | /* Two-byte opcode? */ | 1036 | /* Two-byte opcode? */ |
1024 | if (c->b == 0x0f) { | 1037 | if (c->b == 0x0f) { |
1025 | c->twobyte = 1; | 1038 | c->twobyte = 1; |
1026 | c->b = insn_fetch(u8, 1, c->eip); | 1039 | c->b = insn_fetch(u8, 1, c->eip); |
1027 | c->d = twobyte_table[c->b].flags; | 1040 | opcode = twobyte_table[c->b]; |
1028 | } | 1041 | } |
1029 | } | 1042 | } |
1043 | c->d = opcode.flags; | ||
1030 | 1044 | ||
1031 | if (c->d & Group) { | 1045 | if (c->d & Group) { |
1032 | group = c->d & GroupMask; | 1046 | group = c->d & GroupMask; |
@@ -1034,12 +1048,27 @@ done_prefixes: | |||
1034 | c->modrm = insn_fetch(u8, 1, c->eip); | 1048 | c->modrm = insn_fetch(u8, 1, c->eip); |
1035 | --c->eip; | 1049 | --c->eip; |
1036 | 1050 | ||
1037 | group = (group << 3) + ((c->modrm >> 3) & 7); | 1051 | if (group) { |
1052 | g_mod012 = g_mod3 = &group_table[group * 8]; | ||
1053 | if (c->d & GroupDual) | ||
1054 | g_mod3 = &group2_table[group * 8]; | ||
1055 | } else { | ||
1056 | if (c->d & GroupDual) { | ||
1057 | g_mod012 = opcode.u.gdual->mod012; | ||
1058 | g_mod3 = opcode.u.gdual->mod3; | ||
1059 | } else | ||
1060 | g_mod012 = g_mod3 = opcode.u.group; | ||
1061 | } | ||
1062 | |||
1038 | c->d &= ~(Group | GroupDual | GroupMask); | 1063 | c->d &= ~(Group | GroupDual | GroupMask); |
1039 | if (dual && (c->modrm >> 6) == 3) | 1064 | |
1040 | c->d |= group2_table[group].flags; | 1065 | goffset = (c->modrm >> 3) & 7; |
1066 | |||
1067 | if ((c->modrm >> 6) == 3) | ||
1068 | opcode = g_mod3[goffset]; | ||
1041 | else | 1069 | else |
1042 | c->d |= group_table[group].flags; | 1070 | opcode = g_mod012[goffset]; |
1071 | c->d |= opcode.flags; | ||
1043 | } | 1072 | } |
1044 | 1073 | ||
1045 | /* Unrecognised? */ | 1074 | /* Unrecognised? */ |