* [PATCH 0/2] Emulate MMX MOVQ @ 2012-03-21 18:40 Avi Kivity 2012-03-21 18:40 ` [PATCH 1/2] KVM: x86 emulator: MMX support Avi Kivity 2012-03-21 18:40 ` [PATCH 2/2] KVM: x86 emulator: implement MMX MOVQ (opcodes 0f 6f, 0f 7f) Avi Kivity 0 siblings, 2 replies; 5+ messages in thread From: Avi Kivity @ 2012-03-21 18:40 UTC (permalink / raw) To: kvm This patchset emulates two instructions: MOVQ mm, mm/m64 MOVQ mm/m64, mm Needed by https://bugzilla.kernel.org/show_bug.cgi?id=42779. However it seems to fail sometimes in my unit test, generating a math fault at the fwait instruction (which is duly trapped). Hints appreciated. Avi Kivity (2): KVM: x86 emulator: MMX support KVM: x86 emulator: implement MMX MOVQ (opcodes 0f 6f, 0f 7f) arch/x86/include/asm/kvm_emulate.h | 4 +- arch/x86/kvm/emulate.c | 98 ++++++++++++++++++++++++++++++++++-- 2 files changed, 96 insertions(+), 6 deletions(-) -- 1.7.9 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/2] KVM: x86 emulator: MMX support 2012-03-21 18:40 [PATCH 0/2] Emulate MMX MOVQ Avi Kivity @ 2012-03-21 18:40 ` Avi Kivity 2012-03-21 21:32 ` Avi Kivity 2012-03-21 18:40 ` [PATCH 2/2] KVM: x86 emulator: implement MMX MOVQ (opcodes 0f 6f, 0f 7f) Avi Kivity 1 sibling, 1 reply; 5+ messages in thread From: Avi Kivity @ 2012-03-21 18:40 UTC (permalink / raw) To: kvm General support for the MMX instruction set. Special care is taken to trap pending x87 exceptions so that they are properly reflected to the guest. Signed-off-by: Avi Kivity <avi@redhat.com> --- arch/x86/include/asm/kvm_emulate.h | 4 +- arch/x86/kvm/emulate.c | 90 ++++++++++++++++++++++++++++++++++-- 2 files changed, 89 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index c222e1a..1ac46c22 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_MM, OP_NONE } type; unsigned int bytes; union { unsigned long orig_val; @@ -213,12 +213,14 @@ struct operand { unsigned seg; } mem; unsigned xmm; + unsigned mm; } addr; union { unsigned long val; u64 val64; char valptr[sizeof(unsigned long) + 2]; sse128_t vec_val; + u64 mm_val; }; }; diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 8375622..19aec76 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<<40) /* MMX Vector instruction */ #define X2(x...) x, x #define X3(x...) X2(x), x @@ -859,6 +860,40 @@ static void write_sse_reg(struct x86_emulate_ctxt *ctxt, sse128_t *data, ctxt->ops->put_fpu(ctxt); } +static void read_mmx_reg(struct x86_emulate_ctxt *ctxt, u64 *data, int reg) +{ + ctxt->ops->get_fpu(ctxt); + switch (reg) { + case 0: asm("movq %%mm0, %0" : "=m"(*data)); break; + case 1: asm("movq %%mm1, %0" : "=m"(*data)); break; + case 2: asm("movq %%mm2, %0" : "=m"(*data)); break; + case 3: asm("movq %%mm3, %0" : "=m"(*data)); break; + case 4: asm("movq %%mm4, %0" : "=m"(*data)); break; + case 5: asm("movq %%mm5, %0" : "=m"(*data)); break; + case 6: asm("movq %%mm6, %0" : "=m"(*data)); break; + case 7: asm("movq %%mm7, %0" : "=m"(*data)); break; + default: BUG(); + } + ctxt->ops->put_fpu(ctxt); +} + +static void write_mmx_reg(struct x86_emulate_ctxt *ctxt, u64 *data, int reg) +{ + ctxt->ops->get_fpu(ctxt); + switch (reg) { + case 0: asm("movq %0, %%mm0" : : "m"(*data)); break; + case 1: asm("movq %0, %%mm1" : : "m"(*data)); break; + case 2: asm("movq %0, %%mm2" : : "m"(*data)); break; + case 3: asm("movq %0, %%mm3" : : "m"(*data)); break; + case 4: asm("movq %0, %%mm4" : : "m"(*data)); break; + case 5: asm("movq %0, %%mm5" : : "m"(*data)); break; + case 6: asm("movq %0, %%mm6" : : "m"(*data)); break; + case 7: asm("movq %0, %%mm7" : : "m"(*data)); break; + default: BUG(); + } + ctxt->ops->put_fpu(ctxt); +} + static void decode_register_operand(struct x86_emulate_ctxt *ctxt, struct operand *op) { @@ -875,6 +910,14 @@ static void decode_register_operand(struct x86_emulate_ctxt *ctxt, read_sse_reg(ctxt, &op->vec_val, reg); return; } + if (ctxt->d & Mmx) { + reg &= 7; + op->type = OP_MM; + op->bytes = 8; + op->addr.mm = reg; + read_mmx_reg(ctxt, &op->mm_val, reg); + return; + } op->type = OP_REG; if (ctxt->d & ByteOp) { @@ -920,6 +963,13 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt, read_sse_reg(ctxt, &op->vec_val, ctxt->modrm_rm); return rc; } + if (ctxt->d & Mmx) { + op->type = OP_MM; + op->bytes = 8; + op->addr.xmm = ctxt->modrm_rm & 7; + read_mmx_reg(ctxt, &op->mm_val, ctxt->modrm_rm); + return rc; + } fetch_register_operand(op); return rc; } @@ -1387,6 +1437,9 @@ 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_MM: + write_mmx_reg(ctxt, &ctxt->dst.mm_val, ctxt->dst.addr.mm); + break; case OP_NONE: /* no writeback */ break; @@ -3960,6 +4013,8 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) 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) { @@ -4030,6 +4085,28 @@ static bool string_insn_completed(struct x86_emulate_ctxt *ctxt) return false; } +static int flush_pending_x87_faults(struct x86_emulate_ctxt *ctxt) +{ + bool fault = false; + + ctxt->ops->get_fpu(ctxt); + asm volatile("1: fwait \n\t" + "2: \n\t" + ".pushsection .fixup,\"ax\" \n\t" + "3: \n\t" + "movb $1, %[fault] \n\t" + "jmp 2b \n\t" + ".popsection \n\t" + _ASM_EXTABLE(1b, 3b) + : [fault]"=rm"(fault)); + ctxt->ops->put_fpu(ctxt); + + if (unlikely(fault)) + return emulate_exception(ctxt, MF_VECTOR, 0, false); + + return X86EMUL_CONTINUE; +} + int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) { struct x86_emulate_ops *ops = ctxt->ops; @@ -4054,18 +4131,23 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) goto done; } - if ((ctxt->d & Sse) - && ((ops->get_cr(ctxt, 0) & X86_CR0_EM) - || !(ops->get_cr(ctxt, 4) & X86_CR4_OSFXSR))) { + if ((ctxt->d & (Sse|Mmx)) && ((ops->get_cr(ctxt, 0) & X86_CR0_EM)) + || (ctxt->d & Sse) && !(ops->get_cr(ctxt, 4) & X86_CR4_OSFXSR)) { rc = emulate_ud(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; } + if (ctxt->d & Mmx) { + rc = flush_pending_x87_faults(ctxt); + if (rc != X86EMUL_CONTINUE) + return rc; + } + if (unlikely(ctxt->guest_mode) && ctxt->intercept) { rc = emulator_check_intercept(ctxt, ctxt->intercept, X86_ICPT_PRE_EXCEPT); -- 1.7.9 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] KVM: x86 emulator: MMX support 2012-03-21 18:40 ` [PATCH 1/2] KVM: x86 emulator: MMX support Avi Kivity @ 2012-03-21 21:32 ` Avi Kivity 0 siblings, 0 replies; 5+ messages in thread From: Avi Kivity @ 2012-03-21 21:32 UTC (permalink / raw) To: kvm On 03/21/2012 08:40 PM, Avi Kivity wrote: > > +static int flush_pending_x87_faults(struct x86_emulate_ctxt *ctxt) > +{ > + bool fault = false; > + > + ctxt->ops->get_fpu(ctxt); > + asm volatile("1: fwait \n\t" > + "2: \n\t" > + ".pushsection .fixup,\"ax\" \n\t" > + "3: \n\t" > + "movb $1, %[fault] \n\t" > + "jmp 2b \n\t" > + ".popsection \n\t" > + _ASM_EXTABLE(1b, 3b) > + : [fault]"=rm"(fault)); > "=" tells gcc that the asm section unconditionally writes 'fault', so it skips the initialization. Use "+" instead. -- I have a truly marvellous patch that fixes the bug which this signature is too narrow to contain. ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 2/2] KVM: x86 emulator: implement MMX MOVQ (opcodes 0f 6f, 0f 7f) 2012-03-21 18:40 [PATCH 0/2] Emulate MMX MOVQ Avi Kivity 2012-03-21 18:40 ` [PATCH 1/2] KVM: x86 emulator: MMX support Avi Kivity @ 2012-03-21 18:40 ` Avi Kivity 1 sibling, 0 replies; 5+ messages in thread From: Avi Kivity @ 2012-03-21 18:40 UTC (permalink / raw) To: kvm Needed by some framebuffer drivers. See https://bugzilla.kernel.org/show_bug.cgi?id=42779 Signed-off-by: Avi Kivity <avi@redhat.com> --- arch/x86/kvm/emulate.c | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 19aec76..5997513 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -2929,6 +2929,12 @@ static int em_movdqu(struct x86_emulate_ctxt *ctxt) return X86EMUL_CONTINUE; } +static int em_movq(struct x86_emulate_ctxt *ctxt) +{ + ctxt->dst.mm_val = ctxt->src.mm_val; + return X86EMUL_CONTINUE; +} + static int em_invlpg(struct x86_emulate_ctxt *ctxt) { int rc; @@ -3468,7 +3474,7 @@ static int check_perm_out(struct x86_emulate_ctxt *ctxt) }; static struct gprefix pfx_0f_6f_0f_7f = { - N, N, N, I(Sse, em_movdqu), + I(Mmx, em_movq), N, N, I(Sse, em_movdqu), }; static struct opcode opcode_table[256] = { -- 1.7.9 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 0/2] Emulate MMX MOVQ @ 2012-03-22 10:56 Avi Kivity 2012-03-22 10:56 ` [PATCH 1/2] KVM: x86 emulator: MMX support Avi Kivity 0 siblings, 1 reply; 5+ messages in thread From: Avi Kivity @ 2012-03-22 10:56 UTC (permalink / raw) To: kvm, Marcelo Tosatti This patchset emulates two instructions: MOVQ mm, mm/m64 MOVQ mm/m64, mm Needed by https://bugzilla.kernel.org/show_bug.cgi?id=42779. Changes from v1: - fix spurious traps propgated into the guest - delay loading mmx register state until after we're sure it won't trap Avi Kivity (2): KVM: x86 emulator: MMX support KVM: x86 emulator: implement MMX MOVQ (opcodes 0f 6f, 0f 7f) arch/x86/include/asm/kvm_emulate.h | 4 +- arch/x86/kvm/emulate.c | 111 ++++++++++++++++++++++++++++++++++-- 2 files changed, 109 insertions(+), 6 deletions(-) -- 1.7.9 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/2] KVM: x86 emulator: MMX support 2012-03-22 10:56 [PATCH 0/2] Emulate MMX MOVQ Avi Kivity @ 2012-03-22 10:56 ` Avi Kivity 0 siblings, 0 replies; 5+ messages in thread From: Avi Kivity @ 2012-03-22 10:56 UTC (permalink / raw) To: kvm, Marcelo Tosatti General support for the MMX instruction set. Special care is taken to trap pending x87 exceptions so that they are properly reflected to the guest. Signed-off-by: Avi Kivity <avi@redhat.com> --- arch/x86/include/asm/kvm_emulate.h | 4 +- arch/x86/kvm/emulate.c | 103 ++++++++++++++++++++++++++++++++++-- 2 files changed, 102 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index c222e1a..1ac46c22 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_MM, OP_NONE } type; unsigned int bytes; union { unsigned long orig_val; @@ -213,12 +213,14 @@ struct operand { unsigned seg; } mem; unsigned xmm; + unsigned mm; } addr; union { unsigned long val; u64 val64; char valptr[sizeof(unsigned long) + 2]; sse128_t vec_val; + u64 mm_val; }; }; diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 8375622..f87d74e 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<<40) /* MMX Vector instruction */ #define X2(x...) x, x #define X3(x...) X2(x), x @@ -859,6 +860,40 @@ static void write_sse_reg(struct x86_emulate_ctxt *ctxt, sse128_t *data, ctxt->ops->put_fpu(ctxt); } +static void read_mmx_reg(struct x86_emulate_ctxt *ctxt, u64 *data, int reg) +{ + ctxt->ops->get_fpu(ctxt); + switch (reg) { + case 0: asm("movq %%mm0, %0" : "=m"(*data)); break; + case 1: asm("movq %%mm1, %0" : "=m"(*data)); break; + case 2: asm("movq %%mm2, %0" : "=m"(*data)); break; + case 3: asm("movq %%mm3, %0" : "=m"(*data)); break; + case 4: asm("movq %%mm4, %0" : "=m"(*data)); break; + case 5: asm("movq %%mm5, %0" : "=m"(*data)); break; + case 6: asm("movq %%mm6, %0" : "=m"(*data)); break; + case 7: asm("movq %%mm7, %0" : "=m"(*data)); break; + default: BUG(); + } + ctxt->ops->put_fpu(ctxt); +} + +static void write_mmx_reg(struct x86_emulate_ctxt *ctxt, u64 *data, int reg) +{ + ctxt->ops->get_fpu(ctxt); + switch (reg) { + case 0: asm("movq %0, %%mm0" : : "m"(*data)); break; + case 1: asm("movq %0, %%mm1" : : "m"(*data)); break; + case 2: asm("movq %0, %%mm2" : : "m"(*data)); break; + case 3: asm("movq %0, %%mm3" : : "m"(*data)); break; + case 4: asm("movq %0, %%mm4" : : "m"(*data)); break; + case 5: asm("movq %0, %%mm5" : : "m"(*data)); break; + case 6: asm("movq %0, %%mm6" : : "m"(*data)); break; + case 7: asm("movq %0, %%mm7" : : "m"(*data)); break; + default: BUG(); + } + ctxt->ops->put_fpu(ctxt); +} + static void decode_register_operand(struct x86_emulate_ctxt *ctxt, struct operand *op) { @@ -875,6 +910,13 @@ static void decode_register_operand(struct x86_emulate_ctxt *ctxt, read_sse_reg(ctxt, &op->vec_val, reg); return; } + if (ctxt->d & Mmx) { + reg &= 7; + op->type = OP_MM; + op->bytes = 8; + op->addr.mm = reg; + return; + } op->type = OP_REG; if (ctxt->d & ByteOp) { @@ -920,6 +962,12 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt, read_sse_reg(ctxt, &op->vec_val, ctxt->modrm_rm); return rc; } + if (ctxt->d & Mmx) { + op->type = OP_MM; + op->bytes = 8; + op->addr.xmm = ctxt->modrm_rm & 7; + return rc; + } fetch_register_operand(op); return rc; } @@ -1387,6 +1435,9 @@ 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_MM: + write_mmx_reg(ctxt, &ctxt->dst.mm_val, ctxt->dst.addr.mm); + break; case OP_NONE: /* no writeback */ break; @@ -3960,6 +4011,8 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) 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) { @@ -4030,6 +4083,35 @@ static bool string_insn_completed(struct x86_emulate_ctxt *ctxt) return false; } +static int flush_pending_x87_faults(struct x86_emulate_ctxt *ctxt) +{ + bool fault = false; + + ctxt->ops->get_fpu(ctxt); + asm volatile("1: fwait \n\t" + "2: \n\t" + ".pushsection .fixup,\"ax\" \n\t" + "3: \n\t" + "movb $1, %[fault] \n\t" + "jmp 2b \n\t" + ".popsection \n\t" + _ASM_EXTABLE(1b, 3b) + : [fault]"+rm"(fault)); + ctxt->ops->put_fpu(ctxt); + + if (unlikely(fault)) + return emulate_exception(ctxt, MF_VECTOR, 0, false); + + return X86EMUL_CONTINUE; +} + +static void fetch_possible_mmx_operand(struct x86_emulate_ctxt *ctxt, + struct operand *op) +{ + if (op->type == OP_MM) + read_mmx_reg(ctxt, &op->mm_val, op->addr.mm); +} + int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) { struct x86_emulate_ops *ops = ctxt->ops; @@ -4054,18 +4136,31 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) goto done; } - if ((ctxt->d & Sse) - && ((ops->get_cr(ctxt, 0) & X86_CR0_EM) - || !(ops->get_cr(ctxt, 4) & X86_CR4_OSFXSR))) { + if (((ctxt->d & (Sse|Mmx)) && ((ops->get_cr(ctxt, 0) & X86_CR0_EM))) + || ((ctxt->d & Sse) && !(ops->get_cr(ctxt, 4) & X86_CR4_OSFXSR))) { rc = emulate_ud(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; } + if (ctxt->d & Mmx) { + rc = flush_pending_x87_faults(ctxt); + if (rc != X86EMUL_CONTINUE) + return rc; + /* + * Now that we know the fpu is exception safe, we can fetch + * operands from it. + */ + fetch_possible_mmx_operand(ctxt, &ctxt->src); + fetch_possible_mmx_operand(ctxt, &ctxt->src2); + if (!(ctxt->d & Mov)) + fetch_possible_mmx_operand(ctxt, &ctxt->dst); + } + if (unlikely(ctxt->guest_mode) && ctxt->intercept) { rc = emulator_check_intercept(ctxt, ctxt->intercept, X86_ICPT_PRE_EXCEPT); -- 1.7.9 ^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2012-03-22 10:57 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2012-03-21 18:40 [PATCH 0/2] Emulate MMX MOVQ Avi Kivity 2012-03-21 18:40 ` [PATCH 1/2] KVM: x86 emulator: MMX support Avi Kivity 2012-03-21 21:32 ` Avi Kivity 2012-03-21 18:40 ` [PATCH 2/2] KVM: x86 emulator: implement MMX MOVQ (opcodes 0f 6f, 0f 7f) Avi Kivity -- strict thread matches above, loose matches on Subject: below -- 2012-03-22 10:56 [PATCH 0/2] Emulate MMX MOVQ Avi Kivity 2012-03-22 10:56 ` [PATCH 1/2] KVM: x86 emulator: MMX support Avi Kivity
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox