Skip to content

Commit 9a9d864

Browse files
dvlasenkIngo Molnar
authored andcommitted
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: Denys 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.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
1 parent b8e4a91 commit 9a9d864

File tree

3 files changed

+87
-9
lines changed

3 files changed

+87
-9
lines changed

arch/x86/math-emu/fpu_aux.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,76 @@ void fxch_i(void)
169169
fpu_tag_word = tag_word;
170170
}
171171

172+
static void fcmovCC(void)
173+
{
174+
/* fcmovCC st(i) */
175+
int i = FPU_rm;
176+
FPU_REG *st0_ptr = &st(0);
177+
FPU_REG *sti_ptr = &st(i);
178+
long tag_word = fpu_tag_word;
179+
int regnr = top & 7;
180+
int regnri = (top + i) & 7;
181+
u_char sti_tag = (tag_word >> (regnri * 2)) & 3;
182+
183+
if (sti_tag == TAG_Empty) {
184+
FPU_stack_underflow();
185+
clear_C1();
186+
return;
187+
}
188+
reg_copy(sti_ptr, st0_ptr);
189+
tag_word &= ~(3 << (regnr * 2));
190+
tag_word |= (sti_tag << (regnr * 2));
191+
fpu_tag_word = tag_word;
192+
}
193+
194+
void fcmovb(void)
195+
{
196+
if (FPU_EFLAGS & X86_EFLAGS_CF)
197+
fcmovCC();
198+
}
199+
200+
void fcmove(void)
201+
{
202+
if (FPU_EFLAGS & X86_EFLAGS_ZF)
203+
fcmovCC();
204+
}
205+
206+
void fcmovbe(void)
207+
{
208+
if (FPU_EFLAGS & (X86_EFLAGS_CF|X86_EFLAGS_ZF))
209+
fcmovCC();
210+
}
211+
212+
void fcmovu(void)
213+
{
214+
if (FPU_EFLAGS & X86_EFLAGS_PF)
215+
fcmovCC();
216+
}
217+
218+
void fcmovnb(void)
219+
{
220+
if (!(FPU_EFLAGS & X86_EFLAGS_CF))
221+
fcmovCC();
222+
}
223+
224+
void fcmovne(void)
225+
{
226+
if (!(FPU_EFLAGS & X86_EFLAGS_ZF))
227+
fcmovCC();
228+
}
229+
230+
void fcmovnbe(void)
231+
{
232+
if (!(FPU_EFLAGS & (X86_EFLAGS_CF|X86_EFLAGS_ZF)))
233+
fcmovCC();
234+
}
235+
236+
void fcmovnu(void)
237+
{
238+
if (!(FPU_EFLAGS & X86_EFLAGS_PF))
239+
fcmovCC();
240+
}
241+
172242
void ffree_(void)
173243
{
174244
/* ffree st(i) */

arch/x86/math-emu/fpu_entry.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040

4141
#define __BAD__ FPU_illegal /* Illegal on an 80486, causes SIGILL */
4242

43-
/* f(u)comi(p) are enabled if CPUID(1).EDX(15) "cmov" is set */
43+
/* fcmovCC and f(u)comi(p) are enabled if CPUID(1).EDX(15) "cmov" is set */
4444

4545
/* WARNING: "u" entries are not documented by Intel in their 80486 manual
4646
and may not work on FPU clones or later Intel FPUs.
@@ -49,13 +49,13 @@
4949
static FUNC const st_instr_table[64] = {
5050
/* Opcode: d8 d9 da db */
5151
/* dc dd de df */
52-
/* c0..7 */ fadd__, fld_i_, __BAD__, __BAD__,
52+
/* c0..7 */ fadd__, fld_i_, fcmovb, fcmovnb,
5353
/* c0..7 */ fadd_i, ffree_, faddp_, ffreep,/*u*/
54-
/* c8..f */ fmul__, fxch_i, __BAD__, __BAD__,
54+
/* c8..f */ fmul__, fxch_i, fcmove, fcmovne,
5555
/* c8..f */ fmul_i, fxch_i,/*u*/ fmulp_, fxch_i,/*u*/
56-
/* d0..7 */ fcom_st, fp_nop, __BAD__, __BAD__,
56+
/* d0..7 */ fcom_st, fp_nop, fcmovbe, fcmovnbe,
5757
/* d0..7 */ fcom_st,/*u*/ fst_i_, fcompst,/*u*/ fstp_i,/*u*/
58-
/* d8..f */ fcompst, fstp_i,/*u*/ __BAD__, __BAD__,
58+
/* d8..f */ fcompst, fstp_i,/*u*/ fcmovu, fcmovnu,
5959
/* d8..f */ fcompst,/*u*/ fstp_i, fcompp, fstp_i,/*u*/
6060
/* e0..7 */ fsub__, FPU_etc, __BAD__, finit_,
6161
/* e0..7 */ fsubri, fucom_, fsubrp, fstsw_,
@@ -80,10 +80,10 @@ static FUNC const st_instr_table[64] = {
8080

8181
static u_char const type_table[64] = {
8282
/* Opcode: d8 d9 da db dc dd de df */
83-
/* c0..7 */ _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_,
84-
/* c8..f */ _REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_,
85-
/* d0..7 */ _REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
86-
/* d8..f */ _REGIc, _REG0_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
83+
/* c0..7 */ _REGI_, _NONE_, _REGIn, _REGIn, _REGIi, _REGi_, _REGIp, _REGi_,
84+
/* c8..f */ _REGI_, _REGIn, _REGIn, _REGIn, _REGIi, _REGI_, _REGIp, _REGI_,
85+
/* d0..7 */ _REGIc, _NONE_, _REGIn, _REGIn, _REGIc, _REG0_, _REGIc, _REG0_,
86+
/* d8..f */ _REGIc, _REG0_, _REGIn, _REGIn, _REGIc, _REG0_, _REGIc, _REG0_,
8787
/* e0..7 */ _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
8888
/* e8..f */ _REGI_, _NONE_, _REGIc, _REGIc, _REGIi, _REGIc, _REGIp, _REGIc,
8989
/* f0..7 */ _REGI_, _NONE_, _null_, _REGIc, _REGIi, _null_, _REGIp, _REGIc,

arch/x86/math-emu/fpu_proto.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,14 @@ extern void fstsw_(void);
4646
extern void fp_nop(void);
4747
extern void fld_i_(void);
4848
extern void fxch_i(void);
49+
extern void fcmovb(void);
50+
extern void fcmove(void);
51+
extern void fcmovbe(void);
52+
extern void fcmovu(void);
53+
extern void fcmovnb(void);
54+
extern void fcmovne(void);
55+
extern void fcmovnbe(void);
56+
extern void fcmovnu(void);
4957
extern void ffree_(void);
5058
extern void ffreep(void);
5159
extern void fst_i_(void);

0 commit comments

Comments
 (0)