1 // SPDX-License-Identifier: GPL-2.0
2 /*---------------------------------------------------------------------------+
5 | The entry functions for wm-FPU-emu |
7 | Copyright (C) 1992,1993,1994,1996,1997 |
8 | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
9 | E-mail billm@suburbia.net |
11 | See the files "README" and "COPYING" for further copyright and warranty |
14 +---------------------------------------------------------------------------*/
16 /*---------------------------------------------------------------------------+
18 | The file contains code which accesses user memory. |
19 | Emulator static data may change when user memory is accessed, due to |
20 | other processes using the emulator while swapping is in progress. |
21 +---------------------------------------------------------------------------*/
23 /*---------------------------------------------------------------------------+
24 | math_emulate(), restore_i387_soft() and save_i387_soft() are the only |
25 | entry points for wm-FPU-emu. |
26 +---------------------------------------------------------------------------*/
28 #include <linux/signal.h>
29 #include <linux/regset.h>
31 #include <linux/uaccess.h>
32 #include <asm/traps.h>
34 #include <asm/fpu/internal.h>
36 #include "fpu_system.h"
38 #include "exception.h"
39 #include "control_w.h"
42 #define __BAD__ FPU_illegal /* Illegal on an 80486, causes SIGILL */
44 /* fcmovCC and f(u)comi(p) are enabled if CPUID(1).EDX(15) "cmov" is set */
46 /* WARNING: "u" entries are not documented by Intel in their 80486 manual
47 and may not work on FPU clones or later Intel FPUs.
48 Changes to support them provided by Linus Torvalds. */
50 static FUNC
const st_instr_table
[64] = {
51 /* Opcode: d8 d9 da db */
53 /* c0..7 */ fadd__
, fld_i_
, fcmovb
, fcmovnb
,
54 /* c0..7 */ fadd_i
, ffree_
, faddp_
, ffreep
,/*u*/
55 /* c8..f */ fmul__
, fxch_i
, fcmove
, fcmovne
,
56 /* c8..f */ fmul_i
, fxch_i
,/*u*/ fmulp_
, fxch_i
,/*u*/
57 /* d0..7 */ fcom_st
, fp_nop
, fcmovbe
, fcmovnbe
,
58 /* d0..7 */ fcom_st
,/*u*/ fst_i_
, fcompst
,/*u*/ fstp_i
,/*u*/
59 /* d8..f */ fcompst
, fstp_i
,/*u*/ fcmovu
, fcmovnu
,
60 /* d8..f */ fcompst
,/*u*/ fstp_i
, fcompp
, fstp_i
,/*u*/
61 /* e0..7 */ fsub__
, FPU_etc
, __BAD__
, finit_
,
62 /* e0..7 */ fsubri
, fucom_
, fsubrp
, fstsw_
,
63 /* e8..f */ fsubr_
, fconst
, fucompp
, fucomi_
,
64 /* e8..f */ fsub_i
, fucomp
, fsubp_
, fucomip
,
65 /* f0..7 */ fdiv__
, FPU_triga
, __BAD__
, fcomi_
,
66 /* f0..7 */ fdivri
, __BAD__
, fdivrp
, fcomip
,
67 /* f8..f */ fdivr_
, FPU_trigb
, __BAD__
, __BAD__
,
68 /* f8..f */ fdiv_i
, __BAD__
, fdivp_
, __BAD__
,
71 #define _NONE_ 0 /* Take no special action */
72 #define _REG0_ 1 /* Need to check for not empty st(0) */
73 #define _REGI_ 2 /* Need to check for not empty st(0) and st(rm) */
74 #define _REGi_ 0 /* Uses st(rm) */
75 #define _PUSH_ 3 /* Need to check for space to push onto stack */
76 #define _null_ 4 /* Function illegal or not implemented */
77 #define _REGIi 5 /* Uses st(0) and st(rm), result to st(rm) */
78 #define _REGIp 6 /* Uses st(0) and st(rm), result to st(rm) then pop */
79 #define _REGIc 0 /* Compare st(0) and st(rm) */
80 #define _REGIn 0 /* Uses st(0) and st(rm), but handle checks later */
82 static u_char
const type_table
[64] = {
83 /* Opcode: d8 d9 da db dc dd de df */
84 /* c0..7 */ _REGI_
, _NONE_
, _REGIn
, _REGIn
, _REGIi
, _REGi_
, _REGIp
, _REGi_
,
85 /* c8..f */ _REGI_
, _REGIn
, _REGIn
, _REGIn
, _REGIi
, _REGI_
, _REGIp
, _REGI_
,
86 /* d0..7 */ _REGIc
, _NONE_
, _REGIn
, _REGIn
, _REGIc
, _REG0_
, _REGIc
, _REG0_
,
87 /* d8..f */ _REGIc
, _REG0_
, _REGIn
, _REGIn
, _REGIc
, _REG0_
, _REGIc
, _REG0_
,
88 /* e0..7 */ _REGI_
, _NONE_
, _null_
, _NONE_
, _REGIi
, _REGIc
, _REGIp
, _NONE_
,
89 /* e8..f */ _REGI_
, _NONE_
, _REGIc
, _REGIc
, _REGIi
, _REGIc
, _REGIp
, _REGIc
,
90 /* f0..7 */ _REGI_
, _NONE_
, _null_
, _REGIc
, _REGIi
, _null_
, _REGIp
, _REGIc
,
91 /* f8..f */ _REGI_
, _NONE_
, _null_
, _null_
, _REGIi
, _null_
, _REGIp
, _null_
,
94 #ifdef RE_ENTRANT_CHECKING
96 #endif /* RE_ENTRANT_CHECKING */
98 static int valid_prefix(u_char
*Byte
, u_char __user
** fpu_eip
,
99 overrides
* override
);
101 void math_emulate(struct math_emu_info
*info
)
103 u_char FPU_modrm
, byte1
;
105 fpu_addr_modes addr_modes
;
109 u_char loaded_tag
, st0_tag
;
110 void __user
*data_address
;
111 struct address data_sel_off
;
112 struct address entry_sel_off
;
113 unsigned long code_base
= 0;
114 unsigned long code_limit
= 0; /* Initialized to stop compiler warnings */
115 struct desc_struct code_descriptor
;
117 #ifdef RE_ENTRANT_CHECKING
119 printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
122 #endif /* RE_ENTRANT_CHECKING */
126 FPU_ORIG_EIP
= FPU_EIP
;
128 if ((FPU_EFLAGS
& 0x00020000) != 0) {
129 /* Virtual 8086 mode */
130 addr_modes
.default_mode
= VM86
;
131 FPU_EIP
+= code_base
= FPU_CS
<< 4;
132 code_limit
= code_base
+ 0xffff; /* Assumes code_base <= 0xffff0000 */
133 } else if (FPU_CS
== __USER_CS
&& FPU_DS
== __USER_DS
) {
134 addr_modes
.default_mode
= 0;
135 } else if (FPU_CS
== __KERNEL_CS
) {
136 printk("math_emulate: %04x:%08lx\n", FPU_CS
, FPU_EIP
);
137 panic("Math emulation needed in kernel");
140 if ((FPU_CS
& 4) != 4) { /* Must be in the LDT */
141 /* Can only handle segmented addressing via the LDT
142 for now, and it must be 16 bit */
143 printk("FPU emulator: Unsupported addressing mode\n");
144 math_abort(FPU_info
, SIGILL
);
147 code_descriptor
= FPU_get_ldt_descriptor(FPU_CS
);
148 if (code_descriptor
.d
) {
149 /* The above test may be wrong, the book is not clear */
150 /* Segmented 32 bit protected mode */
151 addr_modes
.default_mode
= SEG32
;
153 /* 16 bit protected mode */
154 addr_modes
.default_mode
= PM16
;
156 FPU_EIP
+= code_base
= seg_get_base(&code_descriptor
);
157 code_limit
= seg_get_limit(&code_descriptor
) + 1;
158 code_limit
*= seg_get_granularity(&code_descriptor
);
159 code_limit
+= code_base
- 1;
160 if (code_limit
< code_base
)
161 code_limit
= 0xffffffff;
164 FPU_lookahead
= !(FPU_EFLAGS
& X86_EFLAGS_TF
);
166 if (!valid_prefix(&byte1
, (u_char __user
**) & FPU_EIP
,
167 &addr_modes
.override
)) {
168 RE_ENTRANT_CHECK_OFF
;
170 ("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n"
171 "FPU emulator: self-modifying code! (emulation impossible)\n",
174 EXCEPTION(EX_INTERNAL
| 0x126);
175 math_abort(FPU_info
, SIGILL
);
178 do_another_FPU_instruction
:
182 FPU_EIP
++; /* We have fetched the prefix and first code bytes. */
184 if (addr_modes
.default_mode
) {
185 /* This checks for the minimum instruction bytes.
186 We also need to check any extra (address mode) code access. */
187 if (FPU_EIP
> code_limit
)
188 math_abort(FPU_info
, SIGSEGV
);
191 if ((byte1
& 0xf8) != 0xd8) {
192 if (byte1
== FWAIT_OPCODE
) {
193 if (partial_status
& SW_Summary
)
194 goto do_the_FPU_interrupt
;
199 EXCEPTION(EX_INTERNAL
| 0x128);
200 math_abort(FPU_info
, SIGILL
);
201 #endif /* PARANOID */
204 RE_ENTRANT_CHECK_OFF
;
205 FPU_code_access_ok(1);
206 FPU_get_user(FPU_modrm
, (u_char __user
*) FPU_EIP
);
210 if (partial_status
& SW_Summary
) {
211 /* Ignore the error for now if the current instruction is a no-wait
212 control instruction */
213 /* The 80486 manual contradicts itself on this topic,
214 but a real 80486 uses the following instructions:
215 fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex.
217 code
= (FPU_modrm
<< 8) | byte1
;
218 if (!((((code
& 0xf803) == 0xe003) || /* fnclex, fninit, fnstsw */
219 (((code
& 0x3003) == 0x3001) && /* fnsave, fnstcw, fnstenv,
221 ((code
& 0xc000) != 0xc000))))) {
223 * We need to simulate the action of the kernel to FPU
226 do_the_FPU_interrupt
:
228 FPU_EIP
= FPU_ORIG_EIP
; /* Point to current FPU instruction. */
230 RE_ENTRANT_CHECK_OFF
;
231 current
->thread
.trap_nr
= X86_TRAP_MF
;
232 current
->thread
.error_code
= 0;
233 send_sig(SIGFPE
, current
, 1);
238 entry_sel_off
.offset
= FPU_ORIG_EIP
;
239 entry_sel_off
.selector
= FPU_CS
;
240 entry_sel_off
.opcode
= (byte1
<< 8) | FPU_modrm
;
241 entry_sel_off
.empty
= 0;
243 FPU_rm
= FPU_modrm
& 7;
245 if (FPU_modrm
< 0300) {
246 /* All of these instructions use the mod/rm byte to get a data address */
248 if ((addr_modes
.default_mode
& SIXTEEN
)
249 ^ (addr_modes
.override
.address_size
== ADDR_SIZE_PREFIX
))
251 FPU_get_address_16(FPU_modrm
, &FPU_EIP
,
252 &data_sel_off
, addr_modes
);
255 FPU_get_address(FPU_modrm
, &FPU_EIP
, &data_sel_off
,
258 if (addr_modes
.default_mode
) {
259 if (FPU_EIP
- 1 > code_limit
)
260 math_abort(FPU_info
, SIGSEGV
);
264 unsigned short status1
= partial_status
;
267 st0_tag
= FPU_gettag0();
269 /* Stack underflow has priority */
271 if (addr_modes
.default_mode
& PROTECTED
) {
272 /* This table works for 16 and 32 bit protected mode */
274 data_sizes_16
[(byte1
>> 1) & 3])
275 math_abort(FPU_info
, SIGSEGV
);
278 unmasked
= 0; /* Do this here to stop compiler warnings. */
279 switch ((byte1
>> 1) & 3) {
282 FPU_load_single((float __user
*)
285 loaded_tag
= unmasked
& 0xff;
290 FPU_load_int32((long __user
*)
296 FPU_load_double((double __user
*)
299 loaded_tag
= unmasked
& 0xff;
303 default: /* Used here to suppress gcc warnings. */
305 FPU_load_int16((short __user
*)
311 /* No more access to user memory, it is safe
312 to use static data now */
314 /* NaN operands have the next priority. */
315 /* We have to delay looking at st(0) until after
316 loading the data, because that data might contain an SNaN */
317 if (((st0_tag
== TAG_Special
) && isNaN(st0_ptr
))
318 || ((loaded_tag
== TAG_Special
)
319 && isNaN(&loaded_data
))) {
320 /* Restore the status word; we might have loaded a
322 partial_status
= status1
;
323 if ((FPU_modrm
& 0x30) == 0x10) {
325 EXCEPTION(EX_Invalid
);
326 setcc(SW_C3
| SW_C2
| SW_C0
);
327 if ((FPU_modrm
& 0x08)
330 FPU_pop(); /* fcomp, masked, so we pop. */
332 if (loaded_tag
== TAG_Special
)
337 /* This is not really needed, but gives behaviour
338 identical to an 80486 */
339 if ((FPU_modrm
& 0x28) == 0x20)
346 #endif /* PECULIAR_486 */
347 /* fadd, fdivr, fmul, or fsubr */
353 goto reg_mem_instr_done
;
356 if (unmasked
&& !((FPU_modrm
& 0x30) == 0x10)) {
357 /* Is not a comparison instruction. */
358 if ((FPU_modrm
& 0x38) == 0x38) {
360 if ((st0_tag
== TAG_Zero
) &&
361 ((loaded_tag
== TAG_Valid
)
367 if (FPU_divide_by_zero
372 /* We use the fact here that the unmasked
373 exception in the loaded data was for a
375 /* Restore the state of the denormal op bit */
389 goto reg_mem_instr_done
;
392 switch ((FPU_modrm
>> 3) & 7) {
395 FPU_add(&loaded_data
, loaded_tag
, 0,
400 FPU_mul(&loaded_data
, loaded_tag
, 0,
404 FPU_compare_st_data(&loaded_data
,
408 if (!FPU_compare_st_data
409 (&loaded_data
, loaded_tag
)
415 FPU_sub(LOADED
| loaded_tag
,
421 FPU_sub(REV
| LOADED
| loaded_tag
,
427 FPU_div(LOADED
| loaded_tag
,
433 if (st0_tag
== TAG_Zero
)
434 partial_status
= status1
; /* Undo any denorm tag,
435 zero-divide has priority. */
436 FPU_div(REV
| LOADED
| loaded_tag
,
442 if ((FPU_modrm
& 0x30) == 0x10) {
443 /* The instruction is fcom or fcomp */
444 EXCEPTION(EX_StackUnder
);
445 setcc(SW_C3
| SW_C2
| SW_C0
);
446 if ((FPU_modrm
& 0x08)
447 && (control_word
& CW_Invalid
))
448 FPU_pop(); /* fcomp */
450 FPU_stack_underflow();
453 operand_address
= data_sel_off
;
456 FPU_load_store(((FPU_modrm
& 0x38) | (byte1
& 6))
457 >> 1, addr_modes
, data_address
))) {
458 operand_address
= data_sel_off
;
463 /* None of these instructions access user memory */
464 u_char instr_index
= (FPU_modrm
& 0x38) | (byte1
& 7);
467 /* This is supposed to be undefined, but a real 80486 seems
469 operand_address
.offset
= 0;
470 operand_address
.selector
= FPU_DS
;
471 #endif /* PECULIAR_486 */
474 st0_tag
= FPU_gettag0();
475 switch (type_table
[(int)instr_index
]) {
476 case _NONE_
: /* also _REGIc: _REGIn */
479 if (!NOT_EMPTY_ST0
) {
480 FPU_stack_underflow();
481 goto FPU_instruction_done
;
485 if (!NOT_EMPTY_ST0
|| !NOT_EMPTY(FPU_rm
)) {
486 FPU_stack_underflow_i(FPU_rm
);
487 goto FPU_instruction_done
;
491 if (!NOT_EMPTY_ST0
|| !NOT_EMPTY(FPU_rm
)) {
492 FPU_stack_underflow_pop(FPU_rm
);
493 goto FPU_instruction_done
;
497 if (!NOT_EMPTY_ST0
|| !NOT_EMPTY(FPU_rm
)) {
498 FPU_stack_underflow();
499 goto FPU_instruction_done
;
502 case _PUSH_
: /* Only used by the fld st(i) instruction */
506 goto FPU_instruction_done
;
508 EXCEPTION(EX_INTERNAL
| 0x111);
509 goto FPU_instruction_done
;
511 (*st_instr_table
[(int)instr_index
]) ();
513 FPU_instruction_done
:
518 instruction_address
= entry_sel_off
;
523 RE_ENTRANT_CHECK_OFF
;
528 if (FPU_lookahead
&& !need_resched()) {
529 FPU_ORIG_EIP
= FPU_EIP
- code_base
;
530 if (valid_prefix(&byte1
, (u_char __user
**) & FPU_EIP
,
531 &addr_modes
.override
))
532 goto do_another_FPU_instruction
;
535 if (addr_modes
.default_mode
)
536 FPU_EIP
-= code_base
;
538 RE_ENTRANT_CHECK_OFF
;
541 /* Support for prefix bytes is not yet complete. To properly handle
542 all prefix bytes, further changes are needed in the emulator code
543 which accesses user address space. Access to separate segments is
544 important for msdos emulation. */
545 static int valid_prefix(u_char
*Byte
, u_char __user
**fpu_eip
,
546 overrides
* override
)
549 u_char __user
*ip
= *fpu_eip
;
551 *override
= (overrides
) {
552 0, 0, PREFIX_DEFAULT
}; /* defaults */
554 RE_ENTRANT_CHECK_OFF
;
555 FPU_code_access_ok(1);
556 FPU_get_user(byte
, ip
);
561 case ADDR_SIZE_PREFIX
:
562 override
->address_size
= ADDR_SIZE_PREFIX
;
566 override
->operand_size
= OP_SIZE_PREFIX
;
570 override
->segment
= PREFIX_CS_
;
573 override
->segment
= PREFIX_ES_
;
576 override
->segment
= PREFIX_SS_
;
579 override
->segment
= PREFIX_FS_
;
582 override
->segment
= PREFIX_GS_
;
585 override
->segment
= PREFIX_DS_
;
588 /* lock is not a valid prefix for FPU instructions,
589 let the cpu handle it to generate a SIGILL. */
590 /* case PREFIX_LOCK: */
592 /* rep.. prefixes have no meaning for FPU instructions */
598 RE_ENTRANT_CHECK_OFF
;
599 FPU_code_access_ok(1);
600 FPU_get_user(byte
, ip
);
607 if ((byte
& 0xf8) == 0xd8) {
612 /* Not a valid sequence of prefix bytes followed by
613 an FPU instruction. */
614 *Byte
= byte
; /* Needed for error message. */
621 void math_abort(struct math_emu_info
*info
, unsigned int signal
)
623 FPU_EIP
= FPU_ORIG_EIP
;
624 current
->thread
.trap_nr
= X86_TRAP_MF
;
625 current
->thread
.error_code
= 0;
626 send_sig(signal
, current
, 1);
627 RE_ENTRANT_CHECK_OFF
;
628 __asm__("movl %0,%%esp ; ret": :"g"(((long)info
) - 4));
630 printk("ERROR: wm-FPU-emu math_abort failed!\n");
631 #endif /* PARANOID */
634 #define S387 ((struct swregs_state *)s387)
635 #define sstatus_word() \
636 ((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top))
638 int fpregs_soft_set(struct task_struct
*target
,
639 const struct user_regset
*regset
,
640 unsigned int pos
, unsigned int count
,
641 const void *kbuf
, const void __user
*ubuf
)
643 struct swregs_state
*s387
= &target
->thread
.fpu
.state
.soft
;
644 void *space
= s387
->st_space
;
646 int offset
, other
, i
, tags
, regnr
, tag
, newtop
;
648 RE_ENTRANT_CHECK_OFF
;
649 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
, s387
, 0,
650 offsetof(struct swregs_state
, st_space
));
656 S387
->ftop
= (S387
->swd
>> SW_Top_Shift
) & 7;
657 offset
= (S387
->ftop
& 7) * 10;
660 RE_ENTRANT_CHECK_OFF
;
662 /* Copy all registers in stack order. */
663 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
664 space
+ offset
, 0, other
);
666 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
671 /* The tags may need to be corrected now. */
674 for (i
= 0; i
< 8; i
++) {
675 regnr
= (i
+ newtop
) & 7;
676 if (((tags
>> ((regnr
& 7) * 2)) & 3) != TAG_Empty
) {
677 /* The loaded data over-rides all other cases. */
679 FPU_tagof((FPU_REG
*) ((u_char
*) S387
->st_space
+
681 tags
&= ~(3 << (regnr
* 2));
682 tags
|= (tag
& 3) << (regnr
* 2);
690 int fpregs_soft_get(struct task_struct
*target
,
691 const struct user_regset
*regset
,
694 struct swregs_state
*s387
= &target
->thread
.fpu
.state
.soft
;
695 const void *space
= s387
->st_space
;
696 int offset
= (S387
->ftop
& 7) * 10, other
= 80 - offset
;
698 RE_ENTRANT_CHECK_OFF
;
701 S387
->cwd
&= ~0xe080;
702 /* An 80486 sets nearly all of the reserved bits to 1. */
703 S387
->cwd
|= 0xffff0040;
704 S387
->swd
= sstatus_word() | 0xffff0000;
705 S387
->twd
|= 0xffff0000;
706 S387
->fcs
&= ~0xf8000000;
707 S387
->fos
|= 0xffff0000;
708 #endif /* PECULIAR_486 */
710 membuf_write(&to
, s387
, offsetof(struct swregs_state
, st_space
));
711 membuf_write(&to
, space
+ offset
, other
);
712 membuf_write(&to
, space
, offset
);