KVM: x86 emulator: Add unary mul, imul, div, and idiv instructions
authorMohammed Gamal <m.gamal005@gmail.com>
Sun, 8 Aug 2010 18:11:37 +0000 (21:11 +0300)
committerAvi Kivity <avi@redhat.com>
Sun, 24 Oct 2010 08:51:04 +0000 (10:51 +0200)
This adds unary mul, imul, div, and idiv instructions (group 3 r/m 4-7).

Signed-off-by: Mohammed Gamal <m.gamal005@gmail.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
arch/x86/kvm/emulate.c

index a9b2b9e6a3f059a522c2dd7875214bbde5444677..f0415eab6591cd6704a49262af9ec9f970d01a37 100644 (file)
@@ -315,6 +315,31 @@ struct group_dual {
                }                                                       \
        } while (0)
 
+#define __emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags, _suffix)         \
+       do {                                                            \
+               unsigned long _tmp;                                     \
+                                                                       \
+               __asm__ __volatile__ (                                  \
+                       _PRE_EFLAGS("0", "4", "1")                      \
+                       _op _suffix " %5; "                             \
+                       _POST_EFLAGS("0", "4", "1")                     \
+                       : "=m" (_eflags), "=&r" (_tmp),                 \
+                         "+a" (_rax), "+d" (_rdx)                      \
+                       : "i" (EFLAGS_MASK), "m" ((_src).val),          \
+                         "a" (_rax), "d" (_rdx));                      \
+       } while (0)
+
+/* instruction has only one source operand, destination is implicit (e.g. mul, div, imul, idiv) */
+#define emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags)                    \
+       do {                                                                    \
+               switch((_src).bytes) {                                          \
+               case 1: __emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags, "b"); break; \
+               case 2: __emulate_1op_rax_rdx(_op, _src, _rax, _rdx,  _eflags, "w"); break; \
+               case 4: __emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags, "l"); break; \
+               case 8: ON64(__emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags, "q")); break; \
+               }                                                       \
+       } while (0)
+
 /* Fetch next part of the instruction being emulated. */
 #define insn_fetch(_type, _size, _eip)                                  \
 ({     unsigned long _x;                                               \
@@ -1373,6 +1398,8 @@ static inline int emulate_grp3(struct x86_emulate_ctxt *ctxt,
                               struct x86_emulate_ops *ops)
 {
        struct decode_cache *c = &ctxt->decode;
+       unsigned long *rax = &c->regs[VCPU_REGS_RAX];
+       unsigned long *rdx = &c->regs[VCPU_REGS_RDX];
 
        switch (c->modrm_reg) {
        case 0 ... 1:   /* test */
@@ -1384,6 +1411,18 @@ static inline int emulate_grp3(struct x86_emulate_ctxt *ctxt,
        case 3: /* neg */
                emulate_1op("neg", c->dst, ctxt->eflags);
                break;
+       case 4: /* mul */
+               emulate_1op_rax_rdx("mul", c->src, *rax, *rdx, ctxt->eflags);
+               break;
+       case 5: /* imul */
+               emulate_1op_rax_rdx("imul", c->src, *rax, *rdx, ctxt->eflags);
+               break;
+       case 6: /* div */
+               emulate_1op_rax_rdx("div", c->src, *rax, *rdx, ctxt->eflags);
+               break;
+       case 7: /* idiv */
+               emulate_1op_rax_rdx("idiv", c->src, *rax, *rdx, ctxt->eflags);
+               break;
        default:
                return 0;
        }
@@ -2138,7 +2177,7 @@ static struct opcode group1A[] = {
 static struct opcode group3[] = {
        D(DstMem | SrcImm | ModRM), D(DstMem | SrcImm | ModRM),
        D(DstMem | SrcNone | ModRM | Lock), D(DstMem | SrcNone | ModRM | Lock),
-       X4(D(Undefined)),
+       X4(D(SrcMem | ModRM)),
 };
 
 static struct opcode group4[] = {