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