# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1208425614 -3600
# Node ID d178c5ee6822a269e365d206da74e9704f059fa1
# Parent a38a41de0800cefca755ffb600d6d5e96f084697
x86_emulate: Emulate MMX movq instructions.
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
xen/arch/x86/hvm/emulate.c | 19 +++++++-
xen/arch/x86/x86_emulate/x86_emulate.c | 77 ++++++++++++++++++++++++++-------
xen/arch/x86/x86_emulate/x86_emulate.h | 9 +++
3 files changed, 87 insertions(+), 18 deletions(-)
diff -r a38a41de0800 -r d178c5ee6822 xen/arch/x86/hvm/emulate.c
--- a/xen/arch/x86/hvm/emulate.c Wed Apr 16 16:42:47 2008 +0100
+++ b/xen/arch/x86/hvm/emulate.c Thu Apr 17 10:46:54 2008 +0100
@@ -674,16 +674,33 @@ static int hvmemul_inject_sw_interrupt(
return X86EMUL_OKAY;
}
-static void hvmemul_get_fpu(
+static int hvmemul_get_fpu(
void (*exception_callback)(void *, struct cpu_user_regs *),
void *exception_callback_arg,
+ enum x86_emulate_fpu_type type,
struct x86_emulate_ctxt *ctxt)
{
struct vcpu *curr = current;
+
+ switch ( type )
+ {
+ case X86EMUL_FPU_fpu:
+ break;
+ case X86EMUL_FPU_mmx:
+ if ( !cpu_has_mmx )
+ return X86EMUL_UNHANDLEABLE;
+ break;
+ default:
+ return X86EMUL_UNHANDLEABLE;
+ }
+
if ( !curr->fpu_dirtied )
hvm_funcs.fpu_dirty_intercept();
+
curr->arch.hvm_vcpu.fpu_exception_callback = exception_callback;
curr->arch.hvm_vcpu.fpu_exception_callback_arg = exception_callback_arg;
+
+ return X86EMUL_OKAY;
}
static void hvmemul_put_fpu(
diff -r a38a41de0800 -r d178c5ee6822 xen/arch/x86/x86_emulate/x86_emulate.c
--- a/xen/arch/x86/x86_emulate/x86_emulate.c Wed Apr 16 16:42:47 2008 +0100
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c Thu Apr 17 10:46:54 2008 +0100
@@ -195,9 +195,9 @@ static uint8_t twobyte_table[256] = {
/* 0x50 - 0x5F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x60 - 0x6F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM,
/* 0x70 - 0x7F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM,
/* 0x80 - 0x87 */
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
@@ -558,41 +558,48 @@ static void fpu_handle_exception(void *_
regs->eip += fic->insn_bytes;
}
+#define get_fpu(_type, _fic) \
+do{ (_fic)->exn_raised = 0; \
+ fail_if(ops->get_fpu == NULL); \
+ rc = ops->get_fpu(fpu_handle_exception, _fic, _type, ctxt); \
+ if ( rc ) goto done; \
+} while (0)
+#define put_fpu(_fic) \
+do{ \
+ if ( ops->put_fpu != NULL ) \
+ ops->put_fpu(ctxt); \
+ generate_exception_if((_fic)->exn_raised, EXC_MF, -1); \
+} while (0)
+
#define emulate_fpu_insn(_op) \
-do{ struct fpu_insn_ctxt fic = { 0 }; \
- fail_if(ops->get_fpu == NULL); \
- ops->get_fpu(fpu_handle_exception, &fic, ctxt); \
+do{ struct fpu_insn_ctxt fic; \
+ get_fpu(X86EMUL_FPU_fpu, &fic); \
asm volatile ( \
"movb $2f-1f,%0 \n" \
"1: " _op " \n" \
"2: \n" \
: "=m" (fic.insn_bytes) : : "memory" ); \
- ops->put_fpu(ctxt); \
- generate_exception_if(fic.exn_raised, EXC_MF, -1); \
+ put_fpu(&fic); \
} while (0)
#define emulate_fpu_insn_memdst(_op, _arg) \
-do{ struct fpu_insn_ctxt fic = { 0 }; \
- fail_if(ops->get_fpu == NULL); \
- ops->get_fpu(fpu_handle_exception, &fic, ctxt); \
+do{ struct fpu_insn_ctxt fic; \
+ get_fpu(X86EMUL_FPU_fpu, &fic); \
asm volatile ( \
"movb $2f-1f,%0 \n" \
"1: " _op " %1 \n" \
"2: \n" \
: "=m" (fic.insn_bytes), "=m" (_arg) \
: : "memory" ); \
- ops->put_fpu(ctxt); \
- generate_exception_if(fic.exn_raised, EXC_MF, -1); \
+ put_fpu(&fic); \
} while (0)
#define emulate_fpu_insn_stub(_bytes...) \
do{ uint8_t stub[] = { _bytes, 0xc3 }; \
struct fpu_insn_ctxt fic = { .insn_bytes = sizeof(stub)-1 }; \
- fail_if(ops->get_fpu == NULL); \
- ops->get_fpu(fpu_handle_exception, &fic, ctxt); \
+ get_fpu(X86EMUL_FPU_fpu, &fic); \
(*(void(*)(void))stub)(); \
- ops->put_fpu(ctxt); \
- generate_exception_if(fic.exn_raised, EXC_MF, -1); \
+ put_fpu(&fic); \
} while (0)
static unsigned long __get_rep_prefix(
@@ -3369,6 +3376,44 @@ x86_emulate(
break;
}
+ case 0x6f: /* movq mm/m64,mm */ {
+ uint8_t stub[] = { 0x0f, 0x6f, modrm, 0xc3 };
+ struct fpu_insn_ctxt fic = { .insn_bytes = sizeof(stub)-1 };
+ uint64_t val;
+ if ( ea.type == OP_MEM )
+ {
+ unsigned long lval, hval;
+ if ( (rc = ops->read(ea.mem.seg, ea.mem.off+0, &lval, 4, ctxt)) ||
+ (rc = ops->read(ea.mem.seg, ea.mem.off+4, &hval, 4, ctxt)) )
+ goto done;
+ val = ((uint64_t)hval << 32) | (uint32_t)lval;
+ stub[2] = modrm & 0x38; /* movq (%eax),%mmN */
+ }
+ get_fpu(X86EMUL_FPU_mmx, &fic);
+ asm volatile ( "call *%0" : : "r" (stub), "a" (&val) : "memory" );
+ put_fpu(&fic);
+ break;
+ }
+
+ case 0x7f: /* movq mm,mm/m64 */ {
+ uint8_t stub[] = { 0x0f, 0x7f, modrm, 0xc3 };
+ struct fpu_insn_ctxt fic = { .insn_bytes = sizeof(stub)-1 };
+ uint64_t val;
+ if ( ea.type == OP_MEM )
+ stub[2] = modrm & 0x38; /* movq %mmN,(%eax) */
+ get_fpu(X86EMUL_FPU_mmx, &fic);
+ asm volatile ( "call *%0" : : "r" (stub), "a" (&val) : "memory" );
+ put_fpu(&fic);
+ if ( ea.type == OP_MEM )
+ {
+ unsigned long lval = (uint32_t)val, hval = (uint32_t)(val >> 32);
+ if ( (rc = ops->write(ea.mem.seg, ea.mem.off+0, lval, 4, ctxt)) ||
+ (rc = ops->write(ea.mem.seg, ea.mem.off+4, hval, 4, ctxt)) )
+ goto done;
+ }
+ break;
+ }
+
case 0x80 ... 0x8f: /* jcc (near) */ {
int rel = (((op_bytes == 2) && !mode_64bit())
? (int32_t)insn_fetch_type(int16_t)
diff -r a38a41de0800 -r d178c5ee6822 xen/arch/x86/x86_emulate/x86_emulate.h
--- a/xen/arch/x86/x86_emulate/x86_emulate.h Wed Apr 16 16:42:47 2008 +0100
+++ b/xen/arch/x86/x86_emulate/x86_emulate.h Thu Apr 17 10:46:54 2008 +0100
@@ -95,6 +95,12 @@ struct segment_register {
/* (cmpxchg accessor): CMPXCHG failed. Maps to X86EMUL_RETRY in caller. */
#define X86EMUL_CMPXCHG_FAILED 3
+/* FPU sub-types which may be requested via ->get_fpu(). */
+enum x86_emulate_fpu_type {
+ X86EMUL_FPU_fpu, /* Standard FPU coprocessor instruction set */
+ X86EMUL_FPU_mmx /* MMX instruction set (%mm0-%mm7) */
+};
+
/*
* These operations represent the instruction emulator's interface to memory.
*
@@ -347,9 +353,10 @@ struct x86_emulate_ops
* @exn_callback: On any FPU or SIMD exception, pass control to
* (*exception_callback)(exception_callback_arg, regs).
*/
- void (*get_fpu)(
+ int (*get_fpu)(
void (*exception_callback)(void *, struct cpu_user_regs *),
void *exception_callback_arg,
+ enum x86_emulate_fpu_type type,
struct x86_emulate_ctxt *ctxt);
/* put_fpu: Relinquish the FPU. Unhook from FPU/SIMD exception handlers. */
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|