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