Coverage Report

Created: 2026-09-18 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/xen/xen/arch/x86/x86_emulate/fpu.c
Line
Count
Source
1
/* SPDX-License-Identifier: GPL-2.0-or-later */
2
/******************************************************************************
3
 * fpu.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/amd.h>
15
# define cpu_has_amd_erratum(nr) \
16
         cpu_has_amd_erratum(&current_cpu_data, AMD_ERRATUM_##nr)
17
#else
18
# define cpu_has_amd_erratum(nr) 0
19
#endif
20
21
/* Floating point status word definitions. */
22
3.40k
#define FSW_ES    (1U << 7)
23
24
static inline bool fpu_check_write(void)
25
3.40k
{
26
3.40k
    uint16_t fsw;
27
28
3.40k
    asm ( "fnstsw %0" : "=am" (fsw) );
29
30
3.40k
    return !(fsw & FSW_ES);
31
3.40k
}
32
33
4.36k
#define emulate_fpu_insn_memdst(opc, ext, arg)                          \
34
4.36k
do {                                                                    \
35
4.36k
    void *_p = get_stub(stub);                                          \
36
4.36k
    /* ModRM: mod=0, reg=ext, rm=0, i.e. a (%rax) operand */            \
37
4.36k
    *insn_bytes = 2;                                                    \
38
4.36k
    memcpy(_p, ((uint8_t[]){ opc, ((ext) & 7) << 3 }), 2); _p += 2;     \
39
4.36k
    place_ret(_p);                                                      \
40
4.36k
    invoke_stub("", "", "+m" (arg) : "a" (&(arg)));                     \
41
4.36k
    put_stub(stub);                                                     \
42
4.36k
} while (0)
43
44
3.38k
#define emulate_fpu_insn_memsrc(opc, ext, arg)                          \
45
3.38k
do {                                                                    \
46
3.38k
    void *_p = get_stub(stub);                                          \
47
3.38k
    /* ModRM: mod=0, reg=ext, rm=0, i.e. a (%rax) operand */            \
48
3.38k
    memcpy(_p, ((uint8_t[]){ opc, ((ext) & 7) << 3 }), 2); _p += 2;     \
49
3.38k
    place_ret(_p);                                                      \
50
3.38k
    invoke_stub("", "", "=m" (dummy) : "m" (arg), "a" (&(arg)));        \
51
3.38k
    put_stub(stub);                                                     \
52
3.38k
} while (0)
53
54
35.3k
#define emulate_fpu_insn_stub(bytes...)                                 \
55
35.3k
do {                                                                    \
56
35.3k
    void *_p = get_stub(stub);                                          \
57
35.3k
    unsigned int nr_ = sizeof((uint8_t[]){ bytes });                    \
58
35.3k
    memcpy(_p, ((uint8_t[]){ bytes }), nr_); _p += nr_;                 \
59
35.3k
    place_ret(_p);                                                      \
60
35.3k
    invoke_stub("", "", "=m" (dummy) : "i" (0));                        \
61
35.3k
    put_stub(stub);                                                     \
62
35.3k
} while (0)
63
64
23.6k
#define emulate_fpu_insn_stub_eflags(bytes...)                          \
65
23.6k
do {                                                                    \
66
23.6k
    void *_p = get_stub(stub);                                          \
67
23.6k
    unsigned int nr_ = sizeof((uint8_t[]){ bytes });                    \
68
23.6k
    unsigned long tmp_;                                                 \
69
23.6k
    memcpy(_p, ((uint8_t[]){ bytes }), nr_); _p += nr_;                 \
70
23.6k
    place_ret(_p);                                                      \
71
23.6k
    invoke_stub(_PRE_EFLAGS("[eflags]", "[mask]", "[tmp]"),             \
72
23.6k
                _POST_EFLAGS("[eflags]", "[mask]", "[tmp]"),            \
73
23.6k
                [eflags] "+g" (regs->eflags), [tmp] "=&r" (tmp_)        \
74
23.6k
                : [mask] "i" (X86_EFLAGS_ZF|X86_EFLAGS_PF|X86_EFLAGS_CF)); \
75
23.6k
    put_stub(stub);                                                     \
76
23.6k
} while (0)
77
78
int x86emul_fpu(struct x86_emulate_state *s,
79
                struct cpu_user_regs *regs,
80
                struct operand *dst,
81
                struct operand *src,
82
                struct x86_emulate_ctxt *ctxt,
83
                const struct x86_emulate_ops *ops,
84
                unsigned int *insn_bytes,
85
                enum x86_emulate_fpu_type *fpu_type,
86
66.8k
#define fpu_type (*fpu_type) /* for get_fpu() */
87
                mmval_t *mmvalp)
