Coverage Report

Created: 2026-08-07 06:03

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