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/api.h>
35 #include <asm/fpu/regset.h>
37 #include "fpu_system.h"
39 #include "exception.h"
40 #include "control_w.h"
43 #define __BAD__ FPU_illegal /* Illegal on an 80486, causes SIGILL */
45 /* fcmovCC and f(u)comi(p) are enabled if CPUID(1).EDX(15) "cmov" is set */
47 /* WARNING: "u" entries are not documented by Intel in their 80486 manual
48 and may not work on FPU clones or later Intel FPUs.
49 Changes to support them provided by Linus Torvalds. */
51 static FUNC
const st_instr_table
[64] = {
52 /* Opcode: d8 d9 da db */
54 /* c0..7 */ fadd__
, fld_i_
, fcmovb
, fcmovnb
,
55 /* c0..7 */ fadd_i
, ffree_
, faddp_
, ffreep
,/*u*/
56 /* c8..f */ fmul__
, fxch_i
, fcmove
, fcmovne
,
57 /* c8..f */ fmul_i
, fxch_i
,/*u*/ fmulp_
, fxch_i
,/*u*/
58 /* d0..7 */ fcom_st
, fp_nop
, fcmovbe
, fcmovnbe
,
59 /* d0..7 */ fcom_st
,/*u*/ fst_i_
, fcompst
,/*u*/ fstp_i
,/*u*/
60 /* d8..f */ fcompst
, fstp_i
,/*u*/ fcmovu
, fcmovnu
,
61 /* d8..f */ fcompst
,/*u*/ fstp_i
, fcompp
, fstp_i
,/*u*/
62 /* e0..7 */ fsub__
, FPU_etc
, __BAD__
, finit_
,
63 /* e0..7 */ fsubri
, fucom_
, fsubrp
, fstsw_
,
64 /* e8..f */ fsubr_
, fconst
, fucompp
, fucomi_
,
65 /* e8..f */ fsub_i
, fucomp
, fsubp_
, fucomip
,
66 /* f0..7 */ fdiv__
, FPU_triga
, __BAD__
, fcomi_
,
67 /* f0..7 */ fdivri
, __BAD__
, fdivrp
, fcomip
,
68 /* f8..f */ fdivr_
, FPU_trigb
, __BAD__
, __BAD__
,
69 /* f8..f */ fdiv_i
, __BAD__
, fdivp_
, __BAD__
,
72 #define _NONE_ 0 /* Take no special action */
73 #define _REG0_ 1 /* Need to check for not empty st(0) */
74 #define _REGI_ 2 /* Need to check for not empty st(0) and st(rm) */
75 #define _REGi_ 0 /* Uses st(rm) */
76 #define _PUSH_ 3 /* Need to check for space to push onto stack */
77 #define _null_ 4 /* Function illegal or not implemented */
78 #define _REGIi 5 /* Uses st(0) and st(rm), result to st(rm) */
79 #define _REGIp 6 /* Uses st(0) and st(rm), result to st(rm) then pop */
80 #define _REGIc 0 /* Compare st(0) and st(rm) */
81 #define _REGIn 0 /* Uses st(0) and st(rm), but handle checks later */
83 static u_char
const type_table
[64] = {
84 /* Opcode: d8 d9 da db dc dd de df */
85 /* c0..7 */ _REGI_
, _NONE_
, _REGIn
, _REGIn
, _REGIi
, _REGi_
, _REGIp
, _REGi_
,
86 /* c8..f */ _REGI_
, _REGIn
, _REGIn
, _REGIn
, _REGIi
, _REGI_
, _REGIp
, _REGI_
,
87 /* d0..7 */ _REGIc
, _NONE_
, _REGIn
, _REGIn
, _REGIc
, _REG0_
, _REGIc
, _REG0_
,
88 /* d8..f */ _REGIc
, _REG0_
, _REGIn
, _REGIn
, _REGIc
, _REG0_
, _REGIc
, _REG0_
,
89 /* e0..7 */ _REGI_
, _NONE_
, _null_
, _NONE_
, _REGIi
, _REGIc
, _REGIp
, _NONE_
,
90 /* e8..f */ _REGI_
, _NONE_
, _REGIc
, _REGIc
, _REGIi
, _REGIc
, _REGIp
, _REGIc
,
91 /* f0..7 */ _REGI_
, _NONE_
, _null_
, _REGIc
, _REGIi
, _null_
, _REGIp
, _REGIc
,
92 /* f8..f */ _REGI_
, _NONE_
, _null_
, _null_
, _REGIi
, _null_
, _REGIp
, _null_
,
95 #ifdef RE_ENTRANT_CHECKING
97 #endif /* RE_ENTRANT_CHECKING */
99 static int valid_prefix(u_char
*Byte
, u_char __user
** fpu_eip
,
100 overrides
* override
);
102 void math_emulate(struct math_emu_info
*info
)
104 u_char FPU_modrm
, byte1
;
106 fpu_addr_modes addr_modes
;
110 u_char loaded_tag
, st0_tag
;
111 void __user
*data_address
;
112 struct address data_sel_off
;
113 struct address entry_sel_off
;
114 unsigned long code_base
= 0;
115 unsigned long code_limit
= 0; /* Initialized to stop compiler warnings */
116 struct desc_struct code_descriptor
;
118 #ifdef RE_ENTRANT_CHECKING
120 printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
123 #endif /* RE_ENTRANT_CHECKING */
127 FPU_ORIG_EIP
= FPU_EIP
;
129 if ((FPU_EFLAGS
& 0x00020000) != 0) {
130 /* Virtual 8086 mode */
131 addr_modes
.default_mode
= VM86
;
132 FPU_EIP
+= code_base
= FPU_CS
<< 4;
133 code_limit
= code_base
+ 0xffff; /* Assumes code_base <= 0xffff0000 */
134 } else if (FPU_CS
== __USER_CS
&& FPU_DS
== __USER_DS
) {
135 addr_modes
.default_mode
= 0;
136 } else if (FPU_CS
== __KERNEL_CS
) {
137 printk("math_emulate: %04x:%08lx\n", FPU_CS
, FPU_EIP
);
138 panic("Math emulation needed in kernel");
141 if ((FPU_CS
& 4) != 4) { /* Must be in the LDT */
142 /* Can only handle segmented addressing via the LDT
143 for now, and it must be 16 bit */
144 printk("FPU emulator: Unsupported addressing mode\n");
145 math_abort(FPU_info
, SIGILL
);
148 code_descriptor
= FPU_get_ldt_descriptor(FPU_CS
);
149 if (code_descriptor
.d
) {
150 /* The above test may be wrong, the book is not clear */
151 /* Segmented 32 bit protected mode */
152 addr_modes
.default_mode
= SEG32
;
154 /* 16 bit protected mode */
155 addr_modes
.default_mode
= PM16
;
157 FPU_EIP
+= code_base
= seg_get_base(&code_descriptor
);
158 code_limit
= seg_get_limit(&code_descriptor
) + 1;
159 code_limit
*= seg_get_granularity(&code_descriptor
);
160 code_limit
+= code_base
- 1;
161 if (code_limit
< code_base
)
162 code_limit
= 0xffffffff;
165 FPU_lookahead
= !(FPU_EFLAGS
& X86_EFLAGS_TF
);
167 if (!valid_prefix(&byte1
, (u_char __user
**) & FPU_EIP
,
168 &addr_modes
.override
)) {
169 RE_ENTRANT_CHECK_OFF
;
171 ("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n"
172 "FPU emulator: self-modifying code! (emulation impossible)\n",
175 EXCEPTION(EX_INTERNAL
| 0x126);
176 math_abort(FPU_info
, SIGILL
);
179 do_another_FPU_instruction
:
183 FPU_EIP
++; /* We have fetched the prefix and first code bytes. */
185 if (addr_modes
.default_mode
) {
186 /* This checks for the minimum instruction bytes.
187 We also need to check any extra (address mode) code access. */
188 if (FPU_EIP
> code_limit
)
189 math_abort(FPU_info
, SIGSEGV
);
192 if ((byte1
& 0xf8) != 0xd8) {
193 if (byte1
== FWAIT_OPCODE
) {
194 if (partial_status
& SW_Summary
)
195 goto do_the_FPU_interrupt
;
200 EXCEPTION(EX_INTERNAL
| 0x128);
201 math_abort(FPU_info
, SIGILL
);
202 #endif /* PARANOID */
205 RE_ENTRANT_CHECK_OFF
;
206 FPU_code_access_ok(1);
207 FPU_get_user(FPU_modrm
, (u_char __user
*) FPU_EIP
);
211 if (partial_status
& SW_Summary
) {
212 /* Ignore the error for now if the current instruction is a no-wait
213 control instruction */
214 /* The 80486 manual contradicts itself on this topic,
215 but a real 80486 uses the following instructions:
216 fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex.
218 code
= (FPU_modrm
<< 8) | byte1
;
219 if (!((((code
& 0xf803) == 0xe003) || /* fnclex, fninit, fnstsw */
220 (((code
& 0x3003) == 0x3001) && /* fnsave, fnstcw, fnstenv,
222 ((code
& 0xc000) != 0xc000))))) {
224 * We need to simulate the action of the kernel to FPU
227 do_the_FPU_interrupt
:
229 FPU_EIP
= FPU_ORIG_EIP
; /* Point to current FPU instruction. */
231 RE_ENTRANT_CHECK_OFF
;
232 current
->thread
.trap_nr
= X86_TRAP_MF
;
233 current
->thread
.error_code
= 0;
234 send_sig(SIGFPE
, current
, 1);
239 entry_sel_off
.offset
= FPU_ORIG_EIP
;
240 entry_sel_off
.selector
= FPU_CS
;
241 entry_sel_off
.opcode
= (byte1
<< 8) | FPU_modrm
;
242 entry_sel_off
.empty
= 0;
244 FPU_rm
= FPU_modrm
& 7;
246 if (FPU_modrm
< 0300) {
247 /* All of these instructions use the mod/rm byte to get a data address */
249 if ((addr_modes
.default_mode
& SIXTEEN
)
250 ^ (addr_modes
.override
.address_size
== ADDR_SIZE_PREFIX
))
252 FPU_get_address_16(FPU_modrm
, &FPU_EIP
,
253 &data_sel_off
, addr_modes
);
256 FPU_get_address(FPU_modrm
, &FPU_EIP
, &data_sel_off
,
259 if (addr_modes
.default_mode
) {
260 if (FPU_EIP
- 1 > code_limit
)
261 math_abort(FPU_info
, SIGSEGV
);
265 unsigned short status1
= partial_status
;
268 st0_tag
= FPU_gettag0();
270 /* Stack underflow has priority */
272 if (addr_modes
.default_mode
& PROTECTED
) {
273 /* This table works for 16 and 32 bit protected mode */
275 data_sizes_16
[(byte1
>> 1) & 3])
276 math_abort(FPU_info
, SIGSEGV
);
279 unmasked
= 0; /* Do this here to stop compiler warnings. */
280 switch ((byte1
>> 1) & 3) {
283 FPU_load_single((float __user
*)
286 loaded_tag
= unmasked
& 0xff;
291 FPU_load_int32((long __user
*)
297 FPU_load_double((double __user
*)
300 loaded_tag
= unmasked
& 0xff;
304 default: /* Used here to suppress gcc warnings. */
306 FPU_load_int16((short __user
*)
312 /* No more access to user memory, it is safe
313 to use static data now */
315 /* NaN operands have the next priority. */
316 /* We have to delay looking at st(0) until after
317 loading the data, because that data might contain an SNaN */
318 if (((st0_tag
== TAG_Special
) && isNaN(st0_ptr
))
319 || ((loaded_tag
== TAG_Special
)
320 && isNaN(&loaded_data
))) {
321 /* Restore the status word; we might have loaded a
323 partial_status
= status1
;
324 if ((FPU_modrm
& 0x30) == 0x10) {
326 EXCEPTION(EX_Invalid
);
327 setcc(SW_C3
| SW_C2
| SW_C0
);
328 if ((FPU_modrm
& 0x08)
331 FPU_pop(); /* fcomp, masked, so we pop. */
333 if (loaded_tag
== TAG_Special
)
338 /* This is not really needed, but gives behaviour
339 identical to an 80486 */
340 if ((FPU_modrm
& 0x28) == 0x20)
347 #endif /* PECULIAR_486 */
348 /* fadd, fdivr, fmul, or fsubr */
354 goto reg_mem_instr_done
;
357 if (unmasked
&& !((FPU_modrm
& 0x30) == 0x10)) {
358 /* Is not a comparison instruction. */
359 if ((FPU_modrm
& 0x38) == 0x38) {
361 if ((st0_tag
== TAG_Zero
) &&
362 ((loaded_tag
== TAG_Valid
)
368 if (FPU_divide_by_zero
373 /* We use the fact here that the unmasked
374 exception in the loaded data was for a
376 /* Restore the state of the denormal op bit */
390 goto reg_mem_instr_done
;
393 switch ((FPU_modrm
>> 3) & 7) {
396 FPU_add(&loaded_data
, loaded_tag
, 0,
401 FPU_mul(&loaded_data
, loaded_tag
, 0,
405 FPU_compare_st_data(&loaded_data
,
409 if (!FPU_compare_st_data
410 (&loaded_data
, loaded_tag
)
416 FPU_sub(LOADED
| loaded_tag
,
422 FPU_sub(REV
| LOADED
| loaded_tag
,
428 FPU_div(LOADED
| loaded_tag
,
434 if (st0_tag
== TAG_Zero
)
435 partial_status
= status1
; /* Undo any denorm tag,
436 zero-divide has priority. */
437 FPU_div(REV
| LOADED
| loaded_tag
,
443 if ((FPU_modrm
& 0x30) == 0x10) {
444 /* The instruction is fcom or fcomp */
445 EXCEPTION(EX_StackUnder
);
446 setcc(SW_C3
| SW_C2
| SW_C0
);
447 if ((FPU_modrm
& 0x08)
448 && (control_word
& CW_Invalid
))
449 FPU_pop(); /* fcomp */
451 FPU_stack_underflow();
454 operand_address
= data_sel_off
;
457 FPU_load_store(((FPU_modrm
& 0x38) | (byte1
& 6))
458 >> 1, addr_modes
, data_address
))) {
459 operand_address
= data_sel_off
;
464 /* None of these instructions access user memory */
465 u_char instr_index
= (FPU_modrm
& 0x38) | (byte1
& 7);
468 /* This is supposed to be undefined, but a real 80486 seems
470 operand_address
.offset
= 0;
471 operand_address
.selector
= FPU_DS
;
472 #endif /* PECULIAR_486 */
475 st0_tag
= FPU_gettag0();
476 switch (type_table
[(int)instr_index
]) {
477 case _NONE_
: /* also _REGIc: _REGIn */
480 if (!NOT_EMPTY_ST0
) {
481 FPU_stack_underflow();
482 goto FPU_instruction_done
;
486 if (!NOT_EMPTY_ST0
|| !NOT_EMPTY(FPU_rm
)) {
487 FPU_stack_underflow_i(FPU_rm
);
488 goto FPU_instruction_done
;
492 if (!NOT_EMPTY_ST0
|| !NOT_EMPTY(FPU_rm
)) {
493 FPU_stack_underflow_pop(FPU_rm
);
494 goto FPU_instruction_done
;
498 if (!NOT_EMPTY_ST0
|| !NOT_EMPTY(FPU_rm
)) {
499 FPU_stack_underflow();
500 goto FPU_instruction_done
;
503 case _PUSH_
: /* Only used by the fld st(i) instruction */
507 goto FPU_instruction_done
;
509 EXCEPTION(EX_INTERNAL
| 0x111);
510 goto FPU_instruction_done
;
512 (*st_instr_table
[(int)instr_index
]) ();
514 FPU_instruction_done
:
519 instruction_address
= entry_sel_off
;
524 RE_ENTRANT_CHECK_OFF
;
529 if (FPU_lookahead
&& !need_resched()) {
530 FPU_ORIG_EIP
= FPU_EIP
- code_base
;
531 if (valid_prefix(&byte1
, (u_char __user
**) & FPU_EIP
,
532 &addr_modes
.override
))
533 goto do_another_FPU_instruction
;
536 if (addr_modes
.default_mode
)
537 FPU_EIP
-= code_base
;
539 RE_ENTRANT_CHECK_OFF
;
542 /* Support for prefix bytes is not yet complete. To properly handle
543 all prefix bytes, further changes are needed in the emulator code
544 which accesses user address space. Access to separate segments is
545 important for msdos emulation. */
546 static int valid_prefix(u_char
*Byte
, u_char __user
**fpu_eip
,
547 overrides
* override
)
550 u_char __user
*ip
= *fpu_eip
;
552 *override
= (overrides
) {
553 0, 0, PREFIX_DEFAULT
}; /* defaults */
555 RE_ENTRANT_CHECK_OFF
;
556 FPU_code_access_ok(1);
557 FPU_get_user(byte
, ip
);
562 case ADDR_SIZE_PREFIX
:
563 override
->address_size
= ADDR_SIZE_PREFIX
;
567 override
->operand_size
= OP_SIZE_PREFIX
;
571 override
->segment
= PREFIX_CS_
;
574 override
->segment
= PREFIX_ES_
;
577 override
->segment
= PREFIX_SS_
;
580 override
->segment
= PREFIX_FS_
;
583 override
->segment
= PREFIX_GS_
;
586 override
->segment
= PREFIX_DS_
;
589 /* lock is not a valid prefix for FPU instructions,
590 let the cpu handle it to generate a SIGILL. */
591 /* case PREFIX_LOCK: */
593 /* rep.. prefixes have no meaning for FPU instructions */
599 RE_ENTRANT_CHECK_OFF
;
600 FPU_code_access_ok(1);
601 FPU_get_user(byte
, ip
);
608 if ((byte
& 0xf8) == 0xd8) {
613 /* Not a valid sequence of prefix bytes followed by
614 an FPU instruction. */
615 *Byte
= byte
; /* Needed for error message. */
622 void math_abort(struct math_emu_info
*info
, unsigned int signal
)
624 FPU_EIP
= FPU_ORIG_EIP
;
625 current
->thread
.trap_nr
= X86_TRAP_MF
;
626 current
->thread
.error_code
= 0;
627 send_sig(signal
, current
, 1);
628 RE_ENTRANT_CHECK_OFF
;
629 __asm__("movl %0,%%esp ; ret": :"g"(((long)info
) - 4));
631 printk("ERROR: wm-FPU-emu math_abort failed!\n");
632 #endif /* PARANOID */
635 #define S387 ((struct swregs_state *)s387)
636 #define sstatus_word() \
637 ((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top))
639 int fpregs_soft_set(struct task_struct
*target
,
640 const struct user_regset
*regset
,
641 unsigned int pos
, unsigned int count
,
642 const void *kbuf
, const void __user
*ubuf
)
644 struct swregs_state
*s387
= &target
->thread
.fpu
.fpstate
->regs
.soft
;
645 void *space
= s387
->st_space
;
647 int offset
, other
, i
, tags
, regnr
, tag
, newtop
;
649 RE_ENTRANT_CHECK_OFF
;
650 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
, s387
, 0,
651 offsetof(struct swregs_state
, st_space
));
657 S387
->ftop
= (S387
->swd
>> SW_Top_Shift
) & 7;
658 offset
= (S387
->ftop
& 7) * 10;
661 RE_ENTRANT_CHECK_OFF
;
663 /* Copy all registers in stack order. */
664 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
665 space
+ offset
, 0, other
);
667 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
672 /* The tags may need to be corrected now. */
675 for (i
= 0; i
< 8; i
++) {
676 regnr
= (i
+ newtop
) & 7;
677 if (((tags
>> ((regnr
& 7) * 2)) & 3) != TAG_Empty
) {
678 /* The loaded data over-rides all other cases. */
680 FPU_tagof((FPU_REG
*) ((u_char
*) S387
->st_space
+
682 tags
&= ~(3 << (regnr
* 2));
683 tags
|= (tag
& 3) << (regnr
* 2);
691 int fpregs_soft_get(struct task_struct
*target
,
692 const struct user_regset
*regset
,
695 struct swregs_state
*s387
= &target
->thread
.fpu
.fpstate
->regs
.soft
;
696 const void *space
= s387
->st_space
;
697 int offset
= (S387
->ftop
& 7) * 10, other
= 80 - offset
;
699 RE_ENTRANT_CHECK_OFF
;
702 S387
->cwd
&= ~0xe080;
703 /* An 80486 sets nearly all of the reserved bits to 1. */
704 S387
->cwd
|= 0xffff0040;
705 S387
->swd
= sstatus_word() | 0xffff0000;
706 S387
->twd
|= 0xffff0000;
707 S387
->fcs
&= ~0xf8000000;
708 S387
->fos
|= 0xffff0000;
709 #endif /* PECULIAR_486 */
711 membuf_write(&to
, s387
, offsetof(struct swregs_state
, st_space
));
712 membuf_write(&to
, space
+ offset
, other
);
713 membuf_write(&to
, space
, offset
);