1 #include "x86-emulate.h"
2
3 #include <stdio.h>
4
5 enum mem_access { mem_none, mem_read, mem_write };
6 enum pfx { pfx_none, pfx_66, pfx_f3, pfx_f2 };
7 static const uint8_t prefixes[] = { 0x66, 0xf3, 0xf2 };
8
9 #define F false
10 #define T true
11
12 #define N mem_none
13 #define R mem_read
14 #define W mem_write
15
16 /*
17 * ModR/M bytes and immediates don't need spelling out in the opcodes,
18 * unless the implied zeros aren't good enough.
19 */
20 static const struct {
21 uint8_t opc[8];
22 uint8_t len[2]; /* 32- and 64-bit mode */
23 bool modrm:1; /* Should register form (also) be tested? */
24 unsigned int mem:2;
25 unsigned int pfx:2;
26 #define REG(opc, more...) \
27 { { (opc) | 0 }, more }, /* %?ax */ \
28 { { (opc) | 1 }, more }, /* %?cx */ \
29 { { (opc) | 2 }, more }, /* %?dx */ \
30 { { (opc) | 3 }, more }, /* %?bx */ \
31 { { (opc) | 4 }, more }, /* %?sp */ \
32 { { (opc) | 5 }, more }, /* %?bp */ \
33 { { (opc) | 6 }, more }, /* %?si */ \
34 { { (opc) | 7 }, more } /* %?di */
35 #define CND(opc, more...) \
36 { { (opc) | 0x0 }, more }, /* ..o */ \
37 { { (opc) | 0x1 }, more }, /* ..no */ \
38 { { (opc) | 0x2 }, more }, /* ..c / ..b */ \
39 { { (opc) | 0x3 }, more }, /* ..nc / ..nb */ \
40 { { (opc) | 0x4 }, more }, /* ..z / ..e */ \
41 { { (opc) | 0x5 }, more }, /* ..nz / ..ne */ \
42 { { (opc) | 0x6 }, more }, /* ..be / ..na */ \
43 { { (opc) | 0x7 }, more }, /* ..a / ..nbe */ \
44 { { (opc) | 0x8 }, more }, /* ..s */ \
45 { { (opc) | 0x9 }, more }, /* ..ns */ \
46 { { (opc) | 0xa }, more }, /* ..pe / ..p */ \
47 { { (opc) | 0xb }, more }, /* ..po / ..np */ \
48 { { (opc) | 0xc }, more }, /* ..l / ..nge */ \
49 { { (opc) | 0xd }, more }, /* ..ge / ..nl */ \
50 { { (opc) | 0xe }, more }, /* ..le / ..ng */ \
51 { { (opc) | 0xf }, more } /* ..g / .. nle */
52 } legacy[] = {
53 { { 0x00 }, { 2, 2 }, T, W }, /* add */
54 { { 0x01 }, { 2, 2 }, T, W }, /* add */
55 { { 0x02 }, { 2, 2 }, T, R }, /* add */
56 { { 0x03 }, { 2, 2 }, T, R }, /* add */
57 { { 0x04 }, { 2, 2 }, F, N }, /* add */
58 { { 0x05 }, { 5, 5 }, F, N }, /* add */
59 { { 0x06 }, { 1, 0 }, F, W }, /* push %es */
60 { { 0x07 }, { 1, 0 }, F, R }, /* pop %es */
61 { { 0x08 }, { 2, 2 }, T, W }, /* or */
62 { { 0x09 }, { 2, 2 }, T, W }, /* or */
63 { { 0x0a }, { 2, 2 }, T, R }, /* or */
64 { { 0x0b }, { 2, 2 }, T, R }, /* or */
65 { { 0x0c }, { 2, 2 }, F, N }, /* or */
66 { { 0x0d }, { 5, 5 }, F, N }, /* or */
67 { { 0x0e }, { 1, 0 }, F, W }, /* push %cs */
68 { { 0x10 }, { 2, 2 }, T, W }, /* adc */
69 { { 0x11 }, { 2, 2 }, T, W }, /* adc */
70 { { 0x12 }, { 2, 2 }, T, R }, /* adc */
71 { { 0x13 }, { 2, 2 }, T, R }, /* adc */
72 { { 0x14 }, { 2, 2 }, F, N }, /* adc */
73 { { 0x15 }, { 5, 5 }, F, N }, /* adc */
74 { { 0x16 }, { 1, 0 }, F, W }, /* push %ss */
75 { { 0x17 }, { 1, 0 }, F, R }, /* pop %ss */
76 { { 0x18 }, { 2, 2 }, T, W }, /* adc */
77 { { 0x19 }, { 2, 2 }, T, W }, /* adc */
78 { { 0x1a }, { 2, 2 }, T, R }, /* adc */
79 { { 0x1b }, { 2, 2 }, T, R }, /* adc */
80 { { 0x1c }, { 2, 2 }, F, N }, /* adc */
81 { { 0x1d }, { 5, 5 }, F, N }, /* adc */
82 { { 0x1e }, { 1, 0 }, F, W }, /* push %ds */
83 { { 0x1f }, { 1, 0 }, F, R }, /* pop %ds */
84 { { 0x20 }, { 2, 2 }, T, W }, /* and */
85 { { 0x21 }, { 2, 2 }, T, W }, /* and */
86 { { 0x22 }, { 2, 2 }, T, R }, /* and */
87 { { 0x23 }, { 2, 2 }, T, R }, /* and */
88 { { 0x24 }, { 2, 2 }, F, N }, /* and */
89 { { 0x25 }, { 5, 5 }, F, N }, /* and */
90 { { 0x27 }, { 1, 0 }, F, N }, /* daa */
91 { { 0x28 }, { 2, 2 }, T, W }, /* sub */
92 { { 0x29 }, { 2, 2 }, T, W }, /* sub */
93 { { 0x2a }, { 2, 2 }, T, R }, /* sub */
94 { { 0x2b }, { 2, 2 }, T, R }, /* sub */
95 { { 0x2c }, { 2, 2 }, F, N }, /* sub */
96 { { 0x2d }, { 5, 5 }, F, N }, /* sub */
97 { { 0x2f }, { 1, 0 }, F, N }, /* das */
98 { { 0x30 }, { 2, 2 }, T, W }, /* xor */
99 { { 0x31 }, { 2, 2 }, T, W }, /* xor */
100 { { 0x32 }, { 2, 2 }, T, R }, /* xor */
101 { { 0x33 }, { 2, 2 }, T, R }, /* xor */
102 { { 0x34 }, { 2, 2 }, F, N }, /* xor */
103 { { 0x35 }, { 5, 5 }, F, N }, /* xor */
104 { { 0x37 }, { 1, 0 }, F, N }, /* aaa */
105 { { 0x38 }, { 2, 2 }, T, R }, /* cmp */
106 { { 0x39 }, { 2, 2 }, T, R }, /* cmp */
107 { { 0x3a }, { 2, 2 }, T, R }, /* cmp */
108 { { 0x3b }, { 2, 2 }, T, R }, /* cmp */
109 { { 0x3c }, { 2, 2 }, F, N }, /* cmp */
110 { { 0x3d }, { 5, 5 }, F, N }, /* cmp */
111 { { 0x3f }, { 1, 0 }, F, N }, /* aas */
112 REG(0x40, { 1, 0 }, F, N ), /* inc */
113 REG(0x48, { 1, 0 }, F, N ), /* dec */
114 REG(0x50, { 1, 0 }, F, W ), /* push */
115 REG(0x58, { 1, 0 }, F, R ), /* pop */
116 { { 0x60 }, { 1, 0 }, F, W }, /* pusha */
117 { { 0x61 }, { 1, 0 }, F, R }, /* popa */
118 { { 0x62 }, { 2, 0 }, F, R }, /* bound */
119 { { 0x63 }, { 2, 0 }, F, W }, /* arpl */
120 { { 0x63 }, { 0, 2 }, F, R }, /* movsxd */
121 { { 0x68 }, { 5, 5 }, F, W }, /* push */
122 { { 0x69 }, { 6, 6 }, T, R }, /* imul */
123 { { 0x6a }, { 2, 2 }, F, W }, /* push */
124 { { 0x6b }, { 3, 3 }, T, R }, /* imul */
125 { { 0x6c }, { 1, 1 }, F, W }, /* ins */
126 { { 0x6d }, { 1, 1 }, F, W }, /* ins */
127 { { 0x6e }, { 1, 1 }, F, R }, /* outs */
128 { { 0x6f }, { 1, 1 }, F, R }, /* outs */
129 CND(0x70, { 2, 2 }, F, N ), /* j<cc> */
130 { { 0x80, 0x00 }, { 3, 3 }, T, W }, /* add */
131 { { 0x80, 0x08 }, { 3, 3 }, T, W }, /* or */
132 { { 0x80, 0x10 }, { 3, 3 }, T, W }, /* adc */
133 { { 0x80, 0x18 }, { 3, 3 }, T, W }, /* sbb */
134 { { 0x80, 0x20 }, { 3, 3 }, T, W }, /* and */
135 { { 0x80, 0x28 }, { 3, 3 }, T, W }, /* sub */
136 { { 0x80, 0x30 }, { 3, 3 }, T, W }, /* xor */
137 { { 0x80, 0x38 }, { 3, 3 }, T, R }, /* cmp */
138 { { 0x81, 0x00 }, { 6, 6 }, T, W }, /* add */
139 { { 0x81, 0x08 }, { 6, 6 }, T, W }, /* or */
140 { { 0x81, 0x10 }, { 6, 6 }, T, W }, /* adc */
141 { { 0x81, 0x18 }, { 6, 6 }, T, W }, /* sbb */
142 { { 0x81, 0x20 }, { 6, 6 }, T, W }, /* and */
143 { { 0x81, 0x28 }, { 6, 6 }, T, W }, /* sub */
144 { { 0x81, 0x30 }, { 6, 6 }, T, W }, /* add */
145 { { 0x81, 0x38 }, { 6, 6 }, T, R }, /* cmp */
146 { { 0x82, 0x00 }, { 3, 0 }, T, W }, /* xor */
147 { { 0x82, 0x08 }, { 3, 0 }, T, W }, /* or */
148 { { 0x82, 0x10 }, { 3, 0 }, T, W }, /* adc */
149 { { 0x82, 0x18 }, { 3, 0 }, T, W }, /* sbb */
150 { { 0x82, 0x20 }, { 3, 0 }, T, W }, /* and */
151 { { 0x82, 0x28 }, { 3, 0 }, T, W }, /* sub */
152 { { 0x82, 0x30 }, { 3, 0 }, T, W }, /* xor */
153 { { 0x82, 0x38 }, { 3, 0 }, T, R }, /* cmp */
154 { { 0x83, 0x00 }, { 3, 3 }, T, W }, /* add */
155 { { 0x83, 0x08 }, { 3, 3 }, T, W }, /* or */
156 { { 0x83, 0x10 }, { 3, 3 }, T, W }, /* adc */
157 { { 0x83, 0x18 }, { 3, 3 }, T, W }, /* sbb */
158 { { 0x83, 0x20 }, { 3, 3 }, T, W }, /* and */
159 { { 0x83, 0x28 }, { 3, 3 }, T, W }, /* sub */
160 { { 0x83, 0x30 }, { 3, 3 }, T, W }, /* xor */
161 { { 0x83, 0x38 }, { 3, 3 }, T, R }, /* cmp */
162 { { 0x84 }, { 2, 2 }, T, R }, /* test */
163 { { 0x85 }, { 2, 2 }, T, R }, /* test */
164 { { 0x86 }, { 2, 2 }, T, W }, /* xchg */
165 { { 0x87 }, { 2, 2 }, T, W }, /* xchg */
166 { { 0x88 }, { 2, 2 }, T, W }, /* mov */
167 { { 0x89 }, { 2, 2 }, T, W }, /* mov */
168 { { 0x8a }, { 2, 2 }, T, R }, /* mov */
169 { { 0x8b }, { 2, 2 }, T, R }, /* mov */
170 { { 0x8c }, { 2, 2 }, T, W }, /* mov */
171 { { 0x8d }, { 2, 2 }, F, N }, /* lea */
172 { { 0x8e }, { 2, 2 }, T, R }, /* mov */
173 { { 0x8f, 0x00 }, { 2, 2 }, F, W }, /* pop */
174 { { 0x8f, 0xc0 }, { 2, 2 }, F, R }, /* pop */
175 REG(0x90, { 1, 0 }, F, N ), /* xchg */
176 { { 0x98 }, { 1, 1 }, F, N }, /* cbw */
177 { { 0x99 }, { 1, 1 }, F, N }, /* cwd */
178 { { 0x9a }, { 7, 0 }, F, W }, /* lcall */
179 { { 0x9b }, { 1, 1 }, F, N }, /* wait */
180 { { 0x9c }, { 1, 1 }, F, W }, /* pushf */
181 { { 0x9d }, { 1, 1 }, F, R }, /* popf */
182 { { 0x9e }, { 1, 1 }, F, N }, /* sahf */
183 { { 0x9f }, { 1, 1 }, F, N }, /* lahf */
184 { { 0xa0 }, { 5, 9 }, F, R }, /* mov */
185 { { 0xa1 }, { 5, 9 }, F, R }, /* mov */
186 { { 0xa2 }, { 5, 9 }, F, W }, /* mov */
187 { { 0xa3 }, { 5, 9 }, F, W }, /* mov */
188 { { 0xa4 }, { 1, 1 }, F, W }, /* movs */
189 { { 0xa5 }, { 1, 1 }, F, W }, /* movs */
190 { { 0xa6 }, { 1, 1 }, F, R }, /* cmps */
191 { { 0xa7 }, { 1, 1 }, F, R }, /* cmps */
192 { { 0xa8 }, { 2, 2 }, F, N }, /* test */
193 { { 0xa9 }, { 5, 5 }, F, N }, /* test */
194 { { 0xaa }, { 1, 1 }, F, W }, /* stos */
195 { { 0xab }, { 1, 1 }, F, W }, /* stos */
196 { { 0xac }, { 1, 1 }, F, R }, /* lods */
197 { { 0xad }, { 1, 1 }, F, R }, /* lods */
198 { { 0xae }, { 1, 1 }, F, R }, /* scas */
199 { { 0xaf }, { 1, 1 }, F, R }, /* scas */
200 REG(0xb0, { 2, 2 }, F, N ), /* mov */
201 REG(0xb8, { 5, 5 }, F, N ), /* mov */
202 { { 0xc0, 0x00 }, { 3, 3 }, T, W }, /* rol */
203 { { 0xc0, 0x08 }, { 3, 3 }, T, W }, /* ror */
204 { { 0xc0, 0x10 }, { 3, 3 }, T, W }, /* rcl */
205 { { 0xc0, 0x18 }, { 3, 3 }, T, W }, /* rcr */
206 { { 0xc0, 0x20 }, { 3, 3 }, T, W }, /* shl */
207 { { 0xc0, 0x28 }, { 3, 3 }, T, W }, /* shr */
208 { { 0xc0, 0x30 }, { 3, 3 }, T, W }, /* sal */
209 { { 0xc0, 0x38 }, { 3, 3 }, T, W }, /* sar */
210 { { 0xc1, 0x00 }, { 3, 3 }, T, W }, /* rol */
211 { { 0xc1, 0x08 }, { 3, 3 }, T, W }, /* ror */
212 { { 0xc1, 0x10 }, { 3, 3 }, T, W }, /* rcl */
213 { { 0xc1, 0x18 }, { 3, 3 }, T, W }, /* rcr */
214 { { 0xc1, 0x20 }, { 3, 3 }, T, W }, /* shl */
215 { { 0xc1, 0x28 }, { 3, 3 }, T, W }, /* shr */
216 { { 0xc1, 0x30 }, { 3, 3 }, T, W }, /* sal */
217 { { 0xc1, 0x38 }, { 3, 3 }, T, W }, /* sar */
218 { { 0xc2 }, { 3, 3 }, F, R }, /* ret */
219 { { 0xc3 }, { 1, 1 }, F, R }, /* ret */
220 { { 0xc4 }, { 2, 0 }, F, R }, /* les */
221 { { 0xc5 }, { 2, 0 }, F, R }, /* lds */
222 { { 0xc6, 0x00 }, { 3, 3 }, T, W }, /* mov */
223 { { 0xc6, 0xf8 }, { 3, 3 }, F, N }, /* xabort */
224 { { 0xc7, 0x00 }, { 6, 6 }, T, W }, /* mov */
225 { { 0xc7, 0xf8 }, { 6, 6 }, F, N }, /* xbegin */
226 { { 0xc8 }, { 4, 4 }, F, W }, /* enter */
227 { { 0xc9 }, { 1, 1 }, F, R }, /* leave */
228 { { 0xca }, { 3, 3 }, F, R }, /* lret */
229 { { 0xcb }, { 1, 1 }, F, R }, /* lret */
230 { { 0xcc }, { 1, 1 }, F, N }, /* int3 */
231 { { 0xcd }, { 2, 2 }, F, N }, /* int */
232 { { 0xce }, { 1, 0 }, F, N }, /* into */
233 { { 0xcf }, { 1, 1 }, F, N }, /* iret */
234 { { 0xd0, 0x00 }, { 2, 2 }, T, W }, /* rol */
235 { { 0xd0, 0x08 }, { 2, 2 }, T, W }, /* ror */
236 { { 0xd0, 0x10 }, { 2, 2 }, T, W }, /* rcl */
237 { { 0xd0, 0x18 }, { 2, 2 }, T, W }, /* rcr */
238 { { 0xd0, 0x20 }, { 2, 2 }, T, W }, /* shl */
239 { { 0xd0, 0x28 }, { 2, 2 }, T, W }, /* shr */
240 { { 0xd0, 0x30 }, { 2, 2 }, T, W }, /* sal */
241 { { 0xd0, 0x38 }, { 2, 2 }, T, W }, /* sar */
242 { { 0xd1, 0x00 }, { 2, 2 }, T, W }, /* rol */
243 { { 0xd1, 0x08 }, { 2, 2 }, T, W }, /* ror */
244 { { 0xd1, 0x10 }, { 2, 2 }, T, W }, /* rcl */
245 { { 0xd1, 0x18 }, { 2, 2 }, T, W }, /* rcr */
246 { { 0xd1, 0x20 }, { 2, 2 }, T, W }, /* shl */
247 { { 0xd1, 0x28 }, { 2, 2 }, T, W }, /* shr */
248 { { 0xd1, 0x30 }, { 2, 2 }, T, W }, /* sal */
249 { { 0xd1, 0x38 }, { 2, 2 }, T, W }, /* sar */
250 { { 0xd2, 0x00 }, { 2, 2 }, T, W }, /* rol */
251 { { 0xd2, 0x08 }, { 2, 2 }, T, W }, /* ror */
252 { { 0xd2, 0x10 }, { 2, 2 }, T, W }, /* rcl */
253 { { 0xd2, 0x18 }, { 2, 2 }, T, W }, /* rcr */
254 { { 0xd2, 0x20 }, { 2, 2 }, T, W }, /* shl */
255 { { 0xd2, 0x28 }, { 2, 2 }, T, W }, /* shr */
256 { { 0xd2, 0x30 }, { 2, 2 }, T, W }, /* sal */
257 { { 0xd2, 0x38 }, { 2, 2 }, T, W }, /* sar */
258 { { 0xd3, 0x00 }, { 2, 2 }, T, W }, /* rol */
259 { { 0xd3, 0x08 }, { 2, 2 }, T, W }, /* ror */
260 { { 0xd3, 0x10 }, { 2, 2 }, T, W }, /* rcl */
261 { { 0xd3, 0x18 }, { 2, 2 }, T, W }, /* rcr */
262 { { 0xd3, 0x20 }, { 2, 2 }, T, W }, /* shl */
263 { { 0xd3, 0x28 }, { 2, 2 }, T, W }, /* shr */
264 { { 0xd3, 0x30 }, { 2, 2 }, T, W }, /* sal */
265 { { 0xd3, 0x38 }, { 2, 2 }, T, W }, /* sar */
266 { { 0xd4 }, { 2, 0 }, F, N }, /* aam */
267 { { 0xd5 }, { 2, 0 }, F, N }, /* aad */
268 { { 0xd6 }, { 1, 0 }, F, N }, /* salc */
269 { { 0xd7 }, { 1, 1 }, F, R }, /* xlat */
270 { { 0xe0 }, { 2, 2 }, F, N }, /* loopne */
271 { { 0xe1 }, { 2, 2 }, F, N }, /* loope */
272 { { 0xe2 }, { 2, 2 }, F, N }, /* loop */
273 { { 0xe3 }, { 2, 2 }, F, N }, /* j?cxz */
274 { { 0xe4 }, { 2, 2 }, F, N }, /* in */
275 { { 0xe5 }, { 2, 2 }, F, N }, /* in */
276 { { 0xe6 }, { 2, 2 }, F, N }, /* out */
277 { { 0xe7 }, { 2, 2 }, F, N }, /* out */
278 { { 0xe8 }, { 5, 5 }, F, W }, /* call */
279 { { 0xe9 }, { 5, 5 }, F, N }, /* jmp */
280 { { 0xea }, { 7, 0 }, F, N }, /* ljmp */
281 { { 0xeb }, { 2, 2 }, F, N }, /* jmp */
282 { { 0xec }, { 1, 1 }, F, N }, /* in */
283 { { 0xed }, { 1, 1 }, F, N }, /* in */
284 { { 0xee }, { 1, 1 }, F, N }, /* out */
285 { { 0xef }, { 1, 1 }, F, N }, /* out */
286 { { 0xf1 }, { 1, 1 }, F, N }, /* icebp */
287 { { 0xf4 }, { 1, 1 }, F, N }, /* hlt */
288 { { 0xf5 }, { 1, 1 }, F, N }, /* cmc */
289 { { 0xf6, 0x00 }, { 3, 3 }, T, R }, /* test */
290 { { 0xf6, 0x08 }, { 3, 3 }, T, R }, /* test */
291 { { 0xf6, 0x10 }, { 2, 2 }, T, W }, /* not */
292 { { 0xf6, 0x18 }, { 2, 2 }, T, W }, /* neg */
293 { { 0xf6, 0x20 }, { 2, 2 }, T, R }, /* mul */
294 { { 0xf6, 0x28 }, { 2, 2 }, T, R }, /* imul */
295 { { 0xf6, 0x30 }, { 2, 2 }, T, R }, /* div */
296 { { 0xf6, 0x38 }, { 2, 2 }, T, R }, /* idiv */
297 { { 0xf7, 0x00 }, { 6, 6 }, T, R }, /* test */
298 { { 0xf7, 0x08 }, { 6, 6 }, T, R }, /* test */
299 { { 0xf7, 0x10 }, { 2, 2 }, T, W }, /* not */
300 { { 0xf7, 0x18 }, { 2, 2 }, T, W }, /* neg */
301 { { 0xf7, 0x20 }, { 2, 2 }, T, R }, /* mul */
302 { { 0xf7, 0x28 }, { 2, 2 }, T, R }, /* imul */
303 { { 0xf7, 0x30 }, { 2, 2 }, T, R }, /* div */
304 { { 0xf7, 0x38 }, { 2, 2 }, T, R }, /* idiv */
305 { { 0xf8 }, { 1, 1 }, F, N }, /* clc */
306 { { 0xf9 }, { 1, 1 }, F, N }, /* stc */
307 { { 0xfa }, { 1, 1 }, F, N }, /* cli */
308 { { 0xfb }, { 1, 1 }, F, N }, /* sti */
309 { { 0xfc }, { 1, 1 }, F, N }, /* cld */
310 { { 0xfd }, { 1, 1 }, F, N }, /* std */
311 { { 0xfe, 0x00 }, { 2, 2 }, T, W }, /* inc */
312 { { 0xfe, 0x08 }, { 2, 2 }, T, W }, /* dec */
313 { { 0xff, 0x00 }, { 2, 2 }, T, W }, /* inc */
314 { { 0xff, 0x08 }, { 2, 2 }, T, W }, /* dec */
315 { { 0xff, 0x10 }, { 2, 2 }, F, W }, /* call */
316 { { 0xff, 0x18 }, { 2, 2 }, F, W }, /* lcall */
317 { { 0xff, 0x20 }, { 2, 2 }, T, R }, /* jmp */
318 { { 0xff, 0x28 }, { 2, 2 }, F, R }, /* ljmp */
319 { { 0xff, 0x30 }, { 2, 2 }, F, W }, /* push */
320 { { 0xff, 0xd0 }, { 2, 2 }, F, W }, /* call */
321 { { 0xff, 0xf0 }, { 2, 2 }, F, W }, /* push */
322 }, legacy_0f[] = {
323 { { 0x00, 0x00 }, { 2, 2 }, T, W }, /* sldt */
324 { { 0x00, 0x08 }, { 2, 2 }, T, W }, /* str */
325 { { 0x00, 0x10 }, { 2, 2 }, T, R }, /* lldt */
326 { { 0x00, 0x18 }, { 2, 2 }, T, R }, /* ltr */
327 { { 0x00, 0x20 }, { 2, 2 }, T, R }, /* verr */
328 { { 0x00, 0x28 }, { 2, 2 }, T, R }, /* verw */
329 { { 0x01, 0x00 }, { 2, 2 }, F, W }, /* sgdt */
330 { { 0x01, 0x08 }, { 2, 2 }, F, W }, /* sidt */
331 { { 0x01, 0x10 }, { 2, 2 }, F, R }, /* lgdt */
332 { { 0x01, 0x18 }, { 2, 2 }, F, R }, /* lidt */
333 { { 0x01, 0x20 }, { 2, 2 }, T, W }, /* smsw */
334 /*{ 0x01, 0x28 }, { 2, 2 }, F, W, pfx_f3 }, rstorssp */
335 { { 0x01, 0x30 }, { 2, 2 }, T, R }, /* lmsw */
336 { { 0x01, 0x38 }, { 2, 2 }, F, N }, /* invlpg */
337 { { 0x01, 0xc0 }, { 2, 2 }, T, N }, /* enclv */
338 { { 0x01, 0xc1 }, { 2, 2 }, T, N }, /* vmcall */
339 /*{ 0x01, 0xc2 }, { 2, 2 }, F, R }, vmlaunch */
340 /*{ 0x01, 0xc3 }, { 2, 2 }, F, R }, vmresume */
341 { { 0x01, 0xc4 }, { 2, 2 }, T, N }, /* vmxoff */
342 { { 0x01, 0xc5 }, { 2, 2 }, T, N }, /* pconfig */
343 { { 0x01, 0xc8 }, { 2, 2 }, T, N }, /* monitor */
344 { { 0x01, 0xc9 }, { 2, 2 }, T, N }, /* mwait */
345 { { 0x01, 0xca }, { 2, 2 }, T, N }, /* clac */
346 { { 0x01, 0xcb }, { 2, 2 }, T, N }, /* stac */
347 { { 0x01, 0xcf }, { 2, 2 }, T, N }, /* encls */
348 { { 0x01, 0xd0 }, { 2, 2 }, T, N }, /* xgetbv */
349 { { 0x01, 0xd1 }, { 2, 2 }, T, N }, /* xsetbv */
350 { { 0x01, 0xd4 }, { 2, 2 }, T, N }, /* vmfunc */
351 { { 0x01, 0xd5 }, { 2, 2 }, T, N }, /* xend */
352 { { 0x01, 0xd6 }, { 2, 2 }, T, N }, /* xtest */
353 { { 0x01, 0xd7 }, { 2, 2 }, T, N }, /* enclu */
354 /*{ 0x01, 0xd8 }, { 2, 2 }, F, R }, vmrun */
355 { { 0x01, 0xd9 }, { 2, 2 }, T, N }, /* vmcall */
356 { { 0x01, 0xd9 }, { 2, 2 }, T, N, pfx_f3 }, /* vmgexit */
357 { { 0x01, 0xd9 }, { 2, 2 }, T, N, pfx_f2 }, /* vmgexit */
358 /*{ 0x01, 0xda }, { 2, 2 }, F, R }, vmload */
359 /*{ 0x01, 0xdb }, { 2, 2 }, F, W }, vmsave */
360 { { 0x01, 0xdc }, { 2, 2 }, T, N }, /* stgi */
361 { { 0x01, 0xdd }, { 2, 2 }, T, N }, /* clgi */
362 /*{ 0x01, 0xde }, { 2, 2 }, F, R }, skinit */
363 { { 0x01, 0xdf }, { 2, 2 }, T, N }, /* invlpga */
364 { { 0x01, 0xe8 }, { 2, 2 }, T, N }, /* serialize */
365 /*{ 0x01, 0xe8 }, { 2, 2 }, F, W, pfx_f3 }, setssbsy */
366 { { 0x01, 0xe8 }, { 2, 2 }, T, N, pfx_f2 }, /* xsusldtrk */
367 { { 0x01, 0xe9 }, { 2, 2 }, T, N, pfx_f2 }, /* xresldtrk */
368 /*{ 0x01, 0xea }, { 2, 2 }, F, W, pfx_f3 }, saveprevssp */
369 { { 0x01, 0xee }, { 2, 2 }, T, N }, /* rdpkru */
370 { { 0x01, 0xef }, { 2, 2 }, T, N }, /* wrpkru */
371 { { 0x01, 0xf8 }, { 0, 2 }, T, N }, /* swapgs */
372 { { 0x01, 0xf9 }, { 2, 2 }, T, N }, /* rdtscp */
373 { { 0x01, 0xfa }, { 2, 2 }, T, N }, /* monitorx */
374 { { 0x01, 0xfa }, { 2, 2 }, T, N, pfx_f3 }, /* mcommit */
375 { { 0x01, 0xfb }, { 2, 2 }, T, N }, /* mwaitx */
376 { { 0x01, 0xfc }, { 2, 2 }, F, W }, /* clzero */
377 { { 0x01, 0xfd }, { 2, 2 }, T, N }, /* rdpru */
378 { { 0x01, 0xfe }, { 2, 2 }, T, N }, /* invlpgb */
379 { { 0x01, 0xfe }, { 0, 2 }, T, N, pfx_f3 }, /* rmpadjust */
380 { { 0x01, 0xfe }, { 0, 2 }, T, N, pfx_f2 }, /* rmpupdate */
381 { { 0x01, 0xff }, { 2, 2 }, T, N }, /* tlbsync */
382 { { 0x01, 0xff }, { 0, 2 }, T, N, pfx_f3 }, /* psmash */
383 { { 0x01, 0xff }, { 0, 2 }, T, N, pfx_f2 }, /* pvalidate */
384 { { 0x02 }, { 2, 2 }, T, R }, /* lar */
385 { { 0x03 }, { 2, 2 }, T, R }, /* lsl */
386 { { 0x05 }, { 1, 1 }, F, N }, /* syscall */
387 { { 0x06 }, { 1, 1 }, F, N }, /* clts */
388 { { 0x07 }, { 1, 1 }, F, N }, /* sysret */
389 { { 0x08 }, { 1, 1 }, F, N }, /* invd */
390 { { 0x09 }, { 1, 1 }, F, N }, /* wbinvd */
391 { { 0x09 }, { 1, 1 }, F, N, pfx_f3 }, /* wbnoinvd */
392 { { 0x0b }, { 1, 1 }, F, N }, /* ud2 */
393 { { 0x0d, 0x00 }, { 2, 2 }, F, N }, /* prefetch */
394 { { 0x0d, 0x08 }, { 2, 2 }, F, N }, /* prefetchw */
395 { { 0x0e }, { 1, 1 }, F, N }, /* femms */
396 { { 0x18, 0x00 }, { 2, 2 }, F, N }, /* prefetchnta */
397 { { 0x18, 0x08 }, { 2, 2 }, F, N }, /* prefetch0 */
398 { { 0x18, 0x10 }, { 2, 2 }, F, N }, /* prefetch1 */
399 { { 0x18, 0x18 }, { 2, 2 }, F, N }, /* prefetch2 */
400 /*{ 0x1a }, { 2, 2 }, F, R }, bndldx */
401 /*{ 0x1a }, { 2, 2 }, T, R, pfx_66 }, bndmov */
402 { { 0x1a }, { 2, 2 }, T, N, pfx_f3 }, /* bndcl */
403 { { 0x1a }, { 2, 2 }, T, N, pfx_f2 }, /* bndcu */
404 /*{ 0x1b }, { 2, 2 }, F, W }, bndstx */
405 /*{ 0x1b }, { 2, 2 }, T, W, pfx_66 }, bndmov */
406 { { 0x1b }, { 2, 2 }, F, N, pfx_f3 }, /* bndmk */
407 { { 0x1b }, { 2, 2 }, T, N, pfx_f2 }, /* bndcn */
408 { { 0x1c, 0x00 }, { 2, 2 }, F, N }, /* cldemote */
409 { { 0x1e, 0xc8 }, { 2, 2 }, F, N, pfx_f3 }, /* rdssp */
410 { { 0x1e, 0xfa }, { 2, 2 }, F, N, pfx_f3 }, /* endbr64 */
411 { { 0x1e, 0xfb }, { 2, 2 }, F, N, pfx_f3 }, /* endbr32 */
412 { { 0x1f, 0x00 }, { 2, 2 }, T, N }, /* nop */
413 { { 0x20 }, { 2, 2 }, T, N }, /* mov */
414 { { 0x21 }, { 2, 2 }, T, N }, /* mov */
415 { { 0x22 }, { 2, 2 }, T, N }, /* mov */
416 { { 0x23 }, { 2, 2 }, T, N }, /* mov */
417 { { 0x30 }, { 1, 1 }, F, N }, /* wrmsr */
418 { { 0x31 }, { 1, 1 }, F, N }, /* rdtsc */
419 { { 0x32 }, { 1, 1 }, F, N }, /* rdmsr */
420 { { 0x33 }, { 1, 1 }, F, N }, /* rdpmc */
421 { { 0x34 }, { 1, 1 }, F, N }, /* sysenter */
422 { { 0x35 }, { 1, 1 }, F, N }, /* sysexit */
423 CND(0x40, { 2, 2 }, T, R ), /* cmov<cc> */
424 /*{ 0x78 }, { 2, 2 }, T, W }, vmread */
425 { { 0x79 }, { 2, 2 }, T, R }, /* vmwrite */
426 CND(0x80, { 5, 5 }, F, N ), /* j<cc> */
427 CND(0x90, { 2, 2 }, T, W ), /* set<cc> */
428 { { 0xa0 }, { 1, 1 }, F, W }, /* push %fs */
429 { { 0xa1 }, { 1, 1 }, F, R }, /* pop %fs */
430 { { 0xa2 }, { 1, 1 }, F, N }, /* cpuid */
431 { { 0xa3 }, { 2, 2 }, T, R }, /* bt */
432 { { 0xa4 }, { 3, 3 }, T, W }, /* shld */
433 { { 0xa5 }, { 2, 2 }, T, W }, /* shld */
434 { { 0xa8 }, { 1, 1 }, F, W }, /* push %gs */
435 { { 0xa9 }, { 1, 1 }, F, R }, /* pop %gs */
436 { { 0xaa }, { 1, 1 }, F, N }, /* rsm */
437 { { 0xab }, { 2, 2 }, T, W }, /* bts */
438 { { 0xac }, { 3, 3 }, T, W }, /* shrd */
439 { { 0xad }, { 2, 2 }, T, W }, /* shrd */
440 { { 0xae, 0x00 }, { 2, 2 }, F, W }, /* fxsave */
441 { { 0xae, 0x08 }, { 2, 2 }, F, R }, /* fxrstor */
442 { { 0xae, 0x10 }, { 2, 2 }, F, R }, /* ldmxcsr */
443 { { 0xae, 0x18 }, { 2, 2 }, F, W }, /* stmxcsr */
444 { { 0xae, 0x20 }, { 2, 2 }, F, W }, /* xsave */
445 { { 0xae, 0x20 }, { 2, 2 }, F, R, pfx_f3 }, /* ptwrite */
446 { { 0xae, 0x28 }, { 2, 2 }, F, R }, /* xrstor */
447 { { 0xae, 0x30 }, { 2, 2 }, F, W }, /* xsaveopt */
448 { { 0xae, 0x30 }, { 2, 2 }, F, N, pfx_66 }, /* clwb */
449 /*{ 0xae, 0x30 }, { 2, 2 }, F, W, pfx_f3 }, clrssbsy */
450 { { 0xae, 0x38 }, { 2, 2 }, F, N }, /* clflush */
451 { { 0xae, 0x38 }, { 2, 2 }, F, N, pfx_66 }, /* clflushopt */
452 { { 0xae, 0xc0 }, { 0, 2 }, F, N, pfx_f3 }, /* rdfsbase */
453 { { 0xae, 0xc8 }, { 0, 2 }, F, N, pfx_f3 }, /* rdgsbase */
454 { { 0xae, 0xd0 }, { 0, 2 }, F, N, pfx_f3 }, /* wrfsbase */
455 { { 0xae, 0xd8 }, { 0, 2 }, F, N, pfx_f3 }, /* wrgsbase */
456 { { 0xae, 0xe8 }, { 2, 2 }, F, N }, /* lfence */
457 /*{ 0xae, 0xe8 }, { 2, 2 }, F, R, pfx_f3 }, incssp */
458 { { 0xae, 0xf0 }, { 2, 2 }, F, N }, /* mfence */
459 { { 0xae, 0xf0 }, { 2, 2 }, F, N, pfx_66 }, /* tpause */
460 { { 0xae, 0xf0 }, { 2, 2 }, F, N, pfx_f3 }, /* umonitor */
461 { { 0xae, 0xf0 }, { 2, 2 }, F, N, pfx_f2 }, /* umwait */
462 { { 0xae, 0xf8 }, { 2, 2 }, F, N }, /* sfence */
463 { { 0xaf }, { 2, 2 }, T, R }, /* imul */
464 { { 0xb0 }, { 2, 2 }, F, W }, /* cmpxchg */
465 { { 0xb1 }, { 2, 2 }, F, W }, /* cmpxchg */
466 { { 0xb2 }, { 2, 2 }, F, R }, /* lss */
467 { { 0xb3 }, { 2, 2 }, T, W }, /* btr */
468 { { 0xb4 }, { 2, 2 }, F, R }, /* lfs */
469 { { 0xb5 }, { 2, 2 }, F, R }, /* lgs */
470 { { 0xb6 }, { 2, 2 }, F, R }, /* movzx */
471 { { 0xb7 }, { 2, 2 }, F, R }, /* movzx */
472 { { 0xb8 }, { 2, 2 }, F, R }, /* popcnt */
473 { { 0xb9 }, { 2, 2 }, F, N }, /* ud1 */
474 { { 0xba, 0x20 }, { 3, 3 }, T, R }, /* bt */
475 { { 0xba, 0x28 }, { 3, 3 }, T, W }, /* bts */
476 { { 0xba, 0x30 }, { 3, 3 }, T, W }, /* btr */
477 { { 0xba, 0x38 }, { 3, 3 }, T, W }, /* btc */
478 { { 0xbb }, { 2, 2 }, T, W }, /* btc */
479 { { 0xbc }, { 2, 2 }, T, R }, /* bsf */
480 { { 0xbc }, { 2, 2 }, T, R, pfx_f3 }, /* tzcnt */
481 { { 0xbd }, { 2, 2 }, T, R }, /* bsr */
482 { { 0xbd }, { 2, 2 }, T, R, pfx_f3 }, /* lzcnt */
483 { { 0xbe }, { 2, 2 }, F, R }, /* movsx */
484 { { 0xbf }, { 2, 2 }, F, R }, /* movsx */
485 { { 0xc0 }, { 2, 2 }, F, W }, /* xadd */
486 { { 0xc1 }, { 2, 2 }, F, W }, /* xadd */
487 { { 0xc3 }, { 2, 2 }, F, W }, /* movnti */
488 { { 0xc7, 0x08 }, { 2, 2 }, F, W }, /* cmpxchg8b */
489 { { 0xc7, 0x18 }, { 2, 2 }, F, R }, /* xrstors */
490 { { 0xc7, 0x20 }, { 2, 2 }, F, W }, /* xsavec */
491 { { 0xc7, 0x28 }, { 2, 2 }, F, W }, /* xsaves */
492 { { 0xc7, 0x30 }, { 2, 2 }, F, R }, /* vmptrld */
493 { { 0xc7, 0x30 }, { 2, 2 }, F, R, pfx_66 }, /* vmclear */
494 { { 0xc7, 0x30 }, { 2, 2 }, F, R, pfx_f3 }, /* vmxon */
495 { { 0xc7, 0x38 }, { 2, 2 }, F, R }, /* vmptrst */
496 { { 0xc7, 0xf0 }, { 2, 2 }, F, N }, /* rdrand */
497 { { 0xc7, 0xf8 }, { 2, 2 }, F, N }, /* rdseed */
498 { { 0xc7, 0xf8 }, { 2, 2 }, F, N, pfx_f3 }, /* rdpid */
499 REG(0xc8, { 1, 1 }, F, N ), /* bswap */
500 { { 0xff }, { 2, 2 }, F, N }, /* ud0 */
501 }, legacy_0f38[] = {
502 { { 0x80 }, { 2, 2 }, T, R, pfx_66 }, /* invept */
503 { { 0x81 }, { 2, 2 }, T, R, pfx_66 }, /* invvpid */
504 { { 0x82 }, { 2, 2 }, T, R, pfx_66 }, /* invpcid */
505 { { 0xf0 }, { 2, 2 }, T, R }, /* movbe */
506 { { 0xf0 }, { 2, 2 }, T, R, pfx_f2 }, /* crc32 */
507 { { 0xf1 }, { 2, 2 }, T, W }, /* movbe */
508 { { 0xf1 }, { 2, 2 }, T, R, pfx_f2 }, /* crc32 */
509 /*{ 0xf5 }, { 2, 2 }, F, W, pfx_66 }, wruss */
510 /*{ 0xf6 }, { 2, 2 }, F, W }, wrss */
511 { { 0xf6 }, { 2, 2 }, T, R, pfx_66 }, /* adcx */
512 { { 0xf6 }, { 2, 2 }, T, R, pfx_f3 }, /* adox */
513 { { 0xf8 }, { 2, 2 }, F, W, pfx_66 }, /* movdir64b */
514 { { 0xf8 }, { 2, 2 }, F, W, pfx_f3 }, /* enqcmds */
515 { { 0xf8 }, { 2, 2 }, F, W, pfx_f2 }, /* enqcmd */
516 { { 0xf9 }, { 2, 2 }, F, W }, /* movdiri */
517 };
518 #undef CND
519 #undef REG
520 #undef F
521 #undef N
522 #undef R
523 #undef T
524 #undef W
525
526 static unsigned int errors;
527
print_insn(const uint8_t * instr,unsigned int len)528 static void print_insn(const uint8_t *instr, unsigned int len)
529 {
530 if ( !errors++ )
531 puts("");
532 while ( len--)
533 printf("%02x%c", *instr++, len ? ' ' : ':');
534 }
535
do_test(uint8_t * instr,unsigned int len,unsigned int modrm,enum mem_access mem,struct x86_emulate_ctxt * ctxt,int (* fetch)(enum x86_segment seg,unsigned long offset,void * p_data,unsigned int bytes,struct x86_emulate_ctxt * ctxt))536 void do_test(uint8_t *instr, unsigned int len, unsigned int modrm,
537 enum mem_access mem, struct x86_emulate_ctxt *ctxt,
538 int (*fetch)(enum x86_segment seg,
539 unsigned long offset,
540 void *p_data,
541 unsigned int bytes,
542 struct x86_emulate_ctxt *ctxt))
543 {
544 struct x86_emulate_state *s;
545
546 if ( !modrm || mem != mem_none )
547 {
548 s = x86_decode_insn(ctxt, fetch);
549
550 if ( x86_insn_length(s, ctxt) != len )
551 {
552 print_insn(instr, len);
553 printf(" length %u (expected %u)\n", x86_insn_length(s, ctxt), len);
554 }
555
556 if ( x86_insn_is_mem_access(s, ctxt) != (mem != mem_none) )
557 {
558 print_insn(instr, len);
559 printf(" mem access %d (expected %d)\n",
560 x86_insn_is_mem_access(s, ctxt), mem != mem_none);
561 }
562
563 if ( x86_insn_is_mem_write(s, ctxt) != (mem == mem_write) )
564 {
565 print_insn(instr, len);
566 printf(" mem write %d (expected %d)\n",
567 x86_insn_is_mem_write(s, ctxt), mem == mem_write);
568 }
569
570 x86_emulate_free_state(s);
571 }
572
573 if ( modrm )
574 {
575 instr[modrm] |= 0xc0;
576
577 s = x86_decode_insn(ctxt, fetch);
578
579 if ( x86_insn_length(s, ctxt) != len )
580 {
581 print_insn(instr, len);
582 printf(" length %u (expected %u)\n", x86_insn_length(s, ctxt), len);
583 }
584
585 if ( x86_insn_is_mem_access(s, ctxt) ||
586 x86_insn_is_mem_write(s, ctxt) )
587 {
588 print_insn(instr, len);
589 printf(" mem access %d / write %d unexpected\n",
590 x86_insn_is_mem_access(s, ctxt),
591 x86_insn_is_mem_write(s, ctxt));
592 }
593
594 x86_emulate_free_state(s);
595 }
596 }
597
predicates_test(void * instr,struct x86_emulate_ctxt * ctxt,int (* fetch)(enum x86_segment seg,unsigned long offset,void * p_data,unsigned int bytes,struct x86_emulate_ctxt * ctxt))598 void predicates_test(void *instr, struct x86_emulate_ctxt *ctxt,
599 int (*fetch)(enum x86_segment seg,
600 unsigned long offset,
601 void *p_data,
602 unsigned int bytes,
603 struct x86_emulate_ctxt *ctxt))
604 {
605 unsigned int m;
606
607 ctxt->regs->eip = (unsigned long)instr;
608
609 for ( m = 0; m < sizeof(long) / sizeof(int); ++m )
610 {
611 unsigned int t;
612
613 ctxt->addr_size = 32 << m;
614 ctxt->sp_size = 32 << m;
615 ctxt->lma = ctxt->sp_size == 64;
616
617 printf("Testing %u-bit decoding / predicates...", ctxt->sp_size);
618
619 for ( t = 0; t < ARRAY_SIZE(legacy); ++t )
620 {
621 if ( !legacy[t].len[m] )
622 continue;
623
624 assert(!legacy[t].pfx);
625
626 memset(instr + 1, 0xcc, 14);
627 memcpy(instr, legacy[t].opc, legacy[t].len[m]);
628
629 do_test(instr, legacy[t].len[m], legacy[t].modrm, legacy[t].mem,
630 ctxt, fetch);
631 }
632
633 for ( t = 0; t < ARRAY_SIZE(legacy_0f); ++t )
634 {
635 uint8_t *ptr = instr;
636
637 if ( !legacy_0f[t].len[m] )
638 continue;
639
640 memset(instr + 2, 0xcc, 13);
641 if ( legacy_0f[t].pfx )
642 *ptr++ = prefixes[legacy_0f[t].pfx - 1];
643 *ptr++ = 0x0f;
644 memcpy(ptr, legacy_0f[t].opc, legacy_0f[t].len[m]);
645
646 do_test(instr, legacy_0f[t].len[m] + ((void *)ptr - instr),
647 legacy_0f[t].modrm ? (void *)ptr - instr + 1 : 0,
648 legacy_0f[t].mem, ctxt, fetch);
649 }
650
651 for ( t = 0; t < ARRAY_SIZE(legacy_0f38); ++t )
652 {
653 uint8_t *ptr = instr;
654
655 if ( !legacy_0f38[t].len[m] )
656 continue;
657
658 memset(instr + 3, 0xcc, 12);
659 if ( legacy_0f38[t].pfx )
660 *ptr++ = prefixes[legacy_0f38[t].pfx - 1];
661 *ptr++ = 0x0f;
662 *ptr++ = 0x38;
663 memcpy(ptr, legacy_0f38[t].opc, legacy_0f38[t].len[m]);
664
665 do_test(instr, legacy_0f38[t].len[m] + ((void *)ptr - instr),
666 legacy_0f38[t].modrm ? (void *)ptr - instr + 1 : 0,
667 legacy_0f38[t].mem, ctxt, fetch);
668 }
669
670 if ( errors )
671 exit(1);
672
673 puts(" okay");
674 }
675 }
676