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