Coverage Report

Created: 2026-07-09 06:12

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
/* 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"