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;
116 struct fpu *fpu = ¤t->thread.fpu;
118 fpu__initialize(fpu);
120 #ifdef RE_ENTRANT_CHECKING
122 printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
125 #endif /* RE_ENTRANT_CHECKING */
129 FPU_ORIG_EIP = FPU_EIP;
131 if ((FPU_EFLAGS & 0x00020000) != 0) {
132 /* Virtual 8086 mode */
133 addr_modes.default_mode = VM86;
134 FPU_EIP += code_base = FPU_CS << 4;
135 code_limit = code_base + 0xffff; /* Assumes code_base <= 0xffff0000 */
136 } else if (FPU_CS == __USER_CS && FPU_DS == __USER_DS) {
137 addr_modes.default_mode = 0;
138 } else if (FPU_CS == __KERNEL_CS) {
139 printk("math_emulate: %04x:%08lx\n", FPU_CS, FPU_EIP);
140 panic("Math emulation needed in kernel");
143 if ((FPU_CS & 4) != 4) { /* Must be in the LDT */
144 /* Can only handle segmented addressing via the LDT
145 for now, and it must be 16 bit */
146 printk("FPU emulator: Unsupported addressing mode\n");
147 math_abort(FPU_info, SIGILL);
150 code_descriptor = FPU_get_ldt_descriptor(FPU_CS);
151 if (code_descriptor.d) {
152 /* The above test may be wrong, the book is not clear */
153 /* Segmented 32 bit protected mode */
154 addr_modes.default_mode = SEG32;
156 /* 16 bit protected mode */
157 addr_modes.default_mode = PM16;
159 FPU_EIP += code_base = seg_get_base(&code_descriptor);
160 code_limit = seg_get_limit(&code_descriptor) + 1;
161 code_limit *= seg_get_granularity(&code_descriptor);
162 code_limit += code_base - 1;
163 if (code_limit < code_base)
164 code_limit = 0xffffffff;
167 FPU_lookahead = !(FPU_EFLAGS & X86_EFLAGS_TF);
169 if (!valid_prefix(&byte1, (u_char __user **) & FPU_EIP,
170 &addr_modes.override)) {
171 RE_ENTRANT_CHECK_OFF;
173 ("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n"
174 "FPU emulator: self-modifying code! (emulation impossible)\n",
177 EXCEPTION(EX_INTERNAL | 0x126);
178 math_abort(FPU_info, SIGILL);
181 do_another_FPU_instruction:
185 FPU_EIP++; /* We have fetched the prefix and first code bytes. */
187 if (addr_modes.default_mode) {
188 /* This checks for the minimum instruction bytes.
189 We also need to check any extra (address mode) code access. */
190 if (FPU_EIP > code_limit)
191 math_abort(FPU_info, SIGSEGV);
194 if ((byte1 & 0xf8) != 0xd8) {
195 if (byte1 == FWAIT_OPCODE) {
196 if (partial_status & SW_Summary)
197 goto do_the_FPU_interrupt;
202 EXCEPTION(EX_INTERNAL | 0x128);
203 math_abort(FPU_info, SIGILL);
204 #endif /* PARANOID */
207 RE_ENTRANT_CHECK_OFF;
208 FPU_code_access_ok(1);
209 FPU_get_user(FPU_modrm, (u_char __user *) FPU_EIP);
213 if (partial_status & SW_Summary) {
214 /* Ignore the error for now if the current instruction is a no-wait
215 control instruction */
216 /* The 80486 manual contradicts itself on this topic,
217 but a real 80486 uses the following instructions:
218 fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex.
220 code = (FPU_modrm << 8) | byte1;
221 if (!((((code & 0xf803) == 0xe003) || /* fnclex, fninit, fnstsw */
222 (((code & 0x3003) == 0x3001) && /* fnsave, fnstcw, fnstenv,
224 ((code & 0xc000) != 0xc000))))) {
226 * We need to simulate the action of the kernel to FPU
229 do_the_FPU_interrupt:
231 FPU_EIP = FPU_ORIG_EIP; /* Point to current FPU instruction. */
233 RE_ENTRANT_CHECK_OFF;
234 current->thread.trap_nr = X86_TRAP_MF;
235 current->thread.error_code = 0;
236 send_sig(SIGFPE, current, 1);
241 entry_sel_off.offset = FPU_ORIG_EIP;
242 entry_sel_off.selector = FPU_CS;
243 entry_sel_off.opcode = (byte1 << 8) | FPU_modrm;
244 entry_sel_off.empty = 0;
246 FPU_rm = FPU_modrm & 7;
248 if (FPU_modrm < 0300) {
249 /* All of these instructions use the mod/rm byte to get a data address */
251 if ((addr_modes.default_mode & SIXTEEN)
252 ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX))
254 FPU_get_address_16(FPU_modrm, &FPU_EIP,
255 &data_sel_off, addr_modes);
258 FPU_get_address(FPU_modrm, &FPU_EIP, &data_sel_off,
261 if (addr_modes.default_mode) {
262 if (FPU_EIP - 1 > code_limit)
263 math_abort(FPU_info, SIGSEGV);
267 unsigned short status1 = partial_status;
270 st0_tag = FPU_gettag0();
272 /* Stack underflow has priority */
274 if (addr_modes.default_mode & PROTECTED) {
275 /* This table works for 16 and 32 bit protected mode */
277 data_sizes_16[(byte1 >> 1) & 3])
278 math_abort(FPU_info, SIGSEGV);
281 unmasked = 0; /* Do this here to stop compiler warnings. */
282 switch ((byte1 >> 1) & 3) {
285 FPU_load_single((float __user *)
288 loaded_tag = unmasked & 0xff;
293 FPU_load_int32((long __user *)
299 FPU_load_double((double __user *)
302 loaded_tag = unmasked & 0xff;
306 default: /* Used here to suppress gcc warnings. */
308 FPU_load_int16((short __user *)
314 /* No more access to user memory, it is safe
315 to use static data now */
317 /* NaN operands have the next priority. */
318 /* We have to delay looking at st(0) until after
319 loading the data, because that data might contain an SNaN */
320 if (((st0_tag == TAG_Special) && isNaN(st0_ptr))
321 || ((loaded_tag == TAG_Special)
322 && isNaN(&loaded_data))) {
323 /* Restore the status word; we might have loaded a
325 partial_status = status1;
326 if ((FPU_modrm & 0x30) == 0x10) {
328 EXCEPTION(EX_Invalid);
329 setcc(SW_C3 | SW_C2 | SW_C0);
330 if ((FPU_modrm & 0x08)
333 FPU_pop(); /* fcomp, masked, so we pop. */
335 if (loaded_tag == TAG_Special)
340 /* This is not really needed, but gives behaviour
341 identical to an 80486 */
342 if ((FPU_modrm & 0x28) == 0x20)
349 #endif /* PECULIAR_486 */
350 /* fadd, fdivr, fmul, or fsubr */
356 goto reg_mem_instr_done;
359 if (unmasked && !((FPU_modrm & 0x30) == 0x10)) {
360 /* Is not a comparison instruction. */
361 if ((FPU_modrm & 0x38) == 0x38) {
363 if ((st0_tag == TAG_Zero) &&
364 ((loaded_tag == TAG_Valid)
370 if (FPU_divide_by_zero
375 /* We use the fact here that the unmasked
376 exception in the loaded data was for a
378 /* Restore the state of the denormal op bit */
392 goto reg_mem_instr_done;
395 switch ((FPU_modrm >> 3) & 7) {
398 FPU_add(&loaded_data, loaded_tag, 0,
403 FPU_mul(&loaded_data, loaded_tag, 0,
407 FPU_compare_st_data(&loaded_data,
411 if (!FPU_compare_st_data
412 (&loaded_data, loaded_tag)
418 FPU_sub(LOADED | loaded_tag,
424 FPU_sub(REV | LOADED | loaded_tag,
430 FPU_div(LOADED | loaded_tag,
436 if (st0_tag == TAG_Zero)
437 partial_status = status1; /* Undo any denorm tag,
438 zero-divide has priority. */
439 FPU_div(REV | LOADED | loaded_tag,
445 if ((FPU_modrm & 0x30) == 0x10) {
446 /* The instruction is fcom or fcomp */
447 EXCEPTION(EX_StackUnder);
448 setcc(SW_C3 | SW_C2 | SW_C0);
449 if ((FPU_modrm & 0x08)
450 && (control_word & CW_Invalid))
451 FPU_pop(); /* fcomp */
453 FPU_stack_underflow();
456 operand_address = data_sel_off;
459 FPU_load_store(((FPU_modrm & 0x38) | (byte1 & 6))
460 >> 1, addr_modes, data_address))) {
461 operand_address = data_sel_off;
466 /* None of these instructions access user memory */
467 u_char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
470 /* This is supposed to be undefined, but a real 80486 seems
472 operand_address.offset = 0;
473 operand_address.selector = FPU_DS;
474 #endif /* PECULIAR_486 */
477 st0_tag = FPU_gettag0();
478 switch (type_table[(int)instr_index]) {
479 case _NONE_: /* also _REGIc: _REGIn */
482 if (!NOT_EMPTY_ST0) {
483 FPU_stack_underflow();
484 goto FPU_instruction_done;
488 if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
489 FPU_stack_underflow_i(FPU_rm);
490 goto FPU_instruction_done;
494 if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
495 FPU_stack_underflow_pop(FPU_rm);
496 goto FPU_instruction_done;
500 if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
501 FPU_stack_underflow();
502 goto FPU_instruction_done;
505 case _PUSH_: /* Only used by the fld st(i) instruction */
509 goto FPU_instruction_done;
511 EXCEPTION(EX_INTERNAL | 0x111);
512 goto FPU_instruction_done;
514 (*st_instr_table[(int)instr_index]) ();
516 FPU_instruction_done:
521 instruction_address = entry_sel_off;
526 RE_ENTRANT_CHECK_OFF;
531 if (FPU_lookahead && !need_resched()) {
532 FPU_ORIG_EIP = FPU_EIP - code_base;
533 if (valid_prefix(&byte1, (u_char __user **) & FPU_EIP,
534 &addr_modes.override))
535 goto do_another_FPU_instruction;
538 if (addr_modes.default_mode)
539 FPU_EIP -= code_base;
541 RE_ENTRANT_CHECK_OFF;
544 /* Support for prefix bytes is not yet complete. To properly handle
545 all prefix bytes, further changes are needed in the emulator code
546 which accesses user address space. Access to separate segments is
547 important for msdos emulation. */
548 static int valid_prefix(u_char *Byte, u_char __user **fpu_eip,
549 overrides * override)
552 u_char __user *ip = *fpu_eip;
554 *override = (overrides) {
555 0, 0, PREFIX_DEFAULT}; /* defaults */
557 RE_ENTRANT_CHECK_OFF;
558 FPU_code_access_ok(1);
559 FPU_get_user(byte, ip);
564 case ADDR_SIZE_PREFIX:
565 override->address_size = ADDR_SIZE_PREFIX;
569 override->operand_size = OP_SIZE_PREFIX;
573 override->segment = PREFIX_CS_;
576 override->segment = PREFIX_ES_;
579 override->segment = PREFIX_SS_;
582 override->segment = PREFIX_FS_;
585 override->segment = PREFIX_GS_;
588 override->segment = PREFIX_DS_;
591 /* lock is not a valid prefix for FPU instructions,
592 let the cpu handle it to generate a SIGILL. */
593 /* case PREFIX_LOCK: */
595 /* rep.. prefixes have no meaning for FPU instructions */
601 RE_ENTRANT_CHECK_OFF;
602 FPU_code_access_ok(1);
603 FPU_get_user(byte, ip);
610 if ((byte & 0xf8) == 0xd8) {
615 /* Not a valid sequence of prefix bytes followed by
616 an FPU instruction. */
617 *Byte = byte; /* Needed for error message. */
624 void math_abort(struct math_emu_info *info, unsigned int signal)
626 FPU_EIP = FPU_ORIG_EIP;
627 current->thread.trap_nr = X86_TRAP_MF;
628 current->thread.error_code = 0;
629 send_sig(signal, current, 1);
630 RE_ENTRANT_CHECK_OFF;
631 __asm__("movl %0,%%esp ; ret": :"g"(((long)info) - 4));
633 printk("ERROR: wm-FPU-emu math_abort failed!\n");
634 #endif /* PARANOID */
637 #define S387 ((struct swregs_state *)s387)
638 #define sstatus_word() \
639 ((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top))
641 int fpregs_soft_set(struct task_struct *target,
642 const struct user_regset *regset,
643 unsigned int pos, unsigned int count,
644 const void *kbuf, const void __user *ubuf)
646 struct swregs_state *s387 = &target->thread.fpu.state.soft;
647 void *space = s387->st_space;
649 int offset, other, i, tags, regnr, tag, newtop;
651 RE_ENTRANT_CHECK_OFF;
652 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, s387, 0,
653 offsetof(struct swregs_state, st_space));
659 S387->ftop = (S387->swd >> SW_Top_Shift) & 7;
660 offset = (S387->ftop & 7) * 10;
663 RE_ENTRANT_CHECK_OFF;
665 /* Copy all registers in stack order. */
666 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
667 space + offset, 0, other);
669 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
674 /* The tags may need to be corrected now. */
677 for (i = 0; i < 8; i++) {
678 regnr = (i + newtop) & 7;
679 if (((tags >> ((regnr & 7) * 2)) & 3) != TAG_Empty) {
680 /* The loaded data over-rides all other cases. */
682 FPU_tagof((FPU_REG *) ((u_char *) S387->st_space +
684 tags &= ~(3 << (regnr * 2));
685 tags |= (tag & 3) << (regnr * 2);
693 int fpregs_soft_get(struct task_struct *target,
694 const struct user_regset *regset,
695 unsigned int pos, unsigned int count,
696 void *kbuf, void __user *ubuf)
698 struct swregs_state *s387 = &target->thread.fpu.state.soft;
699 const void *space = s387->st_space;
701 int offset = (S387->ftop & 7) * 10, other = 80 - offset;
703 RE_ENTRANT_CHECK_OFF;
706 S387->cwd &= ~0xe080;
707 /* An 80486 sets nearly all of the reserved bits to 1. */
708 S387->cwd |= 0xffff0040;
709 S387->swd = sstatus_word() | 0xffff0000;
710 S387->twd |= 0xffff0000;
711 S387->fcs &= ~0xf8000000;
712 S387->fos |= 0xffff0000;
713 #endif /* PECULIAR_486 */
715 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, s387, 0,
716 offsetof(struct swregs_state, st_space));
718 /* Copy all registers in stack order. */
720 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
721 space + offset, 0, other);
723 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,