blob: 5d87f586f8d7242cc48c41265a90ab67069a7800 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*---------------------------------------------------------------------------+
2 | fpu_entry.c |
3 | |
4 | The entry functions for wm-FPU-emu |
5 | |
6 | Copyright (C) 1992,1993,1994,1996,1997 |
7 | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
8 | E-mail billm@suburbia.net |
9 | |
10 | See the files "README" and "COPYING" for further copyright and warranty |
11 | information. |
12 | |
13 +---------------------------------------------------------------------------*/
14
15/*---------------------------------------------------------------------------+
16 | Note: |
17 | The file contains code which accesses user memory. |
18 | Emulator static data may change when user memory is accessed, due to |
19 | other processes using the emulator while swapping is in progress. |
20 +---------------------------------------------------------------------------*/
21
22/*---------------------------------------------------------------------------+
23 | math_emulate(), restore_i387_soft() and save_i387_soft() are the only |
24 | entry points for wm-FPU-emu. |
25 +---------------------------------------------------------------------------*/
26
27#include <linux/signal.h>
Roland McGrathff0ebb22008-01-30 13:31:49 +010028#include <linux/regset.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <asm/uaccess.h>
31#include <asm/desc.h>
Roland McGrathff0ebb22008-01-30 13:31:49 +010032#include <asm/user.h>
Suresh Siddhae8a496a2008-05-23 16:26:37 -070033#include <asm/i387.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
35#include "fpu_system.h"
36#include "fpu_emu.h"
37#include "exception.h"
38#include "control_w.h"
39#include "status_w.h"
40
Ingo Molnar3d0d14f2008-01-30 13:30:11 +010041#define __BAD__ FPU_illegal /* Illegal on an 80486, causes SIGILL */
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
Ingo Molnar3d0d14f2008-01-30 13:30:11 +010043#ifndef NO_UNDOC_CODE /* Un-documented FPU op-codes supported by default. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
45/* WARNING: These codes are not documented by Intel in their 80486 manual
46 and may not work on FPU clones or later Intel FPUs. */
47
48/* Changes to support the un-doc codes provided by Linus Torvalds. */
49
Ingo Molnar3d0d14f2008-01-30 13:30:11 +010050#define _d9_d8_ fstp_i /* unofficial code (19) */
51#define _dc_d0_ fcom_st /* unofficial code (14) */
52#define _dc_d8_ fcompst /* unofficial code (1c) */
53#define _dd_c8_ fxch_i /* unofficial code (0d) */
54#define _de_d0_ fcompst /* unofficial code (16) */
55#define _df_c0_ ffreep /* unofficial code (07) ffree + pop */
56#define _df_c8_ fxch_i /* unofficial code (0f) */
57#define _df_d0_ fstp_i /* unofficial code (17) */
58#define _df_d8_ fstp_i /* unofficial code (1f) */
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
60static FUNC const st_instr_table[64] = {
Ingo Molnar3d0d14f2008-01-30 13:30:11 +010061 fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, _df_c0_,
62 fmul__, fxch_i, __BAD__, __BAD__, fmul_i, _dd_c8_, fmulp_, _df_c8_,
63 fcom_st, fp_nop, __BAD__, __BAD__, _dc_d0_, fst_i_, _de_d0_, _df_d0_,
64 fcompst, _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i, fcompp, _df_d8_,
65 fsub__, FPU_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
66 fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
67 fdiv__, FPU_triga, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
68 fdivr_, FPU_trigb, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
Linus Torvalds1da177e2005-04-16 15:20:36 -070069};
70
Ingo Molnar3d0d14f2008-01-30 13:30:11 +010071#else /* Support only documented FPU op-codes */
Linus Torvalds1da177e2005-04-16 15:20:36 -070072
73static FUNC const st_instr_table[64] = {
Ingo Molnar3d0d14f2008-01-30 13:30:11 +010074 fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__,
75 fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__,
76 fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__,
77 fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__,
78 fsub__, FPU_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
79 fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
80 fdiv__, FPU_triga, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
81 fdivr_, FPU_trigb, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
Linus Torvalds1da177e2005-04-16 15:20:36 -070082};
83
84#endif /* NO_UNDOC_CODE */
85
Ingo Molnar3d0d14f2008-01-30 13:30:11 +010086#define _NONE_ 0 /* Take no special action */
87#define _REG0_ 1 /* Need to check for not empty st(0) */
88#define _REGI_ 2 /* Need to check for not empty st(0) and st(rm) */
89#define _REGi_ 0 /* Uses st(rm) */
90#define _PUSH_ 3 /* Need to check for space to push onto stack */
91#define _null_ 4 /* Function illegal or not implemented */
92#define _REGIi 5 /* Uses st(0) and st(rm), result to st(rm) */
93#define _REGIp 6 /* Uses st(0) and st(rm), result to st(rm) then pop */
94#define _REGIc 0 /* Compare st(0) and st(rm) */
95#define _REGIn 0 /* Uses st(0) and st(rm), but handle checks later */
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
97#ifndef NO_UNDOC_CODE
98
99/* Un-documented FPU op-codes supported by default. (see above) */
100
101static u_char const type_table[64] = {
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100102 _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_,
103 _REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_,
104 _REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
105 _REGIc, _REG0_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
106 _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
107 _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
108 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
109 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110};
111
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100112#else /* Support only documented FPU op-codes */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113
114static u_char const type_table[64] = {
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100115 _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _null_,
116 _REGI_, _REGIn, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
117 _REGIc, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_,
118 _REGIc, _null_, _null_, _null_, _null_, _REG0_, _REGIc, _null_,
119 _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
120 _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
121 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
122 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123};
124
125#endif /* NO_UNDOC_CODE */
126
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127#ifdef RE_ENTRANT_CHECKING
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100128u_char emulating = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129#endif /* RE_ENTRANT_CHECKING */
130
Ingo Molnare8d591d2008-01-30 13:30:12 +0100131static int valid_prefix(u_char *Byte, u_char __user ** fpu_eip,
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100132 overrides * override);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133
Tejun Heod3157602009-02-09 22:17:39 +0900134void math_emulate(struct math_emu_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135{
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100136 u_char FPU_modrm, byte1;
137 unsigned short code;
138 fpu_addr_modes addr_modes;
139 int unmasked;
140 FPU_REG loaded_data;
141 FPU_REG *st0_ptr;
142 u_char loaded_tag, st0_tag;
143 void __user *data_address;
144 struct address data_sel_off;
145 struct address entry_sel_off;
146 unsigned long code_base = 0;
147 unsigned long code_limit = 0; /* Initialized to stop compiler warnings */
148 struct desc_struct code_descriptor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
Suresh Siddhae8a496a2008-05-23 16:26:37 -0700150 if (!used_math()) {
151 if (init_fpu(current)) {
152 do_group_exit(SIGKILL);
153 return;
154 }
155 }
156
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157#ifdef RE_ENTRANT_CHECKING
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100158 if (emulating) {
159 printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
160 }
161 RE_ENTRANT_CHECK_ON;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162#endif /* RE_ENTRANT_CHECKING */
163
Tejun Heod3157602009-02-09 22:17:39 +0900164 FPU_info = info;
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100165
166 FPU_ORIG_EIP = FPU_EIP;
167
168 if ((FPU_EFLAGS & 0x00020000) != 0) {
169 /* Virtual 8086 mode */
170 addr_modes.default_mode = VM86;
171 FPU_EIP += code_base = FPU_CS << 4;
172 code_limit = code_base + 0xffff; /* Assumes code_base <= 0xffff0000 */
173 } else if (FPU_CS == __USER_CS && FPU_DS == __USER_DS) {
174 addr_modes.default_mode = 0;
175 } else if (FPU_CS == __KERNEL_CS) {
176 printk("math_emulate: %04x:%08lx\n", FPU_CS, FPU_EIP);
177 panic("Math emulation needed in kernel");
178 } else {
179
180 if ((FPU_CS & 4) != 4) { /* Must be in the LDT */
181 /* Can only handle segmented addressing via the LDT
182 for now, and it must be 16 bit */
183 printk("FPU emulator: Unsupported addressing mode\n");
184 math_abort(FPU_info, SIGILL);
185 }
186
187 code_descriptor = LDT_DESCRIPTOR(FPU_CS);
188 if (SEG_D_SIZE(code_descriptor)) {
189 /* The above test may be wrong, the book is not clear */
190 /* Segmented 32 bit protected mode */
191 addr_modes.default_mode = SEG32;
192 } else {
193 /* 16 bit protected mode */
194 addr_modes.default_mode = PM16;
195 }
196 FPU_EIP += code_base = SEG_BASE_ADDR(code_descriptor);
197 code_limit = code_base
198 + (SEG_LIMIT(code_descriptor) +
199 1) * SEG_GRANULARITY(code_descriptor)
200 - 1;
201 if (code_limit < code_base)
202 code_limit = 0xffffffff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 }
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100204
Roland McGrathff0ebb22008-01-30 13:31:49 +0100205 FPU_lookahead = !(FPU_EFLAGS & X86_EFLAGS_TF);
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100206
207 if (!valid_prefix(&byte1, (u_char __user **) & FPU_EIP,
208 &addr_modes.override)) {
209 RE_ENTRANT_CHECK_OFF;
210 printk
211 ("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n"
212 "FPU emulator: self-modifying code! (emulation impossible)\n",
213 byte1);
214 RE_ENTRANT_CHECK_ON;
215 EXCEPTION(EX_INTERNAL | 0x126);
216 math_abort(FPU_info, SIGILL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100219 do_another_FPU_instruction:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100221 no_ip_update = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100223 FPU_EIP++; /* We have fetched the prefix and first code bytes. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100225 if (addr_modes.default_mode) {
226 /* This checks for the minimum instruction bytes.
227 We also need to check any extra (address mode) code access. */
228 if (FPU_EIP > code_limit)
229 math_abort(FPU_info, SIGSEGV);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 }
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100231
232 if ((byte1 & 0xf8) != 0xd8) {
233 if (byte1 == FWAIT_OPCODE) {
234 if (partial_status & SW_Summary)
235 goto do_the_FPU_interrupt;
236 else
237 goto FPU_fwait_done;
238 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239#ifdef PARANOID
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100240 EXCEPTION(EX_INTERNAL | 0x128);
241 math_abort(FPU_info, SIGILL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242#endif /* PARANOID */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 }
244
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100245 RE_ENTRANT_CHECK_OFF;
246 FPU_code_access_ok(1);
247 FPU_get_user(FPU_modrm, (u_char __user *) FPU_EIP);
248 RE_ENTRANT_CHECK_ON;
249 FPU_EIP++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100251 if (partial_status & SW_Summary) {
252 /* Ignore the error for now if the current instruction is a no-wait
253 control instruction */
254 /* The 80486 manual contradicts itself on this topic,
255 but a real 80486 uses the following instructions:
256 fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex.
257 */
258 code = (FPU_modrm << 8) | byte1;
259 if (!((((code & 0xf803) == 0xe003) || /* fnclex, fninit, fnstsw */
260 (((code & 0x3003) == 0x3001) && /* fnsave, fnstcw, fnstenv,
261 fnstsw */
262 ((code & 0xc000) != 0xc000))))) {
263 /*
264 * We need to simulate the action of the kernel to FPU
265 * interrupts here.
266 */
267 do_the_FPU_interrupt:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100269 FPU_EIP = FPU_ORIG_EIP; /* Point to current FPU instruction. */
270
271 RE_ENTRANT_CHECK_OFF;
272 current->thread.trap_no = 16;
273 current->thread.error_code = 0;
274 send_sig(SIGFPE, current, 1);
275 return;
276 }
277 }
278
279 entry_sel_off.offset = FPU_ORIG_EIP;
280 entry_sel_off.selector = FPU_CS;
281 entry_sel_off.opcode = (byte1 << 8) | FPU_modrm;
Andrew Mortoncc7594e2008-03-18 18:46:06 -0700282 entry_sel_off.empty = 0;
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100283
284 FPU_rm = FPU_modrm & 7;
285
286 if (FPU_modrm < 0300) {
287 /* All of these instructions use the mod/rm byte to get a data address */
288
289 if ((addr_modes.default_mode & SIXTEEN)
290 ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX))
291 data_address =
292 FPU_get_address_16(FPU_modrm, &FPU_EIP,
293 &data_sel_off, addr_modes);
294 else
295 data_address =
296 FPU_get_address(FPU_modrm, &FPU_EIP, &data_sel_off,
297 addr_modes);
298
299 if (addr_modes.default_mode) {
300 if (FPU_EIP - 1 > code_limit)
301 math_abort(FPU_info, SIGSEGV);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 }
303
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100304 if (!(byte1 & 1)) {
305 unsigned short status1 = partial_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100307 st0_ptr = &st(0);
308 st0_tag = FPU_gettag0();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100310 /* Stack underflow has priority */
311 if (NOT_EMPTY_ST0) {
312 if (addr_modes.default_mode & PROTECTED) {
313 /* This table works for 16 and 32 bit protected mode */
314 if (access_limit <
315 data_sizes_16[(byte1 >> 1) & 3])
316 math_abort(FPU_info, SIGSEGV);
317 }
318
319 unmasked = 0; /* Do this here to stop compiler warnings. */
320 switch ((byte1 >> 1) & 3) {
321 case 0:
322 unmasked =
323 FPU_load_single((float __user *)
324 data_address,
325 &loaded_data);
326 loaded_tag = unmasked & 0xff;
327 unmasked &= ~0xff;
328 break;
329 case 1:
330 loaded_tag =
331 FPU_load_int32((long __user *)
332 data_address,
333 &loaded_data);
334 break;
335 case 2:
336 unmasked =
337 FPU_load_double((double __user *)
338 data_address,
339 &loaded_data);
340 loaded_tag = unmasked & 0xff;
341 unmasked &= ~0xff;
342 break;
343 case 3:
344 default: /* Used here to suppress gcc warnings. */
345 loaded_tag =
346 FPU_load_int16((short __user *)
347 data_address,
348 &loaded_data);
349 break;
350 }
351
352 /* No more access to user memory, it is safe
353 to use static data now */
354
355 /* NaN operands have the next priority. */
356 /* We have to delay looking at st(0) until after
357 loading the data, because that data might contain an SNaN */
358 if (((st0_tag == TAG_Special) && isNaN(st0_ptr))
359 || ((loaded_tag == TAG_Special)
360 && isNaN(&loaded_data))) {
361 /* Restore the status word; we might have loaded a
362 denormal. */
363 partial_status = status1;
364 if ((FPU_modrm & 0x30) == 0x10) {
365 /* fcom or fcomp */
366 EXCEPTION(EX_Invalid);
367 setcc(SW_C3 | SW_C2 | SW_C0);
368 if ((FPU_modrm & 0x08)
369 && (control_word &
370 CW_Invalid))
371 FPU_pop(); /* fcomp, masked, so we pop. */
372 } else {
373 if (loaded_tag == TAG_Special)
374 loaded_tag =
375 FPU_Special
376 (&loaded_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377#ifdef PECULIAR_486
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100378 /* This is not really needed, but gives behaviour
379 identical to an 80486 */
380 if ((FPU_modrm & 0x28) == 0x20)
381 /* fdiv or fsub */
382 real_2op_NaN
383 (&loaded_data,
384 loaded_tag, 0,
385 &loaded_data);
386 else
387#endif /* PECULIAR_486 */
388 /* fadd, fdivr, fmul, or fsubr */
389 real_2op_NaN
390 (&loaded_data,
391 loaded_tag, 0,
392 st0_ptr);
393 }
394 goto reg_mem_instr_done;
395 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100397 if (unmasked && !((FPU_modrm & 0x30) == 0x10)) {
398 /* Is not a comparison instruction. */
399 if ((FPU_modrm & 0x38) == 0x38) {
400 /* fdivr */
401 if ((st0_tag == TAG_Zero) &&
402 ((loaded_tag == TAG_Valid)
403 || (loaded_tag ==
404 TAG_Special
405 &&
406 isdenormal
407 (&loaded_data)))) {
408 if (FPU_divide_by_zero
409 (0,
410 getsign
411 (&loaded_data))
412 < 0) {
413 /* We use the fact here that the unmasked
414 exception in the loaded data was for a
415 denormal operand */
416 /* Restore the state of the denormal op bit */
417 partial_status
418 &=
419 ~SW_Denorm_Op;
420 partial_status
421 |=
422 status1 &
423 SW_Denorm_Op;
424 } else
425 setsign(st0_ptr,
426 getsign
427 (&loaded_data));
428 }
429 }
430 goto reg_mem_instr_done;
431 }
432
433 switch ((FPU_modrm >> 3) & 7) {
434 case 0: /* fadd */
435 clear_C1();
436 FPU_add(&loaded_data, loaded_tag, 0,
437 control_word);
438 break;
439 case 1: /* fmul */
440 clear_C1();
441 FPU_mul(&loaded_data, loaded_tag, 0,
442 control_word);
443 break;
444 case 2: /* fcom */
445 FPU_compare_st_data(&loaded_data,
446 loaded_tag);
447 break;
448 case 3: /* fcomp */
449 if (!FPU_compare_st_data
450 (&loaded_data, loaded_tag)
451 && !unmasked)
452 FPU_pop();
453 break;
454 case 4: /* fsub */
455 clear_C1();
456 FPU_sub(LOADED | loaded_tag,
457 (int)&loaded_data,
458 control_word);
459 break;
460 case 5: /* fsubr */
461 clear_C1();
462 FPU_sub(REV | LOADED | loaded_tag,
463 (int)&loaded_data,
464 control_word);
465 break;
466 case 6: /* fdiv */
467 clear_C1();
468 FPU_div(LOADED | loaded_tag,
469 (int)&loaded_data,
470 control_word);
471 break;
472 case 7: /* fdivr */
473 clear_C1();
474 if (st0_tag == TAG_Zero)
475 partial_status = status1; /* Undo any denorm tag,
476 zero-divide has priority. */
477 FPU_div(REV | LOADED | loaded_tag,
478 (int)&loaded_data,
479 control_word);
480 break;
481 }
482 } else {
483 if ((FPU_modrm & 0x30) == 0x10) {
484 /* The instruction is fcom or fcomp */
485 EXCEPTION(EX_StackUnder);
486 setcc(SW_C3 | SW_C2 | SW_C0);
487 if ((FPU_modrm & 0x08)
488 && (control_word & CW_Invalid))
489 FPU_pop(); /* fcomp */
490 } else
491 FPU_stack_underflow();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 }
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100493 reg_mem_instr_done:
494 operand_address = data_sel_off;
495 } else {
496 if (!(no_ip_update =
497 FPU_load_store(((FPU_modrm & 0x38) | (byte1 & 6))
498 >> 1, addr_modes, data_address))) {
499 operand_address = data_sel_off;
500 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 }
502
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100503 } else {
504 /* None of these instructions access user memory */
505 u_char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
507#ifdef PECULIAR_486
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100508 /* This is supposed to be undefined, but a real 80486 seems
509 to do this: */
510 operand_address.offset = 0;
511 operand_address.selector = FPU_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512#endif /* PECULIAR_486 */
513
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100514 st0_ptr = &st(0);
515 st0_tag = FPU_gettag0();
516 switch (type_table[(int)instr_index]) {
517 case _NONE_: /* also _REGIc: _REGIn */
518 break;
519 case _REG0_:
520 if (!NOT_EMPTY_ST0) {
521 FPU_stack_underflow();
522 goto FPU_instruction_done;
523 }
524 break;
525 case _REGIi:
526 if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
527 FPU_stack_underflow_i(FPU_rm);
528 goto FPU_instruction_done;
529 }
530 break;
531 case _REGIp:
532 if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
533 FPU_stack_underflow_pop(FPU_rm);
534 goto FPU_instruction_done;
535 }
536 break;
537 case _REGI_:
538 if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
539 FPU_stack_underflow();
540 goto FPU_instruction_done;
541 }
542 break;
543 case _PUSH_: /* Only used by the fld st(i) instruction */
544 break;
545 case _null_:
546 FPU_illegal();
547 goto FPU_instruction_done;
548 default:
549 EXCEPTION(EX_INTERNAL | 0x111);
550 goto FPU_instruction_done;
551 }
552 (*st_instr_table[(int)instr_index]) ();
553
554 FPU_instruction_done:
555 ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100558 if (!no_ip_update)
559 instruction_address = entry_sel_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100561 FPU_fwait_done:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
563#ifdef DEBUG
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100564 RE_ENTRANT_CHECK_OFF;
565 FPU_printall();
566 RE_ENTRANT_CHECK_ON;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567#endif /* DEBUG */
568
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100569 if (FPU_lookahead && !need_resched()) {
570 FPU_ORIG_EIP = FPU_EIP - code_base;
571 if (valid_prefix(&byte1, (u_char __user **) & FPU_EIP,
572 &addr_modes.override))
573 goto do_another_FPU_instruction;
574 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100576 if (addr_modes.default_mode)
577 FPU_EIP -= code_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100579 RE_ENTRANT_CHECK_OFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580}
581
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582/* Support for prefix bytes is not yet complete. To properly handle
583 all prefix bytes, further changes are needed in the emulator code
584 which accesses user address space. Access to separate segments is
585 important for msdos emulation. */
Ingo Molnare8d591d2008-01-30 13:30:12 +0100586static int valid_prefix(u_char *Byte, u_char __user **fpu_eip,
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100587 overrides * override)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588{
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100589 u_char byte;
590 u_char __user *ip = *fpu_eip;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100592 *override = (overrides) {
593 0, 0, PREFIX_DEFAULT}; /* defaults */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100595 RE_ENTRANT_CHECK_OFF;
596 FPU_code_access_ok(1);
597 FPU_get_user(byte, ip);
598 RE_ENTRANT_CHECK_ON;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100600 while (1) {
601 switch (byte) {
602 case ADDR_SIZE_PREFIX:
603 override->address_size = ADDR_SIZE_PREFIX;
604 goto do_next_byte;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100606 case OP_SIZE_PREFIX:
607 override->operand_size = OP_SIZE_PREFIX;
608 goto do_next_byte;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100610 case PREFIX_CS:
611 override->segment = PREFIX_CS_;
612 goto do_next_byte;
613 case PREFIX_ES:
614 override->segment = PREFIX_ES_;
615 goto do_next_byte;
616 case PREFIX_SS:
617 override->segment = PREFIX_SS_;
618 goto do_next_byte;
619 case PREFIX_FS:
620 override->segment = PREFIX_FS_;
621 goto do_next_byte;
622 case PREFIX_GS:
623 override->segment = PREFIX_GS_;
624 goto do_next_byte;
625 case PREFIX_DS:
626 override->segment = PREFIX_DS_;
627 goto do_next_byte;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
629/* lock is not a valid prefix for FPU instructions,
630 let the cpu handle it to generate a SIGILL. */
631/* case PREFIX_LOCK: */
632
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100633 /* rep.. prefixes have no meaning for FPU instructions */
634 case PREFIX_REPE:
635 case PREFIX_REPNE:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100637 do_next_byte:
638 ip++;
639 RE_ENTRANT_CHECK_OFF;
640 FPU_code_access_ok(1);
641 FPU_get_user(byte, ip);
642 RE_ENTRANT_CHECK_ON;
643 break;
644 case FWAIT_OPCODE:
645 *Byte = byte;
646 return 1;
647 default:
648 if ((byte & 0xf8) == 0xd8) {
649 *Byte = byte;
650 *fpu_eip = ip;
651 return 1;
652 } else {
653 /* Not a valid sequence of prefix bytes followed by
654 an FPU instruction. */
655 *Byte = byte; /* Needed for error message. */
656 return 0;
657 }
658 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660}
661
Tejun Heoae6af412009-02-09 22:17:39 +0900662void math_abort(struct math_emu_info *info, unsigned int signal)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663{
664 FPU_EIP = FPU_ORIG_EIP;
665 current->thread.trap_no = 16;
666 current->thread.error_code = 0;
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100667 send_sig(signal, current, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 RE_ENTRANT_CHECK_OFF;
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100669 __asm__("movl %0,%%esp ; ret": :"g"(((long)info) - 4));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670#ifdef PARANOID
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100671 printk("ERROR: wm-FPU-emu math_abort failed!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672#endif /* PARANOID */
673}
674
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675#define S387 ((struct i387_soft_struct *)s387)
676#define sstatus_word() \
677 ((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top))
678
Roland McGrathff0ebb22008-01-30 13:31:49 +0100679int fpregs_soft_set(struct task_struct *target,
680 const struct user_regset *regset,
681 unsigned int pos, unsigned int count,
682 const void *kbuf, const void __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683{
Suresh Siddha61c46282008-03-10 15:28:04 -0700684 struct i387_soft_struct *s387 = &target->thread.xstate->soft;
Roland McGrathff0ebb22008-01-30 13:31:49 +0100685 void *space = s387->st_space;
686 int ret;
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100687 int offset, other, i, tags, regnr, tag, newtop;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100689 RE_ENTRANT_CHECK_OFF;
Roland McGrathff0ebb22008-01-30 13:31:49 +0100690 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, s387, 0,
691 offsetof(struct i387_soft_struct, st_space));
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100692 RE_ENTRANT_CHECK_ON;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
Roland McGrathff0ebb22008-01-30 13:31:49 +0100694 if (ret)
695 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100697 S387->ftop = (S387->swd >> SW_Top_Shift) & 7;
698 offset = (S387->ftop & 7) * 10;
699 other = 80 - offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100701 RE_ENTRANT_CHECK_OFF;
Roland McGrathff0ebb22008-01-30 13:31:49 +0100702
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100703 /* Copy all registers in stack order. */
Roland McGrathff0ebb22008-01-30 13:31:49 +0100704 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
705 space + offset, 0, other);
706 if (!ret && offset)
707 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
708 space, 0, offset);
709
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100710 RE_ENTRANT_CHECK_ON;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100712 /* The tags may need to be corrected now. */
713 tags = S387->twd;
714 newtop = S387->ftop;
715 for (i = 0; i < 8; i++) {
716 regnr = (i + newtop) & 7;
717 if (((tags >> ((regnr & 7) * 2)) & 3) != TAG_Empty) {
718 /* The loaded data over-rides all other cases. */
719 tag =
720 FPU_tagof((FPU_REG *) ((u_char *) S387->st_space +
721 10 * regnr));
722 tags &= ~(3 << (regnr * 2));
723 tags |= (tag & 3) << (regnr * 2);
724 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 }
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100726 S387->twd = tags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727
Roland McGrathff0ebb22008-01-30 13:31:49 +0100728 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729}
730
Roland McGrathff0ebb22008-01-30 13:31:49 +0100731int fpregs_soft_get(struct task_struct *target,
732 const struct user_regset *regset,
733 unsigned int pos, unsigned int count,
734 void *kbuf, void __user *ubuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735{
Suresh Siddha61c46282008-03-10 15:28:04 -0700736 struct i387_soft_struct *s387 = &target->thread.xstate->soft;
Roland McGrathff0ebb22008-01-30 13:31:49 +0100737 const void *space = s387->st_space;
738 int ret;
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100739 int offset = (S387->ftop & 7) * 10, other = 80 - offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100741 RE_ENTRANT_CHECK_OFF;
Roland McGrathff0ebb22008-01-30 13:31:49 +0100742
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743#ifdef PECULIAR_486
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100744 S387->cwd &= ~0xe080;
745 /* An 80486 sets nearly all of the reserved bits to 1. */
746 S387->cwd |= 0xffff0040;
747 S387->swd = sstatus_word() | 0xffff0000;
748 S387->twd |= 0xffff0000;
749 S387->fcs &= ~0xf8000000;
750 S387->fos |= 0xffff0000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751#endif /* PECULIAR_486 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
Roland McGrathff0ebb22008-01-30 13:31:49 +0100753 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, s387, 0,
754 offsetof(struct i387_soft_struct, st_space));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100756 /* Copy all registers in stack order. */
Roland McGrathff0ebb22008-01-30 13:31:49 +0100757 if (!ret)
758 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
759 space + offset, 0, other);
760 if (!ret)
761 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
762 space, 0, offset);
763
Ingo Molnar3d0d14f2008-01-30 13:30:11 +0100764 RE_ENTRANT_CHECK_ON;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
Roland McGrathff0ebb22008-01-30 13:31:49 +0100766 return ret;
767}