OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [i386/] [math-emu/] [fpu_entry.c] - Blame information for rev 1782

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1623 jcastillo
/*---------------------------------------------------------------------------+
2
 |  fpu_entry.c                                                              |
3
 |                                                                           |
4
 | The entry functions for wm-FPU-emu                                        |
5
 |                                                                           |
6
 | Copyright (C) 1992,1993,1994,1996                                         |
7
 |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
8
 |                  E-mail   billm@jacobi.maths.monash.edu.au                |
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
 
29
#include <asm/segment.h>
30
 
31
#include "fpu_system.h"
32
#include "fpu_emu.h"
33
#include "exception.h"
34
#include "control_w.h"
35
#include "status_w.h"
36
 
37
#define __BAD__ FPU_illegal   /* Illegal on an 80486, causes SIGILL */
38
 
39
#ifndef NO_UNDOC_CODE    /* Un-documented FPU op-codes supported by default. */
40
 
41
/* WARNING: These codes are not documented by Intel in their 80486 manual
42
   and may not work on FPU clones or later Intel FPUs. */
43
 
44
/* Changes to support the un-doc codes provided by Linus Torvalds. */
45
 
46
#define _d9_d8_ fstp_i    /* unofficial code (19) */
47
#define _dc_d0_ fcom_st   /* unofficial code (14) */
48
#define _dc_d8_ fcompst   /* unofficial code (1c) */
49
#define _dd_c8_ fxch_i    /* unofficial code (0d) */
50
#define _de_d0_ fcompst   /* unofficial code (16) */
51
#define _df_c0_ ffreep    /* unofficial code (07) ffree + pop */
52
#define _df_c8_ fxch_i    /* unofficial code (0f) */
53
#define _df_d0_ fstp_i    /* unofficial code (17) */
54
#define _df_d8_ fstp_i    /* unofficial code (1f) */
55
 
56
static FUNC const st_instr_table[64] = {
57
  fadd__,   fld_i_,  __BAD__, __BAD__, fadd_i,  ffree_,  faddp_,  _df_c0_,
58
  fmul__,   fxch_i,  __BAD__, __BAD__, fmul_i,  _dd_c8_, fmulp_,  _df_c8_,
59
  fcom_st,  fp_nop,  __BAD__, __BAD__, _dc_d0_, fst_i_,  _de_d0_, _df_d0_,
60
  fcompst,  _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i,  fcompp,  _df_d8_,
61
  fsub__,   fp_etc,  __BAD__, finit_,  fsubri,  fucom_,  fsubrp,  fstsw_,
62
  fsubr_,   fconst,  fucompp, __BAD__, fsub_i,  fucomp,  fsubp_,  __BAD__,
63
  fdiv__,   trig_a,  __BAD__, __BAD__, fdivri,  __BAD__, fdivrp,  __BAD__,
64
  fdivr_,   trig_b,  __BAD__, __BAD__, fdiv_i,  __BAD__, fdivp_,  __BAD__,
65
};
66
 
67
#else     /* Support only documented FPU op-codes */
68
 
69
static FUNC const st_instr_table[64] = {
70
  fadd__,   fld_i_,  __BAD__, __BAD__, fadd_i,  ffree_,  faddp_,  __BAD__,
71
  fmul__,   fxch_i,  __BAD__, __BAD__, fmul_i,  __BAD__, fmulp_,  __BAD__,
72
  fcom_st,  fp_nop,  __BAD__, __BAD__, __BAD__, fst_i_,  __BAD__, __BAD__,
73
  fcompst,  __BAD__, __BAD__, __BAD__, __BAD__, fstp_i,  fcompp,  __BAD__,
74
  fsub__,   fp_etc,  __BAD__, finit_,  fsubri,  fucom_,  fsubrp,  fstsw_,
75
  fsubr_,   fconst,  fucompp, __BAD__, fsub_i,  fucomp,  fsubp_,  __BAD__,
76
  fdiv__,   trig_a,  __BAD__, __BAD__, fdivri,  __BAD__, fdivrp,  __BAD__,
77
  fdivr_,   trig_b,  __BAD__, __BAD__, fdiv_i,  __BAD__, fdivp_,  __BAD__,
78
};
79
 
80
#endif NO_UNDOC_CODE
81
 
82
 
83
#define _NONE_ 0   /* Take no special action */
84
#define _REG0_ 1   /* Need to check for not empty st(0) */
85
#define _REGI_ 2   /* Need to check for not empty st(0) and st(rm) */
86
#define _REGi_ 0   /* Uses st(rm) */
87
#define _PUSH_ 3   /* Need to check for space to push onto stack */
88
#define _null_ 4   /* Function illegal or not implemented */
89
#define _REGIi 5   /* Uses st(0) and st(rm), result to st(rm) */
90
#define _REGIp 6   /* Uses st(0) and st(rm), result to st(rm) then pop */
91
#define _REGIc 0   /* Compare st(0) and st(rm) */
92
#define _REGIn 0   /* Uses st(0) and st(rm), but handle checks later */
93
 
94
#ifndef NO_UNDOC_CODE
95
 
96
/* Un-documented FPU op-codes supported by default. (see above) */
97
 
98
static unsigned char const type_table[64] = {
99
  _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_,
100
  _REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_,
101
  _REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
102
  _REGIc, _REG0_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
103
  _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
104
  _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
105
  _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
106
  _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
107
};
108
 
109
#else     /* Support only documented FPU op-codes */
110
 
111
static unsigned char const type_table[64] = {
112
  _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _null_,
113
  _REGI_, _REGIn, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
114
  _REGIc, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_,
115
  _REGIc, _null_, _null_, _null_, _null_, _REG0_, _REGIc, _null_,
116
  _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
117
  _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
118
  _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
119
  _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
120
};
121
 
122
#endif NO_UNDOC_CODE
123
 
124
 
125
#ifdef RE_ENTRANT_CHECKING
126
char emulating=0;
127
#endif RE_ENTRANT_CHECKING
128
 
129
static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
130
                        overrides *override);
131
 
