KVM: emulator: implement fninit, fnstsw, fnstcw

Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
This commit is contained in:
Gleb Natapov 2012-12-20 16:57:43 +02:00 committed by Marcelo Tosatti
parent 3a78a4f463
commit 045a282ca4
1 changed files with 125 additions and 1 deletions

View File

@ -115,6 +115,7 @@
#define GroupDual (2<<15) /* Alternate decoding of mod == 3 */ #define GroupDual (2<<15) /* Alternate decoding of mod == 3 */
#define Prefix (3<<15) /* Instruction varies with 66/f2/f3 prefix */ #define Prefix (3<<15) /* Instruction varies with 66/f2/f3 prefix */
#define RMExt (4<<15) /* Opcode extension in ModRM r/m if mod == 3 */ #define RMExt (4<<15) /* Opcode extension in ModRM r/m if mod == 3 */
#define Escape (5<<15) /* Escape to coprocessor instruction */
#define Sse (1<<18) /* SSE Vector instruction */ #define Sse (1<<18) /* SSE Vector instruction */
/* Generic ModRM decode. */ /* Generic ModRM decode. */
#define ModRM (1<<19) #define ModRM (1<<19)
@ -166,6 +167,7 @@ struct opcode {
const struct opcode *group; const struct opcode *group;
const struct group_dual *gdual; const struct group_dual *gdual;
const struct gprefix *gprefix; const struct gprefix *gprefix;
const struct escape *esc;
} u; } u;
int (*check_perm)(struct x86_emulate_ctxt *ctxt); int (*check_perm)(struct x86_emulate_ctxt *ctxt);
}; };
@ -182,6 +184,11 @@ struct gprefix {
struct opcode pfx_f3; struct opcode pfx_f3;
}; };
struct escape {
struct opcode op[8];
struct opcode high[64];
};
/* EFLAGS bit definitions. */ /* EFLAGS bit definitions. */
#define EFLG_ID (1<<21) #define EFLG_ID (1<<21)
#define EFLG_VIP (1<<20) #define EFLG_VIP (1<<20)
@ -991,6 +998,53 @@ static void write_mmx_reg(struct x86_emulate_ctxt *ctxt, u64 *data, int reg)
ctxt->ops->put_fpu(ctxt); ctxt->ops->put_fpu(ctxt);
} }
static int em_fninit(struct x86_emulate_ctxt *ctxt)
{
if (ctxt->ops->get_cr(ctxt, 0) & (X86_CR0_TS | X86_CR0_EM))
return emulate_nm(ctxt);
ctxt->ops->get_fpu(ctxt);
asm volatile("fninit");
ctxt->ops->put_fpu(ctxt);
return X86EMUL_CONTINUE;
}
static int em_fnstcw(struct x86_emulate_ctxt *ctxt)
{
u16 fcw;
if (ctxt->ops->get_cr(ctxt, 0) & (X86_CR0_TS | X86_CR0_EM))
return emulate_nm(ctxt);
ctxt->ops->get_fpu(ctxt);
asm volatile("fnstcw %0": "+m"(fcw));
ctxt->ops->put_fpu(ctxt);
/* force 2 byte destination */
ctxt->dst.bytes = 2;
ctxt->dst.val = fcw;
return X86EMUL_CONTINUE;
}
static int em_fnstsw(struct x86_emulate_ctxt *ctxt)
{
u16 fsw;
if (ctxt->ops->get_cr(ctxt, 0) & (X86_CR0_TS | X86_CR0_EM))
return emulate_nm(ctxt);
ctxt->ops->get_fpu(ctxt);
asm volatile("fnstsw %0": "+m"(fsw));
ctxt->ops->put_fpu(ctxt);
/* force 2 byte destination */
ctxt->dst.bytes = 2;
ctxt->dst.val = fsw;
return X86EMUL_CONTINUE;
}
static void decode_register_operand(struct x86_emulate_ctxt *ctxt, static void decode_register_operand(struct x86_emulate_ctxt *ctxt,
struct operand *op) struct operand *op)
{ {
@ -3590,6 +3644,7 @@ static int check_perm_out(struct x86_emulate_ctxt *ctxt)
#define EXT(_f, _e) { .flags = ((_f) | RMExt), .u.group = (_e) } #define EXT(_f, _e) { .flags = ((_f) | RMExt), .u.group = (_e) }
#define G(_f, _g) { .flags = ((_f) | Group | ModRM), .u.group = (_g) } #define G(_f, _g) { .flags = ((_f) | Group | ModRM), .u.group = (_g) }
#define GD(_f, _g) { .flags = ((_f) | GroupDual | ModRM), .u.gdual = (_g) } #define GD(_f, _g) { .flags = ((_f) | GroupDual | ModRM), .u.gdual = (_g) }
#define E(_f, _e) { .flags = ((_f) | Escape | ModRM), .u.esc = (_e) }
#define I(_f, _e) { .flags = (_f), .u.execute = (_e) } #define I(_f, _e) { .flags = (_f), .u.execute = (_e) }
#define II(_f, _e, _i) \ #define II(_f, _e, _i) \
{ .flags = (_f), .u.execute = (_e), .intercept = x86_intercept_##_i } { .flags = (_f), .u.execute = (_e), .intercept = x86_intercept_##_i }
@ -3725,6 +3780,69 @@ static const struct gprefix pfx_vmovntpx = {
I(0, em_mov), N, N, N, I(0, em_mov), N, N, N,
}; };
static const struct escape escape_d9 = { {
N, N, N, N, N, N, N, I(DstMem, em_fnstcw),
}, {
/* 0xC0 - 0xC7 */
N, N, N, N, N, N, N, N,
/* 0xC8 - 0xCF */
N, N, N, N, N, N, N, N,
/* 0xD0 - 0xC7 */
N, N, N, N, N, N, N, N,
/* 0xD8 - 0xDF */
N, N, N, N, N, N, N, N,
/* 0xE0 - 0xE7 */
N, N, N, N, N, N, N, N,
/* 0xE8 - 0xEF */
N, N, N, N, N, N, N, N,
/* 0xF0 - 0xF7 */
N, N, N, N, N, N, N, N,
/* 0xF8 - 0xFF */
N, N, N, N, N, N, N, N,
} };
static const struct escape escape_db = { {
N, N, N, N, N, N, N, N,
}, {
/* 0xC0 - 0xC7 */
N, N, N, N, N, N, N, N,
/* 0xC8 - 0xCF */
N, N, N, N, N, N, N, N,
/* 0xD0 - 0xC7 */
N, N, N, N, N, N, N, N,
/* 0xD8 - 0xDF */
N, N, N, N, N, N, N, N,
/* 0xE0 - 0xE7 */
N, N, N, I(ImplicitOps, em_fninit), N, N, N, N,
/* 0xE8 - 0xEF */
N, N, N, N, N, N, N, N,
/* 0xF0 - 0xF7 */
N, N, N, N, N, N, N, N,
/* 0xF8 - 0xFF */
N, N, N, N, N, N, N, N,
} };
static const struct escape escape_dd = { {
N, N, N, N, N, N, N, I(DstMem, em_fnstsw),
}, {
/* 0xC0 - 0xC7 */
N, N, N, N, N, N, N, N,
/* 0xC8 - 0xCF */
N, N, N, N, N, N, N, N,
/* 0xD0 - 0xC7 */
N, N, N, N, N, N, N, N,
/* 0xD8 - 0xDF */
N, N, N, N, N, N, N, N,
/* 0xE0 - 0xE7 */
N, N, N, N, N, N, N, N,
/* 0xE8 - 0xEF */
N, N, N, N, N, N, N, N,
/* 0xF0 - 0xF7 */
N, N, N, N, N, N, N, N,
/* 0xF8 - 0xFF */
N, N, N, N, N, N, N, N,
} };
static const struct opcode opcode_table[256] = { static const struct opcode opcode_table[256] = {
/* 0x00 - 0x07 */ /* 0x00 - 0x07 */
I6ALU(Lock, em_add), I6ALU(Lock, em_add),
@ -3821,7 +3939,7 @@ static const struct opcode opcode_table[256] = {
D2bv(DstMem | SrcOne | ModRM), D2bv(DstMem | ModRM), D2bv(DstMem | SrcOne | ModRM), D2bv(DstMem | ModRM),
N, I(DstAcc | SrcImmByte | No64, em_aad), N, N, N, I(DstAcc | SrcImmByte | No64, em_aad), N, N,
/* 0xD8 - 0xDF */ /* 0xD8 - 0xDF */
N, N, N, N, N, N, N, N, N, E(0, &escape_d9), N, E(0, &escape_db), N, E(0, &escape_dd), N, N,
/* 0xE0 - 0xE7 */ /* 0xE0 - 0xE7 */
X3(I(SrcImmByte, em_loop)), X3(I(SrcImmByte, em_loop)),
I(SrcImmByte, em_jcxz), I(SrcImmByte, em_jcxz),
@ -4246,6 +4364,12 @@ done_prefixes:
case 0xf3: opcode = opcode.u.gprefix->pfx_f3; break; case 0xf3: opcode = opcode.u.gprefix->pfx_f3; break;
} }
break; break;
case Escape:
if (ctxt->modrm > 0xbf)
opcode = opcode.u.esc->high[ctxt->modrm - 0xc0];
else
opcode = opcode.u.esc->op[(ctxt->modrm >> 3) & 7];
break;
default: default:
return EMULATION_FAILED; return EMULATION_FAILED;
} }