|
|
1.1 ! root 1: /*---------------------------------------------------------------------------+ ! 2: | fpu_entry.c | ! 3: | | ! 4: | The entry function for wm-FPU-emu | ! 5: | | ! 6: | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | ! 7: | Australia. E-mail [email protected] | ! 8: | | ! 9: | See the files "README" and "COPYING" for further copyright and warranty | ! 10: | information. | ! 11: | | ! 12: +---------------------------------------------------------------------------*/ ! 13: ! 14: /*---------------------------------------------------------------------------+ ! 15: | Note: | ! 16: | The file contains code which accesses user memory. | ! 17: | Emulator static data may change when user memory is accessed, due to | ! 18: | other processes using the emulator while swapping is in progress. | ! 19: +---------------------------------------------------------------------------*/ ! 20: ! 21: /*---------------------------------------------------------------------------+ ! 22: | math_emulate() is the sole entry point for wm-FPU-emu | ! 23: +---------------------------------------------------------------------------*/ ! 24: ! 25: #ifdef KERNEL_MATH_EMULATION ! 26: ! 27: #include <linux/signal.h> ! 28: ! 29: #include "fpu_system.h" ! 30: #include "fpu_emu.h" ! 31: #include "exception.h" ! 32: ! 33: #include <asm/segment.h> ! 34: ! 35: #ifdef COHERENT ! 36: struct _fpstackframe *emCurrent; ! 37: struct _fpemstate *FPU_info; ! 38: #endif ! 39: ! 40: #define __BAD__ Un_impl /* Not implemented */ ! 41: ! 42: static FUNC st_instr_table[64] = { ! 43: fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__, ! 44: fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__, ! 45: fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__, ! 46: fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__, ! 47: fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_, ! 48: fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__, ! 49: fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__, ! 50: fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__, ! 51: }; ! 52: ! 53: #define _NONE_ 0 /* Take no special action */ ! 54: #define _REG0_ 1 /* Need to check for not empty st(0) */ ! 55: #define _REGI_ 2 /* Need to check for not empty st(0) and st(rm) */ ! 56: #define _REGi_ 0 /* Uses st(rm) */ ! 57: #define _PUSH_ 3 /* Need to check for space to push onto stack */ ! 58: #define _null_ 4 /* Function illegal or not implemented */ ! 59: ! 60: static unsigned char type_table[64] = { ! 61: _REGI_, _NONE_, _null_, _null_, _REGI_, _REGi_, _REGI_, _null_, ! 62: _REGI_, _REGI_, _null_, _null_, _REGI_, _null_, _REGI_, _null_, ! 63: _REGI_, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_, ! 64: _REGI_, _null_, _null_, _null_, _null_, _REG0_, _REGI_, _null_, ! 65: _REGI_, _NONE_, _null_, _NONE_, _REGI_, _REGI_, _REGI_, _NONE_, ! 66: _REGI_, _NONE_, _REGI_, _null_, _REGI_, _REGI_, _REGI_, _null_, ! 67: _REGI_, _NONE_, _null_, _null_, _REGI_, _null_, _REGI_, _null_, ! 68: _REGI_, _NONE_, _null_, _null_, _REGI_, _null_, _REGI_, _null_ ! 69: }; ! 70: ! 71: ! 72: /* Be careful when using any of these global variables... ! 73: they might change if swapping is triggered */ ! 74: unsigned char FPU_rm; ! 75: char FPU_st0_tag; ! 76: FPU_REG *FPU_st0_ptr; ! 77: ! 78: #ifdef PARANOID ! 79: char emulating=0; ! 80: #endif PARANOID ! 81: ! 82: #define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x)) ! 83: ! 84: #if COHERENT ! 85: /* Special kernel routines to pack and unpack emulator to normal */ ! 86: void kfsave(struct _fpemstate *fpem, struct _fpstate *fp) ! 87: { ! 88: FPU_info = fpem; ! 89: FPU_data_address = (void *)fp; ! 90: fsave(); ! 91: } ! 92: ! 93: void kfrstor(struct _fpstate *fp, struct _fpemstate *fpem) ! 94: { ! 95: FPU_info = fpem; ! 96: FPU_data_address = (void *)fp; ! 97: frstor(); ! 98: } ! 99: ! 100: void math_emulate(long *saveRegs, struct _fpemstate *fpem, int looker) ! 101: { ! 102: unsigned char FPU_modrm; ! 103: unsigned short code; ! 104: ! 105: emCurrent = (struct _fpstackframe *)(saveRegs - 1); ! 106: FPU_info = fpem; ! 107: ! 108: FPU_lookahead = looker; ! 109: #else ! 110: void math_emulate(long arg) ! 111: { ! 112: unsigned char FPU_modrm; ! 113: unsigned short code; ! 114: ! 115: #ifdef PARANOID ! 116: if ( emulating ) ! 117: { ! 118: printf("ERROR: wm-FPU-emu is not RE-ENTRANT!\r\n"); ! 119: } ! 120: RE_ENTRANT_CHECK_ON ! 121: #endif PARANOID ! 122: ! 123: if (!emCurrent->used_math) ! 124: { ! 125: finit(); ! 126: emCurrent->used_math = 1; ! 127: control_word = 0x037f; ! 128: status_word = 0x0000; ! 129: } ! 130: ! 131: FPU_info = (struct info *) &arg; ! 132: ! 133: /* We cannot handle emulation in v86-mode */ ! 134: if (FPU_EFLAGS & 0x00020000) ! 135: math_abort(FPU_info,SIGILL); ! 136: ! 137: /* 0x000f means user code space */ ! 138: if (FPU_CS != 0x000f) ! 139: { ! 140: printf("math_emulate: %04x:%08x\n\r",FPU_CS,FPU_EIP); ! 141: emPanic("Math emulation needed in kernel"); ! 142: } ! 143: ! 144: FPU_lookahead = 1; ! 145: if (emCurrent->flags & PF_PTRACED) ! 146: FPU_lookahead = 0; ! 147: #endif ! 148: do_another: ! 149: ! 150: FPU_entry_eip = FPU_ORIG_EIP = FPU_EIP; ! 151: ! 152: RE_ENTRANT_CHECK_OFF ! 153: code = get_fs_word((unsigned short *) FPU_EIP); ! 154: RE_ENTRANT_CHECK_ON ! 155: ! 156: if ( (code & 0xff) == 0x66 ) ! 157: { ! 158: FPU_EIP++; ! 159: RE_ENTRANT_CHECK_OFF ! 160: code = get_fs_word((unsigned short *) FPU_EIP); ! 161: RE_ENTRANT_CHECK_ON ! 162: } ! 163: FPU_EIP += 2; ! 164: ! 165: FPU_modrm = code >> 8; ! 166: FPU_rm = FPU_modrm & 7; ! 167: ! 168: if ( FPU_modrm < 0300 ) ! 169: { ! 170: /* All of these instructions use the mod/rm byte to get a data address */ ! 171: get_address(FPU_modrm); ! 172: ! 173: if ( !(code & 1) ) ! 174: { ! 175: switch ( (code >> 1) & 3 ) ! 176: { ! 177: case 0: ! 178: reg_load_single(); ! 179: break; ! 180: case 1: ! 181: reg_load_int32(); ! 182: break; ! 183: case 2: ! 184: reg_load_double(); ! 185: break; ! 186: case 3: ! 187: reg_load_int16(); ! 188: break; ! 189: } ! 190: ! 191: /* No more access to user memory, it is safe ! 192: to use static data now */ ! 193: FPU_st0_ptr = &st(0); ! 194: FPU_st0_tag = FPU_st0_ptr->tag; ! 195: if ( NOT_EMPTY_0 ) ! 196: { ! 197: switch ( (FPU_modrm >> 3) & 7 ) ! 198: { ! 199: case 0: /* fadd */ ! 200: reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr); ! 201: break; ! 202: case 1: /* fmul */ ! 203: reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr); ! 204: break; ! 205: case 2: /* fcom */ ! 206: compare_st_data(); ! 207: break; ! 208: case 3: /* fcomp */ ! 209: compare_st_data(); ! 210: pop(); ! 211: break; ! 212: case 4: /* fsub */ ! 213: reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr); ! 214: break; ! 215: case 5: /* fsubr */ ! 216: reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr); ! 217: break; ! 218: case 6: /* fdiv */ ! 219: reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr); ! 220: break; ! 221: case 7: /* fdivr */ ! 222: reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr); ! 223: break; ! 224: } ! 225: } ! 226: else ! 227: stack_underflow(); ! 228: } ! 229: else ! 230: { ! 231: load_store_instr(((FPU_modrm & 0x38) | (code & 6)) >> 1); ! 232: } ! 233: ! 234: #ifdef COHERENT ! 235: if (data_operand_offset != (unsigned long)FPU_data_address) { ! 236: data_operand_offset = (unsigned long)FPU_data_address; ! 237: operand_selector = FPU_DS; ! 238: } ! 239: #else ! 240: data_operand_offset = (unsigned long)FPU_data_address; ! 241: #endif ! 242: } ! 243: else ! 244: { ! 245: /* None of these instructions access user memory */ ! 246: unsigned char instr_index = (FPU_modrm & 0x38) | (code & 7); ! 247: FPU_st0_ptr = &st(0); ! 248: FPU_st0_tag = FPU_st0_ptr->tag; ! 249: switch ( type_table[(int) instr_index] ) ! 250: { ! 251: case _NONE_: ! 252: break; ! 253: case _REG0_: ! 254: if ( !NOT_EMPTY_0 ) ! 255: { ! 256: stack_underflow(); ! 257: goto instruction_done; ! 258: } ! 259: break; ! 260: case _REGI_: ! 261: if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) ) ! 262: { ! 263: stack_underflow(); ! 264: goto instruction_done; ! 265: } ! 266: break; ! 267: case _PUSH_: /* Only used by the fld st(i) instruction */ ! 268: break; ! 269: case _null_: ! 270: Un_impl(); ! 271: goto instruction_done; ! 272: default: ! 273: EXCEPTION(EX_INTERNAL|0x111); ! 274: goto instruction_done; ! 275: } ! 276: (*st_instr_table[(int) instr_index])(); ! 277: } ! 278: ! 279: instruction_done: ! 280: ! 281: #ifdef COHERENT ! 282: if (ip_offset != FPU_entry_eip) { ! 283: ip_offset = FPU_entry_eip; ! 284: bswapw(code); ! 285: cs_selector = ((code & 0x7ff) << 16) | FPU_CS; ! 286: } ! 287: #else ! 288: ip_offset = FPU_entry_eip; ! 289: bswapw(code); ! 290: *(1 + (unsigned short *)&cs_selector) = code & 0x7ff; ! 291: #endif ! 292: ! 293: #ifdef COHERENT ! 294: if (FPU_lookahead) ! 295: #else ! 296: if (FPU_lookahead && !need_resched) ! 297: #endif ! 298: { ! 299: unsigned char next; ! 300: skip_fwait: ! 301: RE_ENTRANT_CHECK_OFF ! 302: next = get_fs_byte((unsigned char *) FPU_EIP); ! 303: RE_ENTRANT_CHECK_ON ! 304: test_for_fp: ! 305: if ( (next & 0xf8) == 0xd8 ) ! 306: { ! 307: goto do_another; ! 308: } ! 309: if ( next == 0x9b ) /* fwait */ ! 310: { FPU_EIP++; goto skip_fwait; } ! 311: if ( next == 0x66 ) /* size prefix */ ! 312: { ! 313: RE_ENTRANT_CHECK_OFF ! 314: next = get_fs_byte((unsigned char *) (FPU_EIP+1)); ! 315: RE_ENTRANT_CHECK_ON ! 316: if ( (next & 0xf8) == 0xd8 ) ! 317: goto test_for_fp; ! 318: } ! 319: } ! 320: ! 321: RE_ENTRANT_CHECK_OFF ! 322: } ! 323: ! 324: #ifndef COHERENT ! 325: void __math_abort(struct info * info, unsigned int signal) ! 326: { ! 327: FPU_EIP = FPU_ORIG_EIP; ! 328: emSendsig(signal,emCurrent,1); ! 329: __asm__("movl %0,%%esp ; ret"::"g" (((long) info)-4)); ! 330: } ! 331: #endif ! 332: #else /* no math emulation */ ! 333: ! 334: #include <linux/signal.h> ! 335: #include <linux/sched.h> ! 336: ! 337: void math_emulate(long arg) ! 338: { ! 339: emSendsig(SIGFPE,emCurrent,1); ! 340: schedule(); ! 341: } ! 342: ! 343: #endif /* KERNEL_MATH_EMULATION */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.