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