Commit 9a9d8642 authored by Denys Vlasenko's avatar Denys Vlasenko Committed by Ingo Molnar

x86/fpu/math-emu: Add support for FCMOVcc insns

Run-tested by booting with "no387 nofxsr" and running test
program:

  [RUN]   Testing fcmovCC instructions
  [OK]    fcmovCC
Signed-off-by: default avatarDenys Vlasenko <dvlasenk@redhat.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Link: http://lkml.kernel.org/r/1442588010-20055-3-git-send-email-dvlasenk@redhat.comSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent b8e4a910
...@@ -169,6 +169,76 @@ void fxch_i(void) ...@@ -169,6 +169,76 @@ void fxch_i(void)
fpu_tag_word = tag_word; fpu_tag_word = tag_word;
} }
static void fcmovCC(void)
{
/* fcmovCC st(i) */
int i = FPU_rm;
FPU_REG *st0_ptr = &st(0);
FPU_REG *sti_ptr = &st(i);
long tag_word = fpu_tag_word;
int regnr = top & 7;
int regnri = (top + i) & 7;
u_char sti_tag = (tag_word >> (regnri * 2)) & 3;
if (sti_tag == TAG_Empty) {
FPU_stack_underflow();
clear_C1();
return;
}
reg_copy(sti_ptr, st0_ptr);
tag_word &= ~(3 << (regnr * 2));
tag_word |= (sti_tag << (regnr * 2));
fpu_tag_word = tag_word;
}
void fcmovb(void)
{
if (FPU_EFLAGS & X86_EFLAGS_CF)
fcmovCC();
}
void fcmove(void)
{
if (FPU_EFLAGS & X86_EFLAGS_ZF)
fcmovCC();
}
void fcmovbe(void)
{
if (FPU_EFLAGS & (X86_EFLAGS_CF|X86_EFLAGS_ZF))
fcmovCC();
}
void fcmovu(void)
{
if (FPU_EFLAGS & X86_EFLAGS_PF)
fcmovCC();
}
void fcmovnb(void)
{
if (!(FPU_EFLAGS & X86_EFLAGS_CF))
fcmovCC();
}
void fcmovne(void)
{
if (!(FPU_EFLAGS & X86_EFLAGS_ZF))
fcmovCC();
}
void fcmovnbe(void)
{
if (!(FPU_EFLAGS & (X86_EFLAGS_CF|X86_EFLAGS_ZF)))
fcmovCC();
}
void fcmovnu(void)
{
if (!(FPU_EFLAGS & X86_EFLAGS_PF))
fcmovCC();
}
void ffree_(void) void ffree_(void)
{ {
/* ffree st(i) */ /* ffree st(i) */
......
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
#define __BAD__ FPU_illegal /* Illegal on an 80486, causes SIGILL */ #define __BAD__ FPU_illegal /* Illegal on an 80486, causes SIGILL */
/* f(u)comi(p) are enabled if CPUID(1).EDX(15) "cmov" is set */ /* fcmovCC and f(u)comi(p) are enabled if CPUID(1).EDX(15) "cmov" is set */
/* WARNING: "u" entries are not documented by Intel in their 80486 manual /* WARNING: "u" entries are not documented by Intel in their 80486 manual
and may not work on FPU clones or later Intel FPUs. and may not work on FPU clones or later Intel FPUs.
...@@ -49,13 +49,13 @@ ...@@ -49,13 +49,13 @@
static FUNC const st_instr_table[64] = { static FUNC const st_instr_table[64] = {
/* Opcode: d8 d9 da db */ /* Opcode: d8 d9 da db */
/* dc dd de df */ /* dc dd de df */
/* c0..7 */ fadd__, fld_i_, __BAD__, __BAD__, /* c0..7 */ fadd__, fld_i_, fcmovb, fcmovnb,
/* c0..7 */ fadd_i, ffree_, faddp_, ffreep,/*u*/ /* c0..7 */ fadd_i, ffree_, faddp_, ffreep,/*u*/
/* c8..f */ fmul__, fxch_i, __BAD__, __BAD__, /* c8..f */ fmul__, fxch_i, fcmove, fcmovne,
/* c8..f */ fmul_i, fxch_i,/*u*/ fmulp_, fxch_i,/*u*/ /* c8..f */ fmul_i, fxch_i,/*u*/ fmulp_, fxch_i,/*u*/
/* d0..7 */ fcom_st, fp_nop, __BAD__, __BAD__, /* d0..7 */ fcom_st, fp_nop, fcmovbe, fcmovnbe,
/* d0..7 */ fcom_st,/*u*/ fst_i_, fcompst,/*u*/ fstp_i,/*u*/ /* d0..7 */ fcom_st,/*u*/ fst_i_, fcompst,/*u*/ fstp_i,/*u*/
/* d8..f */ fcompst, fstp_i,/*u*/ __BAD__, __BAD__, /* d8..f */ fcompst, fstp_i,/*u*/ fcmovu, fcmovnu,
/* d8..f */ fcompst,/*u*/ fstp_i, fcompp, fstp_i,/*u*/ /* d8..f */ fcompst,/*u*/ fstp_i, fcompp, fstp_i,/*u*/
/* e0..7 */ fsub__, FPU_etc, __BAD__, finit_, /* e0..7 */ fsub__, FPU_etc, __BAD__, finit_,
/* e0..7 */ fsubri, fucom_, fsubrp, fstsw_, /* e0..7 */ fsubri, fucom_, fsubrp, fstsw_,
...@@ -80,10 +80,10 @@ static FUNC const st_instr_table[64] = { ...@@ -80,10 +80,10 @@ static FUNC const st_instr_table[64] = {
static u_char const type_table[64] = { static u_char const type_table[64] = {
/* Opcode: d8 d9 da db dc dd de df */ /* Opcode: d8 d9 da db dc dd de df */
/* c0..7 */ _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_, /* c0..7 */ _REGI_, _NONE_, _REGIn, _REGIn, _REGIi, _REGi_, _REGIp, _REGi_,
/* c8..f */ _REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_, /* c8..f */ _REGI_, _REGIn, _REGIn, _REGIn, _REGIi, _REGI_, _REGIp, _REGI_,
/* d0..7 */ _REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_, /* d0..7 */ _REGIc, _NONE_, _REGIn, _REGIn, _REGIc, _REG0_, _REGIc, _REG0_,
/* d8..f */ _REGIc, _REG0_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_, /* d8..f */ _REGIc, _REG0_, _REGIn, _REGIn, _REGIc, _REG0_, _REGIc, _REG0_,
/* e0..7 */ _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_, /* e0..7 */ _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
/* e8..f */ _REGI_, _NONE_, _REGIc, _REGIc, _REGIi, _REGIc, _REGIp, _REGIc, /* e8..f */ _REGI_, _NONE_, _REGIc, _REGIc, _REGIi, _REGIc, _REGIp, _REGIc,
/* f0..7 */ _REGI_, _NONE_, _null_, _REGIc, _REGIi, _null_, _REGIp, _REGIc, /* f0..7 */ _REGI_, _NONE_, _null_, _REGIc, _REGIi, _null_, _REGIp, _REGIc,
......
...@@ -46,6 +46,14 @@ extern void fstsw_(void); ...@@ -46,6 +46,14 @@ extern void fstsw_(void);
extern void fp_nop(void); extern void fp_nop(void);
extern void fld_i_(void); extern void fld_i_(void);
extern void fxch_i(void); extern void fxch_i(void);
extern void fcmovb(void);
extern void fcmove(void);
extern void fcmovbe(void);
extern void fcmovu(void);
extern void fcmovnb(void);
extern void fcmovne(void);
extern void fcmovnbe(void);
extern void fcmovnu(void);
extern void ffree_(void); extern void ffree_(void);
extern void ffreep(void); extern void ffreep(void);
extern void fst_i_(void); extern void fst_i_(void);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment