Coverage Report

Created: 2026-08-04 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/xen/xen/arch/x86/x86_emulate/0f01.c
Line
Count
Source
1
/* SPDX-License-Identifier: GPL-2.0-or-later */
2
/******************************************************************************
3
 * 0f01.c - helper for x86_emulate.c
4
 *
5
 * Generic x86 (32-bit and 64-bit) instruction decoder and emulator.
6
 *
7
 * Copyright (c) 2005-2007 Keir Fraser
8
 * Copyright (c) 2005-2007 XenSource Inc.
9
 */
10
11
#include "private.h"
12
13
#ifdef __XEN__
14
#include <asm/prot-key.h>
15
#endif
16
17
1.77k
#define ad_bytes (s->ad_bytes) /* for truncate_ea() */
18
19
int x86emul_0f01(struct x86_emulate_state *s,
20
                 struct cpu_user_regs *regs,
21
                 struct operand *dst,
22
                 struct x86_emulate_ctxt *ctxt,
23
                 const struct x86_emulate_ops *ops)
24
36.5k
{
25
36.5k
    enum x86_segment seg = (s->modrm_reg & 1) ? x86_seg_idtr : x86_seg_gdtr;
26
36.5k
    int rc;
27
28
36.5k
    switch ( s->modrm )
29
36.5k
    {
30
0
        unsigned long base, limit, cr0, cr0w, cr4;
31
0
        struct segment_register sreg;
32
0
        uint64_t msr_val;
33
34
199
    case 0xc6:
35
199
        switch ( s->vex.pfx )
36
199
        {
37
198
        case vex_np: /* wrmsrns */
38
198
            vcpu_must_have(wrmsrns);
39
198
            generate_exception_if(!mode_ring0(), X86_EXC_GP, 0);
40
198
            fail_if(!ops->write_msr);
41
196
            rc = ops->write_msr(regs->ecx,
42
196
                                ((uint64_t)regs->r(dx) << 32) | regs->eax,
43
196
                                ctxt, true);
44
196
            goto done;
45
199
        }
46
1
        generate_exception(X86_EXC_UD);
47
48
19
    case 0xca: /* clac */
49
216
    case 0xcb: /* stac */
50
216
        vcpu_must_have(smap);
51
216
        generate_exception_if(s->vex.pfx || !mode_ring0(), X86_EXC_UD);
52
53
216
        regs->eflags &= ~X86_EFLAGS_AC;
54
213
        if ( s->modrm == 0xcb )
55
194
            regs->eflags |= X86_EFLAGS_AC;
56
213
        break;
57
58
70
    case 0xd0: /* xgetbv */
59
70
        generate_exception_if(s->vex.pfx, X86_EXC_UD);
60
70
        if ( !ops->read_cr || !ops->read_xcr ||
61
68
             ops->read_cr(4, &cr4, ctxt) != X86EMUL_OKAY )
62
1
            cr4 = 0;
63
69
        generate_exception_if(!(cr4 & X86_CR4_OSXSAVE), X86_EXC_UD);
64
69
        rc = ops->read_xcr(regs->ecx, &msr_val, ctxt);
65
68
        if ( rc != X86EMUL_OKAY )
66
1
            goto done;
67
67
        regs->r(ax) = (uint32_t)msr_val;
68
67
        regs->r(dx) = msr_val >> 32;
69
67
        break;
70
71
3
    case 0xd1: /* xsetbv */
72
3
        generate_exception_if(s->vex.pfx, X86_EXC_UD);
73
3
        if ( !ops->read_cr || !ops->write_xcr ||
74
0
             ops->read_cr(4, &cr4, ctxt) != X86EMUL_OKAY )
75
2
            cr4 = 0;
76
2
        generate_exception_if(!(cr4 & X86_CR4_OSXSAVE), X86_EXC_UD);
77
2
        generate_exception_if(!mode_ring0(), X86_EXC_GP, 0);
78
0
        rc = ops->write_xcr(regs->ecx,
79
0
                            regs->eax | ((uint64_t)regs->edx << 32), ctxt);
80
0
        if ( rc != X86EMUL_OKAY )
81
0
            goto done;
82
0
        break;
83
84
1
    case 0xd4: /* vmfunc */
85
1
        generate_exception_if(s->vex.pfx, X86_EXC_UD);
86
1
        fail_if(!ops->vmfunc);
87
0
        if ( (rc = ops->vmfunc(ctxt)) != X86EMUL_OKAY )
88
0
            goto done;
89
0
        break;
90
91
2
    case 0xd5: /* xend */
92
2
        generate_exception_if(s->vex.pfx, X86_EXC_UD);
93
2
        generate_exception_if(!vcpu_has_rtm(), X86_EXC_UD);
94
1
        generate_exception_if(vcpu_has_rtm(), X86_EXC_GP, 0);
95
0
        break;
96
97
9
    case 0xd6: /* xtest */
98
9
        generate_exception_if(s->vex.pfx, X86_EXC_UD);
99
9
        generate_exception_if(!vcpu_has_rtm() && !vcpu_has_hle(),
100
8
                              X86_EXC_UD);
101
        /* Neither HLE nor RTM can be active when we get here. */
102
8
        regs->eflags |= X86_EFLAGS_ZF;
103
0
        break;
104
105
455
    case 0xdf: /* invlpga */
106
455
        fail_if(!ops->read_msr);
107
454
        if ( (rc = ops->read_msr(MSR_EFER,
108
454
                                 &msr_val, ctxt)) != X86EMUL_OKAY )
109
0
            goto done;
110
        /* Finding SVME set implies vcpu_has_svm(). */
111
454
        generate_exception_if(!(msr_val & EFER_SVME) ||
112
454
                              !in_protmode(ctxt, ops), X86_EXC_UD);
113
454
        generate_exception_if(!mode_ring0(), X86_EXC_GP, 0);
114
452
        fail_if(!ops->tlb_op);
115
449
        if ( (rc = ops->tlb_op(x86emul_invlpga, truncate_ea(regs->r(ax)),
116
449
                               regs->ecx, ctxt)) != X86EMUL_OKAY )
117
3
            goto done;
118
446
        break;
119
120
446
    case 0xe8:
121
1
        switch ( s->vex.pfx )
122
1
        {
123
0
        case vex_np: /* serialize */
124
0
            vcpu_must_have(serialize);
125
0
            asm volatile ( ".byte 0x0f, 0x01, 0xe8" ); /* Binutils >= 2.34, Clang >= 11 */
126
0
            break;
127
0
        case vex_f2: /* xsusldtrk */
128
0
            vcpu_must_have(tsxldtrk);
129
            /*
130
             * We're never in a transactional region when coming here
131
             * - nothing else to do.
132
             */
133
0
            break;
134
1
        default:
135
1
            return X86EMUL_UNIMPLEMENTED;
136
1
        }
137
0
        break;
138
139
2
    case 0xe9:
140
2
        switch ( s->vex.pfx )
141
2
        {
142
1
        case vex_f2: /* xresldtrk */
143
1
            vcpu_must_have(tsxldtrk);
144
            /*
145
             * We're never in a transactional region when coming here
146
             * - nothing else to do.
147
             */
148
1
            break;
149
1
        default:
150
1
            return X86EMUL_UNIMPLEMENTED;
151
2
        }
152
0
        break;
153
154
241
    case 0xee:
155
241
        switch ( s->vex.pfx )
156
241
        {
157
240
        case vex_np: /* rdpkru */
158
240
            if ( !ops->read_cr ||
159
239
                 ops->read_cr(4, &cr4, ctxt) != X86EMUL_OKAY )
160
1
                cr4 = 0;
161
240
            generate_exception_if(!(cr4 & X86_CR4_PKE), X86_EXC_UD);
162
240
            generate_exception_if(regs->ecx, X86_EXC_GP, 0);
163
239
            regs->r(ax) = rdpkru();
164
194
            regs->r(dx) = 0;
165
194
            break;
166
1
        default:
167
1
            return X86EMUL_UNIMPLEMENTED;
168
241
        }
169
194
        break;
170
171
194
    case 0xef:
172
111
        switch ( s->vex.pfx )
173
111
        {
174
110
        case vex_np: /* wrpkru */
175
110
            if ( !ops->read_cr ||
176
109
                 ops->read_cr(4, &cr4, ctxt) != X86EMUL_OKAY )
177
1
                cr4 = 0;
178
110
            generate_exception_if(!(cr4 & X86_CR4_PKE), X86_EXC_UD);
179
110
            generate_exception_if(regs->ecx | regs->edx, X86_EXC_GP, 0);
180
109
            wrpkru(regs->eax);
181
62
            break;
182
1
        default:
183
1
            return X86EMUL_UNIMPLEMENTED;
184
111
        }
185
62
        break;
186
187
62
    case 0xf8: /* swapgs */
188
5
        generate_exception_if(!mode_64bit(), X86_EXC_UD);
189
5
        generate_exception_if(!mode_ring0(), X86_EXC_GP, 0);
190
4
        fail_if(!ops->read_msr || !ops->write_msr);
191
1
        if ( (rc = ops->read_msr(MSR_GS_BASE, &sreg.base,
192
1
                                 ctxt)) != X86EMUL_OKAY ||
193
0
             (rc = ops->read_msr(MSR_SHADOW_GS_BASE, &msr_val,
194
0
                                 ctxt)) != X86EMUL_OKAY )
195
0
            goto done;
196
1
        if ( (rc = ops->write_msr(MSR_SHADOW_GS_BASE, sreg.base,
197
1
                                  ctxt, false)) != X86EMUL_OKAY ||
198
0
             (rc = ops->write_msr(MSR_GS_BASE, msr_val,
199
0
                                  ctxt, false)) != X86EMUL_OKAY )
200
0
        {
201
            /*
202
             * In real hardware, access to the registers cannot fail.  It is
203
             * an error in Xen if the writes fail given that both MSRs have
204
             * equivalent checks.
205
             */
206
0
            ASSERT_UNREACHABLE();
207
0
            x86_emul_reset_event(ctxt);
208
0
            generate_exception(X86_EXC_DF, 0);
209
0
        }
210
1
        break;
211
212
68
    case 0xf9: /* rdtscp */
213
68
        fail_if(ops->read_msr == NULL);
214
67
        if ( (rc = ops->read_msr(MSR_TSC_AUX,
215
67
                                 &msr_val, ctxt)) != X86EMUL_OKAY )
216
1
            goto done;
217
66
        regs->r(cx) = (uint32_t)msr_val;
218
66
        return X86EMUL_rdtsc;
219
220
1.01k
    case 0xfc: /* clzero */
221
1.01k
    {
222
1.01k
        unsigned long zero = 0;
223
224
1.01k
        vcpu_must_have(clzero);
225
226
1.01k
        base = ad_bytes == 8 ? regs->r(ax) :
227
1.01k
               ad_bytes == 4 ? regs->eax : regs->ax;
228
1.01k
        limit = ctxt->cpuid->basic.clflush_size * 8;
229
1.01k
        generate_exception_if(limit < sizeof(long) ||
230
1.01k
                              (limit & (limit - 1)), X86_EXC_UD);
231
1.01k
        base &= ~(limit - 1);
232
1.01k
        if ( ops->rep_stos )
233
799
        {
234
799
            unsigned long nr_reps = limit / sizeof(zero);
235
236
799
            rc = ops->rep_stos(&zero, s->ea.mem.seg, base, sizeof(zero),
237
799
                               &nr_reps, ctxt);
238
799
            if ( rc == X86EMUL_OKAY )
239
589
            {
240
589
                base += nr_reps * sizeof(zero);
241
589
                limit -= nr_reps * sizeof(zero);
242
589
            }
243
210
            else if ( rc != X86EMUL_UNHANDLEABLE )
244
11
                goto done;
245
799
        }
246
1.00k
        fail_if(limit && !ops->write);
247
4.20k
        while ( limit )
248
3.21k
        {
249
3.21k
            rc = ops->write(s->ea.mem.seg, base, &zero, sizeof(zero), ctxt);
250
3.21k
            if ( rc != X86EMUL_OKAY )
251
17
                goto done;
252
3.19k
            base += sizeof(zero);
253
3.19k
            limit -= sizeof(zero);
254
3.19k
        }
255
985
        break;
256
1.00k
    }
257
258
985
#define _GRP7(mod, reg) \
259
76.2k
        (((mod) << 6) | ((reg) << 3)) ... (((mod) << 6) | ((reg) << 3) | 7)
260
39.5k
#define GRP7_MEM(reg) _GRP7(0, reg): case _GRP7(1, reg): case _GRP7(2, reg)
261
12.5k
#define GRP7_ALL(reg) GRP7_MEM(reg): case _GRP7(3, reg)
262
263
7.56k
    case GRP7_MEM(0): /* sgdt */
264
16.4k
    case GRP7_MEM(1): /* sidt */
265
16.4k
        ASSERT(s->ea.type == OP_MEM);
266
16.4k
        generate_exception_if(umip_active(ctxt, ops), X86_EXC_GP, 0);
267
9.01k
        fail_if(!ops->read_segment || !ops->write);
268
8.99k
        if ( (rc = ops->read_segment(seg, &sreg, ctxt)) )
269
0
            goto done;
270
8.99k
        if ( mode_64bit() )
271
2.37k
            s->op_bytes = 8;
272
6.61k
        else if ( s->op_bytes == 2 )
273
4.96k
        {
274
4.96k
            sreg.base &= 0xffffff;
275
4.96k
            s->op_bytes = 4;
276
4.96k
        }
277
8.99k
        if ( (rc = ops->write(s->ea.mem.seg, s->ea.mem.off, &sreg.limit,
278
8.99k
                              2, ctxt)) != X86EMUL_OKAY ||
279
8.86k
             (rc = ops->write(s->ea.mem.seg, truncate_ea(s->ea.mem.off + 2),
280
8.86k
                              &sreg.base, s->op_bytes, ctxt)) != X86EMUL_OKAY )
281
214
            goto done;
282
8.77k
        break;
283
284
8.77k
    case GRP7_MEM(2): /* lgdt */
285
15.1k
    case GRP7_MEM(3): /* lidt */
286
15.1k
        ASSERT(s->ea.type == OP_MEM);
287
15.1k
        generate_exception_if(!mode_ring0(), X86_EXC_GP, 0);
288
8.16k
        fail_if(ops->write_segment == NULL);
289
8.14k
        memset(&sreg, 0, sizeof(sreg));
290
8.14k
        if ( (rc = read_ulong(s->ea.mem.seg, s->ea.mem.off,
291
8.14k
                              &limit, 2, ctxt, ops)) ||
292
7.92k
             (rc = read_ulong(s->ea.mem.seg, truncate_ea(s->ea.mem.off + 2),
293
7.92k
                              &base, mode_64bit() ? 8 : 4, ctxt, ops)) )
294
273
            goto done;
295
8.14k
        generate_exception_if(!is_canonical_address(base), X86_EXC_GP, 0);
296
7.86k
        sreg.base = base;
297
7.86k
        sreg.limit = limit;
298
7.86k
        if ( !mode_64bit() && s->op_bytes == 2 )
299
6.68k
            sreg.base &= 0xffffff;
300
7.86k
        if ( (rc = ops->write_segment(seg, &sreg, ctxt)) )
301
8
            goto done;
302
7.85k
        break;
303
304
14.9k
    case GRP7_ALL(4): /* smsw */
305
14.9k
        generate_exception_if(umip_active(ctxt, ops), X86_EXC_GP, 0);
306
14.9k
        if ( s->ea.type == OP_MEM )
307
4.87k
        {
308
4.87k
            fail_if(!ops->write);
309
4.86k
            s->desc |= Mov; /* force writeback */
310
4.86k
            s->ea.bytes = 2;
311
4.86k
        }
312
1.58k
        else
313
1.58k
            s->ea.bytes = s->op_bytes;
314
6.44k
        *dst = s->ea;
315
6.44k
        fail_if(ops->read_cr == NULL);
316
6.44k
        if ( (rc = ops->read_cr(0, &dst->val, ctxt)) )
317
0
            goto done;
318
6.44k
        break;
319
320
14.4k
    case GRP7_ALL(6): /* lmsw */
321
14.4k
        fail_if(ops->read_cr == NULL);
322
6.07k
        fail_if(ops->write_cr == NULL);
323
6.07k
        generate_exception_if(!mode_ring0(), X86_EXC_GP, 0);
324
6.07k
        if ( (rc = ops->read_cr(0, &cr0, ctxt)) )
325
0
            goto done;
326
6.06k
        if ( s->ea.type == OP_REG )
327
1.22k
            cr0w = *s->ea.reg;
328
4.83k
        else if ( (rc = read_ulong(s->ea.mem.seg, s->ea.mem.off,
329
4.83k
                                   &cr0w, 2, ctxt, ops)) )
330
90
            goto done;
331
        /* LMSW can: (1) set bits 0-3; (2) clear bits 1-3. */
332
5.97k
        cr0 = (cr0 & ~0xe) | (cr0w & 0xf);
333
5.97k
        if ( (rc = ops->write_cr(0, cr0, ctxt)) )
334
36
            goto done;
335
5.94k
        break;
336
337
8.05k
    case GRP7_MEM(7): /* invlpg */
338
8.05k
        ASSERT(s->ea.type == OP_MEM);
339
8.05k
        generate_exception_if(!mode_ring0(), X86_EXC_GP, 0);
340
4.40k
        fail_if(!ops->tlb_op);
341
4.40k
        if ( (rc = ops->tlb_op(x86emul_invlpg, s->ea.mem.off, s->ea.mem.seg,
342
4.40k
                               ctxt)) != X86EMUL_OKAY )
343
4
            goto done;
344
4.39k
        break;
345
346
4.39k
#undef GRP7_ALL
347
4.39k
#undef GRP7_MEM
348
4.39k
#undef _GRP7
349
350
4.39k
    default:
351
2
        return X86EMUL_UNIMPLEMENTED;
352
36.5k
    }
353
354
35.3k
    rc = X86EMUL_OKAY;
355
356
36.4k
 done:
357
36.4k
    return rc;
358
35.3k
}