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