1 /*---------------------------------------------------------------------------+
4 | The entry functions for wm-FPU-emu |
6 | Copyright (C) 1992,1993,1994,1996,1997 |
7 | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
8 | E-mail billm@suburbia.net |
10 | See the files "README" and "COPYING" for further copyright and warranty |
13 +---------------------------------------------------------------------------*/
15 /*---------------------------------------------------------------------------+
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 +---------------------------------------------------------------------------*/
22 /*---------------------------------------------------------------------------+
23 | math_emulate(), restore_i387_soft() and save_i387_soft() are the only |
24 | entry points for wm-FPU-emu. |
25 +---------------------------------------------------------------------------*/
27 #include <linux/signal.h>
28 #include <linux/regset.h>
30 #include <linux/uaccess.h>
31 #include <asm/traps.h>
33 #include <asm/fpu/internal.h>
35 #include "fpu_system.h"
37 #include "exception.h"
38 #include "control_w.h"
41 #define __BAD__ FPU_illegal /* Illegal on an 80486, causes SIGILL */
43 /* fcmovCC and f(u)comi(p) are enabled if CPUID(1).EDX(15) "cmov" is set */
45 /* WARNING: "u" entries are not documented by Intel in their 80486 manual
46 and may not work on FPU clones or later Intel FPUs.
47 Changes to support them provided by Linus Torvalds. */
49 static FUNC
const st_instr_table
[64] = {
50 /* Opcode: d8 d9 da db */
52 /* c0..7 */ fadd__
, fld_i_
, fcmovb
, fcmovnb
,
53 /* c0..7 */ fadd_i
, ffree_
, faddp_
, ffreep
,/*u*/
54 /* c8..f */ fmul__
, fxch_i
, fcmove
, fcmovne
,
55 /* c8..f */ fmul_i
, fxch_i
,/*u*/ fmulp_
, fxch_i
,/*u*/
56 /* d0..7 */ fcom_st
, fp_nop
, fcmovbe
, fcmovnbe
,
57 /* d0..7 */ fcom_st
,/*u*/ fst_i_
, fcompst
,/*u*/ fstp_i
,/*u*/
58 /* d8..f */ fcompst
, fstp_i
,/*u*/ fcmovu
, fcmovnu
,
59 /* d8..f */ fcompst
,/*u*/ fstp_i
, fcompp
, fstp_i
,/*u*/
60 /* e0..7 */ fsub__
, FPU_etc
, __BAD__
, finit_
,
61 /* e0..7 */ fsubri
, fucom_
, fsubrp
, fstsw_
,
62 /* e8..f */ fsubr_
, fconst
, fucompp
, fucomi_
,
63 /* e8..f */ fsub_i
, fucomp
, fsubp_
, fucomip
,
64 /* f0..7 */ fdiv__
, FPU_triga
, __BAD__
, fcomi_
,
65 /* f0..7 */ fdivri
, __BAD__
, fdivrp
, fcomip
,
66 /* f8..f */ fdivr_
, FPU_trigb
, __BAD__
, __BAD__
,
67 /* f8..f */ fdiv_i
, __BAD__
, fdivp_
, __BAD__
,
70 #define _NONE_ 0 /* Take no special action */
71 #define _REG0_ 1 /* Need to check for not empty st(0) */
72 #define _REGI_ 2 /* Need to check for not empty st(0) and st(rm) */
73 #define _REGi_ 0 /* Uses st(rm) */
74 #define _PUSH_ 3 /* Need to check for space to push onto stack */
75 #define _null_ 4 /* Function illegal or not implemented */
76 #define _REGIi 5 /* Uses st(0) and st(rm), result to st(rm) */
77 #define _REGIp 6 /* Uses st(0) and st(rm), result to st(rm) then pop */
78 #define _REGIc 0 /* Compare st(0) and st(rm) */
79 #define _REGIn 0 /* Uses st(0) and st(rm), but handle checks later */
81 static u_char
const type_table
[64] = {
82 /* Opcode: d8 d9 da db dc dd de df */
83 /* c0..7 */ _REGI_
, _NONE_
, _REGIn
, _REGIn
, _REGIi
, _REGi_
, _REGIp
, _REGi_
,
84 /* c8..f */ _REGI_
, _REGIn
, _REGIn
, _REGIn
, _REGIi
, _REGI_
, _REGIp
, _REGI_
,
85 /* d0..7 */ _REGIc
, _NONE_
, _REGIn
, _REGIn
, _REGIc
, _REG0_
, _REGIc
, _REG0_
,
86 /* d8..f */ _REGIc
, _REG0_
, _REGIn
, _REGIn
, _REGIc
, _REG0_
, _REGIc
, _REG0_
,
87 /* e0..7 */ _REGI_
, _NONE_
, _null_
, _NONE_
, _REGIi
, _REGIc
, _REGIp
, _NONE_
,
88 /* e8..f */ _REGI_
, _NONE_
, _REGIc
, _REGIc
, _REGIi
, _REGIc
, _REGIp
, _REGIc
,
89 /* f0..7 */ _REGI_
, _NONE_
, _null_
, _REGIc
, _REGIi
, _null_
, _REGIp
, _REGIc
,
90 /* f8..f */ _REGI_
, _NONE_
, _null_
, _null_
, _REGIi
, _null_
, _REGIp
, _null_
,
93 #ifdef RE_ENTRANT_CHECKING
95 #endif /* RE_ENTRANT_CHECKING */
97 static int valid_prefix(u_char
*Byte
, u_char __user
** fpu_eip
,
98 overrides
* override
);
100 void math_emulate(struct math_emu_info
*info
)
102 u_char FPU_modrm
, byte1
;
104 fpu_addr_modes addr_modes
;
108 u_char loaded_tag
, st0_tag
;
109 void __user
*data_address
;
110 struct address data_sel_off
;
111 struct address entry_sel_off
;
112 unsigned long code_base
= 0;
113 unsigned long code_limit
= 0; /* Initialized to stop compiler warnings */
114 struct desc_struct code_descriptor
;
115 struct fpu
*fpu
= ¤t
->thread
.fpu
;
117 fpu__initialize(fpu
);
119 #ifdef RE_ENTRANT_CHECKING
121 printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
124 #endif /* RE_ENTRANT_CHECKING */
128 FPU_ORIG_EIP
= FPU_EIP
;
130 if ((FPU_EFLAGS
& 0x00020000) != 0) {
131 /* Virtual 8086 mode */
132 addr_modes
.default_mode
= VM86
;
133 FPU_EIP
+= code_base
= FPU_CS
<< 4;
134 code_limit
= code_base
+ 0xffff; /* Assumes code_base <= 0xffff0000 */
135 } else if (FPU_CS
== __USER_CS
&& FPU_DS
== __USER_DS
) {
136 addr_modes
.default_mode
= 0;
137 } else if (FPU_CS
== __KERNEL_CS
) {
138 printk("math_emulate: %04x:%08lx\n", FPU_CS
, FPU_EIP
);
139 panic("Math emulation needed in kernel");
142 if ((FPU_CS
& 4) != 4) { /* Must be in the LDT */
143 /* Can only handle segmented addressing via the LDT
144 for now, and it must be 16 bit */
145 printk("FPU emulator: Unsupported addressing mode\n");
146 math_abort(FPU_info
, SIGILL
);
149 code_descriptor
= FPU_get_ldt_descriptor(FPU_CS
);
150 if (code_descriptor
.d
) {
151 /* The above test may be wrong, the book is not clear */
152 /* Segmented 32 bit protected mode */
153 addr_modes
.default_mode
= SEG32
;
155 /* 16 bit protected mode */
156 addr_modes
.default_mode
= PM16
;
158 FPU_EIP
+= code_base
= seg_get_base(&code_descriptor
);
159 code_limit
= seg_get_limit(&code_descriptor
) + 1;
160 code_limit
*= seg_get_granularity(&code_descriptor
);
161 code_limit
+= code_base
- 1;
162 if (code_limit
< code_base
)
163 code_limit
= 0xffffffff;
166 FPU_lookahead
= !(FPU_EFLAGS
& X86_EFLAGS_TF
);
168 if (!valid_prefix(&byte1
, (u_char __user
**) & FPU_EIP
,
169 &addr_modes
.override
)) {
170 RE_ENTRANT_CHECK_OFF
;
172 ("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n"
173 "FPU emulator: self-modifying code! (emulation impossible)\n",
176 EXCEPTION(EX_INTERNAL
| 0x126);
177 math_abort(FPU_info
, SIGILL
);
180 do_another_FPU_instruction
:
184 FPU_EIP
++; /* We have fetched the prefix and first code bytes. */
186 if (addr_modes
.default_mode
) {
187 /* This checks for the minimum instruction bytes.
188 We also need to check any extra (address mode) code access. */
189 if (FPU_EIP
> code_limit
)
190 math_abort(FPU_info
, SIGSEGV
);
193 if ((byte1
& 0xf8) != 0xd8) {
194 if (byte1
== FWAIT_OPCODE
) {
195 if (partial_status
& SW_Summary
)
196 goto do_the_FPU_interrupt
;
201 EXCEPTION(EX_INTERNAL
| 0x128);
202 math_abort(FPU_info
, SIGILL
);
203 #endif /* PARANOID */
206 RE_ENTRANT_CHECK_OFF
;
207 FPU_code_access_ok(1);
208 FPU_get_user(FPU_modrm
, (u_char __user
*) FPU_EIP
);
212 if (partial_status
& SW_Summary
) {
213 /* Ignore the error for now if the current instruction is a no-wait
214 control instruction */
215 /* The 80486 manual contradicts itself on this topic,
216 but a real 80486 uses the following instructions:
217 fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex.
219 code
= (FPU_modrm
<< 8) | byte1
;
220 if (!((((code
& 0xf803) == 0xe003) || /* fnclex, fninit, fnstsw */
221 (((code
& 0x3003) == 0x3001) && /* fnsave, fnstcw, fnstenv,
223 ((code
& 0xc000) != 0xc000))))) {
225 * We need to simulate the action of the kernel to FPU
228 do_the_FPU_interrupt
:
230 FPU_EIP
= FPU_ORIG_EIP
; /* Point to current FPU instruction. */
232 RE_ENTRANT_CHECK_OFF
;
233 current
->thread
.trap_nr
= X86_TRAP_MF
;
234 current
->thread
.error_code
= 0;
235 send_sig(SIGFPE
, current
, 1);
240 entry_sel_off
.offset
= FPU_ORIG_EIP
;
241 entry_sel_off
.selector
= FPU_CS
;
242 entry_sel_off
.opcode
= (byte1
<< 8) | FPU_modrm
;
243 entry_sel_off
.empty
= 0;
245 FPU_rm
= FPU_modrm
& 7;
247 if (FPU_modrm
< 0300) {
248 /* All of these instructions use the mod/rm byte to get a data address */
250 if ((addr_modes
.default_mode
& SIXTEEN
)
251 ^ (addr_modes
.override
.address_size
== ADDR_SIZE_PREFIX
))
253 FPU_get_address_16(FPU_modrm
, &FPU_EIP
,
254 &data_sel_off
, addr_modes
);
257 FPU_get_address(FPU_modrm
, &FPU_EIP
, &data_sel_off
,
260 if (addr_modes
.default_mode
) {
261 if (FPU_EIP
- 1 > code_limit
)
262 math_abort(FPU_info
, SIGSEGV
);
266 unsigned short status1
= partial_status
;
269 st0_tag
= FPU_gettag0();
271 /* Stack underflow has priority */
273 if (addr_modes
.default_mode
& PROTECTED
) {
274 /* This table works for 16 and 32 bit protected mode */
276 data_sizes_16
[(byte1
>> 1) & 3])
277 math_abort(FPU_info
, SIGSEGV
);
280 unmasked
= 0; /* Do this here to stop compiler warnings. */
281 switch ((byte1
>> 1) & 3) {
284 FPU_load_single((float __user
*)
287 loaded_tag
= unmasked
& 0xff;
292 FPU_load_int32((long __user
*)
298 FPU_load_double((double __user
*)
301 loaded_tag
= unmasked
& 0xff;
305 default: /* Used here to suppress gcc warnings. */
307 FPU_load_int16((short __user
*)
313 /* No more access to user memory, it is safe
314 to use static data now */
316 /* NaN operands have the next priority. */
317 /* We have to delay looking at st(0) until after
318 loading the data, because that data might contain an SNaN */
319 if (((st0_tag
== TAG_Special
) && isNaN(st0_ptr
))
320 || ((loaded_tag
== TAG_Special
)
321 && isNaN(&loaded_data
))) {
322 /* Restore the status word; we might have loaded a
324 partial_status
= status1
;
325 if ((FPU_modrm
& 0x30) == 0x10) {
327 EXCEPTION(EX_Invalid
);
328 setcc(SW_C3
| SW_C2
| SW_C0
);
329 if ((FPU_modrm
& 0x08)
332 FPU_pop(); /* fcomp, masked, so we pop. */
334 if (loaded_tag
== TAG_Special
)
339 /* This is not really needed, but gives behaviour
340 identical to an 80486 */
341 if ((FPU_modrm
& 0x28) == 0x20)
348 #endif /* PECULIAR_486 */
349 /* fadd, fdivr, fmul, or fsubr */
355 goto reg_mem_instr_done
;
358 if (unmasked
&& !((FPU_modrm
& 0x30) == 0x10)) {
359 /* Is not a comparison instruction. */
360 if ((FPU_modrm
& 0x38) == 0x38) {
362 if ((st0_tag
== TAG_Zero
) &&
363 ((loaded_tag
== TAG_Valid
)
369 if (FPU_divide_by_zero
374 /* We use the fact here that the unmasked
375 exception in the loaded data was for a
377 /* Restore the state of the denormal op bit */
391 goto reg_mem_instr_done
;
394 switch ((FPU_modrm
>> 3) & 7) {
397 FPU_add(&loaded_data
, loaded_tag
, 0,
402 FPU_mul(&loaded_data
, loaded_tag
, 0,
406 FPU_compare_st_data(&loaded_data
,
410 if (!FPU_compare_st_data
411 (&loaded_data
, loaded_tag
)
417 FPU_sub(LOADED
| loaded_tag
,
423 FPU_sub(REV
| LOADED
| loaded_tag
,
429 FPU_div(LOADED
| loaded_tag
,
435 if (st0_tag
== TAG_Zero
)
436 partial_status
= status1
; /* Undo any denorm tag,
437 zero-divide has priority. */
438 FPU_div(REV
| LOADED
| loaded_tag
,
444 if ((FPU_modrm
& 0x30) == 0x10) {
445 /* The instruction is fcom or fcomp */
446 EXCEPTION(EX_StackUnder
);
447 setcc(SW_C3
| SW_C2
| SW_C0
);
448 if ((FPU_modrm
& 0x08)
449 && (control_word
& CW_Invalid
))
450 FPU_pop(); /* fcomp */
452 FPU_stack_underflow();
455 operand_address
= data_sel_off
;
458 FPU_load_store(((FPU_modrm
& 0x38) | (byte1
& 6))
459 >> 1, addr_modes
, data_address
))) {
460 operand_address
= data_sel_off
;
465 /* None of these instructions access user memory */
466 u_char instr_index
= (FPU_modrm
& 0x38) | (byte1
& 7);
469 /* This is supposed to be undefined, but a real 80486 seems
471 operand_address
.offset
= 0;
472 operand_address
.selector
= FPU_DS
;
473 #endif /* PECULIAR_486 */
476 st0_tag
= FPU_gettag0();
477 switch (type_table
[(int)instr_index
]) {
478 case _NONE_
: /* also _REGIc: _REGIn */
481 if (!NOT_EMPTY_ST0
) {
482 FPU_stack_underflow();
483 goto FPU_instruction_done
;
487 if (!NOT_EMPTY_ST0
|| !NOT_EMPTY(FPU_rm
)) {
488 FPU_stack_underflow_i(FPU_rm
);
489 goto FPU_instruction_done
;
493 if (!NOT_EMPTY_ST0
|| !NOT_EMPTY(FPU_rm
)) {
494 FPU_stack_underflow_pop(FPU_rm
);
495 goto FPU_instruction_done
;
499 if (!NOT_EMPTY_ST0
|| !NOT_EMPTY(FPU_rm
)) {
500 FPU_stack_underflow();
501 goto FPU_instruction_done
;
504 case _PUSH_
: /* Only used by the fld st(i) instruction */
508 goto FPU_instruction_done
;
510 EXCEPTION(EX_INTERNAL
| 0x111);
511 goto FPU_instruction_done
;
513 (*st_instr_table
[(int)instr_index
]) ();
515 FPU_instruction_done
:
520 instruction_address
= entry_sel_off
;
525 RE_ENTRANT_CHECK_OFF
;
530 if (FPU_lookahead
&& !need_resched()) {
531 FPU_ORIG_EIP
= FPU_EIP
- code_base
;
532 if (valid_prefix(&byte1
, (u_char __user
**) & FPU_EIP
,
533 &addr_modes
.override
))
534 goto do_another_FPU_instruction
;
537 if (addr_modes
.default_mode
)
538 FPU_EIP
-= code_base
;
540 RE_ENTRANT_CHECK_OFF
;
543 /* Support for prefix bytes is not yet complete. To properly handle
544 all prefix bytes, further changes are needed in the emulator code
545 which accesses user address space. Access to separate segments is
546 important for msdos emulation. */
547 static int valid_prefix(u_char
*Byte
, u_char __user
**fpu_eip
,
548 overrides
* override
)
551 u_char __user
*ip
= *fpu_eip
;
553 *override
= (overrides
) {
554 0, 0, PREFIX_DEFAULT
}; /* defaults */
556 RE_ENTRANT_CHECK_OFF
;
557 FPU_code_access_ok(1);
558 FPU_get_user(byte
, ip
);
563 case ADDR_SIZE_PREFIX
:
564 override
->address_size
= ADDR_SIZE_PREFIX
;
568 override
->operand_size
= OP_SIZE_PREFIX
;
572 override
->segment
= PREFIX_CS_
;
575 override
->segment
= PREFIX_ES_
;
578 override
->segment
= PREFIX_SS_
;
581 override
->segment
= PREFIX_FS_
;
584 override
->segment
= PREFIX_GS_
;
587 override
->segment
= PREFIX_DS_
;
590 /* lock is not a valid prefix for FPU instructions,
591 let the cpu handle it to generate a SIGILL. */
592 /* case PREFIX_LOCK: */
594 /* rep.. prefixes have no meaning for FPU instructions */
600 RE_ENTRANT_CHECK_OFF
;
601 FPU_code_access_ok(1);
602 FPU_get_user(byte
, ip
);
609 if ((byte
& 0xf8) == 0xd8) {
614 /* Not a valid sequence of prefix bytes followed by
615 an FPU instruction. */
616 *Byte
= byte
; /* Needed for error message. */
623 void math_abort(struct math_emu_info
*info
, unsigned int signal
)
625 FPU_EIP
= FPU_ORIG_EIP
;
626 current
->thread
.trap_nr
= X86_TRAP_MF
;
627 current
->thread
.error_code
= 0;
628 send_sig(signal
, current
, 1);
629 RE_ENTRANT_CHECK_OFF
;
630 __asm__("movl %0,%%esp ; ret": :"g"(((long)info
) - 4));
632 printk("ERROR: wm-FPU-emu math_abort failed!\n");
633 #endif /* PARANOID */
636 #define S387 ((struct swregs_state *)s387)
637 #define sstatus_word() \
638 ((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top))
640 int fpregs_soft_set(struct task_struct
*target
,
641 const struct user_regset
*regset
,
642 unsigned int pos
, unsigned int count
,
643 const void *kbuf
, const void __user
*ubuf
)
645 struct swregs_state
*s387
= &target
->thread
.fpu
.state
.soft
;
646 void *space
= s387
->st_space
;
648 int offset
, other
, i
, tags
, regnr
, tag
, newtop
;
650 RE_ENTRANT_CHECK_OFF
;
651 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
, s387
, 0,
652 offsetof(struct swregs_state
, st_space
));
658 S387
->ftop
= (S387
->swd
>> SW_Top_Shift
) & 7;
659 offset
= (S387
->ftop
& 7) * 10;
662 RE_ENTRANT_CHECK_OFF
;
664 /* Copy all registers in stack order. */
665 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
666 space
+ offset
, 0, other
);
668 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
673 /* The tags may need to be corrected now. */
676 for (i
= 0; i
< 8; i
++) {
677 regnr
= (i
+ newtop
) & 7;
678 if (((tags
>> ((regnr
& 7) * 2)) & 3) != TAG_Empty
) {
679 /* The loaded data over-rides all other cases. */
681 FPU_tagof((FPU_REG
*) ((u_char
*) S387
->st_space
+
683 tags
&= ~(3 << (regnr
* 2));
684 tags
|= (tag
& 3) << (regnr
* 2);
692 int fpregs_soft_get(struct task_struct
*target
,
693 const struct user_regset
*regset
,
694 unsigned int pos
, unsigned int count
,
695 void *kbuf
, void __user
*ubuf
)
697 struct swregs_state
*s387
= &target
->thread
.fpu
.state
.soft
;
698 const void *space
= s387
->st_space
;
700 int offset
= (S387
->ftop
& 7) * 10, other
= 80 - offset
;
702 RE_ENTRANT_CHECK_OFF
;
705 S387
->cwd
&= ~0xe080;
706 /* An 80486 sets nearly all of the reserved bits to 1. */
707 S387
->cwd
|= 0xffff0040;
708 S387
->swd
= sstatus_word() | 0xffff0000;
709 S387
->twd
|= 0xffff0000;
710 S387
->fcs
&= ~0xf8000000;
711 S387
->fos
|= 0xffff0000;
712 #endif /* PECULIAR_486 */
714 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
, s387
, 0,
715 offsetof(struct swregs_state
, st_space
));
717 /* Copy all registers in stack order. */
719 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
720 space
+ offset
, 0, other
);
722 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,