aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/math-emu/fpu_entry.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-01-30 07:30:11 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-30 07:30:11 -0500
commit3d0d14f983b55a570b976976284df4c434af3223 (patch)
tree864f11c0ce5ee1e15acdd196018b79d0d0e2685d /arch/x86/math-emu/fpu_entry.c
parenta4ec1effce83796209a0258602b0cf50026d86f2 (diff)
x86: lindent arch/i386/math-emu
lindent these files: errors lines of code errors/KLOC arch/x86/math-emu/ 2236 9424 237.2 arch/x86/math-emu/ 128 8706 14.7 no other changes. No code changed: text data bss dec hex filename 5589802 612739 3833856 10036397 9924ad vmlinux.before 5589802 612739 3833856 10036397 9924ad vmlinux.after the intent of this patch is to ease the automated tracking of kernel code quality - it's just much easier for us to maintain it if every file in arch/x86 is supposed to be clean. NOTE: it is a known problem of lindent that it causes some style damage of its own, but it's a safe tool (well, except for the gcc array range initializers extension), so we did the bulk of the changes via lindent, and did the manual fixups in a followup patch. the resulting math-emu code has been tested by Thomas Gleixner on a real 386 DX CPU as well, and it works fine. Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/math-emu/fpu_entry.c')
-rw-r--r--arch/x86/math-emu/fpu_entry.c1220
1 files changed, 607 insertions, 613 deletions
diff --git a/arch/x86/math-emu/fpu_entry.c b/arch/x86/math-emu/fpu_entry.c
index 1853524c8b57..cbb8717f09fd 100644
--- a/arch/x86/math-emu/fpu_entry.c
+++ b/arch/x86/math-emu/fpu_entry.c
@@ -36,726 +36,720 @@
36#include "control_w.h" 36#include "control_w.h"
37#include "status_w.h" 37#include "status_w.h"
38 38
39#define __BAD__ FPU_illegal /* Illegal on an 80486, causes SIGILL */ 39#define __BAD__ FPU_illegal /* Illegal on an 80486, causes SIGILL */
40 40
41#ifndef NO_UNDOC_CODE /* Un-documented FPU op-codes supported by default. */ 41#ifndef NO_UNDOC_CODE /* Un-documented FPU op-codes supported by default. */
42 42
43/* WARNING: These codes are not documented by Intel in their 80486 manual 43/* WARNING: These codes are not documented by Intel in their 80486 manual
44 and may not work on FPU clones or later Intel FPUs. */ 44 and may not work on FPU clones or later Intel FPUs. */
45 45
46/* Changes to support the un-doc codes provided by Linus Torvalds. */ 46/* Changes to support the un-doc codes provided by Linus Torvalds. */
47 47
48#define _d9_d8_ fstp_i /* unofficial code (19) */ 48#define _d9_d8_ fstp_i /* unofficial code (19) */
49#define _dc_d0_ fcom_st /* unofficial code (14) */ 49#define _dc_d0_ fcom_st /* unofficial code (14) */
50#define _dc_d8_ fcompst /* unofficial code (1c) */ 50#define _dc_d8_ fcompst /* unofficial code (1c) */
51#define _dd_c8_ fxch_i /* unofficial code (0d) */ 51#define _dd_c8_ fxch_i /* unofficial code (0d) */
52#define _de_d0_ fcompst /* unofficial code (16) */ 52#define _de_d0_ fcompst /* unofficial code (16) */
53#define _df_c0_ ffreep /* unofficial code (07) ffree + pop */ 53#define _df_c0_ ffreep /* unofficial code (07) ffree + pop */
54#define _df_c8_ fxch_i /* unofficial code (0f) */ 54#define _df_c8_ fxch_i /* unofficial code (0f) */
55#define _df_d0_ fstp_i /* unofficial code (17) */ 55#define _df_d0_ fstp_i /* unofficial code (17) */
56#define _df_d8_ fstp_i /* unofficial code (1f) */ 56#define _df_d8_ fstp_i /* unofficial code (1f) */
57 57
58static FUNC const st_instr_table[64] = { 58static FUNC const st_instr_table[64] = {
59 fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, _df_c0_, 59 fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, _df_c0_,
60 fmul__, fxch_i, __BAD__, __BAD__, fmul_i, _dd_c8_, fmulp_, _df_c8_, 60 fmul__, fxch_i, __BAD__, __BAD__, fmul_i, _dd_c8_, fmulp_, _df_c8_,
61 fcom_st, fp_nop, __BAD__, __BAD__, _dc_d0_, fst_i_, _de_d0_, _df_d0_, 61 fcom_st, fp_nop, __BAD__, __BAD__, _dc_d0_, fst_i_, _de_d0_, _df_d0_,
62 fcompst, _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i, fcompp, _df_d8_, 62 fcompst, _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i, fcompp, _df_d8_,
63 fsub__, FPU_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_, 63 fsub__, FPU_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
64 fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__, 64 fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
65 fdiv__, FPU_triga, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__, 65 fdiv__, FPU_triga, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
66 fdivr_, FPU_trigb, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__, 66 fdivr_, FPU_trigb, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
67}; 67};
68 68
69#else /* Support only documented FPU op-codes */ 69#else /* Support only documented FPU op-codes */
70 70
71static FUNC const st_instr_table[64] = { 71static FUNC const st_instr_table[64] = {
72 fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__, 72 fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__,
73 fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__, 73 fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__,
74 fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__, 74 fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__,
75 fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__, 75 fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__,
76 fsub__, FPU_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_, 76 fsub__, FPU_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
77 fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__, 77 fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
78 fdiv__, FPU_triga, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__, 78 fdiv__, FPU_triga, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
79 fdivr_, FPU_trigb, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__, 79 fdivr_, FPU_trigb, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
80}; 80};
81 81
82#endif /* NO_UNDOC_CODE */ 82#endif /* NO_UNDOC_CODE */
83 83
84 84#define _NONE_ 0 /* Take no special action */
85#define _NONE_ 0 /* Take no special action */ 85#define _REG0_ 1 /* Need to check for not empty st(0) */
86#define _REG0_ 1 /* Need to check for not empty st(0) */ 86#define _REGI_ 2 /* Need to check for not empty st(0) and st(rm) */
87#define _REGI_ 2 /* Need to check for not empty st(0) and st(rm) */ 87#define _REGi_ 0 /* Uses st(rm) */
88#define _REGi_ 0 /* Uses st(rm) */ 88#define _PUSH_ 3 /* Need to check for space to push onto stack */
89#define _PUSH_ 3 /* Need to check for space to push onto stack */ 89#define _null_ 4 /* Function illegal or not implemented */
90#define _null_ 4 /* Function illegal or not implemented */ 90#define _REGIi 5 /* Uses st(0) and st(rm), result to st(rm) */
91#define _REGIi 5 /* Uses st(0) and st(rm), result to st(rm) */ 91#define _REGIp 6 /* Uses st(0) and st(rm), result to st(rm) then pop */
92#define _REGIp 6 /* Uses st(0) and st(rm), result to st(rm) then pop */ 92#define _REGIc 0 /* Compare st(0) and st(rm) */
93#define _REGIc 0 /* Compare st(0) and st(rm) */ 93#define _REGIn 0 /* Uses st(0) and st(rm), but handle checks later */
94#define _REGIn 0 /* Uses st(0) and st(rm), but handle checks later */
95 94
96#ifndef NO_UNDOC_CODE 95#ifndef NO_UNDOC_CODE
97 96
98/* Un-documented FPU op-codes supported by default. (see above) */ 97/* Un-documented FPU op-codes supported by default. (see above) */
99 98
100static u_char const type_table[64] = { 99static u_char const type_table[64] = {
101 _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_, 100 _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_,
102 _REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_, 101 _REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_,
103 _REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_, 102 _REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
104 _REGIc, _REG0_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_, 103 _REGIc, _REG0_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
105 _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_, 104 _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
106 _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_, 105 _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
107 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_, 106 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
108 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_ 107 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
109}; 108};
110 109
111#else /* Support only documented FPU op-codes */ 110#else /* Support only documented FPU op-codes */
112 111
113static u_char const type_table[64] = { 112static u_char const type_table[64] = {
114 _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _null_, 113 _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _null_,
115 _REGI_, _REGIn, _null_, _null_, _REGIi, _null_, _REGIp, _null_, 114 _REGI_, _REGIn, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
116 _REGIc, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_, 115 _REGIc, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_,
117 _REGIc, _null_, _null_, _null_, _null_, _REG0_, _REGIc, _null_, 116 _REGIc, _null_, _null_, _null_, _null_, _REG0_, _REGIc, _null_,
118 _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_, 117 _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
119 _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_, 118 _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
120 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_, 119 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
121 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_ 120 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
122}; 121};
123 122
124#endif /* NO_UNDOC_CODE */ 123#endif /* NO_UNDOC_CODE */
125 124
126
127#ifdef RE_ENTRANT_CHECKING 125#ifdef RE_ENTRANT_CHECKING
128u_char emulating=0; 126u_char emulating = 0;
129#endif /* RE_ENTRANT_CHECKING */ 127#endif /* RE_ENTRANT_CHECKING */
130 128
131static int valid_prefix(u_char *Byte, u_char __user **fpu_eip, 129static int valid_prefix(u_char * Byte, u_char __user ** fpu_eip,
132 overrides *override); 130 overrides * override);
133 131
134asmlinkage void math_emulate(long arg) 132asmlinkage void math_emulate(long arg)
135{ 133{
136 u_char FPU_modrm, byte1; 134 u_char FPU_modrm, byte1;
137 unsigned short code; 135 unsigned short code;
138 fpu_addr_modes addr_modes; 136 fpu_addr_modes addr_modes;
139 int unmasked; 137 int unmasked;
140 FPU_REG loaded_data; 138 FPU_REG loaded_data;
141 FPU_REG *st0_ptr; 139 FPU_REG *st0_ptr;
142 u_char loaded_tag, st0_tag; 140 u_char loaded_tag, st0_tag;
143 void __user *data_address; 141 void __user *data_address;
144 struct address data_sel_off; 142 struct address data_sel_off;
145 struct address entry_sel_off; 143 struct address entry_sel_off;
146 unsigned long code_base = 0; 144 unsigned long code_base = 0;
147 unsigned long code_limit = 0; /* Initialized to stop compiler warnings */ 145 unsigned long code_limit = 0; /* Initialized to stop compiler warnings */
148 struct desc_struct code_descriptor; 146 struct desc_struct code_descriptor;
149 147
150#ifdef RE_ENTRANT_CHECKING 148#ifdef RE_ENTRANT_CHECKING
151 if ( emulating ) 149 if (emulating) {
152 { 150 printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
153 printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n"); 151 }
154 } 152 RE_ENTRANT_CHECK_ON;
155 RE_ENTRANT_CHECK_ON;
156#endif /* RE_ENTRANT_CHECKING */ 153#endif /* RE_ENTRANT_CHECKING */
157 154
158 if (!used_math()) 155 if (!used_math()) {
159 { 156 finit();
160 finit(); 157 set_used_math();
161 set_used_math();
162 }
163
164 SETUP_DATA_AREA(arg);
165
166 FPU_ORIG_EIP = FPU_EIP;
167
168 if ( (FPU_EFLAGS & 0x00020000) != 0 )
169 {
170 /* Virtual 8086 mode */
171 addr_modes.default_mode = VM86;
172 FPU_EIP += code_base = FPU_CS << 4;
173 code_limit = code_base + 0xffff; /* Assumes code_base <= 0xffff0000 */
174 }
175 else if ( FPU_CS == __USER_CS && FPU_DS == __USER_DS )
176 {
177 addr_modes.default_mode = 0;
178 }
179 else if ( FPU_CS == __KERNEL_CS )
180 {
181 printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP);
182 panic("Math emulation needed in kernel");
183 }
184 else
185 {
186
187 if ( (FPU_CS & 4) != 4 ) /* Must be in the LDT */
188 {
189 /* Can only handle segmented addressing via the LDT
190 for now, and it must be 16 bit */
191 printk("FPU emulator: Unsupported addressing mode\n");
192 math_abort(FPU_info, SIGILL);
193 } 158 }
194 159
195 code_descriptor = LDT_DESCRIPTOR(FPU_CS); 160 SETUP_DATA_AREA(arg);
196 if ( SEG_D_SIZE(code_descriptor) ) 161
197 { 162 FPU_ORIG_EIP = FPU_EIP;
198 /* The above test may be wrong, the book is not clear */ 163
199 /* Segmented 32 bit protected mode */ 164 if ((FPU_EFLAGS & 0x00020000) != 0) {
200 addr_modes.default_mode = SEG32; 165 /* Virtual 8086 mode */
166 addr_modes.default_mode = VM86;
167 FPU_EIP += code_base = FPU_CS << 4;
168 code_limit = code_base + 0xffff; /* Assumes code_base <= 0xffff0000 */
169 } else if (FPU_CS == __USER_CS && FPU_DS == __USER_DS) {
170 addr_modes.default_mode = 0;
171 } else if (FPU_CS == __KERNEL_CS) {
172 printk("math_emulate: %04x:%08lx\n", FPU_CS, FPU_EIP);
173 panic("Math emulation needed in kernel");
174 } else {
175
176 if ((FPU_CS & 4) != 4) { /* Must be in the LDT */
177 /* Can only handle segmented addressing via the LDT
178 for now, and it must be 16 bit */
179 printk("FPU emulator: Unsupported addressing mode\n");
180 math_abort(FPU_info, SIGILL);
181 }
182
183 code_descriptor = LDT_DESCRIPTOR(FPU_CS);
184 if (SEG_D_SIZE(code_descriptor)) {
185 /* The above test may be wrong, the book is not clear */
186 /* Segmented 32 bit protected mode */
187 addr_modes.default_mode = SEG32;
188 } else {
189 /* 16 bit protected mode */
190 addr_modes.default_mode = PM16;
191 }
192 FPU_EIP += code_base = SEG_BASE_ADDR(code_descriptor);
193 code_limit = code_base
194 + (SEG_LIMIT(code_descriptor) +
195 1) * SEG_GRANULARITY(code_descriptor)
196 - 1;
197 if (code_limit < code_base)
198 code_limit = 0xffffffff;
201 } 199 }
202 else 200
203 { 201 FPU_lookahead = 1;
204 /* 16 bit protected mode */ 202 if (current->ptrace & PT_PTRACED)
205 addr_modes.default_mode = PM16; 203 FPU_lookahead = 0;
204
205 if (!valid_prefix(&byte1, (u_char __user **) & FPU_EIP,
206 &addr_modes.override)) {
207 RE_ENTRANT_CHECK_OFF;
208 printk
209 ("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n"
210 "FPU emulator: self-modifying code! (emulation impossible)\n",
211 byte1);
212 RE_ENTRANT_CHECK_ON;
213 EXCEPTION(EX_INTERNAL | 0x126);
214 math_abort(FPU_info, SIGILL);
206 } 215 }
207 FPU_EIP += code_base = SEG_BASE_ADDR(code_descriptor); 216
208 code_limit = code_base 217 do_another_FPU_instruction:
209 + (SEG_LIMIT(code_descriptor)+1) * SEG_GRANULARITY(code_descriptor) 218
210 - 1; 219 no_ip_update = 0;
211 if ( code_limit < code_base ) code_limit = 0xffffffff; 220
212 } 221 FPU_EIP++; /* We have fetched the prefix and first code bytes. */
213 222
214 FPU_lookahead = 1; 223 if (addr_modes.default_mode) {
215 if (current->ptrace & PT_PTRACED) 224 /* This checks for the minimum instruction bytes.
216 FPU_lookahead = 0; 225 We also need to check any extra (address mode) code access. */
217 226 if (FPU_EIP > code_limit)
218 if ( !valid_prefix(&byte1, (u_char __user **)&FPU_EIP, 227 math_abort(FPU_info, SIGSEGV);
219 &addr_modes.override) )
220 {
221 RE_ENTRANT_CHECK_OFF;
222 printk("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n"
223 "FPU emulator: self-modifying code! (emulation impossible)\n",
224 byte1);
225 RE_ENTRANT_CHECK_ON;
226 EXCEPTION(EX_INTERNAL|0x126);
227 math_abort(FPU_info,SIGILL);
228 }
229
230do_another_FPU_instruction:
231
232 no_ip_update = 0;
233
234 FPU_EIP++; /* We have fetched the prefix and first code bytes. */
235
236 if ( addr_modes.default_mode )
237 {
238 /* This checks for the minimum instruction bytes.
239 We also need to check any extra (address mode) code access. */
240 if ( FPU_EIP > code_limit )
241 math_abort(FPU_info,SIGSEGV);
242 }
243
244 if ( (byte1 & 0xf8) != 0xd8 )
245 {
246 if ( byte1 == FWAIT_OPCODE )
247 {
248 if (partial_status & SW_Summary)
249 goto do_the_FPU_interrupt;
250 else
251 goto FPU_fwait_done;
252 } 228 }
229
230 if ((byte1 & 0xf8) != 0xd8) {
231 if (byte1 == FWAIT_OPCODE) {
232 if (partial_status & SW_Summary)
233 goto do_the_FPU_interrupt;
234 else
235 goto FPU_fwait_done;
236 }
253#ifdef PARANOID 237#ifdef PARANOID
254 EXCEPTION(EX_INTERNAL|0x128); 238 EXCEPTION(EX_INTERNAL | 0x128);
255 math_abort(FPU_info,SIGILL); 239 math_abort(FPU_info, SIGILL);
256#endif /* PARANOID */ 240#endif /* PARANOID */
257 }
258
259 RE_ENTRANT_CHECK_OFF;
260 FPU_code_access_ok(1);
261 FPU_get_user(FPU_modrm, (u_char __user *) FPU_EIP);
262 RE_ENTRANT_CHECK_ON;
263 FPU_EIP++;
264
265 if (partial_status & SW_Summary)
266 {
267 /* Ignore the error for now if the current instruction is a no-wait
268 control instruction */
269 /* The 80486 manual contradicts itself on this topic,
270 but a real 80486 uses the following instructions:
271 fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex.
272 */
273 code = (FPU_modrm << 8) | byte1;
274 if ( ! ( (((code & 0xf803) == 0xe003) || /* fnclex, fninit, fnstsw */
275 (((code & 0x3003) == 0x3001) && /* fnsave, fnstcw, fnstenv,
276 fnstsw */
277 ((code & 0xc000) != 0xc000))) ) )
278 {
279 /*
280 * We need to simulate the action of the kernel to FPU
281 * interrupts here.
282 */
283 do_the_FPU_interrupt:
284
285 FPU_EIP = FPU_ORIG_EIP; /* Point to current FPU instruction. */
286
287 RE_ENTRANT_CHECK_OFF;
288 current->thread.trap_no = 16;
289 current->thread.error_code = 0;
290 send_sig(SIGFPE, current, 1);
291 return;
292 }
293 }
294
295 entry_sel_off.offset = FPU_ORIG_EIP;
296 entry_sel_off.selector = FPU_CS;
297 entry_sel_off.opcode = (byte1 << 8) | FPU_modrm;
298
299 FPU_rm = FPU_modrm & 7;
300
301 if ( FPU_modrm < 0300 )
302 {
303 /* All of these instructions use the mod/rm byte to get a data address */
304
305 if ( (addr_modes.default_mode & SIXTEEN)
306 ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX) )
307 data_address = FPU_get_address_16(FPU_modrm, &FPU_EIP, &data_sel_off,
308 addr_modes);
309 else
310 data_address = FPU_get_address(FPU_modrm, &FPU_EIP, &data_sel_off,
311 addr_modes);
312
313 if ( addr_modes.default_mode )
314 {
315 if ( FPU_EIP-1 > code_limit )
316 math_abort(FPU_info,SIGSEGV);
317 } 241 }
318 242
319 if ( !(byte1 & 1) ) 243 RE_ENTRANT_CHECK_OFF;
320 { 244 FPU_code_access_ok(1);
321 unsigned short status1 = partial_status; 245 FPU_get_user(FPU_modrm, (u_char __user *) FPU_EIP);
322 246 RE_ENTRANT_CHECK_ON;
323 st0_ptr = &st(0); 247 FPU_EIP++;
324 st0_tag = FPU_gettag0(); 248
325 249 if (partial_status & SW_Summary) {
326 /* Stack underflow has priority */ 250 /* Ignore the error for now if the current instruction is a no-wait
327 if ( NOT_EMPTY_ST0 ) 251 control instruction */
328 { 252 /* The 80486 manual contradicts itself on this topic,
329 if ( addr_modes.default_mode & PROTECTED ) 253 but a real 80486 uses the following instructions:
330 { 254 fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex.
331 /* This table works for 16 and 32 bit protected mode */ 255 */
332 if ( access_limit < data_sizes_16[(byte1 >> 1) & 3] ) 256 code = (FPU_modrm << 8) | byte1;
333 math_abort(FPU_info,SIGSEGV); 257 if (!((((code & 0xf803) == 0xe003) || /* fnclex, fninit, fnstsw */
258 (((code & 0x3003) == 0x3001) && /* fnsave, fnstcw, fnstenv,
259 fnstsw */
260 ((code & 0xc000) != 0xc000))))) {
261 /*
262 * We need to simulate the action of the kernel to FPU
263 * interrupts here.
264 */
265 do_the_FPU_interrupt:
266
267 FPU_EIP = FPU_ORIG_EIP; /* Point to current FPU instruction. */
268
269 RE_ENTRANT_CHECK_OFF;
270 current->thread.trap_no = 16;
271 current->thread.error_code = 0;
272 send_sig(SIGFPE, current, 1);
273 return;
334 } 274 }
275 }
335 276
336 unmasked = 0; /* Do this here to stop compiler warnings. */ 277 entry_sel_off.offset = FPU_ORIG_EIP;
337 switch ( (byte1 >> 1) & 3 ) 278 entry_sel_off.selector = FPU_CS;
338 { 279 entry_sel_off.opcode = (byte1 << 8) | FPU_modrm;
339 case 0:
340 unmasked = FPU_load_single((float __user *)data_address,
341 &loaded_data);
342 loaded_tag = unmasked & 0xff;
343 unmasked &= ~0xff;
344 break;
345 case 1:
346 loaded_tag = FPU_load_int32((long __user *)data_address, &loaded_data);
347 break;
348 case 2:
349 unmasked = FPU_load_double((double __user *)data_address,
350 &loaded_data);
351 loaded_tag = unmasked & 0xff;
352 unmasked &= ~0xff;
353 break;
354 case 3:
355 default: /* Used here to suppress gcc warnings. */
356 loaded_tag = FPU_load_int16((short __user *)data_address, &loaded_data);
357 break;
358 }
359 280
360 /* No more access to user memory, it is safe 281 FPU_rm = FPU_modrm & 7;
361 to use static data now */
362
363 /* NaN operands have the next priority. */
364 /* We have to delay looking at st(0) until after
365 loading the data, because that data might contain an SNaN */
366 if ( ((st0_tag == TAG_Special) && isNaN(st0_ptr)) ||
367 ((loaded_tag == TAG_Special) && isNaN(&loaded_data)) )
368 {
369 /* Restore the status word; we might have loaded a
370 denormal. */
371 partial_status = status1;
372 if ( (FPU_modrm & 0x30) == 0x10 )
373 {
374 /* fcom or fcomp */
375 EXCEPTION(EX_Invalid);
376 setcc(SW_C3 | SW_C2 | SW_C0);
377 if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
378 FPU_pop(); /* fcomp, masked, so we pop. */
379 }
380 else
381 {
382 if ( loaded_tag == TAG_Special )
383 loaded_tag = FPU_Special(&loaded_data);
384#ifdef PECULIAR_486
385 /* This is not really needed, but gives behaviour
386 identical to an 80486 */
387 if ( (FPU_modrm & 0x28) == 0x20 )
388 /* fdiv or fsub */
389 real_2op_NaN(&loaded_data, loaded_tag, 0, &loaded_data);
390 else
391#endif /* PECULIAR_486 */
392 /* fadd, fdivr, fmul, or fsubr */
393 real_2op_NaN(&loaded_data, loaded_tag, 0, st0_ptr);
394 }
395 goto reg_mem_instr_done;
396 }
397 282
398 if ( unmasked && !((FPU_modrm & 0x30) == 0x10) ) 283 if (FPU_modrm < 0300) {
399 { 284 /* All of these instructions use the mod/rm byte to get a data address */
400 /* Is not a comparison instruction. */
401 if ( (FPU_modrm & 0x38) == 0x38 )
402 {
403 /* fdivr */
404 if ( (st0_tag == TAG_Zero) &&
405 ((loaded_tag == TAG_Valid)
406 || (loaded_tag == TAG_Special
407 && isdenormal(&loaded_data))) )
408 {
409 if ( FPU_divide_by_zero(0, getsign(&loaded_data))
410 < 0 )
411 {
412 /* We use the fact here that the unmasked
413 exception in the loaded data was for a
414 denormal operand */
415 /* Restore the state of the denormal op bit */
416 partial_status &= ~SW_Denorm_Op;
417 partial_status |= status1 & SW_Denorm_Op;
418 }
419 else
420 setsign(st0_ptr, getsign(&loaded_data));
421 }
422 }
423 goto reg_mem_instr_done;
424 }
425 285
426 switch ( (FPU_modrm >> 3) & 7 ) 286 if ((addr_modes.default_mode & SIXTEEN)
427 { 287 ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX))
428 case 0: /* fadd */ 288 data_address =
429 clear_C1(); 289 FPU_get_address_16(FPU_modrm, &FPU_EIP,
430 FPU_add(&loaded_data, loaded_tag, 0, control_word); 290 &data_sel_off, addr_modes);
431 break; 291 else
432 case 1: /* fmul */ 292 data_address =
433 clear_C1(); 293 FPU_get_address(FPU_modrm, &FPU_EIP, &data_sel_off,
434 FPU_mul(&loaded_data, loaded_tag, 0, control_word); 294 addr_modes);
435 break; 295
436 case 2: /* fcom */ 296 if (addr_modes.default_mode) {
437 FPU_compare_st_data(&loaded_data, loaded_tag); 297 if (FPU_EIP - 1 > code_limit)
438 break; 298 math_abort(FPU_info, SIGSEGV);
439 case 3: /* fcomp */
440 if ( !FPU_compare_st_data(&loaded_data, loaded_tag)
441 && !unmasked )
442 FPU_pop();
443 break;
444 case 4: /* fsub */
445 clear_C1();
446 FPU_sub(LOADED|loaded_tag, (int)&loaded_data, control_word);
447 break;
448 case 5: /* fsubr */
449 clear_C1();
450 FPU_sub(REV|LOADED|loaded_tag, (int)&loaded_data, control_word);
451 break;
452 case 6: /* fdiv */
453 clear_C1();
454 FPU_div(LOADED|loaded_tag, (int)&loaded_data, control_word);
455 break;
456 case 7: /* fdivr */
457 clear_C1();
458 if ( st0_tag == TAG_Zero )
459 partial_status = status1; /* Undo any denorm tag,
460 zero-divide has priority. */
461 FPU_div(REV|LOADED|loaded_tag, (int)&loaded_data, control_word);
462 break;
463 } 299 }
464 } 300
465 else 301 if (!(byte1 & 1)) {
466 { 302 unsigned short status1 = partial_status;
467 if ( (FPU_modrm & 0x30) == 0x10 ) 303
468 { 304 st0_ptr = &st(0);
469 /* The instruction is fcom or fcomp */ 305 st0_tag = FPU_gettag0();
470 EXCEPTION(EX_StackUnder); 306
471 setcc(SW_C3 | SW_C2 | SW_C0); 307 /* Stack underflow has priority */
472 if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) ) 308 if (NOT_EMPTY_ST0) {
473 FPU_pop(); /* fcomp */ 309 if (addr_modes.default_mode & PROTECTED) {
310 /* This table works for 16 and 32 bit protected mode */
311 if (access_limit <
312 data_sizes_16[(byte1 >> 1) & 3])
313 math_abort(FPU_info, SIGSEGV);
314 }
315
316 unmasked = 0; /* Do this here to stop compiler warnings. */
317 switch ((byte1 >> 1) & 3) {
318 case 0:
319 unmasked =
320 FPU_load_single((float __user *)
321 data_address,
322 &loaded_data);
323 loaded_tag = unmasked & 0xff;
324 unmasked &= ~0xff;
325 break;
326 case 1:
327 loaded_tag =
328 FPU_load_int32((long __user *)
329 data_address,
330 &loaded_data);
331 break;
332 case 2:
333 unmasked =
334 FPU_load_double((double __user *)
335 data_address,
336 &loaded_data);
337 loaded_tag = unmasked & 0xff;
338 unmasked &= ~0xff;
339 break;
340 case 3:
341 default: /* Used here to suppress gcc warnings. */
342 loaded_tag =
343 FPU_load_int16((short __user *)
344 data_address,
345 &loaded_data);
346 break;
347 }
348
349 /* No more access to user memory, it is safe
350 to use static data now */
351
352 /* NaN operands have the next priority. */
353 /* We have to delay looking at st(0) until after
354 loading the data, because that data might contain an SNaN */
355 if (((st0_tag == TAG_Special) && isNaN(st0_ptr))
356 || ((loaded_tag == TAG_Special)
357 && isNaN(&loaded_data))) {
358 /* Restore the status word; we might have loaded a
359 denormal. */
360 partial_status = status1;
361 if ((FPU_modrm & 0x30) == 0x10) {
362 /* fcom or fcomp */
363 EXCEPTION(EX_Invalid);
364 setcc(SW_C3 | SW_C2 | SW_C0);
365 if ((FPU_modrm & 0x08)
366 && (control_word &
367 CW_Invalid))
368 FPU_pop(); /* fcomp, masked, so we pop. */
369 } else {
370 if (loaded_tag == TAG_Special)
371 loaded_tag =
372 FPU_Special
373 (&loaded_data);
374#ifdef PECULIAR_486
375 /* This is not really needed, but gives behaviour
376 identical to an 80486 */
377 if ((FPU_modrm & 0x28) == 0x20)
378 /* fdiv or fsub */
379 real_2op_NaN
380 (&loaded_data,
381 loaded_tag, 0,
382 &loaded_data);
383 else
384#endif /* PECULIAR_486 */
385 /* fadd, fdivr, fmul, or fsubr */
386 real_2op_NaN
387 (&loaded_data,
388 loaded_tag, 0,
389 st0_ptr);
390 }
391 goto reg_mem_instr_done;
392 }
393
394 if (unmasked && !((FPU_modrm & 0x30) == 0x10)) {
395 /* Is not a comparison instruction. */
396 if ((FPU_modrm & 0x38) == 0x38) {
397 /* fdivr */
398 if ((st0_tag == TAG_Zero) &&
399 ((loaded_tag == TAG_Valid)
400 || (loaded_tag ==
401 TAG_Special
402 &&
403 isdenormal
404 (&loaded_data)))) {
405 if (FPU_divide_by_zero
406 (0,
407 getsign
408 (&loaded_data))
409 < 0) {
410 /* We use the fact here that the unmasked
411 exception in the loaded data was for a
412 denormal operand */
413 /* Restore the state of the denormal op bit */
414 partial_status
415 &=
416 ~SW_Denorm_Op;
417 partial_status
418 |=
419 status1 &
420 SW_Denorm_Op;
421 } else
422 setsign(st0_ptr,
423 getsign
424 (&loaded_data));
425 }
426 }
427 goto reg_mem_instr_done;
428 }
429
430 switch ((FPU_modrm >> 3) & 7) {
431 case 0: /* fadd */
432 clear_C1();
433 FPU_add(&loaded_data, loaded_tag, 0,
434 control_word);
435 break;
436 case 1: /* fmul */
437 clear_C1();
438 FPU_mul(&loaded_data, loaded_tag, 0,
439 control_word);
440 break;
441 case 2: /* fcom */
442 FPU_compare_st_data(&loaded_data,
443 loaded_tag);
444 break;
445 case 3: /* fcomp */
446 if (!FPU_compare_st_data
447 (&loaded_data, loaded_tag)
448 && !unmasked)
449 FPU_pop();
450 break;
451 case 4: /* fsub */
452 clear_C1();
453 FPU_sub(LOADED | loaded_tag,
454 (int)&loaded_data,
455 control_word);
456 break;
457 case 5: /* fsubr */
458 clear_C1();
459 FPU_sub(REV | LOADED | loaded_tag,
460 (int)&loaded_data,
461 control_word);
462 break;
463 case 6: /* fdiv */
464 clear_C1();
465 FPU_div(LOADED | loaded_tag,
466 (int)&loaded_data,
467 control_word);
468 break;
469 case 7: /* fdivr */
470 clear_C1();
471 if (st0_tag == TAG_Zero)
472 partial_status = status1; /* Undo any denorm tag,
473 zero-divide has priority. */
474 FPU_div(REV | LOADED | loaded_tag,
475 (int)&loaded_data,
476 control_word);
477 break;
478 }
479 } else {
480 if ((FPU_modrm & 0x30) == 0x10) {
481 /* The instruction is fcom or fcomp */
482 EXCEPTION(EX_StackUnder);
483 setcc(SW_C3 | SW_C2 | SW_C0);
484 if ((FPU_modrm & 0x08)
485 && (control_word & CW_Invalid))
486 FPU_pop(); /* fcomp */
487 } else
488 FPU_stack_underflow();
489 }
490 reg_mem_instr_done:
491 operand_address = data_sel_off;
492 } else {
493 if (!(no_ip_update =
494 FPU_load_store(((FPU_modrm & 0x38) | (byte1 & 6))
495 >> 1, addr_modes, data_address))) {
496 operand_address = data_sel_off;
497 }
474 } 498 }
475 else
476 FPU_stack_underflow();
477 }
478 reg_mem_instr_done:
479 operand_address = data_sel_off;
480 }
481 else
482 {
483 if ( !(no_ip_update =
484 FPU_load_store(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1,
485 addr_modes, data_address)) )
486 {
487 operand_address = data_sel_off;
488 }
489 }
490 499
491 } 500 } else {
492 else 501 /* None of these instructions access user memory */
493 { 502 u_char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
494 /* None of these instructions access user memory */
495 u_char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
496 503
497#ifdef PECULIAR_486 504#ifdef PECULIAR_486
498 /* This is supposed to be undefined, but a real 80486 seems 505 /* This is supposed to be undefined, but a real 80486 seems
499 to do this: */ 506 to do this: */
500 operand_address.offset = 0; 507 operand_address.offset = 0;
501 operand_address.selector = FPU_DS; 508 operand_address.selector = FPU_DS;
502#endif /* PECULIAR_486 */ 509#endif /* PECULIAR_486 */
503 510
504 st0_ptr = &st(0); 511 st0_ptr = &st(0);
505 st0_tag = FPU_gettag0(); 512 st0_tag = FPU_gettag0();
506 switch ( type_table[(int) instr_index] ) 513 switch (type_table[(int)instr_index]) {
507 { 514 case _NONE_: /* also _REGIc: _REGIn */
508 case _NONE_: /* also _REGIc: _REGIn */ 515 break;
509 break; 516 case _REG0_:
510 case _REG0_: 517 if (!NOT_EMPTY_ST0) {
511 if ( !NOT_EMPTY_ST0 ) 518 FPU_stack_underflow();
512 { 519 goto FPU_instruction_done;
513 FPU_stack_underflow(); 520 }
514 goto FPU_instruction_done; 521 break;
515 } 522 case _REGIi:
516 break; 523 if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
517 case _REGIi: 524 FPU_stack_underflow_i(FPU_rm);
518 if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) ) 525 goto FPU_instruction_done;
519 { 526 }
520 FPU_stack_underflow_i(FPU_rm); 527 break;
521 goto FPU_instruction_done; 528 case _REGIp:
522 } 529 if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
523 break; 530 FPU_stack_underflow_pop(FPU_rm);
524 case _REGIp: 531 goto FPU_instruction_done;
525 if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) ) 532 }
526 { 533 break;
527 FPU_stack_underflow_pop(FPU_rm); 534 case _REGI_:
528 goto FPU_instruction_done; 535 if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
529 } 536 FPU_stack_underflow();
530 break; 537 goto FPU_instruction_done;
531 case _REGI_: 538 }
532 if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) ) 539 break;
533 { 540 case _PUSH_: /* Only used by the fld st(i) instruction */
534 FPU_stack_underflow(); 541 break;
535 goto FPU_instruction_done; 542 case _null_:
536 } 543 FPU_illegal();
537 break; 544 goto FPU_instruction_done;
538 case _PUSH_: /* Only used by the fld st(i) instruction */ 545 default:
539 break; 546 EXCEPTION(EX_INTERNAL | 0x111);
540 case _null_: 547 goto FPU_instruction_done;
541 FPU_illegal(); 548 }
542 goto FPU_instruction_done; 549 (*st_instr_table[(int)instr_index]) ();
543 default:
544 EXCEPTION(EX_INTERNAL|0x111);
545 goto FPU_instruction_done;
546 }
547 (*st_instr_table[(int) instr_index])();
548 550
549FPU_instruction_done: 551 FPU_instruction_done:
550 ; 552 ;
551 } 553 }
552 554
553 if ( ! no_ip_update ) 555 if (!no_ip_update)
554 instruction_address = entry_sel_off; 556 instruction_address = entry_sel_off;
555 557
556FPU_fwait_done: 558 FPU_fwait_done:
557 559
558#ifdef DEBUG 560#ifdef DEBUG
559 RE_ENTRANT_CHECK_OFF; 561 RE_ENTRANT_CHECK_OFF;
560 FPU_printall(); 562 FPU_printall();
561 RE_ENTRANT_CHECK_ON; 563 RE_ENTRANT_CHECK_ON;
562#endif /* DEBUG */ 564#endif /* DEBUG */
563 565
564 if (FPU_lookahead && !need_resched()) 566 if (FPU_lookahead && !need_resched()) {
565 { 567 FPU_ORIG_EIP = FPU_EIP - code_base;
566 FPU_ORIG_EIP = FPU_EIP - code_base; 568 if (valid_prefix(&byte1, (u_char __user **) & FPU_EIP,
567 if ( valid_prefix(&byte1, (u_char __user **)&FPU_EIP, 569 &addr_modes.override))
568 &addr_modes.override) ) 570 goto do_another_FPU_instruction;
569 goto do_another_FPU_instruction; 571 }
570 }
571 572
572 if ( addr_modes.default_mode ) 573 if (addr_modes.default_mode)
573 FPU_EIP -= code_base; 574 FPU_EIP -= code_base;
574 575
575 RE_ENTRANT_CHECK_OFF; 576 RE_ENTRANT_CHECK_OFF;
576} 577}
577 578
578
579/* Support for prefix bytes is not yet complete. To properly handle 579/* Support for prefix bytes is not yet complete. To properly handle
580 all prefix bytes, further changes are needed in the emulator code 580 all prefix bytes, further changes are needed in the emulator code
581 which accesses user address space. Access to separate segments is 581 which accesses user address space. Access to separate segments is
582 important for msdos emulation. */ 582 important for msdos emulation. */
583static int valid_prefix(u_char *Byte, u_char __user **fpu_eip, 583static int valid_prefix(u_char * Byte, u_char __user ** fpu_eip,
584 overrides *override) 584 overrides * override)
585{ 585{
586 u_char byte; 586 u_char byte;
587 u_char __user *ip = *fpu_eip; 587 u_char __user *ip = *fpu_eip;
588 588
589 *override = (overrides) { 0, 0, PREFIX_DEFAULT }; /* defaults */ 589 *override = (overrides) {
590 590 0, 0, PREFIX_DEFAULT}; /* defaults */
591 RE_ENTRANT_CHECK_OFF; 591
592 FPU_code_access_ok(1); 592 RE_ENTRANT_CHECK_OFF;
593 FPU_get_user(byte, ip); 593 FPU_code_access_ok(1);
594 RE_ENTRANT_CHECK_ON; 594 FPU_get_user(byte, ip);
595 595 RE_ENTRANT_CHECK_ON;
596 while ( 1 ) 596
597 { 597 while (1) {
598 switch ( byte ) 598 switch (byte) {
599 { 599 case ADDR_SIZE_PREFIX:
600 case ADDR_SIZE_PREFIX: 600 override->address_size = ADDR_SIZE_PREFIX;
601 override->address_size = ADDR_SIZE_PREFIX; 601 goto do_next_byte;
602 goto do_next_byte; 602
603 603 case OP_SIZE_PREFIX:
604 case OP_SIZE_PREFIX: 604 override->operand_size = OP_SIZE_PREFIX;
605 override->operand_size = OP_SIZE_PREFIX; 605 goto do_next_byte;
606 goto do_next_byte; 606
607 607 case PREFIX_CS:
608 case PREFIX_CS: 608 override->segment = PREFIX_CS_;
609 override->segment = PREFIX_CS_; 609 goto do_next_byte;
610 goto do_next_byte; 610 case PREFIX_ES:
611 case PREFIX_ES: 611 override->segment = PREFIX_ES_;
612 override->segment = PREFIX_ES_; 612 goto do_next_byte;
613 goto do_next_byte; 613 case PREFIX_SS:
614 case PREFIX_SS: 614 override->segment = PREFIX_SS_;
615 override->segment = PREFIX_SS_; 615 goto do_next_byte;
616 goto do_next_byte; 616 case PREFIX_FS:
617 case PREFIX_FS: 617 override->segment = PREFIX_FS_;
618 override->segment = PREFIX_FS_; 618 goto do_next_byte;
619 goto do_next_byte; 619 case PREFIX_GS:
620 case PREFIX_GS: 620 override->segment = PREFIX_GS_;
621 override->segment = PREFIX_GS_; 621 goto do_next_byte;
622 goto do_next_byte; 622 case PREFIX_DS:
623 case PREFIX_DS: 623 override->segment = PREFIX_DS_;
624 override->segment = PREFIX_DS_; 624 goto do_next_byte;
625 goto do_next_byte;
626 625
627/* lock is not a valid prefix for FPU instructions, 626/* lock is not a valid prefix for FPU instructions,
628 let the cpu handle it to generate a SIGILL. */ 627 let the cpu handle it to generate a SIGILL. */
629/* case PREFIX_LOCK: */ 628/* case PREFIX_LOCK: */
630 629
631 /* rep.. prefixes have no meaning for FPU instructions */ 630 /* rep.. prefixes have no meaning for FPU instructions */
632 case PREFIX_REPE: 631 case PREFIX_REPE:
633 case PREFIX_REPNE: 632 case PREFIX_REPNE:
634 633
635 do_next_byte: 634 do_next_byte:
636 ip++; 635 ip++;
637 RE_ENTRANT_CHECK_OFF; 636 RE_ENTRANT_CHECK_OFF;
638 FPU_code_access_ok(1); 637 FPU_code_access_ok(1);
639 FPU_get_user(byte, ip); 638 FPU_get_user(byte, ip);
640 RE_ENTRANT_CHECK_ON; 639 RE_ENTRANT_CHECK_ON;
641 break; 640 break;
642 case FWAIT_OPCODE: 641 case FWAIT_OPCODE:
643 *Byte = byte; 642 *Byte = byte;
644 return 1; 643 return 1;
645 default: 644 default:
646 if ( (byte & 0xf8) == 0xd8 ) 645 if ((byte & 0xf8) == 0xd8) {
647 { 646 *Byte = byte;
648 *Byte = byte; 647 *fpu_eip = ip;
649 *fpu_eip = ip; 648 return 1;
650 return 1; 649 } else {
651 } 650 /* Not a valid sequence of prefix bytes followed by
652 else 651 an FPU instruction. */
653 { 652 *Byte = byte; /* Needed for error message. */
654 /* Not a valid sequence of prefix bytes followed by 653 return 0;
655 an FPU instruction. */ 654 }
656 *Byte = byte; /* Needed for error message. */ 655 }
657 return 0;
658 }
659 } 656 }
660 }
661} 657}
662 658
663 659void math_abort(struct info *info, unsigned int signal)
664void math_abort(struct info * info, unsigned int signal)
665{ 660{
666 FPU_EIP = FPU_ORIG_EIP; 661 FPU_EIP = FPU_ORIG_EIP;
667 current->thread.trap_no = 16; 662 current->thread.trap_no = 16;
668 current->thread.error_code = 0; 663 current->thread.error_code = 0;
669 send_sig(signal,current,1); 664 send_sig(signal, current, 1);
670 RE_ENTRANT_CHECK_OFF; 665 RE_ENTRANT_CHECK_OFF;
671 __asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4)); 666 __asm__("movl %0,%%esp ; ret": :"g"(((long)info) - 4));
672#ifdef PARANOID 667#ifdef PARANOID
673 printk("ERROR: wm-FPU-emu math_abort failed!\n"); 668 printk("ERROR: wm-FPU-emu math_abort failed!\n");
674#endif /* PARANOID */ 669#endif /* PARANOID */
675} 670}
676 671
677
678
679#define S387 ((struct i387_soft_struct *)s387) 672#define S387 ((struct i387_soft_struct *)s387)
680#define sstatus_word() \ 673#define sstatus_word() \
681 ((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top)) 674 ((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top))
682 675
683int restore_i387_soft(void *s387, struct _fpstate __user *buf) 676int restore_i387_soft(void *s387, struct _fpstate __user * buf)
684{ 677{
685 u_char __user *d = (u_char __user *)buf; 678 u_char __user *d = (u_char __user *) buf;
686 int offset, other, i, tags, regnr, tag, newtop; 679 int offset, other, i, tags, regnr, tag, newtop;
687 680
688 RE_ENTRANT_CHECK_OFF; 681 RE_ENTRANT_CHECK_OFF;
689 FPU_access_ok(VERIFY_READ, d, 7*4 + 8*10); 682 FPU_access_ok(VERIFY_READ, d, 7 * 4 + 8 * 10);
690 if (__copy_from_user(&S387->cwd, d, 7*4)) 683 if (__copy_from_user(&S387->cwd, d, 7 * 4))
691 return -1; 684 return -1;
692 RE_ENTRANT_CHECK_ON; 685 RE_ENTRANT_CHECK_ON;
693 686
694 d += 7*4; 687 d += 7 * 4;
695 688
696 S387->ftop = (S387->swd >> SW_Top_Shift) & 7; 689 S387->ftop = (S387->swd >> SW_Top_Shift) & 7;
697 offset = (S387->ftop & 7) * 10; 690 offset = (S387->ftop & 7) * 10;
698 other = 80 - offset; 691 other = 80 - offset;
699 692
700 RE_ENTRANT_CHECK_OFF; 693 RE_ENTRANT_CHECK_OFF;
701 /* Copy all registers in stack order. */ 694 /* Copy all registers in stack order. */
702 if (__copy_from_user(((u_char *)&S387->st_space)+offset, d, other)) 695 if (__copy_from_user(((u_char *) & S387->st_space) + offset, d, other))
703 return -1; 696 return -1;
704 if ( offset ) 697 if (offset)
705 if (__copy_from_user((u_char *)&S387->st_space, d+other, offset)) 698 if (__copy_from_user
706 return -1; 699 ((u_char *) & S387->st_space, d + other, offset))
707 RE_ENTRANT_CHECK_ON; 700 return -1;
708 701 RE_ENTRANT_CHECK_ON;
709 /* The tags may need to be corrected now. */ 702
710 tags = S387->twd; 703 /* The tags may need to be corrected now. */
711 newtop = S387->ftop; 704 tags = S387->twd;
712 for ( i = 0; i < 8; i++ ) 705 newtop = S387->ftop;
713 { 706 for (i = 0; i < 8; i++) {
714 regnr = (i+newtop) & 7; 707 regnr = (i + newtop) & 7;
715 if ( ((tags >> ((regnr & 7)*2)) & 3) != TAG_Empty ) 708 if (((tags >> ((regnr & 7) * 2)) & 3) != TAG_Empty) {
716 { 709 /* The loaded data over-rides all other cases. */
717 /* The loaded data over-rides all other cases. */ 710 tag =
718 tag = FPU_tagof((FPU_REG *)((u_char *)S387->st_space + 10*regnr)); 711 FPU_tagof((FPU_REG *) ((u_char *) S387->st_space +
719 tags &= ~(3 << (regnr*2)); 712 10 * regnr));
720 tags |= (tag & 3) << (regnr*2); 713 tags &= ~(3 << (regnr * 2));
714 tags |= (tag & 3) << (regnr * 2);
715 }
721 } 716 }
722 } 717 S387->twd = tags;
723 S387->twd = tags;
724 718
725 return 0; 719 return 0;
726} 720}
727 721
728
729int save_i387_soft(void *s387, struct _fpstate __user * buf) 722int save_i387_soft(void *s387, struct _fpstate __user * buf)
730{ 723{
731 u_char __user *d = (u_char __user *)buf; 724 u_char __user *d = (u_char __user *) buf;
732 int offset = (S387->ftop & 7) * 10, other = 80 - offset; 725 int offset = (S387->ftop & 7) * 10, other = 80 - offset;
733 726
734 RE_ENTRANT_CHECK_OFF; 727 RE_ENTRANT_CHECK_OFF;
735 FPU_access_ok(VERIFY_WRITE, d, 7*4 + 8*10); 728 FPU_access_ok(VERIFY_WRITE, d, 7 * 4 + 8 * 10);
736#ifdef PECULIAR_486 729#ifdef PECULIAR_486
737 S387->cwd &= ~0xe080; 730 S387->cwd &= ~0xe080;
738 /* An 80486 sets nearly all of the reserved bits to 1. */ 731 /* An 80486 sets nearly all of the reserved bits to 1. */
739 S387->cwd |= 0xffff0040; 732 S387->cwd |= 0xffff0040;
740 S387->swd = sstatus_word() | 0xffff0000; 733 S387->swd = sstatus_word() | 0xffff0000;
741 S387->twd |= 0xffff0000; 734 S387->twd |= 0xffff0000;
742 S387->fcs &= ~0xf8000000; 735 S387->fcs &= ~0xf8000000;
743 S387->fos |= 0xffff0000; 736 S387->fos |= 0xffff0000;
744#endif /* PECULIAR_486 */ 737#endif /* PECULIAR_486 */
745 if (__copy_to_user(d, &S387->cwd, 7*4)) 738 if (__copy_to_user(d, &S387->cwd, 7 * 4))
746 return -1; 739 return -1;
747 RE_ENTRANT_CHECK_ON; 740 RE_ENTRANT_CHECK_ON;
748 741
749 d += 7*4; 742 d += 7 * 4;
750 743
751 RE_ENTRANT_CHECK_OFF; 744 RE_ENTRANT_CHECK_OFF;
752 /* Copy all registers in stack order. */ 745 /* Copy all registers in stack order. */
753 if (__copy_to_user(d, ((u_char *)&S387->st_space)+offset, other)) 746 if (__copy_to_user(d, ((u_char *) & S387->st_space) + offset, other))
754 return -1; 747 return -1;
755 if ( offset ) 748 if (offset)
756 if (__copy_to_user(d+other, (u_char *)&S387->st_space, offset)) 749 if (__copy_to_user
757 return -1; 750 (d + other, (u_char *) & S387->st_space, offset))
758 RE_ENTRANT_CHECK_ON; 751 return -1;
759 752 RE_ENTRANT_CHECK_ON;
760 return 1; 753
754 return 1;
761} 755}