KVM: x86 emulator: add decoding of X,Y parameters from Intel SDM
authorGleb Natapov <gleb@redhat.com>
Thu, 18 Mar 2010 13:20:21 +0000 (15:20 +0200)
committerAvi Kivity <avi@redhat.com>
Mon, 17 May 2010 09:16:21 +0000 (12:16 +0300)
Add decoding of X,Y parameters from Intel SDM which are used by string
instruction to specify source and destination. Use this new decoding
to implement movs, cmps, stos, lods in a generic way.

Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
arch/x86/kvm/emulate.c

index 0eed683..3b32270 100644 (file)
@@ -51,6 +51,7 @@
 #define DstReg      (2<<1)     /* Register operand. */
 #define DstMem      (3<<1)     /* Memory operand. */
 #define DstAcc      (4<<1)      /* Destination Accumulator */
+#define DstDI       (5<<1)     /* Destination is in ES:(E)DI */
 #define DstMask     (7<<1)
 /* Source operand type. */
 #define SrcNone     (0<<4)     /* No source operand. */
@@ -64,6 +65,7 @@
 #define SrcOne      (7<<4)     /* Implied '1' */
 #define SrcImmUByte (8<<4)      /* 8-bit unsigned immediate operand. */
 #define SrcImmU     (9<<4)      /* Immediate operand, unsigned */
+#define SrcSI       (0xa<<4)   /* Source is in the DS:RSI */
 #define SrcMask     (0xf<<4)
 /* Generic ModRM decode. */
 #define ModRM       (1<<8)
@@ -177,12 +179,12 @@ static u32 opcode_table[256] = {
        /* 0xA0 - 0xA7 */
        ByteOp | DstReg | SrcMem | Mov | MemAbs, DstReg | SrcMem | Mov | MemAbs,
        ByteOp | DstMem | SrcReg | Mov | MemAbs, DstMem | SrcReg | Mov | MemAbs,
-       ByteOp | ImplicitOps | Mov | String, ImplicitOps | Mov | String,
-       ByteOp | ImplicitOps | String, ImplicitOps | String,
+       ByteOp | SrcSI | DstDI | Mov | String, SrcSI | DstDI | Mov | String,
+       ByteOp | SrcSI | DstDI | String, SrcSI | DstDI | String,
        /* 0xA8 - 0xAF */
-       0, 0, ByteOp | ImplicitOps | Mov | String, ImplicitOps | Mov | String,
-       ByteOp | ImplicitOps | Mov | String, ImplicitOps | Mov | String,
-       ByteOp | ImplicitOps | String, ImplicitOps | String,
+       0, 0, ByteOp | DstDI | Mov | String, DstDI | Mov | String,
+       ByteOp | SrcSI | DstAcc | Mov | String, SrcSI | DstAcc | Mov | String,
+       ByteOp | DstDI | String, DstDI | String,
        /* 0xB0 - 0xB7 */
        ByteOp | DstReg | SrcImm | Mov, ByteOp | DstReg | SrcImm | Mov,
        ByteOp | DstReg | SrcImm | Mov, ByteOp | DstReg | SrcImm | Mov,
@@ -1145,6 +1147,14 @@ done_prefixes:
                c->src.bytes = 1;
                c->src.val = 1;
                break;
+       case SrcSI:
+               c->src.type = OP_MEM;
+               c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+               c->src.ptr = (unsigned long *)
+                       register_address(c,  seg_override_base(ctxt, c),
+                                        c->regs[VCPU_REGS_RSI]);
+               c->src.val = 0;
+               break;
        }
 
        /*
@@ -1230,6 +1240,14 @@ done_prefixes:
                }
                c->dst.orig_val = c->dst.val;
                break;
+       case DstDI:
+               c->dst.type = OP_MEM;
+               c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+               c->dst.ptr = (unsigned long *)
+                       register_address(c, es_base(ctxt),
+                                        c->regs[VCPU_REGS_RDI]);
+               c->dst.val = 0;
+               break;
        }
 
 done:
@@ -2392,6 +2410,16 @@ int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
        return rc;
 }
 
+static void string_addr_inc(struct x86_emulate_ctxt *ctxt, unsigned long base,
+                           int reg, unsigned long **ptr)
+{
+       struct decode_cache *c = &ctxt->decode;
+       int df = (ctxt->eflags & EFLG_DF) ? -1 : 1;
+
+       register_address_increment(c, &c->regs[reg], df * c->src.bytes);
+       *ptr = (unsigned long *)register_address(c,  base, c->regs[reg]);
+}
+
 int
 x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
 {
@@ -2754,89 +2782,16 @@ special_insn:
                c->dst.val = (unsigned long)c->regs[VCPU_REGS_RAX];
                break;
        case 0xa4 ... 0xa5:     /* movs */
