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