88
#define stub_exn (*s->stub_exn) /* for invoke_stub() */
89
66.8k
{
90
66.8k
    uint8_t b;
91
66.8k
    int rc;
92
66.8k
    struct x86_emulate_stub stub = {};
93
94
66.8k
    switch ( b = ctxt->opcode )
95
66.8k
    {
96
0
        unsigned long dummy;
97
98
2
    case 0x9b:  /* wait/fwait */
99
2
        vcpu_must_have(fpu);
100
2
        get_fpu(X86EMUL_FPU_wait);
101
0
        emulate_fpu_insn_stub(b);
102
0
        break;
103
104
591
    case 0xd8: /* FPU 0xd8 */
105
591
        vcpu_must_have(fpu);
106
591
        get_fpu(X86EMUL_FPU_fpu);
107
589
        switch ( s->modrm )
108
589
        {
109
2
        case 0xc0 ... 0xc7: /* fadd %stN,%st */
110
22
        case 0xc8 ... 0xcf: /* fmul %stN,%st */
111
22
        case 0xd0 ... 0xd7: /* fcom %stN,%st */
112
262
        case 0xd8 ... 0xdf: /* fcomp %stN,%st */
113
265
        case 0xe0 ... 0xe7: /* fsub %stN,%st */
114
269
        case 0xe8 ... 0xef: /* fsubr %stN,%st */
115
288
        case 0xf0 ... 0xf7: /* fdiv %stN,%st */
116
320
        case 0xf8 ... 0xff: /* fdivr %stN,%st */
117
320
            emulate_fpu_insn_stub(0xd8, s->modrm);
118
320
            break;
119
320
        default:
120
1.34k
        fpu_memsrc32:
121
1.34k
            ASSERT(s->ea.type == OP_MEM);
122
1.34k
            if ( (rc = ops->read(s->ea.mem.seg, s->ea.mem.off, &src->val,
123
1.34k
                                 4, ctxt)) != X86EMUL_OKAY )
124
75
                goto done;
125
1.27k
            emulate_fpu_insn_memsrc(b, s->modrm_reg & 7, src->val);
126
1.27k
            break;
127
589
        }
128
1.59k
        break;
129
130
11.9k
    case 0xd9: /* FPU 0xd9 */
131
11.9k
        vcpu_must_have(fpu);
132
11.9k
        get_fpu(X86EMUL_FPU_fpu);
133
11.9k
        switch ( s->modrm )
134
11.9k
        {
135
186
        case 0xfb: /* fsincos */
136
186
            fail_if(cpu_has_amd_erratum(573));
137
            /* fall through */
138
1.80k
        case 0xc0 ... 0xc7: /* fld %stN */
139
3.48k
        case 0xc8 ... 0xcf: /* fxch %stN */
140
3.65k
        case 0xd0: /* fnop */
141
5.70k
        case 0xd8 ... 0xdf: /* fstp %stN (alternative encoding) */
142
5.86k
        case 0xe0: /* fchs */
143
6.45k
        case 0xe1: /* fabs */
144
6.79k
        case 0xe4: /* ftst */
145
7.11k
        case 0xe5: /* fxam */
146
7.31k
        case 0xe8: /* fld1 */
147
7.48k
        case 0xe9: /* fldl2t */
148
7.55k
        case 0xea: /* fldl2e */
149
7.74k
        case 0xeb: /* fldpi */
150
7.94k
        case 0xec: /* fldlg2 */
151
8.03k
        case 0xed: /* fldln2 */
152
8.22k
        case 0xee: /* fldz */
153
8.47k
        case 0xf0: /* f2xm1 */
154
8.68k
        case 0xf1: /* fyl2x */
155
8.73k
        case 0xf2: /* fptan */
156
8.92k
        case 0xf3: /* fpatan */
157
9.08k
        case 0xf4: /* fxtract */
158
9.28k
        case 0xf5: /* fprem1 */
159
9.47k
        case 0xf6: /* fdecstp */
160
9.67k
        case 0xf7: /* fincstp */
161
9.88k
        case 0xf8: /* fprem */
162
10.0k
        case 0xf9: /* fyl2xp1 */
163
10.1k
        case 0xfa: /* fsqrt */
164
10.4k
        case 0xfc: /* frndint */
165
10.6k
        case 0xfd: /* fscale */
166
10.7k
        case 0xfe: /* fsin */
167
10.8k
        case 0xff: /* fcos */
168
10.8k
            emulate_fpu_insn_stub(0xd9, s->modrm);
169
10.8k
            break;
170
10.8k
        default:
171
1.14k
            generate_exception_if(s->ea.type != OP_MEM, X86_EXC_UD);
172
1.14k
            switch ( s->modrm_reg & 7 )
173
1.14k
            {
174
349
            case 0: /* fld m32fp */
175
349
                goto fpu_memsrc32;
176
92
            case 2: /* fst m32fp */
177
335
            case 3: /* fstp m32fp */
178
1.06k
            fpu_memdst32:
179
1.06k
                *dst = s->ea;
180
1.06k
                dst->bytes = 4;
181
1.06k
                emulate_fpu_insn_memdst(b, s->modrm_reg & 7, dst->val);
182
1.06k
                break;
183
1.06k
            case 4: /* fldenv */
184
                /* Raise #MF now if there are pending unmasked exceptions. */
185
1
                emulate_fpu_insn_stub(0xd9, 0xd0 /* fnop */);
186
                /* fall through */
187
3
            case 6: /* fnstenv */
188
3
                fail_if(!ops->blk);
189
0
                s->blk = s->modrm_reg & 2 ? blk_fst : blk_fld;
190
                /*
191
                 * REX is meaningless for these insns by this point - (ab)use
192
                 * the field to communicate real vs protected mode to ->blk().
193
                 */
194
0
                s->rex_prefix = in_protmode(ctxt, ops);
195
0
                if ( (rc = ops->blk(s->ea.mem.seg, s->ea.mem.off, NULL,
196
0
                                    s->op_bytes > 2 ? sizeof(struct x87_env32)
197
0
                                                    : sizeof(struct x87_env16),
198
0
                                    &regs->eflags,
199
0
                                    s, ctxt)) != X86EMUL_OKAY )
200
0
                    goto done;
201
0
                s->fpu_ctrl = true;
202
0
                break;
203
243
            case 5: /* fldcw m2byte */
204
243
                s->fpu_ctrl = true;
205
718
            fpu_memsrc16:
206
718
                if ( (rc = ops->read(s->ea.mem.seg, s->ea.mem.off, &src->val,
207
718
                                     2, ctxt)) != X86EMUL_OKAY )
208
32
                    goto done;
209
686
                emulate_fpu_insn_memsrc(b, s->modrm_reg & 7, src->val);
210
686
                break;
211
686
            case 7: /* fnstcw m2byte */
212
213
                s->fpu_ctrl = true;
213
1.58k
            fpu_memdst16:
214
1.58k
                *dst = s->ea;
215
1.58k
                dst->bytes = 2;
216
1.58k
                emulate_fpu_insn_memdst(b, s->modrm_reg & 7, dst->val);
217
1.58k
                break;
218
1.58k
            default:
219
2
                generate_exception(X86_EXC_UD);
220
1.14k
            }
221
            /*
222
             * Control instructions can't raise FPU exceptions, so we need
223
             * to consider suppressing writes only for non-control ones.
224
             */
225
3.33k
            if ( dst->type == OP_MEM && !s->fpu_ctrl && !fpu_check_write() )
226
0
                dst->type = OP_NONE;
227
3.33k
            break;
228
11.9k
        }
229
14.1k
        break;
230
231
14.1k
    case 0xda: /* FPU 0xda */
232
8.10k
        vcpu_must_have(fpu);
233
8.10k
        get_fpu(X86EMUL_FPU_fpu);
234
8.10k
        switch ( s->modrm )
235
8.10k
        {
236
1.89k
        case 0xc0 ... 0xc7: /* fcmovb %stN */
237
3.54k
        case 0xc8 ... 0xcf: /* fcmove %stN */
238
5.59k
        case 0xd0 ... 0xd7: /* fcmovbe %stN */
239
7.64k
        case 0xd8 ... 0xdf: /* fcmovu %stN */
240
7.64k
            vcpu_must_have(cmov);
241
7.64k
            emulate_fpu_insn_stub_eflags(0xda, s->modrm);
242
7.64k
            break;
243
7.64k
        case 0xe9:          /* fucompp */
244
186
            emulate_fpu_insn_stub(0xda, s->modrm);
245
186
            break;
246
272
        default:
247
272
            generate_exception_if(s->ea.type != OP_MEM, X86_EXC_UD);
248
272
            goto fpu_memsrc32;
249
8.10k
        }
250
7.82k
        break;
251
252
15.3k
    case 0xdb: /* FPU 0xdb */
253
15.3k
        vcpu_must_have(fpu);
254
15.3k
        get_fpu(X86EMUL_FPU_fpu);
255
15.3k
        switch ( s->modrm )
256
15.3k
        {
257
1.43k
        case 0xc0 ... 0xc7: /* fcmovnb %stN */
258
3.72k
        case 0xc8 ... 0xcf: /* fcmovne %stN */
259
6.28k
        case 0xd0 ... 0xd7: /* fcmovnbe %stN */
260
8.07k
        case 0xd8 ... 0xdf: /* fcmovnu %stN */
261
10.1k
        case 0xe8 ... 0xef: /* fucomi %stN */
262
12.1k
        case 0xf0 ... 0xf7: /* fcomi %stN */
263
12.1k
            vcpu_must_have(cmov);
264
12.1k
            emulate_fpu_insn_stub_eflags(0xdb, s->modrm);
265
12.1k
            break;
266
12.1k
        case 0xe0: /* fneni - 8087 only, ignored by 287 */
267
444
        case 0xe1: /* fndisi - 8087 only, ignored by 287 */
268
670
        case 0xe2: /* fnclex */
269
871
        case 0xe3: /* fninit */
270
1.06k
        case 0xe4: /* fnsetpm - 287 only, ignored by 387 */
271
        /* case 0xe5: frstpm - 287 only, #UD on 387 */
272
1.06k
            s->fpu_ctrl = true;
273
1.06k
            emulate_fpu_insn_stub(0xdb, s->modrm);
274
1.06k
            break;
275
2.13k
        default:
276
2.13k
            generate_exception_if(s->ea.type != OP_MEM, X86_EXC_UD);
277
2.13k
            switch ( s->modrm_reg & 7 )
278
2.13k
            {
279
458
            case 0: /* fild m32i */
280
458
                goto fpu_memsrc32;
281
306
            case 1: /* fisttp m32i */
282
306
                vcpu_must_have(sse3);
283
                /* fall through */
284
524
            case 2: /* fist m32i */
285
728
            case 3: /* fistp m32i */
286
728
                goto fpu_memdst32;
287
489
            case 5: /* fld m80fp */
288
755
            fpu_memsrc80:
289
755
                if ( (rc = ops->read(s->ea.mem.seg, s->ea.mem.off, mmvalp,
290
755
                                     10, ctxt)) != X86EMUL_OKAY )
291
16
                    goto done;
292
739
                emulate_fpu_insn_memsrc(b, s->modrm_reg & 7, *mmvalp);
293
739
                break;
294
739
            case 7: /* fstp m80fp */
295
763
            fpu_memdst80:
296
763
                fail_if(!ops->write);
297
762
                emulate_fpu_insn_memdst(b, s->modrm_reg & 7, *mmvalp);
298
762
                if ( fpu_check_write() &&
299
762
                     (rc = ops->write(s->ea.mem.seg, s->ea.mem.off, mmvalp,
300
762
                                      10, ctxt)) != X86EMUL_OKAY )
301
6
                    goto done;
302
756
                break;
303
756
            default:
304
2
                generate_exception(X86_EXC_UD);
305
2.13k
            }
306
1.49k
            break;
307
15.3k
        }
308
14.7k
        break;
309
310
14.7k
    case 0xdc: /* FPU 0xdc */
311
598
        vcpu_must_have(fpu);
312
598
        get_fpu(X86EMUL_FPU_fpu);
313
597
        switch ( s->modrm )
314
597
        {
315
1
        case 0xc0 ... 0xc7: /* fadd %st,%stN */
316
7
        case 0xc8 ... 0xcf: /* fmul %st,%stN */
317
10
        case 0xd0 ... 0xd7: /* fcom %stN,%st (alternative encoding) */
318
290
        case 0xd8 ... 0xdf: /* fcomp %stN,%st (alternative encoding) */
319
424
        case 0xe0 ... 0xe7: /* fsubr %st,%stN */
320
471
        case 0xe8 ... 0xef: /* fsub %st,%stN */
321
496
        case 0xf0 ... 0xf7: /* fdivr %st,%stN */
322
502
        case 0xf8 ... 0xff: /* fdiv %st,%stN */
323
502
            emulate_fpu_insn_stub(0xdc, s->modrm);
324
502
            break;
325
502
        default:
326
328
        fpu_memsrc64:
327
328
            ASSERT(s->ea.type == OP_MEM);
328
328
            if ( (rc = ops->read(s->ea.mem.seg, s->ea.mem.off, &src->val,
329
328
                                 8, ctxt)) != X86EMUL_OKAY )
330
38
                goto done;
331
290
            emulate_fpu_insn_memsrc(b, s->modrm_reg & 7, src->val);
332
290
            break;
333
597
        }
334
792
        break;
335
336
1.39k
    case 0xdd: /* FPU 0xdd */
337
1.39k
        vcpu_must_have(fpu);
338
1.39k
        get_fpu(X86EMUL_FPU_fpu);
339
1.38k
        switch ( s->modrm )
340
1.38k
        {
341
21
        case 0xc0 ... 0xc7: /* ffree %stN */
342
23
        case 0xc8 ... 0xcf: /* fxch %stN (alternative encoding) */
343
36
        case 0xd0 ... 0xd7: /* fst %stN */
344
305
        case 0xd8 ... 0xdf: /* fstp %stN */
345
311
        case 0xe0 ... 0xe7: /* fucom %stN */
346
315
        case 0xe8 ... 0xef: /* fucomp %stN */
347
315
            emulate_fpu_insn_stub(0xdd, s->modrm);
348
315
            break;
349
1.07k
        default:
350
1.07k
            generate_exception_if(s->ea.type != OP_MEM, X86_EXC_UD);
351
1.07k
            switch ( s->modrm_reg & 7 )
352
1.07k
            {
353
50
            case 0: /* fld m64fp */;
354
50
                goto fpu_memsrc64;
355
205
            case 1: /* fisttp m64i */
356
205
                vcpu_must_have(sse3);
357
                /* fall through */
358
392
            case 2: /* fst m64fp */
359
470
            case 3: /* fstp m64fp */
360
760
            fpu_memdst64:
361
760
                *dst = s->ea;
362
760
                dst->bytes = 8;
363
760
                emulate_fpu_insn_memdst(b, s->modrm_reg & 7, dst->val);
364
760
                break;
365
760
            case 4: /* frstor */
366
                /* Raise #MF now if there are pending unmasked exceptions. */
367
2
                emulate_fpu_insn_stub(0xd9, 0xd0 /* fnop */);
368
                /* fall through */
369
3
            case 6: /* fnsave */
370
3
                fail_if(!ops->blk);
371
0
                s->blk = s->modrm_reg & 2 ? blk_fst : blk_fld;
372
                /*
373
                 * REX is meaningless for these insns by this point - (ab)use
374
                 * the field to communicate real vs protected mode to ->blk().
375
                 */
376
0
                s->rex_prefix = in_protmode(ctxt, ops);
377
0
                if ( (rc = ops->blk(s->ea.mem.seg, s->ea.mem.off, NULL,
378
0
                                    s->op_bytes > 2 ? sizeof(struct x87_env32) + 80
379
0
                                                    : sizeof(struct x87_env16) + 80,
380
0
                                    &regs->eflags,
381
0
                                    s, ctxt)) != X86EMUL_OKAY )
382
0
                    goto done;
383
0
                s->fpu_ctrl = true;
384
0
                break;
385
549
            case 7: /* fnstsw m2byte */
386
549
                s->fpu_ctrl = true;
387
549
                goto fpu_memdst16;
388
1
            default:
389
1
                generate_exception(X86_EXC_UD);
390
1.07k
            }
391
            /*
392
             * Control instructions can't raise FPU exceptions, so we need
393
             * to consider suppressing writes only for non-control ones.
394
             */
395
760
            if ( dst->type == OP_MEM && !s->fpu_ctrl && !fpu_check_write() )
396
0
                dst->type = OP_NONE;
397
760
            break;
398
1.38k
        }
399
1.07k
        break;
400
401
14.1k
    case 0xde: /* FPU 0xde */
402
14.1k
        vcpu_must_have(fpu);
403
14.1k
        get_fpu(X86EMUL_FPU_fpu);
404
14.1k
        switch ( s->modrm )
405
14.1k
        {
406
2.04k
        case 0xc0 ... 0xc7: /* faddp %stN */
407
3.97k
        case 0xc8 ... 0xcf: /* fmulp %stN */
408
6.11k
        case 0xd0 ... 0xd7: /* fcomp %stN (alternative encoding) */
409
6.33k
        case 0xd9: /* fcompp */
410
8.83k
        case 0xe0 ... 0xe7: /* fsubrp %stN */
411
10.4k
        case 0xe8 ... 0xef: /* fsubp %stN */
412
12.1k
        case 0xf0 ... 0xf7: /* fdivrp %stN */
413
13.7k
        case 0xf8 ... 0xff: /* fdivp %stN */
414
13.7k
            emulate_fpu_insn_stub(0xde, s->modrm);
415
13.7k
            break;
416
13.7k
        default:
417
397
            generate_exception_if(s->ea.type != OP_MEM, X86_EXC_UD);
418
397
            emulate_fpu_insn_memsrc(b, s->modrm_reg & 7, src->val);
419
395
            break;
420
14.1k
        }
421
14.1k
        break;
422
423
14.7k
    case 0xdf: /* FPU 0xdf */
424
14.7k
        vcpu_must_have(fpu);
425
14.7k
        get_fpu(X86EMUL_FPU_fpu);
426
14.7k
        switch ( s->modrm )
427
14.7k
        {
428
197
        case 0xe0:
429
            /* fnstsw %ax */
430
197
            s->fpu_ctrl = true;
431
197
            dst->bytes = 2;
432
197
            dst->type = OP_REG;
433
197
            dst->reg = (void *)&regs->ax;
434
197
            emulate_fpu_insn_memdst(b, s->modrm_reg & 7, dst->val);
435
197
            break;
436
1.75k
        case 0xe8 ... 0xef: /* fucomip %stN */
437
3.84k
        case 0xf0 ... 0xf7: /* fcomip %stN */
438
3.84k
            vcpu_must_have(cmov);
439
3.84k
            emulate_fpu_insn_stub_eflags(0xdf, s->modrm);
440
3.84k
            break;
441
3.84k
        case 0xc0 ... 0xc7: /* ffreep %stN */
442
4.06k
        case 0xc8 ... 0xcf: /* fxch %stN (alternative encoding) */
443
6.49k
        case 0xd0 ... 0xd7: /* fstp %stN (alternative encoding) */
444
8.31k
        case 0xd8 ... 0xdf: /* fstp %stN (alternative encoding) */
445
8.31k
            emulate_fpu_insn_stub(0xdf, s->modrm);
446
8.31k
            break;
447
8.31k
        default:
448
2.34k
            generate_exception_if(s->ea.type != OP_MEM, X86_EXC_UD);
449
2.34k
            switch ( s->modrm_reg & 7 )
450
2.34k
            {
451
475
            case 0: /* fild m16i */
452
475
                goto fpu_memsrc16;
453
334
            case 1: /* fisttp m16i */
454
334
                vcpu_must_have(sse3);
455
                /* fall through */
456
605
            case 2: /* fist m16i */
457
820
            case 3: /* fistp m16i */
458
820
                goto fpu_memdst16;
459
266
            case 4: /* fbld m80dec */
460
266
                goto fpu_memsrc80;
461
183
            case 5: /* fild m64i */
462
183
                dst->type = OP_NONE;
463
183
                goto fpu_memsrc64;
464
308
            case 6: /* fbstp packed bcd */
465
308
                goto fpu_memdst80;
466
290
            case 7: /* fistp m64i */
467
290
                goto fpu_memdst64;
468
2.34k
            }
469
0
            ASSERT_UNREACHABLE();
470
0
            return X86EMUL_UNHANDLEABLE;
471
14.7k
        }
472
12.3k
        break;
473
474
12.3k
    default:
475
0
        ASSERT_UNREACHABLE();
476
0
        return X86EMUL_UNHANDLEABLE;
477
66.8k
    }
478
479
66.6k
    rc = X86EMUL_OKAY;
480
481
66.8k
 done:
482
66.8k
    put_stub(stub);
483
66.8k
    return rc;
484
485
#ifdef __XEN__
486
 emulation_stub_failure:
487
    return X86EMUL_stub_failure;
488
#endif
489
66.6k
}