ia64/xen-unstable

changeset 17480:a38a41de0800

x86_emulate: Emulate certain FPU instructions by building the opcode
on the stack. This allows us to add emulation for a number of extra
FPU opcodes without inflating the executable code size.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Apr 16 16:42:47 2008 +0100 (2008-04-16)
parents defbab4dba1a
children d178c5ee6822
files xen/arch/x86/x86_emulate/x86_emulate.c
line diff
     1.1 --- a/xen/arch/x86/x86_emulate/x86_emulate.c	Wed Apr 16 16:10:41 2008 +0100
     1.2 +++ b/xen/arch/x86/x86_emulate/x86_emulate.c	Wed Apr 16 16:42:47 2008 +0100
     1.3 @@ -558,7 +558,7 @@ static void fpu_handle_exception(void *_
     1.4      regs->eip += fic->insn_bytes;
     1.5  }
     1.6  
     1.7 -#define __emulate_fpu_insn(_op)                         \
     1.8 +#define emulate_fpu_insn(_op)                           \
     1.9  do{ struct fpu_insn_ctxt fic = { 0 };                   \
    1.10      fail_if(ops->get_fpu == NULL);                      \
    1.11      ops->get_fpu(fpu_handle_exception, &fic, ctxt);     \
    1.12 @@ -571,7 +571,7 @@ do{ struct fpu_insn_ctxt fic = { 0 };   
    1.13      generate_exception_if(fic.exn_raised, EXC_MF, -1);  \
    1.14  } while (0)
    1.15  
    1.16 -#define __emulate_fpu_insn_memdst(_op, _arg)            \
    1.17 +#define emulate_fpu_insn_memdst(_op, _arg)              \
    1.18  do{ struct fpu_insn_ctxt fic = { 0 };                   \
    1.19      fail_if(ops->get_fpu == NULL);                      \
    1.20      ops->get_fpu(fpu_handle_exception, &fic, ctxt);     \
    1.21 @@ -585,6 +585,16 @@ do{ struct fpu_insn_ctxt fic = { 0 };   
    1.22      generate_exception_if(fic.exn_raised, EXC_MF, -1);  \
    1.23  } while (0)
    1.24  
    1.25 +#define emulate_fpu_insn_stub(_bytes...)                                \
    1.26 +do{ uint8_t stub[] = { _bytes, 0xc3 };                                  \
    1.27 +    struct fpu_insn_ctxt fic = { .insn_bytes = sizeof(stub)-1 };        \
    1.28 +    fail_if(ops->get_fpu == NULL);                                      \
    1.29 +    ops->get_fpu(fpu_handle_exception, &fic, ctxt);                     \
    1.30 +    (*(void(*)(void))stub)();                                           \
    1.31 +    ops->put_fpu(ctxt);                                                 \
    1.32 +    generate_exception_if(fic.exn_raised, EXC_MF, -1);                  \
    1.33 +} while (0)
    1.34 +
    1.35  static unsigned long __get_rep_prefix(
    1.36      struct cpu_user_regs *int_regs,
    1.37      struct cpu_user_regs *ext_regs,
    1.38 @@ -2438,7 +2448,7 @@ x86_emulate(
    1.39      }
    1.40  
    1.41      case 0x9b:  /* wait/fwait */
    1.42 -        __emulate_fpu_insn("fwait");
    1.43 +        emulate_fpu_insn("fwait");
    1.44          break;
    1.45  
    1.46      case 0x9c: /* pushf */
    1.47 @@ -2760,32 +2770,52 @@ x86_emulate(
    1.48      case 0xd9: /* FPU 0xd9 */
    1.49          switch ( modrm )
    1.50          {
    1.51 -        case 0xc0: __emulate_fpu_insn(".byte 0xd9,0xc0"); break; /* fld %st0 */
    1.52 -        case 0xc1: __emulate_fpu_insn(".byte 0xd9,0xc1"); break; /* fld %st1 */
    1.53 -        case 0xc2: __emulate_fpu_insn(".byte 0xd9,0xc2"); break; /* fld %st2 */
    1.54 -        case 0xc3: __emulate_fpu_insn(".byte 0xd9,0xc3"); break; /* fld %st3 */
    1.55 -        case 0xc4: __emulate_fpu_insn(".byte 0xd9,0xc4"); break; /* fld %st4 */
    1.56 -        case 0xc5: __emulate_fpu_insn(".byte 0xd9,0xc5"); break; /* fld %st5 */
    1.57 -        case 0xc6: __emulate_fpu_insn(".byte 0xd9,0xc6"); break; /* fld %st6 */
    1.58 -        case 0xc7: __emulate_fpu_insn(".byte 0xd9,0xc7"); break; /* fld %st7 */
    1.59 -        case 0xe0: __emulate_fpu_insn(".byte 0xd9,0xe0"); break; /* fchs */
    1.60 -        case 0xe1: __emulate_fpu_insn(".byte 0xd9,0xe1"); break; /* fabs */
    1.61 -        case 0xe8: __emulate_fpu_insn(".byte 0xd9,0xe8"); break; /* fld1 */
    1.62 -        case 0xee: __emulate_fpu_insn(".byte 0xd9,0xee"); break; /* fldz */
    1.63 +        case 0xc0 ... 0xc7: /* fld %stN */
    1.64 +        case 0xc8 ... 0xcf: /* fxch %stN */
    1.65 +        case 0xd0: /* fnop */
    1.66 +        case 0xe0: /* fchs */
    1.67 +        case 0xe1: /* fabs */
    1.68 +        case 0xe4: /* ftst */
    1.69 +        case 0xe5: /* fxam */
    1.70 +        case 0xe8: /* fld1 */
    1.71 +        case 0xe9: /* fldl2t */
    1.72 +        case 0xea: /* fldl2e */
    1.73 +        case 0xeb: /* fldpi */
    1.74 +        case 0xec: /* fldlg2 */
    1.75 +        case 0xed: /* fldln2 */
    1.76 +        case 0xee: /* fldz */
    1.77 +        case 0xf0: /* f2xm1 */
    1.78 +        case 0xf1: /* fyl2x */
    1.79 +        case 0xf2: /* fptan */
    1.80 +        case 0xf3: /* fpatan */
    1.81 +        case 0xf4: /* fxtract */
    1.82 +        case 0xf5: /* fprem1 */
    1.83 +        case 0xf6: /* fdecstp */
    1.84 +        case 0xf7: /* fincstp */
    1.85 +        case 0xf8: /* fprem */
    1.86 +        case 0xf9: /* fyl2xp1 */
    1.87 +        case 0xfa: /* fsqrt */
    1.88 +        case 0xfb: /* fsincos */
    1.89 +        case 0xfc: /* frndint */
    1.90 +        case 0xfd: /* fscale */
    1.91 +        case 0xfe: /* fsin */
    1.92 +        case 0xff: /* fcos */
    1.93 +            emulate_fpu_insn_stub(0xd9, modrm);
    1.94 +            break;
    1.95          default:
    1.96              fail_if((modrm_reg & 7) != 7);
    1.97              fail_if(modrm >= 0xc0);
    1.98              /* fnstcw m2byte */
    1.99              ea.bytes = 2;
   1.100              dst = ea;
   1.101 -            __emulate_fpu_insn_memdst("fnstcw", dst.val);
   1.102 +            emulate_fpu_insn_memdst("fnstcw", dst.val);
   1.103          }
   1.104          break;
   1.105  
   1.106      case 0xdb: /* FPU 0xdb */
   1.107          fail_if(modrm != 0xe3);
   1.108          /* fninit */
   1.109 -        __emulate_fpu_insn("fninit");
   1.110 +        emulate_fpu_insn("fninit");
   1.111          break;
   1.112  
   1.113      case 0xdd: /* FPU 0xdd */
   1.114 @@ -2794,22 +2824,23 @@ x86_emulate(
   1.115          /* fnstsw m2byte */
   1.116          ea.bytes = 2;
   1.117          dst = ea;
   1.118 -        __emulate_fpu_insn_memdst("fnstsw", dst.val);
   1.119 +        emulate_fpu_insn_memdst("fnstsw", dst.val);
   1.120          break;
   1.121  
   1.122      case 0xde: /* FPU 0xde */
   1.123          switch ( modrm )
   1.124          {
   1.125 -        case 0xd9: __emulate_fpu_insn(".byte 0xde,0xd9"); break;
   1.126 -        case 0xf8: __emulate_fpu_insn(".byte 0xde,0xf8"); break;
   1.127 -        case 0xf9: __emulate_fpu_insn(".byte 0xde,0xf9"); break;
   1.128 -        case 0xfa: __emulate_fpu_insn(".byte 0xde,0xfa"); break;
   1.129 -        case 0xfb: __emulate_fpu_insn(".byte 0xde,0xfb"); break;
   1.130 -        case 0xfc: __emulate_fpu_insn(".byte 0xde,0xfc"); break;
   1.131 -        case 0xfd: __emulate_fpu_insn(".byte 0xde,0xfd"); break;
   1.132 -        case 0xfe: __emulate_fpu_insn(".byte 0xde,0xfe"); break;
   1.133 -        case 0xff: __emulate_fpu_insn(".byte 0xde,0xff"); break;
   1.134 -        default: goto cannot_emulate;
   1.135 +        case 0xc0 ... 0xc7: /* faddp %stN */
   1.136 +        case 0xc8 ... 0xcf: /* fmulp %stN */
   1.137 +        case 0xd9: /* fcompp */
   1.138 +        case 0xe0 ... 0xe7: /* fsubrp %stN */
   1.139 +        case 0xe8 ... 0xef: /* fsubp %stN */
   1.140 +        case 0xf0 ... 0xf7: /* fdivrp %stN */
   1.141 +        case 0xf8 ... 0xff: /* fdivp %stN */
   1.142 +            emulate_fpu_insn_stub(0xde, modrm);
   1.143 +            break;
   1.144 +        default:
   1.145 +            goto cannot_emulate;
   1.146          }
   1.147          break;
   1.148  
   1.149 @@ -2819,7 +2850,7 @@ x86_emulate(
   1.150          dst.bytes = 2;
   1.151          dst.type = OP_REG;
   1.152          dst.reg = (unsigned long *)&_regs.eax;
   1.153 -        __emulate_fpu_insn_memdst("fnstsw", dst.val);
   1.154 +        emulate_fpu_insn_memdst("fnstsw", dst.val);
   1.155          break;
   1.156  
   1.157      case 0xe0 ... 0xe2: /* loop{,z,nz} */ {