1 #include "x86-emulate.h"
2
3 #include <errno.h>
4 #include <sys/mman.h>
5
6 /* See gcc bug 100680, but here don't bother making this version dependent. */
7 #define gcc11_wrap(x) ({ \
8 unsigned long x_; \
9 __asm__ ( "" : "=g" (x_) : "0" (x) ); \
10 (typeof(x))x_; \
11 })
12
13 #define cpu_has_amd_erratum(nr) 0
14 #define cpu_has_mpx false
15 #define read_bndcfgu() 0
16 #define xstate_set_init(what)
17
18 /* For generic assembly code: use macros to define operation/operand sizes. */
19 #ifdef __i386__
20 # define __OS "l" /* Operation Suffix */
21 # define __OP "e" /* Operand Prefix */
22 #else
23 # define __OS "q" /* Operation Suffix */
24 # define __OP "r" /* Operand Prefix */
25 #endif
26
27 uint32_t mxcsr_mask = 0x0000ffbf;
28 struct cpu_policy cp;
29
30 static char fpu_save_area[0x4000] __attribute__((__aligned__((64))));
31 static bool use_xsave;
32
33 /*
34 * Re-use the area above also as scratch space for the emulator itself.
35 * (When debugging the emulator, care needs to be taken when inserting
36 * printf() or alike function calls into regions using this.)
37 */
get_fpu_save_area(void)38 struct x86_fxsr *get_fpu_save_area(void)
39 {
40 return (void *)fpu_save_area;
41 }
42
emul_save_fpu_state(void)43 void emul_save_fpu_state(void)
44 {
45 if ( use_xsave )
46 asm volatile ( "xsave %[ptr]"
47 : [ptr] "=m" (fpu_save_area)
48 : "a" (~0ul), "d" (~0ul) );
49 else
50 asm volatile ( "fxsave %0" : "=m" (fpu_save_area) );
51 }
52
emul_restore_fpu_state(void)53 void emul_restore_fpu_state(void)
54 {
55 /* Older gcc can't deal with "m" array inputs; make them outputs instead. */
56 if ( use_xsave )
57 asm volatile ( "xrstor %[ptr]"
58 : [ptr] "+m" (fpu_save_area)
59 : "a" (~0ul), "d" (~0ul) );
60 else
61 asm volatile ( "fxrstor %0" : "+m" (fpu_save_area) );
62 }
63
emul_test_init(void)64 bool emul_test_init(void)
65 {
66 union {
67 char x[464];
68 struct {
69 uint32_t other[6];
70 uint32_t mxcsr;
71 uint32_t mxcsr_mask;
72 /* ... */
73 };
74 } *fxs = (void *)fpu_save_area;
75
76 unsigned long sp;
77
78 x86_cpu_policy_fill_native(&cp);
79
80 /*
81 * The emulator doesn't use these instructions, so can always emulate
82 * them.
83 */
84 cp.basic.movbe = true;
85 cp.feat.invpcid = true;
86 cp.feat.adx = true;
87 cp.feat.avx512pf = cp.feat.avx512f;
88 cp.feat.rdpid = true;
89 cp.feat.wrmsrns = true;
90 cp.extd.clzero = true;
91
92 if ( cpu_has_xsave )
93 {
94 unsigned int tmp, ebx;
95
96 asm ( "cpuid"
97 : "=a" (tmp), "=b" (ebx), "=c" (tmp), "=d" (tmp)
98 : "a" (0xd), "c" (0) );
99
100 /*
101 * Sanity check that fpu_save_area[] is large enough. This assertion
102 * will trip eventually, at which point fpu_save_area[] needs to get
103 * larger.
104 */
105 assert(ebx < sizeof(fpu_save_area));
106
107 /* Use xsave if available... */
108 use_xsave = true;
109 }
110 else
111 /* But use fxsave if xsave isn't available. */
112 assert(cpu_has_fxsr);
113
114 /* Reuse the save state buffer to find mcxsr_mask. */
115 asm ( "fxsave %0" : "=m" (*fxs) );
116 if ( fxs->mxcsr_mask )
117 mxcsr_mask = fxs->mxcsr_mask;
118
119 /*
120 * Mark the entire stack executable so that the stub executions
121 * don't fault
122 */
123 #ifdef __x86_64__
124 asm ("movq %%rsp, %0" : "=g" (sp));
125 #else
126 asm ("movl %%esp, %0" : "=g" (sp));
127 #endif
128
129 return mprotect((void *)(sp & -0x1000L) - (MMAP_SZ - 0x1000),
130 MMAP_SZ, PROT_READ|PROT_WRITE|PROT_EXEC) == 0;
131 }
132
emul_test_cpuid(uint32_t leaf,uint32_t subleaf,struct cpuid_leaf * res,struct x86_emulate_ctxt * ctxt)133 int emul_test_cpuid(
134 uint32_t leaf,
135 uint32_t subleaf,
136 struct cpuid_leaf *res,
137 struct x86_emulate_ctxt *ctxt)
138 {
139 asm ("cpuid"
140 : "=a" (res->a), "=b" (res->b), "=c" (res->c), "=d" (res->d)
141 : "a" (leaf), "c" (subleaf));
142
143 /*
144 * The emulator doesn't itself use MOVBE, so we can always run the
145 * respective tests.
146 */
147 if ( leaf == 1 )
148 res->c |= 1U << 22;
149
150 /*
151 * The emulator doesn't itself use ADCX/ADOX/RDPID nor the S/G prefetch
152 * insns, so we can always run the respective tests.
153 */
154 if ( leaf == 7 && subleaf == 0 )
155 {
156 res->b |= (1U << 10) | (1U << 19);
157 if ( res->b & (1U << 16) )
158 res->b |= 1U << 26;
159 res->c |= 1U << 22;
160 }
161
162 /*
163 * The emulator doesn't itself use CLZERO, so we can always run the
164 * respective test(s).
165 */
166 if ( leaf == 0x80000008 )
167 res->b |= 1U << 0;
168
169 return X86EMUL_OKAY;
170 }
171
emul_test_read_cr(unsigned int reg,unsigned long * val,struct x86_emulate_ctxt * ctxt)172 int emul_test_read_cr(
173 unsigned int reg,
174 unsigned long *val,
175 struct x86_emulate_ctxt *ctxt)
176 {
177 /* Fake just enough state for the emulator's _get_fpu() to be happy. */
178 switch ( reg )
179 {
180 case 0:
181 *val = 0x00000001; /* PE */
182 return X86EMUL_OKAY;
183
184 case 4:
185 *val = X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT | X86_CR4_PKE |
186 (cpu_has_xsave ? X86_CR4_OSXSAVE : 0);
187 return X86EMUL_OKAY;
188 }
189
190 return X86EMUL_UNHANDLEABLE;
191 }
192
emul_test_read_xcr(unsigned int reg,uint64_t * val,struct x86_emulate_ctxt * ctxt)193 int emul_test_read_xcr(
194 unsigned int reg,
195 uint64_t *val,
196 struct x86_emulate_ctxt *ctxt)
197 {
198 uint32_t lo, hi;
199
200 ASSERT(cpu_has_xsave);
201
202 switch ( reg )
203 {
204 case 0:
205 break;
206
207 case 1:
208 if ( cpu_has_xgetbv1 )
209 break;
210 /* fall through */
211 default:
212 x86_emul_hw_exception(13 /* #GP */, 0, ctxt);
213 return X86EMUL_EXCEPTION;
214 }
215
216 asm ( "xgetbv" : "=a" (lo), "=d" (hi) : "c" (reg) );
217 *val = lo | ((uint64_t)hi << 32);
218
219 return X86EMUL_OKAY;
220 }
221
emul_test_get_fpu(enum x86_emulate_fpu_type type,struct x86_emulate_ctxt * ctxt)222 int emul_test_get_fpu(
223 enum x86_emulate_fpu_type type,
224 struct x86_emulate_ctxt *ctxt)
225 {
226 switch ( type )
227 {
228 case X86EMUL_FPU_fpu:
229 break;
230 case X86EMUL_FPU_mmx:
231 if ( cpu_has_mmx )
232 break;
233 case X86EMUL_FPU_xmm:
234 if ( cpu_has_sse )
235 break;
236 case X86EMUL_FPU_ymm:
237 if ( cpu_has_avx )
238 break;
239 case X86EMUL_FPU_opmask:
240 case X86EMUL_FPU_zmm:
241 if ( cpu_has_avx512f )
242 break;
243 default:
244 return X86EMUL_UNHANDLEABLE;
245 }
246 return X86EMUL_OKAY;
247 }
248
emul_test_put_fpu(struct x86_emulate_ctxt * ctxt,enum x86_emulate_fpu_type backout,const struct x86_emul_fpu_aux * aux)249 void emul_test_put_fpu(
250 struct x86_emulate_ctxt *ctxt,
251 enum x86_emulate_fpu_type backout,
252 const struct x86_emul_fpu_aux *aux)
253 {
254 /* TBD */
255 }
256
257 static uint32_t pkru;
258
rdpkru(void)259 unsigned int rdpkru(void)
260 {
261 return pkru;
262 }
263
wrpkru(unsigned int val)264 void wrpkru(unsigned int val)
265 {
266 pkru = val;
267 }
268
269 #include "x86_emulate/x86_emulate.c"
270