[PATCH] KVM: X86: Add mmx movq emulation

From: Joerg Roedel
Date: Fri May 04 2012 - 07:47:19 EST


Add support to the MMX versions of the movq instructions to
the instruction emulator. Also handle possible exceptions
they may cause.

Signed-off-by: Joerg Roedel <joerg.roedel@xxxxxxx>
---
arch/x86/include/asm/kvm_emulate.h | 2 +-
arch/x86/kvm/emulate.c | 155 +++++++++++++++++++++++++++++++++++-
2 files changed, 154 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index c222e1a..e4833f8 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -200,7 +200,7 @@ typedef u32 __attribute__((vector_size(16))) sse128_t;

/* Type, address-of, and value of an instruction's operand. */
struct operand {
- enum { OP_REG, OP_MEM, OP_IMM, OP_XMM, OP_NONE } type;
+ enum { OP_REG, OP_MEM, OP_IMM, OP_XMM, OP_MMX, OP_NONE } type;
unsigned int bytes;
union {
unsigned long orig_val;
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 8375622..d4bf50c 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -142,6 +142,7 @@
#define Src2FS (OpFS << Src2Shift)
#define Src2GS (OpGS << Src2Shift)
#define Src2Mask (OpMask << Src2Shift)
+#define Mmx (1ULL<<35)

#define X2(x...) x, x
#define X3(x...) X2(x), x
@@ -537,6 +538,11 @@ static int emulate_nm(struct x86_emulate_ctxt *ctxt)
return emulate_exception(ctxt, NM_VECTOR, 0, false);
}

+static int emulate_mf(struct x86_emulate_ctxt *ctxt)
+{
+ return emulate_exception(ctxt, MF_VECTOR, 0, false);
+}
+
static u16 get_segment_selector(struct x86_emulate_ctxt *ctxt, unsigned seg)
{
u16 selector;
@@ -859,6 +865,110 @@ static void write_sse_reg(struct x86_emulate_ctxt *ctxt, sse128_t *data,
ctxt->ops->put_fpu(ctxt);
}

+#define __READ_MMX_SAFE(mmxreg) \
+ asm volatile("2: movq %%" mmxreg ", %[d]\n\t" \
+ "xor %[err], %[err]\n\t" \
+ "1:\n\t" \
+ ".section .fixup,\"ax\"\n\t" \
+ "3: mov %[fault], %[err]; jmp 1b\n\t" \
+ ".previous\n\t" \
+ _ASM_EXTABLE(2b, 3b) \
+ : [err] "=r" (err), [d] "=m"(*data) \
+ : [fault] "i" (X86EMUL_PROPAGATE_FAULT));
+
+
+#define __WRITE_MMX_SAFE(mmxreg) \
+ asm volatile("2: movq %[d], %%" mmxreg "\n\t" \
+ " xor %[err], %[err]\n\t" \
+ "1:\n\t" \
+ ".section .fixup,\"ax\"\n\t" \
+ "3: mov %[fault], %[err]; jmp 1b\n\t" \
+ ".previous\n\t" \
+ _ASM_EXTABLE(2b, 3b) \
+ : [err] "=r" (err) \
+ : [d] "m"(*data), \
+ [fault] "i" (X86EMUL_PROPAGATE_FAULT));
+
+static int read_mmx_reg(struct x86_emulate_ctxt *ctxt, sse128_t *data, int reg)
+{
+ int err = X86EMUL_CONTINUE;
+
+ ctxt->ops->get_fpu(ctxt);
+ switch (reg) {
+ case 0:
+ __READ_MMX_SAFE("mm0");
+ break;
+ case 1:
+ __READ_MMX_SAFE("mm1");
+ break;
+ case 2:
+ __READ_MMX_SAFE("mm2");
+ break;
+ case 3:
+ __READ_MMX_SAFE("mm3");
+ break;
+ case 4:
+ __READ_MMX_SAFE("mm4");
+ break;
+ case 5:
+ __READ_MMX_SAFE("mm5");
+ break;
+ case 6:
+ __READ_MMX_SAFE("mm6");
+ break;
+ case 7:
+ __READ_MMX_SAFE("mm7");
+ break;
+ default:
+ BUG();
+ }
+ ctxt->ops->put_fpu(ctxt);
+
+ return err;
+}
+
+static int write_mmx_reg(struct x86_emulate_ctxt *ctxt, sse128_t *data,
+ int reg)
+{
+ int err = X86EMUL_CONTINUE;
+
+ ctxt->ops->get_fpu(ctxt);
+ switch (reg) {
+ case 0:
+ __WRITE_MMX_SAFE("mm0");
+ break;
+ case 1:
+ __WRITE_MMX_SAFE("mm1");
+ break;
+ case 2:
+ __WRITE_MMX_SAFE("mm2");
+ break;
+ case 3:
+ __WRITE_MMX_SAFE("mm3");
+ break;
+ case 4:
+ __WRITE_MMX_SAFE("mm4");
+ break;
+ case 5:
+ __WRITE_MMX_SAFE("mm5");
+ break;
+ case 6:
+ __WRITE_MMX_SAFE("mm6");
+ break;
+ case 7:
+ __WRITE_MMX_SAFE("mm7");
+ break;
+ default:
+ BUG();
+ }
+ ctxt->ops->put_fpu(ctxt);
+
+ return err;
+}
+
+#undef __READ_MMX_SAFE
+#undef __WRITE_MMX_SAFE
+
static void decode_register_operand(struct x86_emulate_ctxt *ctxt,
struct operand *op)
{
@@ -874,6 +984,11 @@ static void decode_register_operand(struct x86_emulate_ctxt *ctxt,
op->addr.xmm = reg;
read_sse_reg(ctxt, &op->vec_val, reg);
return;
+ } else if (ctxt->d & Mmx) {
+ op->type = OP_MMX;
+ op->bytes = 8;
+ op->addr.xmm = reg;
+ return;
}

op->type = OP_REG;
@@ -919,6 +1034,10 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt,
op->addr.xmm = ctxt->modrm_rm;
read_sse_reg(ctxt, &op->vec_val, ctxt->modrm_rm);
return rc;
+ } else if (ctxt->d & Mmx) {
+ op->type = OP_MMX;
+ op->bytes = 8;
+ op->addr.xmm = ctxt->modrm_rm;
}
fetch_register_operand(op);
return rc;
@@ -1387,6 +1506,19 @@ static int writeback(struct x86_emulate_ctxt *ctxt)
case OP_XMM:
write_sse_reg(ctxt, &ctxt->dst.vec_val, ctxt->dst.addr.xmm);
break;
+ case OP_MMX:
+ if (ctxt->dst.addr.xmm > 7) {
+ emulate_ud(ctxt);
+ return X86EMUL_PROPAGATE_FAULT;
+ }
+
+ rc = write_mmx_reg(ctxt, &ctxt->dst.vec_val, ctxt->dst.addr.xmm);
+
+ if (rc != X86EMUL_CONTINUE) {
+ emulate_mf(ctxt);
+ return rc;
+ }
+ break;
case OP_NONE:
/* no writeback */
break;
@@ -3415,7 +3547,7 @@ static struct opcode group11[] = {
};

static struct gprefix pfx_0f_6f_0f_7f = {
- N, N, N, I(Sse, em_movdqu),
+ I(Mmx, em_movdqu), N, N, I(Sse, em_movdqu),
};

static struct opcode opcode_table[256] = {
@@ -3960,6 +4092,8 @@ done_prefixes:

if (ctxt->d & Sse)
ctxt->op_bytes = 16;
+ else if (ctxt->d & Mmx)
+ ctxt->op_bytes = 8;

/* ModRM and SIB bytes. */
if (ctxt->d & ModRM) {
@@ -4061,7 +4195,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
goto done;
}

- if ((ctxt->d & Sse) && (ops->get_cr(ctxt, 0) & X86_CR0_TS)) {
+ if ((ctxt->d & (Sse | Mmx)) && (ops->get_cr(ctxt, 0) & X86_CR0_TS)) {
rc = emulate_nm(ctxt);
goto done;
}
@@ -4133,6 +4267,23 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
if (rc != X86EMUL_CONTINUE)
goto done;
}
+
+ if ((ctxt->d & Mmx) && (ctxt->src.type == OP_MMX)) {
+ unsigned reg = ctxt->src.addr.xmm;
+
+ if (reg > 7) {
+ emulate_ud(ctxt);
+ goto done;
+ }
+
+ rc = read_mmx_reg(ctxt, &ctxt->src.vec_val, reg);
+
+ if (rc != X86EMUL_CONTINUE) {
+ emulate_mf(ctxt);
+ goto done;
+ }
+ }
+
ctxt->dst.orig_val = ctxt->dst.val;

special_insn:
--
1.7.9.5


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/