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 cpu_policy;
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(&cpu_policy);
79
80 /*
81 * The emulator doesn't use these instructions, so can always emulate
82 * them.
83 */
84 cpu_policy.basic.movbe = true;
85 cpu_policy.feat.invpcid = true;
86 cpu_policy.feat.adx = true;
87 cpu_policy.feat.rdpid = true;
88 cpu_policy.feat.wrmsrns = true;
89 cpu_policy.extd.clzero = true;
90
91 if ( cpu_has_xsave )
92 {
93 unsigned int tmp, ebx;
94
95 asm ( "cpuid"
96 : "=a" (tmp), "=b" (ebx), "=c" (tmp), "=d" (tmp)
97 : "a" (0xd), "c" (0) );
98
99 /*
100 * Sanity check that fpu_save_area[] is large enough. This assertion
101 * will trip eventually, at which point fpu_save_area[] needs to get
102 * larger.
103 */
104 assert(ebx < sizeof(fpu_save_area));
105
106 /* Use xsave if available... */
107 use_xsave = true;
108 }
109 else
110 /* But use fxsave if xsave isn't available. */
111 assert(cpu_has_fxsr);
112
113 /* Reuse the save state buffer to find mcxsr_mask. */
114 asm ( "fxsave %0" : "=m" (*fxs) );
115 if ( fxs->mxcsr_mask )
116 mxcsr_mask = fxs->mxcsr_mask;
117
118 /*
119 * Mark the entire stack executable so that the stub executions
120 * don't fault
121 */
122 #ifdef __x86_64__
123 asm ("movq %%rsp, %0" : "=g" (sp));
124 #else
125 asm ("movl %%esp, %0" : "=g" (sp));
126 #endif
127
128 return mprotect((void *)(sp & -0x1000L) - (MMAP_SZ - 0x1000),
129 MMAP_SZ, PROT_READ|PROT_WRITE|PROT_EXEC) == 0;
130 }
131
emul_test_cpuid(uint32_t leaf,uint32_t subleaf,struct cpuid_leaf * res,struct x86_emulate_ctxt * ctxt)132 int emul_test_cpuid(
133 uint32_t leaf,
134 uint32_t subleaf,
135 struct cpuid_leaf *res,
136 struct x86_emulate_ctxt *ctxt)
137 {
138 asm ("cpuid"
139 : "=a" (res->a), "=b" (res->b), "=c" (res->c), "=d" (res->d)
140 : "a" (leaf), "c" (subleaf));
141
142 /*
143 * The emulator doesn't itself use MOVBE, so we can always run the
144 * respective tests.
145 */
146 if ( leaf == 1 )
147 res->c |= 1U << 22;
148
149 /*
150 * The emulator doesn't itself use ADCX/ADOX/RDPID nor the S/G prefetch
151 * insns, so we can always run the respective tests.
152 */
153 if ( leaf == 7 && subleaf == 0 )
154 {
155 res->b |= (1U << 10) | (1U << 19);
156 if ( res->b & (1U << 16) )
157 res->b |= 1U << 26;
158 res->c |= 1U << 22;
159 }
160
161 /*
162 * The emulator doesn't itself use CLZERO, so we can always run the
163 * respective test(s).
164 */
165 if ( leaf == 0x80000008 )
166 res->b |= 1U << 0;
167
168 return X86EMUL_OKAY;
169 }
170
emul_test_read_cr(unsigned int reg,unsigned long * val,struct x86_emulate_ctxt * ctxt)171 int emul_test_read_cr(
172 unsigned int reg,
173 unsigned long *val,
174 struct x86_emulate_ctxt *ctxt)
175 {
176 /* Fake just enough state for the emulator's _get_fpu() to be happy. */
177 switch ( reg )
178 {
179 case 0:
180 *val = 0x00000001; /* PE */
181 return X86EMUL_OKAY;
182
183 case 4:
184 *val = X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT | X86_CR4_PKE |
185 (cpu_has_xsave ? X86_CR4_OSXSAVE : 0);
186 return X86EMUL_OKAY;
187 }
188
189 return X86EMUL_UNHANDLEABLE;
190 }
191
emul_test_read_xcr(unsigned int reg,uint64_t * val,struct x86_emulate_ctxt * ctxt)192 int emul_test_read_xcr(
193 unsigned int reg,
194 uint64_t *val,
195 struct x86_emulate_ctxt *ctxt)
196 {
197 uint32_t lo, hi;
198
199 ASSERT(cpu_has_xsave);
200
201 switch ( reg )
202 {
203 case 0:
204 break;
205
206 case 1:
207 if ( cpu_has_xgetbv1 )
208 break;
209 /* fall through */
210 default:
211 x86_emul_hw_exception(13 /* #GP */, 0, ctxt);
212 return X86EMUL_EXCEPTION;
213 }
214
215 asm ( "xgetbv" : "=a" (lo), "=d" (hi) : "c" (reg) );
216 *val = lo | ((uint64_t)hi << 32);
217
218 return X86EMUL_OKAY;
219 }
220
emul_test_get_fpu(enum x86_emulate_fpu_type type,struct x86_emulate_ctxt * ctxt)221 int emul_test_get_fpu(
222 enum x86_emulate_fpu_type type,
223 struct x86_emulate_ctxt *ctxt)
224 {
225 switch ( type )
226 {
227 case X86EMUL_FPU_fpu:
228 break;
229 case X86EMUL_FPU_mmx:
230 if ( cpu_has_mmx )
231 break;
232 case X86EMUL_FPU_xmm:
233 if ( cpu_has_sse )
234 break;
235 case X86EMUL_FPU_ymm:
236 if ( cpu_has_avx )
237 break;
238 case X86EMUL_FPU_opmask:
239 case X86EMUL_FPU_zmm:
240 if ( cpu_has_avx512f )
241 break;
242 default:
243 return X86EMUL_UNHANDLEABLE;
244 }
245 return X86EMUL_OKAY;
246 }
247
emul_test_put_fpu(struct x86_emulate_ctxt * ctxt,enum x86_emulate_fpu_type backout,const struct x86_emul_fpu_aux * aux)248 void emul_test_put_fpu(
249 struct x86_emulate_ctxt *ctxt,
250 enum x86_emulate_fpu_type backout,
251 const struct x86_emul_fpu_aux *aux)
252 {
253 /* TBD */
254 }
255
256 static uint32_t pkru;
257
rdpkru(void)258 unsigned int rdpkru(void)
259 {
260 return pkru;
261 }
262
wrpkru(unsigned int val)263 void wrpkru(unsigned int val)
264 {
265 pkru = val;
266 }
267
268 #include "x86_emulate/x86_emulate.c"
269