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