/src/xen/tools/tests/x86_emulator/x86-emulate.c
Line | Count | Source |
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 | 33.0k | #define gcc11_wrap(x) ({ \ |
8 | 33.0k | unsigned long x_; \ |
9 | 33.0k | __asm__ ( "" : "=g" (x_) : "0" (x) ); \ |
10 | 33.0k | (typeof(x))x_; \ |
11 | 33.0k | }) |
12 | | |
13 | | #define cpu_has_amd_erratum(nr) 0 |
14 | 25.4k | #define cpu_has_mpx false |
15 | 0 | #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 | | */ |
38 | | struct x86_fxsr *get_fpu_save_area(void) |
39 | 0 | { |
40 | 0 | return (void *)fpu_save_area; |
41 | 0 | } |
42 | | |
43 | | void emul_save_fpu_state(void) |
44 | 13.4M | { |
45 | 13.4M | if ( use_xsave ) |
46 | 13.4M | asm volatile ( "xsave %[ptr]" |
47 | 13.4M | : [ptr] "=m" (fpu_save_area) |
48 | 13.4M | : "a" (~0ul), "d" (~0ul) ); |
49 | 4 | else |
50 | 4 | asm volatile ( "fxsave %0" : "=m" (fpu_save_area) ); |
51 | 13.4M | } |
52 | | |
53 | | void emul_restore_fpu_state(void) |
54 | 13.4M | { |
55 | | /* Older gcc can't deal with "m" array inputs; make them outputs instead. */ |
56 | 13.4M | if ( use_xsave ) |
57 | 13.4M | asm volatile ( "xrstor %[ptr]" |
58 | 13.4M | : [ptr] "+m" (fpu_save_area) |
59 | 13.4M | : "a" (~0ul), "d" (~0ul) ); |
60 | 4 | else |
61 | 4 | asm volatile ( "fxrstor %0" : "+m" (fpu_save_area) ); |
62 | 13.4M | } |
63 | | |
64 | | bool emul_test_init(void) |
65 | 2 | { |
66 | 2 | union { |
67 | 2 | char x[464]; |
68 | 2 | struct { |
69 | 2 | uint32_t other[6]; |
70 | 2 | uint32_t mxcsr; |
71 | 2 | uint32_t mxcsr_mask; |
72 | | /* ... */ |
73 | 2 | }; |
74 | 2 | } *fxs = (void *)fpu_save_area; |
75 | | |
76 | 2 | unsigned long sp; |
77 | | |
78 | 2 | 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 | 2 | cpu_policy.basic.movbe = true; |
85 | 2 | cpu_policy.feat.invpcid = true; |
86 | 2 | cpu_policy.feat.adx = true; |
87 | 2 | cpu_policy.feat.rdpid = true; |
88 | 2 | cpu_policy.feat.lkgs = true; |
89 | 2 | cpu_policy.feat.wrmsrns = true; |
90 | 2 | cpu_policy.extd.clzero = true; |
91 | | |
92 | 2 | if ( cpu_has_xsave ) |
93 | 2 | { |
94 | 2 | unsigned int tmp, ebx; |
95 | | |
96 | 2 | asm ( "cpuid" |
97 | 2 | : "=a" (tmp), "=b" (ebx), "=c" (tmp), "=d" (tmp) |
98 | 2 | : "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 | 2 | assert(ebx < sizeof(fpu_save_area)); |
106 | | |
107 | | /* Use xsave if available... */ |
108 | 2 | use_xsave = true; |
109 | 2 | } |
110 | 0 | else |
111 | | /* But use fxsave if xsave isn't available. */ |
112 | 2 | assert(cpu_has_fxsr); |
113 | | |
114 | | /* Reuse the save state buffer to find mcxsr_mask. */ |
115 | 2 | asm ( "fxsave %0" : "=m" (*fxs) ); |
116 | 2 | if ( fxs->mxcsr_mask ) |
117 | 2 | mxcsr_mask = fxs->mxcsr_mask; |
118 | | |
119 | | /* |
120 | | * Mark the entire stack executable so that the stub executions |
121 | | * don't fault |
122 | | */ |
123 | 2 | #ifdef __x86_64__ |
124 | 2 | asm ("movq %%rsp, %0" : "=g" (sp)); |
125 | | #else |
126 | | asm ("movl %%esp, %0" : "=g" (sp)); |
127 | | #endif |
128 | | |
129 | 2 | return mprotect((void *)(sp & -0x1000L) - (MMAP_SZ - 0x1000), |
130 | 2 | MMAP_SZ, PROT_READ|PROT_WRITE|PROT_EXEC) == 0; |
131 | 2 | } |
132 | | |
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 | 1.39k | { |
139 | 1.39k | asm ("cpuid" |
140 | 1.39k | : "=a" (res->a), "=b" (res->b), "=c" (res->c), "=d" (res->d) |
141 | 1.39k | : "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 | 1.39k | if ( leaf == 1 ) |
148 | 74 | 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 | 1.39k | if ( leaf == 7 && subleaf == 0 ) |
155 | 374 | { |
156 | 374 | res->b |= (1U << 10) | (1U << 19); |
157 | 374 | if ( res->b & (1U << 16) ) |
158 | 0 | res->b |= 1U << 26; |
159 | 374 | res->c |= 1U << 22; |
160 | 374 | } |
161 | | |
162 | | /* |
163 | | * The emulator doesn't itself use CLZERO, so we can always run the |
164 | | * respective test(s). |
165 | | */ |
166 | 1.39k | if ( leaf == 0x80000008 ) |
167 | 69 | res->b |= 1U << 0; |
168 | | |
169 | 1.39k | return X86EMUL_OKAY; |
170 | 1.39k | } |
171 | | |
172 | | int emul_test_read_cr( |
173 | | unsigned int reg, |
174 | | unsigned long *val, |
175 | | struct x86_emulate_ctxt *ctxt) |
176 | 0 | { |
177 | | /* Fake just enough state for the emulator's _get_fpu() to be happy. */ |
178 | 0 | switch ( reg ) |
179 | 0 | { |
180 | 0 | case 0: |
181 | 0 | *val = 0x00000001; /* PE */ |
182 | 0 | return X86EMUL_OKAY; |
183 | | |
184 | 0 | case 4: |
185 | 0 | *val = X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT | X86_CR4_PKE | |
186 | 0 | (cpu_has_xsave ? X86_CR4_OSXSAVE : 0); |
187 | 0 | return X86EMUL_OKAY; |
188 | 0 | } |
189 | | |
190 | 0 | return X86EMUL_UNHANDLEABLE; |
191 | 0 | } |
192 | | |
193 | | int emul_test_read_xcr( |
194 | | unsigned int reg, |
195 | | uint64_t *val, |
196 | | struct x86_emulate_ctxt *ctxt) |
197 | 32.2k | { |
198 | 32.2k | uint32_t lo, hi; |
199 | | |
200 | 32.2k | ASSERT(cpu_has_xsave); |
201 | | |
202 | 32.2k | switch ( reg ) |
203 | 32.2k | { |
204 | 32.2k | case 0: |
205 | 32.2k | break; |
206 | | |
207 | 1 | case 1: |
208 | 1 | if ( cpu_has_xgetbv1 ) |
209 | 0 | break; |
210 | | /* fall through */ |
211 | 2 | default: |
212 | 2 | x86_emul_hw_exception(13 /* #GP */, 0, ctxt); |
213 | 2 | return X86EMUL_EXCEPTION; |
214 | 32.2k | } |
215 | | |
216 | 32.2k | asm ( "xgetbv" : "=a" (lo), "=d" (hi) : "c" (reg) ); |
217 | 32.2k | *val = lo | ((uint64_t)hi << 32); |
218 | | |
219 | 32.2k | return X86EMUL_OKAY; |
220 | 32.2k | } |
221 | | |
222 | | int emul_test_get_fpu( |
223 | | enum x86_emulate_fpu_type type, |
224 | | struct x86_emulate_ctxt *ctxt) |
225 | 143k | { |
226 | 143k | switch ( type ) |
227 | 143k | { |
228 | 58.4k | case X86EMUL_FPU_fpu: |
229 | 58.4k | break; |
230 | 15.5k | case X86EMUL_FPU_mmx: |
231 | 15.5k | if ( cpu_has_mmx ) |
232 | 15.5k | break; |
233 | 37.9k | case X86EMUL_FPU_xmm: |
234 | 37.9k | if ( cpu_has_sse ) |
235 | 37.9k | break; |
236 | 31.9k | case X86EMUL_FPU_ymm: |
237 | 31.9k | if ( cpu_has_avx ) |
238 | 31.9k | break; |
239 | 0 | case X86EMUL_FPU_opmask: |
240 | 0 | case X86EMUL_FPU_zmm: |
241 | 0 | if ( cpu_has_avx512f ) |
242 | 0 | break; |
243 | 4 | default: |
244 | 4 | return X86EMUL_UNHANDLEABLE; |
245 | 143k | } |
246 | 143k | return X86EMUL_OKAY; |
247 | 143k | } |
248 | | |
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 | 144k | { |
254 | | /* TBD */ |
255 | 144k | } |
256 | | |
257 | | static uint32_t pkru; |
258 | | |
259 | | unsigned int rdpkru(void) |
260 | 66 | { |
261 | 66 | return pkru; |
262 | 66 | } |
263 | | |
264 | | void wrpkru(unsigned int val) |
265 | 34 | { |
266 | 34 | pkru = val; |
267 | 34 | } |
268 | | |
269 | | #include "x86_emulate/x86_emulate.c" |