Skip to content

Commit e4877d6

Browse files
dvlasenkIngo Molnar
authored andcommitted
x86/fpu/math-emu: Add support for FISTTP instructions
These FPU instructions were added in SSE3-enabled CPUs. Run-tested by booting with "no387 nofxsr" and running test program: [RUN] Testing fisttp instructions [OK] fisttp 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: Shuah Khan <shuahkh@osg.samsung.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: linux-kernel@vger.kernel.org Link: http://lkml.kernel.org/r/1442600614-28428-1-git-send-email-dvlasenk@redhat.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
1 parent a58e2ec commit e4877d6

File tree

1 file changed

+51
-12
lines changed

1 file changed

+51
-12
lines changed

arch/x86/math-emu/load_store.c

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,27 +33,32 @@
3333

3434
#define pop_0() { FPU_settag0(TAG_Empty); top++; }
3535

36+
/* index is a 5-bit value: (3-bit FPU_modrm.reg field | opcode[2,1]) */
3637
static u_char const type_table[32] = {
37-
_PUSH_, _PUSH_, _PUSH_, _PUSH_,
38-
_null_, _null_, _null_, _null_,
39-
_REG0_, _REG0_, _REG0_, _REG0_,
40-
_REG0_, _REG0_, _REG0_, _REG0_,
38+
_PUSH_, _PUSH_, _PUSH_, _PUSH_, /* /0: d9:fld f32, db:fild m32, dd:fld f64, df:fild m16 */
39+
_null_, _REG0_, _REG0_, _REG0_, /* /1: d9:undef, db,dd,df:fisttp m32/64/16 */
40+
_REG0_, _REG0_, _REG0_, _REG0_, /* /2: d9:fst f32, db:fist m32, dd:fst f64, df:fist m16 */
41+
_REG0_, _REG0_, _REG0_, _REG0_, /* /3: d9:fstp f32, db:fistp m32, dd:fstp f64, df:fistp m16 */
4142
_NONE_, _null_, _NONE_, _PUSH_,
4243
_NONE_, _PUSH_, _null_, _PUSH_,
4344
_NONE_, _null_, _NONE_, _REG0_,
4445
_NONE_, _REG0_, _NONE_, _REG0_
4546
};
4647

4748
u_char const data_sizes_16[32] = {
48-
4, 4, 8, 2, 0, 0, 0, 0,
49-
4, 4, 8, 2, 4, 4, 8, 2,
49+
4, 4, 8, 2,
50+
0, 4, 8, 2, /* /1: d9:undef, db,dd,df:fisttp */
51+
4, 4, 8, 2,
52+
4, 4, 8, 2,
5053
14, 0, 94, 10, 2, 10, 0, 8,
5154
14, 0, 94, 10, 2, 10, 2, 8
5255
};
5356

5457
static u_char const data_sizes_32[32] = {
55-
4, 4, 8, 2, 0, 0, 0, 0,
56-
4, 4, 8, 2, 4, 4, 8, 2,
58+
4, 4, 8, 2,
59+
0, 4, 8, 2, /* /1: d9:undef, db,dd,df:fisttp */
60+
4, 4, 8, 2,
61+
4, 4, 8, 2,
5762
28, 0, 108, 10, 2, 10, 0, 8,
5863
28, 0, 108, 10, 2, 10, 2, 8
5964
};
@@ -65,6 +70,7 @@ int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
6570
FPU_REG *st0_ptr;
6671
u_char st0_tag = TAG_Empty; /* This is just to stop a gcc warning. */
6772
u_char loaded_tag;
73+
int sv_cw;
6874

6975
st0_ptr = NULL; /* Initialized just to stop compiler warnings. */
7076

@@ -111,7 +117,8 @@ int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
111117
}
112118

113119
switch (type) {
114-
case 000: /* fld m32real */
120+
/* type is a 5-bit value: (3-bit FPU_modrm.reg field | opcode[2,1]) */
121+
case 000: /* fld m32real (d9 /0) */
115122
clear_C1();
116123
loaded_tag =
117124
FPU_load_single((float __user *)data_address, &loaded_data);
@@ -123,13 +130,13 @@ int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
123130
}
124131
FPU_copy_to_reg0(&loaded_data, loaded_tag);
125132
break;
126-
case 001: /* fild m32int */
133+
case 001: /* fild m32int (db /0) */
127134
clear_C1();
128135
loaded_tag =
129136
FPU_load_int32((long __user *)data_address, &loaded_data);
130137
FPU_copy_to_reg0(&loaded_data, loaded_tag);
131138
break;
132-
case 002: /* fld m64real */
139+
case 002: /* fld m64real (dd /0) */
133140
clear_C1();
134141
loaded_tag =
135142
FPU_load_double((double __user *)data_address,
@@ -142,12 +149,44 @@ int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
142149
}
143150
FPU_copy_to_reg0(&loaded_data, loaded_tag);
144151
break;
145-
case 003: /* fild m16int */
152+
case 003: /* fild m16int (df /0) */
146153
clear_C1();
147154
loaded_tag =
148155
FPU_load_int16((short __user *)data_address, &loaded_data);
149156
FPU_copy_to_reg0(&loaded_data, loaded_tag);
150157
break;
158+
/* case 004: undefined (d9 /1) */
159+
/* fisttp are enabled if CPUID(1).ECX(0) "sse3" is set */
160+
case 005: /* fisttp m32int (db /1) */
161+
clear_C1();
162+
sv_cw = control_word;
163+
control_word |= RC_CHOP;
164+
if (FPU_store_int32
165+
(st0_ptr, st0_tag, (long __user *)data_address))
166+
pop_0(); /* pop only if the number was actually stored
167+
(see the 80486 manual p16-28) */
168+
control_word = sv_cw;
169+
break;
170+
case 006: /* fisttp m64int (dd /1) */
171+
clear_C1();
172+
sv_cw = control_word;
173+
control_word |= RC_CHOP;
174+
if (FPU_store_int64
175+
(st0_ptr, st0_tag, (long long __user *)data_address))
176+
pop_0(); /* pop only if the number was actually stored
177+
(see the 80486 manual p16-28) */
178+
control_word = sv_cw;
179+
break;
180+
case 007: /* fisttp m16int (df /1) */
181+
clear_C1();
182+
sv_cw = control_word;
183+
control_word |= RC_CHOP;
184+
if (FPU_store_int16
185+
(st0_ptr, st0_tag, (short __user *)data_address))
186+
pop_0(); /* pop only if the number was actually stored
187+
(see the 80486 manual p16-28) */
188+
control_word = sv_cw;
189+
break;
151190
case 010: /* fst m32real */
152191
clear_C1();
153192
FPU_store_single(st0_ptr, st0_tag,

0 commit comments

Comments
 (0)