0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028 #include <linux/signal.h>
0029 #include <linux/regset.h>
0030
0031 #include <linux/uaccess.h>
0032 #include <asm/traps.h>
0033 #include <asm/user.h>
0034 #include <asm/fpu/api.h>
0035
0036 #include "fpu_system.h"
0037 #include "fpu_emu.h"
0038 #include "exception.h"
0039 #include "control_w.h"
0040 #include "status_w.h"
0041
0042 #define __BAD__ FPU_illegal
0043
0044
0045
0046
0047
0048
0049
0050 static FUNC const st_instr_table[64] = {
0051
0052
0053 fadd__, fld_i_, fcmovb, fcmovnb,
0054 fadd_i, ffree_, faddp_, ffreep,
0055 fmul__, fxch_i, fcmove, fcmovne,
0056 fmul_i, fxch_i, fmulp_, fxch_i,
0057 fcom_st, fp_nop, fcmovbe, fcmovnbe,
0058 fcom_st, fst_i_, fcompst, fstp_i,
0059 fcompst, fstp_i, fcmovu, fcmovnu,
0060 fcompst, fstp_i, fcompp, fstp_i,
0061 fsub__, FPU_etc, __BAD__, finit_,
0062 fsubri, fucom_, fsubrp, fstsw_,
0063 fsubr_, fconst, fucompp, fucomi_,
0064 fsub_i, fucomp, fsubp_, fucomip,
0065 fdiv__, FPU_triga, __BAD__, fcomi_,
0066 fdivri, __BAD__, fdivrp, fcomip,
0067 fdivr_, FPU_trigb, __BAD__, __BAD__,
0068 fdiv_i, __BAD__, fdivp_, __BAD__,
0069 };
0070
0071 #define _NONE_ 0
0072 #define _REG0_ 1
0073 #define _REGI_ 2
0074 #define _REGi_ 0
0075 #define _PUSH_ 3
0076 #define _null_ 4
0077 #define _REGIi 5
0078 #define _REGIp 6
0079 #define _REGIc 0
0080 #define _REGIn 0
0081
0082 static u_char const type_table[64] = {
0083
0084 _REGI_, _NONE_, _REGIn, _REGIn, _REGIi, _REGi_, _REGIp, _REGi_,
0085 _REGI_, _REGIn, _REGIn, _REGIn, _REGIi, _REGI_, _REGIp, _REGI_,
0086 _REGIc, _NONE_, _REGIn, _REGIn, _REGIc, _REG0_, _REGIc, _REG0_,
0087 _REGIc, _REG0_, _REGIn, _REGIn, _REGIc, _REG0_, _REGIc, _REG0_,
0088 _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
0089 _REGI_, _NONE_, _REGIc, _REGIc, _REGIi, _REGIc, _REGIp, _REGIc,
0090 _REGI_, _NONE_, _null_, _REGIc, _REGIi, _null_, _REGIp, _REGIc,
0091 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
0092 };
0093
0094 #ifdef RE_ENTRANT_CHECKING
0095 u_char emulating = 0;
0096 #endif
0097
0098 static int valid_prefix(u_char *Byte, u_char __user ** fpu_eip,
0099 overrides * override);
0100
0101 void math_emulate(struct math_emu_info *info)
0102 {
0103 u_char FPU_modrm, byte1;
0104 unsigned short code;
0105 fpu_addr_modes addr_modes;
0106 int unmasked;
0107 FPU_REG loaded_data;
0108 FPU_REG *st0_ptr;
0109 u_char loaded_tag, st0_tag;
0110 void __user *data_address;
0111 struct address data_sel_off;
0112 struct address entry_sel_off;
0113 unsigned long code_base = 0;
0114 unsigned long code_limit = 0;
0115 struct desc_struct code_descriptor;
0116
0117 #ifdef RE_ENTRANT_CHECKING
0118 if (emulating) {
0119 printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
0120 }
0121 RE_ENTRANT_CHECK_ON;
0122 #endif
0123
0124 FPU_info = info;
0125
0126 FPU_ORIG_EIP = FPU_EIP;
0127
0128 if ((FPU_EFLAGS & 0x00020000) != 0) {
0129
0130 addr_modes.default_mode = VM86;
0131 FPU_EIP += code_base = FPU_CS << 4;
0132 code_limit = code_base + 0xffff;
0133 } else if (FPU_CS == __USER_CS && FPU_DS == __USER_DS) {
0134 addr_modes.default_mode = 0;
0135 } else if (FPU_CS == __KERNEL_CS) {
0136 printk("math_emulate: %04x:%08lx\n", FPU_CS, FPU_EIP);
0137 panic("Math emulation needed in kernel");
0138 } else {
0139
0140 if ((FPU_CS & 4) != 4) {
0141
0142
0143 printk("FPU emulator: Unsupported addressing mode\n");
0144 math_abort(FPU_info, SIGILL);
0145 }
0146
0147 code_descriptor = FPU_get_ldt_descriptor(FPU_CS);
0148 if (code_descriptor.d) {
0149
0150
0151 addr_modes.default_mode = SEG32;
0152 } else {
0153
0154 addr_modes.default_mode = PM16;
0155 }
0156 FPU_EIP += code_base = seg_get_base(&code_descriptor);
0157 code_limit = seg_get_limit(&code_descriptor) + 1;
0158 code_limit *= seg_get_granularity(&code_descriptor);
0159 code_limit += code_base - 1;
0160 if (code_limit < code_base)
0161 code_limit = 0xffffffff;
0162 }
0163
0164 FPU_lookahead = !(FPU_EFLAGS & X86_EFLAGS_TF);
0165
0166 if (!valid_prefix(&byte1, (u_char __user **) & FPU_EIP,
0167 &addr_modes.override)) {
0168 RE_ENTRANT_CHECK_OFF;
0169 printk
0170 ("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n"
0171 "FPU emulator: self-modifying code! (emulation impossible)\n",
0172 byte1);
0173 RE_ENTRANT_CHECK_ON;
0174 EXCEPTION(EX_INTERNAL | 0x126);
0175 math_abort(FPU_info, SIGILL);
0176 }
0177
0178 do_another_FPU_instruction:
0179
0180 no_ip_update = 0;
0181
0182 FPU_EIP++;
0183
0184 if (addr_modes.default_mode) {
0185
0186
0187 if (FPU_EIP > code_limit)
0188 math_abort(FPU_info, SIGSEGV);
0189 }
0190
0191 if ((byte1 & 0xf8) != 0xd8) {
0192 if (byte1 == FWAIT_OPCODE) {
0193 if (partial_status & SW_Summary)
0194 goto do_the_FPU_interrupt;
0195 else
0196 goto FPU_fwait_done;
0197 }
0198 #ifdef PARANOID
0199 EXCEPTION(EX_INTERNAL | 0x128);
0200 math_abort(FPU_info, SIGILL);
0201 #endif
0202 }
0203
0204 RE_ENTRANT_CHECK_OFF;
0205 FPU_code_access_ok(1);
0206 FPU_get_user(FPU_modrm, (u_char __user *) FPU_EIP);
0207 RE_ENTRANT_CHECK_ON;
0208 FPU_EIP++;
0209
0210 if (partial_status & SW_Summary) {
0211
0212
0213
0214
0215
0216
0217 code = (FPU_modrm << 8) | byte1;
0218 if (!((((code & 0xf803) == 0xe003) ||
0219 (((code & 0x3003) == 0x3001) &&
0220
0221 ((code & 0xc000) != 0xc000))))) {
0222
0223
0224
0225
0226 do_the_FPU_interrupt:
0227
0228 FPU_EIP = FPU_ORIG_EIP;
0229
0230 RE_ENTRANT_CHECK_OFF;
0231 current->thread.trap_nr = X86_TRAP_MF;
0232 current->thread.error_code = 0;
0233 send_sig(SIGFPE, current, 1);
0234 return;
0235 }
0236 }
0237
0238 entry_sel_off.offset = FPU_ORIG_EIP;
0239 entry_sel_off.selector = FPU_CS;
0240 entry_sel_off.opcode = (byte1 << 8) | FPU_modrm;
0241 entry_sel_off.empty = 0;
0242
0243 FPU_rm = FPU_modrm & 7;
0244
0245 if (FPU_modrm < 0300) {
0246
0247
0248 if ((addr_modes.default_mode & SIXTEEN)
0249 ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX))
0250 data_address =
0251 FPU_get_address_16(FPU_modrm, &FPU_EIP,
0252 &data_sel_off, addr_modes);
0253 else
0254 data_address =
0255 FPU_get_address(FPU_modrm, &FPU_EIP, &data_sel_off,
0256 addr_modes);
0257
0258 if (addr_modes.default_mode) {
0259 if (FPU_EIP - 1 > code_limit)
0260 math_abort(FPU_info, SIGSEGV);
0261 }
0262
0263 if (!(byte1 & 1)) {
0264 unsigned short status1 = partial_status;
0265
0266 st0_ptr = &st(0);
0267 st0_tag = FPU_gettag0();
0268
0269
0270 if (NOT_EMPTY_ST0) {
0271 if (addr_modes.default_mode & PROTECTED) {
0272
0273 if (access_limit <
0274 data_sizes_16[(byte1 >> 1) & 3])
0275 math_abort(FPU_info, SIGSEGV);
0276 }
0277
0278 unmasked = 0;
0279 switch ((byte1 >> 1) & 3) {
0280 case 0:
0281 unmasked =
0282 FPU_load_single((float __user *)
0283 data_address,
0284 &loaded_data);
0285 loaded_tag = unmasked & 0xff;
0286 unmasked &= ~0xff;
0287 break;
0288 case 1:
0289 loaded_tag =
0290 FPU_load_int32((long __user *)
0291 data_address,
0292 &loaded_data);
0293 break;
0294 case 2:
0295 unmasked =
0296 FPU_load_double((double __user *)
0297 data_address,
0298 &loaded_data);
0299 loaded_tag = unmasked & 0xff;
0300 unmasked &= ~0xff;
0301 break;
0302 case 3:
0303 default:
0304 loaded_tag =
0305 FPU_load_int16((short __user *)
0306 data_address,
0307 &loaded_data);
0308 break;
0309 }
0310
0311
0312
0313
0314
0315
0316
0317 if (((st0_tag == TAG_Special) && isNaN(st0_ptr))
0318 || ((loaded_tag == TAG_Special)
0319 && isNaN(&loaded_data))) {
0320
0321
0322 partial_status = status1;
0323 if ((FPU_modrm & 0x30) == 0x10) {
0324
0325 EXCEPTION(EX_Invalid);
0326 setcc(SW_C3 | SW_C2 | SW_C0);
0327 if ((FPU_modrm & 0x08)
0328 && (control_word &
0329 CW_Invalid))
0330 FPU_pop();
0331 } else {
0332 if (loaded_tag == TAG_Special)
0333 loaded_tag =
0334 FPU_Special
0335 (&loaded_data);
0336 #ifdef PECULIAR_486
0337
0338
0339 if ((FPU_modrm & 0x28) == 0x20)
0340
0341 real_2op_NaN
0342 (&loaded_data,
0343 loaded_tag, 0,
0344 &loaded_data);
0345 else
0346 #endif
0347
0348 real_2op_NaN
0349 (&loaded_data,
0350 loaded_tag, 0,
0351 st0_ptr);
0352 }
0353 goto reg_mem_instr_done;
0354 }
0355
0356 if (unmasked && !((FPU_modrm & 0x30) == 0x10)) {
0357
0358 if ((FPU_modrm & 0x38) == 0x38) {
0359
0360 if ((st0_tag == TAG_Zero) &&
0361 ((loaded_tag == TAG_Valid)
0362 || (loaded_tag ==
0363 TAG_Special
0364 &&
0365 isdenormal
0366 (&loaded_data)))) {
0367 if (FPU_divide_by_zero
0368 (0,
0369 getsign
0370 (&loaded_data))
0371 < 0) {
0372
0373
0374
0375
0376 partial_status
0377 &=
0378 ~SW_Denorm_Op;
0379 partial_status
0380 |=
0381 status1 &
0382 SW_Denorm_Op;
0383 } else
0384 setsign(st0_ptr,
0385 getsign
0386 (&loaded_data));
0387 }
0388 }
0389 goto reg_mem_instr_done;
0390 }
0391
0392 switch ((FPU_modrm >> 3) & 7) {
0393 case 0:
0394 clear_C1();
0395 FPU_add(&loaded_data, loaded_tag, 0,
0396 control_word);
0397 break;
0398 case 1:
0399 clear_C1();
0400 FPU_mul(&loaded_data, loaded_tag, 0,
0401 control_word);
0402 break;
0403 case 2:
0404 FPU_compare_st_data(&loaded_data,
0405 loaded_tag);
0406 break;
0407 case 3:
0408 if (!FPU_compare_st_data
0409 (&loaded_data, loaded_tag)
0410 && !unmasked)
0411 FPU_pop();
0412 break;
0413 case 4:
0414 clear_C1();
0415 FPU_sub(LOADED | loaded_tag,
0416 (int)&loaded_data,
0417 control_word);
0418 break;
0419 case 5:
0420 clear_C1();
0421 FPU_sub(REV | LOADED | loaded_tag,
0422 (int)&loaded_data,
0423 control_word);
0424 break;
0425 case 6:
0426 clear_C1();
0427 FPU_div(LOADED | loaded_tag,
0428 (int)&loaded_data,
0429 control_word);
0430 break;
0431 case 7:
0432 clear_C1();
0433 if (st0_tag == TAG_Zero)
0434 partial_status = status1;
0435
0436 FPU_div(REV | LOADED | loaded_tag,
0437 (int)&loaded_data,
0438 control_word);
0439 break;
0440 }
0441 } else {
0442 if ((FPU_modrm & 0x30) == 0x10) {
0443
0444 EXCEPTION(EX_StackUnder);
0445 setcc(SW_C3 | SW_C2 | SW_C0);
0446 if ((FPU_modrm & 0x08)
0447 && (control_word & CW_Invalid))
0448 FPU_pop();
0449 } else
0450 FPU_stack_underflow();
0451 }
0452 reg_mem_instr_done:
0453 operand_address = data_sel_off;
0454 } else {
0455 if (!(no_ip_update =
0456 FPU_load_store(((FPU_modrm & 0x38) | (byte1 & 6))
0457 >> 1, addr_modes, data_address))) {
0458 operand_address = data_sel_off;
0459 }
0460 }
0461
0462 } else {
0463
0464 u_char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
0465
0466 #ifdef PECULIAR_486
0467
0468
0469 operand_address.offset = 0;
0470 operand_address.selector = FPU_DS;
0471 #endif
0472
0473 st0_ptr = &st(0);
0474 st0_tag = FPU_gettag0();
0475 switch (type_table[(int)instr_index]) {
0476 case _NONE_:
0477 break;
0478 case _REG0_:
0479 if (!NOT_EMPTY_ST0) {
0480 FPU_stack_underflow();
0481 goto FPU_instruction_done;
0482 }
0483 break;
0484 case _REGIi:
0485 if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
0486 FPU_stack_underflow_i(FPU_rm);
0487 goto FPU_instruction_done;
0488 }
0489 break;
0490 case _REGIp:
0491 if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
0492 FPU_stack_underflow_pop(FPU_rm);
0493 goto FPU_instruction_done;
0494 }
0495 break;
0496 case _REGI_:
0497 if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
0498 FPU_stack_underflow();
0499 goto FPU_instruction_done;
0500 }
0501 break;
0502 case _PUSH_:
0503 break;
0504 case _null_:
0505 FPU_illegal();
0506 goto FPU_instruction_done;
0507 default:
0508 EXCEPTION(EX_INTERNAL | 0x111);
0509 goto FPU_instruction_done;
0510 }
0511 (*st_instr_table[(int)instr_index]) ();
0512
0513 FPU_instruction_done:
0514 ;
0515 }
0516
0517 if (!no_ip_update)
0518 instruction_address = entry_sel_off;
0519
0520 FPU_fwait_done:
0521
0522 #ifdef DEBUG
0523 RE_ENTRANT_CHECK_OFF;
0524 FPU_printall();
0525 RE_ENTRANT_CHECK_ON;
0526 #endif
0527
0528 if (FPU_lookahead && !need_resched()) {
0529 FPU_ORIG_EIP = FPU_EIP - code_base;
0530 if (valid_prefix(&byte1, (u_char __user **) & FPU_EIP,
0531 &addr_modes.override))
0532 goto do_another_FPU_instruction;
0533 }
0534
0535 if (addr_modes.default_mode)
0536 FPU_EIP -= code_base;
0537
0538 RE_ENTRANT_CHECK_OFF;
0539 }
0540
0541
0542
0543
0544
0545 static int valid_prefix(u_char *Byte, u_char __user **fpu_eip,
0546 overrides * override)
0547 {
0548 u_char byte;
0549 u_char __user *ip = *fpu_eip;
0550
0551 *override = (overrides) {
0552 0, 0, PREFIX_DEFAULT};
0553
0554 RE_ENTRANT_CHECK_OFF;
0555 FPU_code_access_ok(1);
0556 FPU_get_user(byte, ip);
0557 RE_ENTRANT_CHECK_ON;
0558
0559 while (1) {
0560 switch (byte) {
0561 case ADDR_SIZE_PREFIX:
0562 override->address_size = ADDR_SIZE_PREFIX;
0563 goto do_next_byte;
0564
0565 case OP_SIZE_PREFIX:
0566 override->operand_size = OP_SIZE_PREFIX;
0567 goto do_next_byte;
0568
0569 case PREFIX_CS:
0570 override->segment = PREFIX_CS_;
0571 goto do_next_byte;
0572 case PREFIX_ES:
0573 override->segment = PREFIX_ES_;
0574 goto do_next_byte;
0575 case PREFIX_SS:
0576 override->segment = PREFIX_SS_;
0577 goto do_next_byte;
0578 case PREFIX_FS:
0579 override->segment = PREFIX_FS_;
0580 goto do_next_byte;
0581 case PREFIX_GS:
0582 override->segment = PREFIX_GS_;
0583 goto do_next_byte;
0584 case PREFIX_DS:
0585 override->segment = PREFIX_DS_;
0586 goto do_next_byte;
0587
0588
0589
0590
0591
0592
0593 case PREFIX_REPE:
0594 case PREFIX_REPNE:
0595
0596 do_next_byte:
0597 ip++;
0598 RE_ENTRANT_CHECK_OFF;
0599 FPU_code_access_ok(1);
0600 FPU_get_user(byte, ip);
0601 RE_ENTRANT_CHECK_ON;
0602 break;
0603 case FWAIT_OPCODE:
0604 *Byte = byte;
0605 return 1;
0606 default:
0607 if ((byte & 0xf8) == 0xd8) {
0608 *Byte = byte;
0609 *fpu_eip = ip;
0610 return 1;
0611 } else {
0612
0613
0614 *Byte = byte;
0615 return 0;
0616 }
0617 }
0618 }
0619 }
0620
0621 void math_abort(struct math_emu_info *info, unsigned int signal)
0622 {
0623 FPU_EIP = FPU_ORIG_EIP;
0624 current->thread.trap_nr = X86_TRAP_MF;
0625 current->thread.error_code = 0;
0626 send_sig(signal, current, 1);
0627 RE_ENTRANT_CHECK_OFF;
0628 __asm__("movl %0,%%esp ; ret": :"g"(((long)info) - 4));
0629 #ifdef PARANOID
0630 printk("ERROR: wm-FPU-emu math_abort failed!\n");
0631 #endif
0632 }
0633
0634 #define S387 ((struct swregs_state *)s387)
0635 #define sstatus_word() \
0636 ((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top))
0637
0638 int fpregs_soft_set(struct task_struct *target,
0639 const struct user_regset *regset,
0640 unsigned int pos, unsigned int count,
0641 const void *kbuf, const void __user *ubuf)
0642 {
0643 struct swregs_state *s387 = &target->thread.fpu.fpstate->regs.soft;
0644 void *space = s387->st_space;
0645 int ret;
0646 int offset, other, i, tags, regnr, tag, newtop;
0647
0648 RE_ENTRANT_CHECK_OFF;
0649 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, s387, 0,
0650 offsetof(struct swregs_state, st_space));
0651 RE_ENTRANT_CHECK_ON;
0652
0653 if (ret)
0654 return ret;
0655
0656 S387->ftop = (S387->swd >> SW_Top_Shift) & 7;
0657 offset = (S387->ftop & 7) * 10;
0658 other = 80 - offset;
0659
0660 RE_ENTRANT_CHECK_OFF;
0661
0662
0663 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
0664 space + offset, 0, other);
0665 if (!ret && offset)
0666 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
0667 space, 0, offset);
0668
0669 RE_ENTRANT_CHECK_ON;
0670
0671
0672 tags = S387->twd;
0673 newtop = S387->ftop;
0674 for (i = 0; i < 8; i++) {
0675 regnr = (i + newtop) & 7;
0676 if (((tags >> ((regnr & 7) * 2)) & 3) != TAG_Empty) {
0677
0678 tag =
0679 FPU_tagof((FPU_REG *) ((u_char *) S387->st_space +
0680 10 * regnr));
0681 tags &= ~(3 << (regnr * 2));
0682 tags |= (tag & 3) << (regnr * 2);
0683 }
0684 }
0685 S387->twd = tags;
0686
0687 return ret;
0688 }
0689
0690 int fpregs_soft_get(struct task_struct *target,
0691 const struct user_regset *regset,
0692 struct membuf to)
0693 {
0694 struct swregs_state *s387 = &target->thread.fpu.fpstate->regs.soft;
0695 const void *space = s387->st_space;
0696 int offset = (S387->ftop & 7) * 10, other = 80 - offset;
0697
0698 RE_ENTRANT_CHECK_OFF;
0699
0700 #ifdef PECULIAR_486
0701 S387->cwd &= ~0xe080;
0702
0703 S387->cwd |= 0xffff0040;
0704 S387->swd = sstatus_word() | 0xffff0000;
0705 S387->twd |= 0xffff0000;
0706 S387->fcs &= ~0xf8000000;
0707 S387->fos |= 0xffff0000;
0708 #endif
0709
0710 membuf_write(&to, s387, offsetof(struct swregs_state, st_space));
0711 membuf_write(&to, space + offset, other);
0712 membuf_write(&to, space, offset);
0713
0714 RE_ENTRANT_CHECK_ON;
0715
0716 return 0;
0717 }