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