GNU Linux-libre 4.14.266-gnu1
[releases.git] / arch / x86 / math-emu / fpu_entry.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*---------------------------------------------------------------------------+
3  |  fpu_entry.c                                                              |
4  |                                                                           |
5  | The entry functions for wm-FPU-emu                                        |
6  |                                                                           |
7  | Copyright (C) 1992,1993,1994,1996,1997                                    |
8  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
9  |                  E-mail   billm@suburbia.net                              |
10  |                                                                           |
11  | See the files "README" and "COPYING" for further copyright and warranty   |
12  | information.                                                              |
13  |                                                                           |
14  +---------------------------------------------------------------------------*/
15
16 /*---------------------------------------------------------------------------+
17  | Note:                                                                     |
18  |    The file contains code which accesses user memory.                     |
19  |    Emulator static data may change when user memory is accessed, due to   |
20  |    other processes using the emulator while swapping is in progress.      |
21  +---------------------------------------------------------------------------*/
22
23 /*---------------------------------------------------------------------------+
24  | math_emulate(), restore_i387_soft() and save_i387_soft() are the only     |
25  | entry points for wm-FPU-emu.                                              |
26  +---------------------------------------------------------------------------*/
27
28 #include <linux/signal.h>
29 #include <linux/regset.h>
30
31 #include <linux/uaccess.h>
32 #include <asm/traps.h>
33 #include <asm/user.h>
34 #include <asm/fpu/internal.h>
35
36 #include "fpu_system.h"
37 #include "fpu_emu.h"
38 #include "exception.h"
39 #include "control_w.h"
40 #include "status_w.h"
41
42 #define __BAD__ FPU_illegal     /* Illegal on an 80486, causes SIGILL */
43
44 /* fcmovCC and f(u)comi(p) are enabled if CPUID(1).EDX(15) "cmov" is set */
45
46 /* WARNING: "u" entries are not documented by Intel in their 80486 manual
47    and may not work on FPU clones or later Intel FPUs.
48    Changes to support them provided by Linus Torvalds. */
49
50 static FUNC const st_instr_table[64] = {
51 /* Opcode:      d8              d9              da              db */
52 /*              dc              dd              de              df */
53 /* c0..7 */     fadd__,         fld_i_,         fcmovb,         fcmovnb,
54 /* c0..7 */     fadd_i,         ffree_,         faddp_,         ffreep,/*u*/
55 /* c8..f */     fmul__,         fxch_i,         fcmove,         fcmovne,
56 /* c8..f */     fmul_i,         fxch_i,/*u*/    fmulp_,         fxch_i,/*u*/
57 /* d0..7 */     fcom_st,        fp_nop,         fcmovbe,        fcmovnbe,
58 /* d0..7 */     fcom_st,/*u*/   fst_i_,         fcompst,/*u*/   fstp_i,/*u*/
59 /* d8..f */     fcompst,        fstp_i,/*u*/    fcmovu,         fcmovnu,
60 /* d8..f */     fcompst,/*u*/   fstp_i,         fcompp,         fstp_i,/*u*/
61 /* e0..7 */     fsub__,         FPU_etc,        __BAD__,        finit_,
62 /* e0..7 */     fsubri,         fucom_,         fsubrp,         fstsw_,
63 /* e8..f */     fsubr_,         fconst,         fucompp,        fucomi_,
64 /* e8..f */     fsub_i,         fucomp,         fsubp_,         fucomip,
65 /* f0..7 */     fdiv__,         FPU_triga,      __BAD__,        fcomi_,
66 /* f0..7 */     fdivri,         __BAD__,        fdivrp,         fcomip,
67 /* f8..f */     fdivr_,         FPU_trigb,      __BAD__,        __BAD__,
68 /* f8..f */     fdiv_i,         __BAD__,        fdivp_,         __BAD__,
69 };
70
71 #define _NONE_ 0                /* Take no special action */
72 #define _REG0_ 1                /* Need to check for not empty st(0) */
73 #define _REGI_ 2                /* Need to check for not empty st(0) and st(rm) */
74 #define _REGi_ 0                /* Uses st(rm) */
75 #define _PUSH_ 3                /* Need to check for space to push onto stack */
76 #define _null_ 4                /* Function illegal or not implemented */
77 #define _REGIi 5                /* Uses st(0) and st(rm), result to st(rm) */
78 #define _REGIp 6                /* Uses st(0) and st(rm), result to st(rm) then pop */
79 #define _REGIc 0                /* Compare st(0) and st(rm) */
80 #define _REGIn 0                /* Uses st(0) and st(rm), but handle checks later */
81
82 static u_char const type_table[64] = {
83 /* Opcode:      d8      d9      da      db      dc      dd      de      df */
84 /* c0..7 */     _REGI_, _NONE_, _REGIn, _REGIn, _REGIi, _REGi_, _REGIp, _REGi_,
85 /* c8..f */     _REGI_, _REGIn, _REGIn, _REGIn, _REGIi, _REGI_, _REGIp, _REGI_,
86 /* d0..7 */     _REGIc, _NONE_, _REGIn, _REGIn, _REGIc, _REG0_, _REGIc, _REG0_,
87 /* d8..f */     _REGIc, _REG0_, _REGIn, _REGIn, _REGIc, _REG0_, _REGIc, _REG0_,
88 /* e0..7 */     _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
89 /* e8..f */     _REGI_, _NONE_, _REGIc, _REGIc, _REGIi, _REGIc, _REGIp, _REGIc,
90 /* f0..7 */     _REGI_, _NONE_, _null_, _REGIc, _REGIi, _null_, _REGIp, _REGIc,
91 /* f8..f */     _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
92 };
93
94 #ifdef RE_ENTRANT_CHECKING
95 u_char emulating = 0;
96 #endif /* RE_ENTRANT_CHECKING */
97
98 static int valid_prefix(u_char *Byte, u_char __user ** fpu_eip,
99                         overrides * override);
100
101 void math_emulate(struct math_emu_info *info)
102 {
103         u_char FPU_modrm, byte1;
104         unsigned short code;
105         fpu_addr_modes addr_modes;
106         int unmasked;
107         FPU_REG loaded_data;
108         FPU_REG *st0_ptr;
109         u_char loaded_tag, st0_tag;
110         void __user *data_address;
111         struct address data_sel_off;
112         struct address entry_sel_off;
113         unsigned long code_base = 0;
114         unsigned long code_limit = 0;   /* Initialized to stop compiler warnings */
115         struct desc_struct code_descriptor;
116         struct fpu *fpu = &current->thread.fpu;
117
118         fpu__initialize(fpu);
119
120 #ifdef RE_ENTRANT_CHECKING
121         if (emulating) {
122                 printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
123         }
124         RE_ENTRANT_CHECK_ON;
125 #endif /* RE_ENTRANT_CHECKING */
126
127         FPU_info = info;
128
129         FPU_ORIG_EIP = FPU_EIP;
130
131         if ((FPU_EFLAGS & 0x00020000) != 0) {
132                 /* Virtual 8086 mode */
133                 addr_modes.default_mode = VM86;
134                 FPU_EIP += code_base = FPU_CS << 4;
135                 code_limit = code_base + 0xffff;        /* Assumes code_base <= 0xffff0000 */
136         } else if (FPU_CS == __USER_CS && FPU_DS == __USER_DS) {
137                 addr_modes.default_mode = 0;
138         } else if (FPU_CS == __KERNEL_CS) {
139                 printk("math_emulate: %04x:%08lx\n", FPU_CS, FPU_EIP);
140                 panic("Math emulation needed in kernel");
141         } else {
142
143                 if ((FPU_CS & 4) != 4) {        /* Must be in the LDT */
144                         /* Can only handle segmented addressing via the LDT
145                            for now, and it must be 16 bit */
146                         printk("FPU emulator: Unsupported addressing mode\n");
147                         math_abort(FPU_info, SIGILL);
148                 }
149
150                 code_descriptor = FPU_get_ldt_descriptor(FPU_CS);
151                 if (code_descriptor.d) {
152                         /* The above test may be wrong, the book is not clear */
153                         /* Segmented 32 bit protected mode */
154                         addr_modes.default_mode = SEG32;
155                 } else {
156                         /* 16 bit protected mode */
157                         addr_modes.default_mode = PM16;
158                 }
159                 FPU_EIP += code_base = seg_get_base(&code_descriptor);
160                 code_limit = seg_get_limit(&code_descriptor) + 1;
161                 code_limit *= seg_get_granularity(&code_descriptor);
162                 code_limit += code_base - 1;
163                 if (code_limit < code_base)
164                         code_limit = 0xffffffff;
165         }
166
167         FPU_lookahead = !(FPU_EFLAGS & X86_EFLAGS_TF);
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);
179         }
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);
192         }
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                 }
201 #ifdef PARANOID
202                 EXCEPTION(EX_INTERNAL | 0x128);
203                 math_abort(FPU_info, SIGILL);
204 #endif /* PARANOID */
205         }
206
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;
234                         current->thread.trap_nr = X86_TRAP_MF;
235                         current->thread.error_code = 0;
236                         send_sig(SIGFPE, current, 1);
237                         return;
238                 }
239         }
240
241         entry_sel_off.offset = FPU_ORIG_EIP;
242         entry_sel_off.selector = FPU_CS;
243         entry_sel_off.opcode = (byte1 << 8) | FPU_modrm;
244         entry_sel_off.empty = 0;
245
246         FPU_rm = FPU_modrm & 7;
247
248         if (FPU_modrm < 0300) {
249                 /* All of these instructions use the mod/rm byte to get a data address */
250
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);
264                 }
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                         }
463                 }
464
465         } else {
466                 /* None of these instructions access user memory */
467                 u_char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
468
469 #ifdef PECULIAR_486
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;
474 #endif /* PECULIAR_486 */
475
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]) ();
515
516               FPU_instruction_done:
517                 ;
518         }
519
520         if (!no_ip_update)
521                 instruction_address = entry_sel_off;
522
523       FPU_fwait_done:
524
525 #ifdef DEBUG
526         RE_ENTRANT_CHECK_OFF;
527         FPU_printall();
528         RE_ENTRANT_CHECK_ON;
529 #endif /* DEBUG */
530
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         }
537
538         if (addr_modes.default_mode)
539                 FPU_EIP -= code_base;
540
541         RE_ENTRANT_CHECK_OFF;
542 }
543
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. */
548 static int valid_prefix(u_char *Byte, u_char __user **fpu_eip,
549                         overrides * override)
550 {
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;
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
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                 }
621         }
622 }
623
624 void math_abort(struct math_emu_info *info, unsigned int signal)
625 {
626         FPU_EIP = FPU_ORIG_EIP;
627         current->thread.trap_nr = X86_TRAP_MF;
628         current->thread.error_code = 0;
629         send_sig(signal, current, 1);
630         RE_ENTRANT_CHECK_OFF;
631       __asm__("movl %0,%%esp ; ret": :"g"(((long)info) - 4));
632 #ifdef PARANOID
633         printk("ERROR: wm-FPU-emu math_abort failed!\n");
634 #endif /* PARANOID */
635 }
636
637 #define S387 ((struct swregs_state *)s387)
638 #define sstatus_word() \
639   ((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top))
640
641 int 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)
645 {
646         struct swregs_state *s387 = &target->thread.fpu.state.soft;
647         void *space = s387->st_space;
648         int ret;
649         int offset, other, i, tags, regnr, tag, newtop;
650
651         RE_ENTRANT_CHECK_OFF;
652         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, s387, 0,
653                                  offsetof(struct swregs_state, st_space));
654         RE_ENTRANT_CHECK_ON;
655
656         if (ret)
657                 return ret;
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;
664
665         /* Copy all registers in stack order. */
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
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                 }
687         }
688         S387->twd = tags;
689
690         return ret;
691 }
692
693 int 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)
697 {
698         struct swregs_state *s387 = &target->thread.fpu.state.soft;
699         const void *space = s387->st_space;
700         int ret;
701         int offset = (S387->ftop & 7) * 10, other = 80 - offset;
702
703         RE_ENTRANT_CHECK_OFF;
704
705 #ifdef PECULIAR_486
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;
713 #endif /* PECULIAR_486 */
714
715         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, s387, 0,
716                                   offsetof(struct swregs_state, st_space));
717
718         /* Copy all registers in stack order. */
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
726         RE_ENTRANT_CHECK_ON;
727
728         return ret;
729 }