132
asmlinkage void math_emulate(long arg)
133
{
134
  unsigned char  FPU_modrm, byte1;
135
  unsigned short code;
136
  fpu_addr_modes addr_modes;
137
  int unmasked;
138
  FPU_REG loaded_data;
139
  void *data_address;
140
  struct address data_sel_off;
141
  struct address entry_sel_off;
142
  unsigned long code_base = 0;
143
  unsigned long code_limit = 0;  /* Initialized to stop compiler warnings */
144
  char         st0_tag;
145
  FPU_REG      *st0_ptr;
146
  struct desc_struct code_descriptor;
147
 
148
#ifdef RE_ENTRANT_CHECKING
149
  if ( emulating )
150
    {
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 (!current->used_math)
157
    {
158
      int i;
159
      for ( i = 0; i < 8; i++ )
160
        {
161
          /* Make sure that the registers are compatible
162
             with the assumptions of the emulator. */
163
          if ( !((regs[i].exp == EXP_UNDER) && (regs[i].sigh == 0)
164
                 && (regs[i].sigl == 0)) )
165
            regs[i].sigh |= 0x80000000;
166
        }
167
      finit();
168
      current->used_math = 1;
169
    }
170
 
171
  SETUP_DATA_AREA(arg);
172
 
173
  FPU_ORIG_EIP = FPU_EIP;
174
 
175
  if ( (FPU_EFLAGS & 0x00020000) != 0 )
176
    {
177
      /* Virtual 8086 mode */
178
      addr_modes.default_mode = VM86;
179
      FPU_EIP += code_base = FPU_CS << 4;
180
      code_limit = code_base + 0xffff;  /* Assumes code_base <= 0xffff0000 */
181
    }
182
  else if ( FPU_CS == USER_CS && FPU_DS == USER_DS )
183
    {
184
      addr_modes.default_mode = 0;
185
    }
186
  else if ( FPU_CS == KERNEL_CS )
187
    {
188
      printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP);
189
      panic("Math emulation needed in kernel");
190
    }
191
  else
192
    {
193
 
194
      if ( (FPU_CS & 4) != 4 )   /* Must be in the LDT */
195
        {
196
          /* Can only handle segmented addressing via the LDT
197
             for now, and it must be 16 bit */
198
          printk("FPU emulator: Unsupported addressing mode\n");
199
          math_abort(FPU_info, SIGILL);
200
        }
201
 
202
      if ( SEG_D_SIZE(code_descriptor = LDT_DESCRIPTOR(FPU_CS)) )
203
        {
204
          /* The above test may be wrong, the book is not clear */
205
          /* Segmented 32 bit protected mode */
206
          addr_modes.default_mode = SEG32;
207
        }
208
      else
209
        {
210
          /* 16 bit protected mode */
211
          addr_modes.default_mode = PM16;
212
        }
213
      FPU_EIP += code_base = SEG_BASE_ADDR(code_descriptor);
214
      code_limit = code_base
215
        + (SEG_LIMIT(code_descriptor)+1) * SEG_GRANULARITY(code_descriptor)
216
          - 1;
217
      if ( code_limit < code_base ) code_limit = 0xffffffff;
218
    }
219
 
220
  FPU_lookahead = 1;
221
  if (current->flags & PF_PTRACED)
222
    FPU_lookahead = 0;
223
 
224
  if ( !valid_prefix(&byte1, (unsigned char **)&FPU_EIP,
225
                     &addr_modes.override) )
226
    {
227
      RE_ENTRANT_CHECK_OFF;
228
      printk("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n"
229
             "FPU emulator: self-modifying code! (emulation impossible)\n",
230
             byte1);
231
      RE_ENTRANT_CHECK_ON;
232
      EXCEPTION(EX_INTERNAL|0x126);
233
      math_abort(FPU_info,SIGILL);
234
    }
235
 
236
do_another_FPU_instruction:
237
 
238
  no_ip_update = 0;
239
 
240
  FPU_EIP++;  /* We have fetched the prefix and first code bytes. */
241
 
242
  if ( addr_modes.default_mode )
243
    {
244
      /* This checks for the minimum instruction bytes.
245
         We also need to check any extra (address mode) code access. */
246
      if ( FPU_EIP > code_limit )
247
        math_abort(FPU_info,SIGSEGV);
248
    }
249
 
250
  if ( (byte1 & 0xf8) != 0xd8 )
251
    {
252
      if ( byte1 == FWAIT_OPCODE )
253
        {
254
          if (partial_status & SW_Summary)
255
            goto do_the_FPU_interrupt;
256
          else
257
            goto FPU_fwait_done;
258
        }
259
#ifdef PARANOID
260
      EXCEPTION(EX_INTERNAL|0x128);
261
      math_abort(FPU_info,SIGILL);
262
#endif PARANOID
263
    }
264
 
265
  RE_ENTRANT_CHECK_OFF;
266
  FPU_code_verify_area(1);
267
  FPU_modrm = get_fs_byte((unsigned char *) FPU_EIP);
268
  RE_ENTRANT_CHECK_ON;
269
  FPU_EIP++;
270
 
271
  if (partial_status & SW_Summary)
272
    {
273
      /* Ignore the error for now if the current instruction is a no-wait
274
         control instruction */
275
      /* The 80486 manual contradicts itself on this topic,
276
         but a real 80486 uses the following instructions:
277
         fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex.
278
       */
279
      code = (FPU_modrm << 8) | byte1;
280
      if ( ! ( (((code & 0xf803) == 0xe003) ||    /* fnclex, fninit, fnstsw */
281
                (((code & 0x3003) == 0x3001) &&   /* fnsave, fnstcw, fnstenv,
282
                                                     fnstsw */
283
                 ((code & 0xc000) != 0xc000))) ) )
284
        {
285
          /*
286
           *  We need to simulate the action of the kernel to FPU
287
           *  interrupts here.
288
           */
289
        do_the_FPU_interrupt:
290
          FPU_EIP = FPU_ORIG_EIP;       /* Point to current FPU instruction. */
291
 
292
          RE_ENTRANT_CHECK_OFF;
293
          current->tss.trap_no = 16;
294
          current->tss.error_code = 0;
295
          send_sig(SIGFPE, current, 1);
296
          return;
297
        }
298
    }
299
 
300
  entry_sel_off.offset = FPU_ORIG_EIP;
301
  entry_sel_off.selector = FPU_CS;
302
  entry_sel_off.opcode = (byte1 << 8) | FPU_modrm;
303
 
304
  FPU_rm = FPU_modrm & 7;
305
 
306
  if ( FPU_modrm < 0300 )
307
    {
308
      /* All of these instructions use the mod/rm byte to get a data address */
309
 
310
      if ( (addr_modes.default_mode & SIXTEEN)
311
          ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX) )
312
        data_address = get_address_16(FPU_modrm, &FPU_EIP, &data_sel_off,
313
                                      addr_modes);
314
      else
315
        data_address = get_address(FPU_modrm, &FPU_EIP, &data_sel_off,
316
                                   addr_modes);
317
 
318
      if ( addr_modes.default_mode )
319
        {
320
          if ( FPU_EIP-1 > code_limit )
321
            math_abort(FPU_info,SIGSEGV);
322
        }
323
 
324
      if ( !(byte1 & 1) )
325
        {
326
          unsigned short status1 = partial_status;
327
 
328
          st0_ptr = &st(0);
329
          st0_tag = st0_ptr->tag;
330
 
331
          /* Stack underflow has priority */
332
          if ( NOT_EMPTY_ST0 )
333
            {
334
              if ( addr_modes.default_mode & PROTECTED )
335
                {
336
                  /* This table works for 16 and 32 bit protected mode */
337
                  if ( access_limit < data_sizes_16[(byte1 >> 1) & 3] )
338
                    math_abort(FPU_info,SIGSEGV);
339
                }
340
 
341
              unmasked = 0;  /* Do this here to stop compiler warnings. */
342
              switch ( (byte1 >> 1) & 3 )
343
                {
344
                case 0:
345
                  unmasked = reg_load_single((float *)data_address,
346
                                             &loaded_data);
347
                  break;
348
                case 1:
349
                  reg_load_int32((long *)data_address, &loaded_data);
350
                  break;
351
                case 2:
352
                  unmasked = reg_load_double((double *)data_address,
353
                                             &loaded_data);
354
                  break;
355
                case 3:
356
                  reg_load_int16((short *)data_address, &loaded_data);
357
                  break;
358
                }
359
 
360
              /* No more access to user memory, it is safe
361
                 to use static data now */
362
 
363
              /* NaN operands have the next priority. */
364
              /* We have to delay looking at st(0) until after
365
                 loading the data, because that data might contain an SNaN */
366
              if ( (st0_tag == TW_NaN) ||
367
                  (loaded_data.tag == TW_NaN) )
368
                {
369
                  /* Restore the status word; we might have loaded a
370
                     denormal. */
371
                  partial_status = status1;
372
                  if ( (FPU_modrm & 0x30) == 0x10 )
373
                    {
374
                      /* fcom or fcomp */
375
                      EXCEPTION(EX_Invalid);
376
                      setcc(SW_C3 | SW_C2 | SW_C0);
377
                      if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
378
                        pop();             /* fcomp, masked, so we pop. */
379
                    }
380
                  else
381
                    {
382
#ifdef PECULIAR_486
383
                      /* This is not really needed, but gives behaviour
384
                         identical to an 80486 */
385
                      if ( (FPU_modrm & 0x28) == 0x20 )
386
                        /* fdiv or fsub */
387
                        real_2op_NaN(&loaded_data, st0_ptr,
388
                                     st0_ptr);
389
                      else
390
#endif PECULIAR_486
391
                        /* fadd, fdivr, fmul, or fsubr */
392
                        real_2op_NaN(st0_ptr, &loaded_data,
393
                                     st0_ptr);
394
                    }
395
                  goto reg_mem_instr_done;
396
                }
397
 
398
              if ( unmasked && !((FPU_modrm & 0x30) == 0x10) )
399
                {
400
                  /* Is not a comparison instruction. */
401
                  if ( (FPU_modrm & 0x38) == 0x38 )
402
                    {
403
                      /* fdivr */
404
                      if ( (st0_tag == TW_Zero) &&
405
                          (loaded_data.tag == TW_Valid) )
406
                        {
407
                          if ( divide_by_zero(loaded_data.sign,
408
                                              st0_ptr) )
409
                            {
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 &= ~SW_Denorm_Op;
415
                              partial_status |= status1 & SW_Denorm_Op;
416
                            }
417
                        }
418
                    }
419
                  goto reg_mem_instr_done;
420
                }
421
 
422
              switch ( (FPU_modrm >> 3) & 7 )
423
                {
424
                case 0:         /* fadd */
425
                  clear_C1();
426
                  reg_add(st0_ptr, &loaded_data, st0_ptr,
427
                          control_word);
428
                  break;
429
                case 1:         /* fmul */
430
                  clear_C1();
431
                  reg_mul(st0_ptr, &loaded_data, st0_ptr,
432
                          control_word);
433
                  break;
434
                case 2:         /* fcom */
435
                  compare_st_data(&loaded_data);
436
                  break;
437
                case 3:         /* fcomp */
438
                  if ( !compare_st_data(&loaded_data) && !unmasked )
439
                    pop();
440
                  break;
441
                case 4:         /* fsub */
442
                  clear_C1();
443
                  reg_sub(st0_ptr, &loaded_data, st0_ptr,
444
                          control_word);
445
                  break;
446
                case 5:         /* fsubr */
447
                  clear_C1();
448
                  reg_sub(&loaded_data, st0_ptr, st0_ptr,
449
                          control_word);
450
                  break;
451
                case 6:         /* fdiv */
452
                  clear_C1();
453
                  reg_div(st0_ptr, &loaded_data, st0_ptr,
454
                          control_word);
455
                  break;
456
                case 7:         /* fdivr */
457
                  clear_C1();
458
                  if ( st0_tag == TW_Zero )
459
                    partial_status = status1;  /* Undo any denorm tag,
460
                                               zero-divide has priority. */
461
                  reg_div(&loaded_data, st0_ptr, st0_ptr,
462
                          control_word);
463
                  break;
464
                }
465
            }
466
          else
467
            {
468
              if ( (FPU_modrm & 0x30) == 0x10 )
469
                {
470
                  /* The instruction is fcom or fcomp */
471
                  EXCEPTION(EX_StackUnder);
472
                  setcc(SW_C3 | SW_C2 | SW_C0);
473
                  if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
474
                    pop();             /* fcomp */
475
                }
476
              else
477
                stack_underflow();
478
            }
479
        reg_mem_instr_done:
480
          operand_address = data_sel_off;
481
        }
482
      else
483
        {
484
          if ( !(no_ip_update =
485
                 load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1,
486
                                  addr_modes, data_address)) )
487
            {
488
              operand_address = data_sel_off;
489
            }
490
        }