-               c->dst.type = OP_MEM;
-               c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-               c->dst.ptr = (unsigned long *)register_address(c,
-                                                  es_base(ctxt),
-                                                  c->regs[VCPU_REGS_RDI]);
-               rc = ops->read_emulated(register_address(c,
-                                               seg_override_base(ctxt, c),
-                                               c->regs[VCPU_REGS_RSI]),
-                                       &c->dst.val,
-                                       c->dst.bytes, ctxt->vcpu);
-               if (rc != X86EMUL_CONTINUE)
-                       goto done;
-               register_address_increment(c, &c->regs[VCPU_REGS_RSI],
-                                      (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
-                                                          : c->dst.bytes);
-               register_address_increment(c, &c->regs[VCPU_REGS_RDI],
-                                      (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
-                                                          : c->dst.bytes);
-               break;
+               goto mov;
        case 0xa6 ... 0xa7:     /* cmps */
-               c->src.type = OP_NONE; /* Disable writeback. */
-               c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-               c->src.ptr = (unsigned long *)register_address(c,
-                                      seg_override_base(ctxt, c),
-                                                  c->regs[VCPU_REGS_RSI]);
-               rc = ops->read_emulated((unsigned long)c->src.ptr,
-                                       &c->src.val,
-                                       c->src.bytes,
-                                       ctxt->vcpu);
-               if (rc != X86EMUL_CONTINUE)
-                       goto done;
-
                c->dst.type = OP_NONE; /* Disable writeback. */
-               c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-               c->dst.ptr = (unsigned long *)register_address(c,
-                                                  es_base(ctxt),
-                                                  c->regs[VCPU_REGS_RDI]);
-               rc = ops->read_emulated((unsigned long)c->dst.ptr,
-                                       &c->dst.val,
-                                       c->dst.bytes,
-                                       ctxt->vcpu);
-               if (rc != X86EMUL_CONTINUE)
-                       goto done;
-
                DPRINTF("cmps: mem1=0x%p mem2=0x%p\n", c->src.ptr, c->dst.ptr);
-
-               emulate_2op_SrcV("cmp", c->src, c->dst, ctxt->eflags);
-
-               register_address_increment(c, &c->regs[VCPU_REGS_RSI],
-                                      (ctxt->eflags & EFLG_DF) ? -c->src.bytes
-                                                                 : c->src.bytes);
-               register_address_increment(c, &c->regs[VCPU_REGS_RDI],
-                                      (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
-                                                                 : c->dst.bytes);
-
-               break;
+               goto cmp;
        case 0xaa ... 0xab:     /* stos */
-               c->dst.type = OP_MEM;
-               c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-               c->dst.ptr = (unsigned long *)register_address(c,
-                                                  es_base(ctxt),
-                                                  c->regs[VCPU_REGS_RDI]);
                c->dst.val = c->regs[VCPU_REGS_RAX];
-               register_address_increment(c, &c->regs[VCPU_REGS_RDI],
-                                      (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
-                                                          : c->dst.bytes);
                break;
        case 0xac ... 0xad:     /* lods */
-               c->dst.type = OP_REG;
-               c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-               c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX];
-               rc = ops->read_emulated(register_address(c,
-                                               seg_override_base(ctxt, c),
-                                               c->regs[VCPU_REGS_RSI]),
-                                       &c->dst.val,
-                                       c->dst.bytes,
-                                       ctxt->vcpu);
-               if (rc != X86EMUL_CONTINUE)
-                       goto done;
-               register_address_increment(c, &c->regs[VCPU_REGS_RSI],
-                                      (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
-                                                          : c->dst.bytes);
-               break;
+               goto mov;
        case 0xae ... 0xaf:     /* scas */
                DPRINTF("Urk! I don't handle SCAS.\n");
                goto cannot_emulate;
@@ -2979,6 +2934,14 @@ writeback:
        if (rc != X86EMUL_CONTINUE)
                goto done;
 
+       if ((c->d & SrcMask) == SrcSI)
+               string_addr_inc(ctxt, seg_override_base(ctxt, c), VCPU_REGS_RSI,
+                               &c->src.ptr);
+
+       if ((c->d & DstMask) == DstDI)
+               string_addr_inc(ctxt, es_base(ctxt), VCPU_REGS_RDI,
+                               &c->dst.ptr);
+
        /* Commit shadow register state. */
        memcpy(ctxt->vcpu->arch.regs, c->regs, sizeof c->regs);
        kvm_rip_write(ctxt->vcpu, c->eip);