diff options
author | Masami Hiramatsu <mhiramat@redhat.com> | 2009-10-27 16:42:27 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-10-29 03:47:46 -0400 |
commit | e0e492e99b372c6990a5daca9e4683c341f1330e (patch) | |
tree | 79704aa82391ff2f54d92fe11b1b7958b09a5bb8 /arch/x86/lib/insn.c | |
parent | 82cb57028c864822c5a260f806d051e2ce28c86a (diff) |
x86: AVX instruction set decoder support
Add Intel AVX(Advanced Vector Extensions) instruction set
support to x86 instruction decoder. This adds insn.vex_prefix
field for storing VEX prefixes, and introduces some original
tags for expressing opcodes attributes.
Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Jim Keniston <jkenisto@us.ibm.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Frank Ch. Eigler <fche@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jason Baron <jbaron@redhat.com>
Cc: K.Prasad <prasad@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
LKML-Reference: <20091027204226.30545.23451.stgit@harusame>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/lib/insn.c')
-rw-r--r-- | arch/x86/lib/insn.c | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/arch/x86/lib/insn.c b/arch/x86/lib/insn.c index 9f483179a8a6..9f33b984d0ef 100644 --- a/arch/x86/lib/insn.c +++ b/arch/x86/lib/insn.c | |||
@@ -28,6 +28,9 @@ | |||
28 | #define peek_next(t, insn) \ | 28 | #define peek_next(t, insn) \ |
29 | ({t r; r = *(t*)insn->next_byte; r; }) | 29 | ({t r; r = *(t*)insn->next_byte; r; }) |
30 | 30 | ||
31 | #define peek_nbyte_next(t, insn, n) \ | ||
32 | ({t r; r = *(t*)((insn)->next_byte + n); r; }) | ||
33 | |||
31 | /** | 34 | /** |
32 | * insn_init() - initialize struct insn | 35 | * insn_init() - initialize struct insn |
33 | * @insn: &struct insn to be initialized | 36 | * @insn: &struct insn to be initialized |
@@ -107,6 +110,7 @@ found: | |||
107 | insn->prefixes.bytes[3] = lb; | 110 | insn->prefixes.bytes[3] = lb; |
108 | } | 111 | } |
109 | 112 | ||
113 | /* Decode REX prefix */ | ||
110 | if (insn->x86_64) { | 114 | if (insn->x86_64) { |
111 | b = peek_next(insn_byte_t, insn); | 115 | b = peek_next(insn_byte_t, insn); |
112 | attr = inat_get_opcode_attribute(b); | 116 | attr = inat_get_opcode_attribute(b); |
@@ -120,6 +124,39 @@ found: | |||
120 | } | 124 | } |
121 | } | 125 | } |
122 | insn->rex_prefix.got = 1; | 126 | insn->rex_prefix.got = 1; |
127 | |||
128 | /* Decode VEX prefix */ | ||
129 | b = peek_next(insn_byte_t, insn); | ||
130 | attr = inat_get_opcode_attribute(b); | ||
131 | if (inat_is_vex_prefix(attr)) { | ||
132 | insn_byte_t b2 = peek_nbyte_next(insn_byte_t, insn, 1); | ||
133 | if (!insn->x86_64) { | ||
134 | /* | ||
135 | * In 32-bits mode, if the [7:6] bits (mod bits of | ||
136 | * ModRM) on the second byte are not 11b, it is | ||
137 | * LDS or LES. | ||
138 | */ | ||
139 | if (X86_MODRM_MOD(b2) != 3) | ||
140 | goto vex_end; | ||
141 | } | ||
142 | insn->vex_prefix.bytes[0] = b; | ||
143 | insn->vex_prefix.bytes[1] = b2; | ||
144 | if (inat_is_vex3_prefix(attr)) { | ||
145 | b2 = peek_nbyte_next(insn_byte_t, insn, 2); | ||
146 | insn->vex_prefix.bytes[2] = b2; | ||
147 | insn->vex_prefix.nbytes = 3; | ||
148 | insn->next_byte += 3; | ||
149 | if (insn->x86_64 && X86_VEX_W(b2)) | ||
150 | /* VEX.W overrides opnd_size */ | ||
151 | insn->opnd_bytes = 8; | ||
152 | } else { | ||
153 | insn->vex_prefix.nbytes = 2; | ||
154 | insn->next_byte += 2; | ||
155 | } | ||
156 | } | ||
157 | vex_end: | ||
158 | insn->vex_prefix.got = 1; | ||
159 | |||
123 | prefixes->got = 1; | 160 | prefixes->got = 1; |
124 | return; | 161 | return; |
125 | } | 162 | } |
@@ -147,6 +184,18 @@ void insn_get_opcode(struct insn *insn) | |||
147 | op = get_next(insn_byte_t, insn); | 184 | op = get_next(insn_byte_t, insn); |
148 | opcode->bytes[0] = op; | 185 | opcode->bytes[0] = op; |
149 | opcode->nbytes = 1; | 186 | opcode->nbytes = 1; |
187 | |||
188 | /* Check if there is VEX prefix or not */ | ||
189 | if (insn_is_avx(insn)) { | ||
190 | insn_byte_t m, p; | ||
191 | m = insn_vex_m_bits(insn); | ||
192 | p = insn_vex_p_bits(insn); | ||
193 | insn->attr = inat_get_avx_attribute(op, m, p); | ||
194 | if (!inat_accept_vex(insn->attr)) | ||
195 | insn->attr = 0; /* This instruction is bad */ | ||
196 | goto end; /* VEX has only 1 byte for opcode */ | ||
197 | } | ||
198 | |||
150 | insn->attr = inat_get_opcode_attribute(op); | 199 | insn->attr = inat_get_opcode_attribute(op); |
151 | while (inat_is_escape(insn->attr)) { | 200 | while (inat_is_escape(insn->attr)) { |
152 | /* Get escaped opcode */ | 201 | /* Get escaped opcode */ |
@@ -155,6 +204,9 @@ void insn_get_opcode(struct insn *insn) | |||
155 | pfx = insn_last_prefix(insn); | 204 | pfx = insn_last_prefix(insn); |
156 | insn->attr = inat_get_escape_attribute(op, pfx, insn->attr); | 205 | insn->attr = inat_get_escape_attribute(op, pfx, insn->attr); |
157 | } | 206 | } |
207 | if (inat_must_vex(insn->attr)) | ||
208 | insn->attr = 0; /* This instruction is bad */ | ||
209 | end: | ||
158 | opcode->got = 1; | 210 | opcode->got = 1; |
159 | } | 211 | } |
160 | 212 | ||