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