Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Denys Vlasenko and committed by
Ingo Molnar
e4877d64 a58e2ecd

+51 -12
+51 -12
arch/x86/math-emu/load_store.c
··· 33 33 34 34 #define pop_0() { FPU_settag0(TAG_Empty); top++; } 35 35 36 + /* index is a 5-bit value: (3-bit FPU_modrm.reg field | opcode[2,1]) */ 36 37 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 */ 41 42 _NONE_, _null_, _NONE_, _PUSH_, 42 43 _NONE_, _PUSH_, _null_, _PUSH_, 43 44 _NONE_, _null_, _NONE_, _REG0_, ··· 46 45 }; 47 46 48 47 u_char const data_sizes_16[32] = { 49 - 4, 4, 8, 2, 0, 0, 0, 0, 50 - 4, 4, 8, 2, 4, 4, 8, 2, 48 + 4, 4, 8, 2, 49 + 0, 4, 8, 2, /* /1: d9:undef, db,dd,df:fisttp */ 50 + 4, 4, 8, 2, 51 + 4, 4, 8, 2, 51 52 14, 0, 94, 10, 2, 10, 0, 8, 52 53 14, 0, 94, 10, 2, 10, 2, 8 53 54 }; 54 55 55 56 static u_char const data_sizes_32[32] = { 56 - 4, 4, 8, 2, 0, 0, 0, 0, 57 - 4, 4, 8, 2, 4, 4, 8, 2, 57 + 4, 4, 8, 2, 58 + 0, 4, 8, 2, /* /1: d9:undef, db,dd,df:fisttp */ 59 + 4, 4, 8, 2, 60 + 4, 4, 8, 2, 58 61 28, 0, 108, 10, 2, 10, 0, 8, 59 62 28, 0, 108, 10, 2, 10, 2, 8 60 63 }; ··· 70 65 FPU_REG *st0_ptr; 71 66 u_char st0_tag = TAG_Empty; /* This is just to stop a gcc warning. */ 72 67 u_char loaded_tag; 68 + int sv_cw; 73 69 74 70 st0_ptr = NULL; /* Initialized just to stop compiler warnings. */ 75 71 ··· 117 111 } 118 112 119 113 switch (type) { 120 - case 000: /* fld m32real */ 114 + /* type is a 5-bit value: (3-bit FPU_modrm.reg field | opcode[2,1]) */ 115 + case 000: /* fld m32real (d9 /0) */ 121 116 clear_C1(); 122 117 loaded_tag = 123 118 FPU_load_single((float __user *)data_address, &loaded_data); ··· 130 123 } 131 124 FPU_copy_to_reg0(&loaded_data, loaded_tag); 132 125 break; 133 - case 001: /* fild m32int */ 126 + case 001: /* fild m32int (db /0) */ 134 127 clear_C1(); 135 128 loaded_tag = 136 129 FPU_load_int32((long __user *)data_address, &loaded_data); 137 130 FPU_copy_to_reg0(&loaded_data, loaded_tag); 138 131 break; 139 - case 002: /* fld m64real */ 132 + case 002: /* fld m64real (dd /0) */ 140 133 clear_C1(); 141 134 loaded_tag = 142 135 FPU_load_double((double __user *)data_address, ··· 149 142 } 150 143 FPU_copy_to_reg0(&loaded_data, loaded_tag); 151 144 break; 152 - case 003: /* fild m16int */ 145 + case 003: /* fild m16int (df /0) */ 153 146 clear_C1(); 154 147 loaded_tag = 155 148 FPU_load_int16((short __user *)data_address, &loaded_data); 156 149 FPU_copy_to_reg0(&loaded_data, loaded_tag); 150 + break; 151 + /* case 004: undefined (d9 /1) */ 152 + /* fisttp are enabled if CPUID(1).ECX(0) "sse3" is set */ 153 + case 005: /* fisttp m32int (db /1) */ 154 + clear_C1(); 155 + sv_cw = control_word; 156 + control_word |= RC_CHOP; 157 + if (FPU_store_int32 158 + (st0_ptr, st0_tag, (long __user *)data_address)) 159 + pop_0(); /* pop only if the number was actually stored 160 + (see the 80486 manual p16-28) */ 161 + control_word = sv_cw; 162 + break; 163 + case 006: /* fisttp m64int (dd /1) */ 164 + clear_C1(); 165 + sv_cw = control_word; 166 + control_word |= RC_CHOP; 167 + if (FPU_store_int64 168 + (st0_ptr, st0_tag, (long long __user *)data_address)) 169 + pop_0(); /* pop only if the number was actually stored 170 + (see the 80486 manual p16-28) */ 171 + control_word = sv_cw; 172 + break; 173 + case 007: /* fisttp m16int (df /1) */ 174 + clear_C1(); 175 + sv_cw = control_word; 176 + control_word |= RC_CHOP; 177 + if (FPU_store_int16 178 + (st0_ptr, st0_tag, (short __user *)data_address)) 179 + pop_0(); /* pop only if the number was actually stored 180 + (see the 80486 manual p16-28) */ 181 + control_word = sv_cw; 157 182 break; 158 183 case 010: /* fst m32real */ 159 184 clear_C1();