~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/math-emu/fpu_entry.c

Version: ~ [ linux-5.13-rc7 ] ~ [ linux-5.12.12 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.45 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.127 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.195 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.237 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.273 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.273 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp