]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - arch/x86/kvm/emulate.c
KVM: x86 emulator: implement IMUL REG, R/M, IMM (opcode 69)
[mv-sheeva.git] / arch / x86 / kvm / emulate.c
index 9e58f5054c396d4ac3e56c985e8d7b6eb330769a..55849c3d5d8c1fc64b50e7e531bd2ef2caebbd3c 100644 (file)
@@ -58,7 +58,6 @@
 #define DstMask     (7<<1)
 /* Source operand type. */
 #define SrcNone     (0<<4)     /* No source operand. */
-#define SrcImplicit (0<<4)     /* Source operand is implicit in the opcode. */
 #define SrcReg      (1<<4)     /* Register operand. */
 #define SrcMem      (2<<4)     /* Memory operand. */
 #define SrcMem16    (3<<4)     /* Memory operand (16-bit). */
@@ -96,6 +95,7 @@
 #define Src2CL      (1<<29)
 #define Src2ImmByte (2<<29)
 #define Src2One     (3<<29)
+#define Src2Imm     (4<<29)
 #define Src2Mask    (7<<29)
 
 #define X2(x...) x, x
@@ -2264,6 +2264,38 @@ static int em_ret_near_imm(struct x86_emulate_ctxt *ctxt)
        return X86EMUL_CONTINUE;
 }
 
+static int em_imul(struct x86_emulate_ctxt *ctxt)
+{
+       struct decode_cache *c = &ctxt->decode;
+
+       emulate_2op_SrcV_nobyte("imul", c->src, c->dst, ctxt->eflags);
+       return X86EMUL_CONTINUE;
+}
+
+static int em_imul_3op(struct x86_emulate_ctxt *ctxt)
+{
+       struct decode_cache *c = &ctxt->decode;
+
+       c->dst.val = c->src2.val;
+       return em_imul(ctxt);
+}
+
+static int em_rdtsc(struct x86_emulate_ctxt *ctxt)
+{
+       unsigned cpl = ctxt->ops->cpl(ctxt->vcpu);
+       struct decode_cache *c = &ctxt->decode;
+       u64 tsc = 0;
+
+       if (cpl > 0 && (ctxt->ops->get_cr(4, ctxt->vcpu) & X86_CR4_TSD)) {
+               emulate_gp(ctxt, 0);
+               return X86EMUL_PROPAGATE_FAULT;
+       }
+       ctxt->ops->get_msr(ctxt->vcpu, MSR_IA32_TSC, &tsc);
+       c->regs[VCPU_REGS_RAX] = (u32)tsc;
+       c->regs[VCPU_REGS_RDX] = tsc >> 32;
+       return X86EMUL_CONTINUE;
+}
+
 #define D(_y) { .flags = (_y) }
 #define N    D(0)
 #define G(_f, _g) { .flags = ((_f) | Group), .u.group = (_g) }
@@ -2370,8 +2402,10 @@ static struct opcode opcode_table[256] = {
        N, D(DstReg | SrcMem32 | ModRM | Mov) /* movsxd (x86/64) */ ,
        N, N, N, N,
        /* 0x68 - 0x6F */
-       I(SrcImm | Mov | Stack, em_push), N,
-       I(SrcImmByte | Mov | Stack, em_push), N,
+       I(SrcImm | Mov | Stack, em_push),
+       I(DstReg | SrcMem | ModRM | Src2Imm, em_imul_3op),
+       I(SrcImmByte | Mov | Stack, em_push),
+       I(DstReg | SrcMem | ModRM | Src2ImmByte, em_imul_3op),
        D(DstDI | ByteOp | Mov | String), D(DstDI | Mov | String), /* insb, insw/insd */
        D(SrcSI | ByteOp | ImplicitOps | String), D(SrcSI | ImplicitOps | String), /* outsb, outsw/outsd */
        /* 0x70 - 0x7F */
@@ -2418,7 +2452,7 @@ static struct opcode opcode_table[256] = {
        D(ImplicitOps), D(SrcImmByte), D(ImplicitOps | No64), D(ImplicitOps),
        /* 0xD0 - 0xD7 */
        D(ByteOp | DstMem | SrcOne | ModRM), D(DstMem | SrcOne | ModRM),
-       D(ByteOp | DstMem | SrcImplicit | ModRM), D(DstMem | SrcImplicit | ModRM),
+       D(ByteOp | DstMem | ModRM), D(DstMem | ModRM),
        N, N, N, N,
        /* 0xD8 - 0xDF */
        N, N, N, N, N, N, N, N,
@@ -2453,7 +2487,8 @@ static struct opcode twobyte_table[256] = {
        N, N, N, N,
        N, N, N, N, N, N, N, N,
        /* 0x30 - 0x3F */
-       D(ImplicitOps | Priv), N, D(ImplicitOps | Priv), N,
+       D(ImplicitOps | Priv), I(ImplicitOps, em_rdtsc),
+       D(ImplicitOps | Priv), N,
        D(ImplicitOps), D(ImplicitOps | Priv), N, N,
        N, N, N, N, N, N, N, N,
        /* 0x40 - 0x4F */
@@ -2478,7 +2513,7 @@ static struct opcode twobyte_table[256] = {
        N, D(DstMem | SrcReg | ModRM | BitOp | Lock),
        D(DstMem | SrcReg | Src2ImmByte | ModRM),
        D(DstMem | SrcReg | Src2CL | ModRM),
-       D(ModRM), N,
+       D(ModRM), I(DstReg | SrcMem | ModRM, em_imul),
        /* 0xB0 - 0xB7 */
        D(ByteOp | DstMem | SrcReg | ModRM | Lock), D(DstMem | SrcReg | ModRM | Lock),
        N, D(DstMem | SrcReg | ModRM | BitOp | Lock),
@@ -2508,6 +2543,55 @@ static struct opcode twobyte_table[256] = {
 #undef GD
 #undef I
 
+static unsigned imm_size(struct decode_cache *c)
+{
+       unsigned size;
+
+       size = (c->d & ByteOp) ? 1 : c->op_bytes;
+       if (size == 8)
+               size = 4;
+       return size;
+}
+
+static int decode_imm(struct x86_emulate_ctxt *ctxt, struct operand *op,
+                     unsigned size, bool sign_extension)
+{
+       struct decode_cache *c = &ctxt->decode;
+       struct x86_emulate_ops *ops = ctxt->ops;
+       int rc = X86EMUL_CONTINUE;
+
+       op->type = OP_IMM;
+       op->bytes = size;
+       op->addr.mem = c->eip;
+       /* NB. Immediates are sign-extended as necessary. */
+       switch (op->bytes) {
+       case 1:
+               op->val = insn_fetch(s8, 1, c->eip);
+               break;
+       case 2:
+               op->val = insn_fetch(s16, 2, c->eip);
+               break;
+       case 4:
+               op->val = insn_fetch(s32, 4, c->eip);
+               break;
+       }
+       if (!sign_extension) {
+               switch (op->bytes) {
+               case 1:
+                       op->val &= 0xff;
+                       break;
+               case 2:
+                       op->val &= 0xffff;
+                       break;
+               case 4:
+                       op->val &= 0xffffffff;
+                       break;
+               }
+       }
+done:
+       return rc;
+}
+
 int
 x86_decode_insn(struct x86_emulate_ctxt *ctxt)
 {
@@ -2697,52 +2781,19 @@ done_prefixes:
                c->src = memop;
                break;
        case SrcImmU16:
-               c->src.bytes = 2;
-               goto srcimm;
+               rc = decode_imm(ctxt, &c->src, 2, false);
+               break;
        case SrcImm:
+               rc = decode_imm(ctxt, &c->src, imm_size(c), true);
+               break;
        case SrcImmU:
-               c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-               if (c->src.bytes == 8)
-                       c->src.bytes = 4;
-       srcimm:
-               c->src.type = OP_IMM;
-               c->src.addr.mem = c->eip;
-               /* NB. Immediates are sign-extended as necessary. */
-               switch (c->src.bytes) {
-               case 1:
-                       c->src.val = insn_fetch(s8, 1, c->eip);
-                       break;
-               case 2:
-                       c->src.val = insn_fetch(s16, 2, c->eip);
-                       break;
-               case 4:
-                       c->src.val = insn_fetch(s32, 4, c->eip);
-                       break;
-               }
-               if ((c->d & SrcMask) == SrcImmU
-                   || (c->d & SrcMask) == SrcImmU16) {
-                       switch (c->src.bytes) {
-                       case 1:
-                               c->src.val &= 0xff;
-                               break;
-                       case 2:
-                               c->src.val &= 0xffff;
-                               break;
-                       case 4:
-                               c->src.val &= 0xffffffff;
-                               break;
-                       }
-               }
+               rc = decode_imm(ctxt, &c->src, imm_size(c), false);
                break;
        case SrcImmByte:
+               rc = decode_imm(ctxt, &c->src, 1, true);
+               break;
        case SrcImmUByte:
-               c->src.type = OP_IMM;
-               c->src.addr.mem = c->eip;
-               c->src.bytes = 1;
-               if ((c->d & SrcMask) == SrcImmByte)
-                       c->src.val = insn_fetch(s8, 1, c->eip);
-               else
-                       c->src.val = insn_fetch(u8, 1, c->eip);
+               rc = decode_imm(ctxt, &c->src, 1, false);
                break;
        case SrcAcc:
                c->src.type = OP_REG;
@@ -2774,6 +2825,9 @@ done_prefixes:
                break;
        }
 
+       if (rc != X86EMUL_CONTINUE)
+               goto done;
+
        /*
         * Decode and fetch the second source operand: register, memory
         * or immediate.
@@ -2786,17 +2840,20 @@ done_prefixes:
                c->src2.val = c->regs[VCPU_REGS_RCX] & 0x8;
                break;
        case Src2ImmByte:
-               c->src2.type = OP_IMM;
-               c->src2.addr.mem = c->eip;
-               c->src2.bytes = 1;
-               c->src2.val = insn_fetch(u8, 1, c->eip);
+               rc = decode_imm(ctxt, &c->src2, 1, true);
                break;
        case Src2One:
                c->src2.bytes = 1;
                c->src2.val = 1;
                break;
+       case Src2Imm:
+               rc = decode_imm(ctxt, &c->src2, imm_size(c), true);
+               break;
        }
 
+       if (rc != X86EMUL_CONTINUE)
+               goto done;
+
        /* Decode and fetch the destination operand: register or memory. */
        switch (c->d & DstMask) {
        case DstReg: