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