diff options
author | Jan Beulich <jbeulich@suse.com> | 2011-12-01 08:49:31 +0100 |
---|---|---|
committer | Jan Beulich <jbeulich@suse.com> | 2011-12-01 08:49:31 +0100 |
commit | 316af62170b0d0b12fc0d6bf5bd2b09776914633 (patch) | |
tree | be134057def1eb9507616b9cd0b57664181cbcc3 /xen/arch/x86/x86_emulate | |
parent | 11c35f84b53622c429071049b830bb9b7a880eff (diff) | |
download | xen-316af62170b0d0b12fc0d6bf5bd2b09776914633.tar.gz xen-316af62170b0d0b12fc0d6bf5bd2b09776914633.tar.bz2 xen-316af62170b0d0b12fc0d6bf5bd2b09776914633.zip |
x86/emulator: add emulation of SIMD FP moves
Clone the existing movq emulation to also support the most fundamental
SIMD FP moves.
Extend the testing code to also exercise these instructions.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Keir Fraser <keir@xen.org>
Diffstat (limited to 'xen/arch/x86/x86_emulate')
-rw-r--r-- | xen/arch/x86/x86_emulate/x86_emulate.c | 84 |
1 files changed, 82 insertions, 2 deletions
diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c b/xen/arch/x86/x86_emulate/x86_emulate.c index 3222b61e37..d89a2f9ca5 100644 --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -176,7 +176,7 @@ static uint8_t twobyte_table[256] = { /* 0x08 - 0x0F */ ImplicitOps, ImplicitOps, 0, 0, 0, ImplicitOps|ModRM, 0, 0, /* 0x10 - 0x17 */ - 0, 0, 0, 0, 0, 0, 0, 0, + ImplicitOps|ModRM, ImplicitOps|ModRM, 0, 0, 0, 0, 0, 0, /* 0x18 - 0x1F */ ImplicitOps|ModRM, ImplicitOps|ModRM, ImplicitOps|ModRM, ImplicitOps|ModRM, ImplicitOps|ModRM, ImplicitOps|ModRM, ImplicitOps|ModRM, ImplicitOps|ModRM, @@ -184,7 +184,7 @@ static uint8_t twobyte_table[256] = { ImplicitOps|ModRM, ImplicitOps|ModRM, ImplicitOps|ModRM, ImplicitOps|ModRM, 0, 0, 0, 0, /* 0x28 - 0x2F */ - 0, 0, 0, 0, 0, 0, 0, 0, + ImplicitOps|ModRM, ImplicitOps|ModRM, 0, ImplicitOps|ModRM, 0, 0, 0, 0, /* 0x30 - 0x37 */ ImplicitOps, ImplicitOps, ImplicitOps, 0, ImplicitOps, ImplicitOps, 0, 0, @@ -273,6 +273,16 @@ enum vex_pfx { vex_f2 }; +#define VEX_PREFIX_DOUBLE_MASK 0x1 +#define VEX_PREFIX_SCALAR_MASK 0x2 + +static const uint8_t sse_prefix[] = { 0x66, 0xf3, 0xf2 }; + +#define SET_SSE_PREFIX(dst, vex_pfx) do { \ + if ( vex_pfx ) \ + (dst) = sse_prefix[(vex_pfx) - 1]; \ +} while (0) + union vex { uint8_t raw[2]; struct { @@ -3850,6 +3860,76 @@ x86_emulate( case 0x19 ... 0x1f: /* nop (amd-defined) */ break; + case 0x2b: /* {,v}movntp{s,d} xmm,m128 */ + /* vmovntp{s,d} ymm,m256 */ + fail_if(ea.type != OP_MEM); + /* fall through */ + case 0x28: /* {,v}movap{s,d} xmm/m128,xmm */ + /* vmovap{s,d} ymm/m256,ymm */ + case 0x29: /* {,v}movap{s,d} xmm,xmm/m128 */ + /* vmovap{s,d} ymm,ymm/m256 */ + fail_if(vex.pfx & VEX_PREFIX_SCALAR_MASK); + /* fall through */ + case 0x10: /* {,v}movup{s,d} xmm/m128,xmm */ + /* vmovup{s,d} ymm/m256,ymm */ + /* {,v}movss xmm/m32,xmm */ + /* {,v}movsd xmm/m64,xmm */ + case 0x11: /* {,v}movup{s,d} xmm,xmm/m128 */ + /* vmovup{s,d} ymm,ymm/m256 */ + /* {,v}movss xmm,xmm/m32 */ + /* {,v}movsd xmm,xmm/m64 */ + { + uint8_t stub[] = { 0x3e, 0x3e, 0x0f, b, modrm, 0xc3 }; + struct fpu_insn_ctxt fic = { .insn_bytes = sizeof(stub)-1 }; + + if ( vex.opcx == vex_none ) + { + if ( vex.pfx & VEX_PREFIX_DOUBLE_MASK ) + vcpu_must_have_sse2(); + else + vcpu_must_have_sse(); + ea.bytes = 16; + SET_SSE_PREFIX(stub[0], vex.pfx); + get_fpu(X86EMUL_FPU_xmm, &fic); + } + else + { + fail_if((vex.opcx != vex_0f) || + (vex.reg && ((ea.type == OP_MEM) || + !(vex.pfx & VEX_PREFIX_SCALAR_MASK)))); + vcpu_must_have_avx(); + get_fpu(X86EMUL_FPU_ymm, &fic); + ea.bytes = 16 << vex.l; + } + if ( vex.pfx & VEX_PREFIX_SCALAR_MASK ) + ea.bytes = vex.pfx & VEX_PREFIX_DOUBLE_MASK ? 8 : 4; + if ( ea.type == OP_MEM ) + { + /* XXX enable once there is ops->ea() or equivalent + generate_exception_if((b >= 0x28) && + (ops->ea(ea.mem.seg, ea.mem.off) + & (ea.bytes - 1)), EXC_GP, 0); */ + if ( !(b & 1) ) + rc = ops->read(ea.mem.seg, ea.mem.off+0, mmvalp, + ea.bytes, ctxt); + /* convert memory operand to (%rAX) */ + rex_prefix &= ~REX_B; + vex.b = 1; + stub[4] &= 0x38; + } + if ( !rc ) + { + copy_REX_VEX(stub, rex_prefix, vex); + asm volatile ( "call *%0" : : "r" (stub), "a" (mmvalp) + : "memory" ); + } + put_fpu(&fic); + if ( !rc && (b & 1) && (ea.type == OP_MEM) ) + rc = ops->write(ea.mem.seg, ea.mem.off, mmvalp, + ea.bytes, ctxt); + goto done; + } + case 0x20: /* mov cr,reg */ case 0x21: /* mov dr,reg */ case 0x22: /* mov reg,cr */ |