491
 
492
    }
493
  else
494
    {
495
      /* None of these instructions access user memory */
496
      unsigned char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
497
 
498
#ifdef PECULIAR_486
499
      /* This is supposed to be undefined, but a real 80486 seems
500
         to do this: */
501
      operand_address.offset = 0;
502
      operand_address.selector = FPU_DS;
503
#endif PECULIAR_486
504
 
505
      st0_ptr = &st(0);
506
      st0_tag = st0_ptr->tag;
507
      switch ( type_table[(int) instr_index] )
508
        {
509
        case _NONE_:   /* also _REGIc: _REGIn */
510
          break;
511
        case _REG0_:
512
          if ( !NOT_EMPTY_ST0 )
513
            {
514
              stack_underflow();
515
              goto FPU_instruction_done;
516
            }
517
          break;
518
        case _REGIi:
519
          if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
520
            {
521
              stack_underflow_i(FPU_rm);
522
              goto FPU_instruction_done;
523
            }
524
          break;
525
        case _REGIp:
526
          if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
527
            {
528
              stack_underflow_pop(FPU_rm);
529
              goto FPU_instruction_done;
530
            }
531
          break;
532
        case _REGI_:
533
          if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
534
            {
535
              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
  emu_printall();
562
  RE_ENTRANT_CHECK_ON;
563
#endif DEBUG
564
 
565
  if (FPU_lookahead && !need_resched)
566
    {
567
      FPU_ORIG_EIP = FPU_EIP - code_base;
568
      if ( valid_prefix(&byte1, (unsigned char **)&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
 
580
/* Support for prefix bytes is not yet complete. To properly handle
581
   all prefix bytes, further changes are needed in the emulator code
582
   which accesses user address space. Access to separate segments is
583
   important for msdos emulation. */
584
static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
585
                        overrides *override)
586
{
587
  unsigned char byte;
588
  unsigned char *ip = *fpu_eip;
589
 
590
  *override = (overrides) { 0, 0, PREFIX_DEFAULT };       /* defaults */
591
 
592
  RE_ENTRANT_CHECK_OFF;
593
  FPU_code_verify_area(1);
594
  byte = get_fs_byte(ip);
595
  RE_ENTRANT_CHECK_ON;
596
 
597
  while ( 1 )
598
    {
599
      switch ( byte )
600
        {
601
        case ADDR_SIZE_PREFIX:
602
          override->address_size = ADDR_SIZE_PREFIX;
603
          goto do_next_byte;
604
 
605
        case OP_SIZE_PREFIX:
606
          override->operand_size = OP_SIZE_PREFIX;
607
          goto do_next_byte;
608
 
609
        case PREFIX_CS:
610
          override->segment = PREFIX_CS_;
611
          goto do_next_byte;
612
        case PREFIX_ES:
613
          override->segment = PREFIX_ES_;
614
          goto do_next_byte;
615
        case PREFIX_SS:
616
          override->segment = PREFIX_SS_;
617
          goto do_next_byte;
618
        case PREFIX_FS:
619
          override->segment = PREFIX_FS_;
620
          goto do_next_byte;
621
        case PREFIX_GS:
622
          override->segment = PREFIX_GS_;
623
          goto do_next_byte;
624
        case PREFIX_DS:
625
          override->segment = PREFIX_DS_;
626
          goto do_next_byte;
627
 
628
/* lock is not a valid prefix for FPU instructions,
629
   let the cpu handle it to generate a SIGILL. */
630
/*      case PREFIX_LOCK: */
631
 
632
          /* rep.. prefixes have no meaning for FPU instructions */
633
        case PREFIX_REPE:
634
        case PREFIX_REPNE:
635
 
636
        do_next_byte:
637
          ip++;
638
          RE_ENTRANT_CHECK_OFF;
639
          FPU_code_verify_area(1);
640
          byte = get_fs_byte(ip);
641
          RE_ENTRANT_CHECK_ON;
642
          break;
643
        case FWAIT_OPCODE:
644
          *Byte = byte;
645
          return 1;
646
        default:
647
          if ( (byte & 0xf8) == 0xd8 )
648
            {
649
              *Byte = byte;
650
              *fpu_eip = ip;
651
              return 1;
652
            }
653
          else
654
            {
655
              /* Not a valid sequence of prefix bytes followed by
656
                 an FPU instruction. */
657
              *Byte = byte;  /* Needed for error message. */
658
              return 0;
659
            }
660
        }
661
    }
662
}
663
 
664
 
665
void math_abort(struct info * info, unsigned int signal)
666
{
667
        FPU_EIP = FPU_ORIG_EIP;
668
        current->tss.trap_no = 16;
669
        current->tss.error_code = 0;
670
        send_sig(signal,current,1);
671
        RE_ENTRANT_CHECK_OFF;
672
        __asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4));
673
#ifdef PARANOID
674
      printk("ERROR: wm-FPU-emu math_abort failed!\n");
675
#endif PARANOID
676
}
677
 
678
 
679
 
680
void restore_i387_soft(struct _fpstate *buf)
681
{
682
  fpu_addr_modes addr_modes = {{ 0, 0, PREFIX_DEFAULT }, 0};
683
 
684
  frstor(addr_modes, (char *)buf);
685
}
686
 
687
 
688
struct _fpstate * save_i387_soft(struct _fpstate * buf)
689
{
690
  fpu_addr_modes addr_modes = {{ 0, 0, PREFIX_DEFAULT }, 0};
691
 
692
  fsave(addr_modes, (char *)buf);
693
 
694
  return buf;
695
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.