aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGleb Natapov <gleb@redhat.com>2010-03-18 09:20:21 -0400
committerAvi Kivity <avi@redhat.com>2010-05-17 05:16:21 -0400
commita682e35449abc83d260a8219015c7cb4b25ecced (patch)
tree41349e491e41f4c4c33a12534ece4d4b1cceb898
parent69f55cb11e8d789433d111ac3a0f60be37a1ae01 (diff)
KVM: x86 emulator: add decoding of X,Y parameters from Intel SDM
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>
-rw-r--r--arch/x86/kvm/emulate.c125
1 files changed, 44 insertions, 81 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 0eed6839619f..3b32270a20db 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -51,6 +51,7 @@
51#define DstReg (2<<1) /* Register operand. */ 51#define DstReg (2<<1) /* Register operand. */
52#define DstMem (3<<1) /* Memory operand. */ 52#define DstMem (3<<1) /* Memory operand. */
53#define DstAcc (4<<1) /* Destination Accumulator */ 53#define DstAcc (4<<1) /* Destination Accumulator */
54#define DstDI (5<<1) /* Destination is in ES:(E)DI */
54#define DstMask (7<<1) 55#define DstMask (7<<1)
55/* Source operand type. */ 56/* Source operand type. */
56#define SrcNone (0<<4) /* No source operand. */ 57#define SrcNone (0<<4) /* No source operand. */
@@ -64,6 +65,7 @@
64#define SrcOne (7<<4) /* Implied '1' */ 65#define SrcOne (7<<4) /* Implied '1' */
65#define SrcImmUByte (8<<4) /* 8-bit unsigned immediate operand. */ 66#define SrcImmUByte (8<<4) /* 8-bit unsigned immediate operand. */
66#define SrcImmU (9<<4) /* Immediate operand, unsigned */ 67#define SrcImmU (9<<4) /* Immediate operand, unsigned */
68#define SrcSI (0xa<<4) /* Source is in the DS:RSI */
67#define SrcMask (0xf<<4) 69#define SrcMask (0xf<<4)
68/* Generic ModRM decode. */ 70/* Generic ModRM decode. */
69#define ModRM (1<<8) 71#define ModRM (1<<8)
@@ -177,12 +179,12 @@ static u32 opcode_table[256] = {
177 /* 0xA0 - 0xA7 */ 179 /* 0xA0 - 0xA7 */
178 ByteOp | DstReg | SrcMem | Mov | MemAbs, DstReg | SrcMem | Mov | MemAbs, 180 ByteOp | DstReg | SrcMem | Mov | MemAbs, DstReg | SrcMem | Mov | MemAbs,
179 ByteOp | DstMem | SrcReg | Mov | MemAbs, DstMem | SrcReg | Mov | MemAbs, 181 ByteOp | DstMem | SrcReg | Mov | MemAbs, DstMem | SrcReg | Mov | MemAbs,
180 ByteOp | ImplicitOps | Mov | String, ImplicitOps | Mov | String, 182 ByteOp | SrcSI | DstDI | Mov | String, SrcSI | DstDI | Mov | String,
181 ByteOp | ImplicitOps | String, ImplicitOps | String, 183 ByteOp | SrcSI | DstDI | String, SrcSI | DstDI | String,
182 /* 0xA8 - 0xAF */ 184 /* 0xA8 - 0xAF */
183 0, 0, ByteOp | ImplicitOps | Mov | String, ImplicitOps | Mov | String, 185 0, 0, ByteOp | DstDI | Mov | String, DstDI | Mov | String,
184 ByteOp | ImplicitOps | Mov | String, ImplicitOps | Mov | String, 186 ByteOp | SrcSI | DstAcc | Mov | String, SrcSI | DstAcc | Mov | String,
185 ByteOp | ImplicitOps | String, ImplicitOps | String, 187 ByteOp | DstDI | String, DstDI | String,
186 /* 0xB0 - 0xB7 */ 188 /* 0xB0 - 0xB7 */
187 ByteOp | DstReg | SrcImm | Mov, ByteOp | DstReg | SrcImm | Mov, 189 ByteOp | DstReg | SrcImm | Mov, ByteOp | DstReg | SrcImm | Mov,
188 ByteOp | DstReg | SrcImm | Mov, ByteOp | DstReg | SrcImm | Mov, 190 ByteOp | DstReg | SrcImm | Mov, ByteOp | DstReg | SrcImm | Mov,
@@ -1145,6 +1147,14 @@ done_prefixes:
1145 c->src.bytes = 1; 1147 c->src.bytes = 1;
1146 c->src.val = 1; 1148 c->src.val = 1;
1147 break; 1149 break;
1150 case SrcSI:
1151 c->src.type = OP_MEM;
1152 c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
1153 c->src.ptr = (unsigned long *)
1154 register_address(c, seg_override_base(ctxt, c),
1155 c->regs[VCPU_REGS_RSI]);
1156 c->src.val = 0;
1157 break;
1148 } 1158 }
1149 1159
1150 /* 1160 /*
@@ -1230,6 +1240,14 @@ done_prefixes:
1230 } 1240 }
1231 c->dst.orig_val = c->dst.val; 1241 c->dst.orig_val = c->dst.val;
1232 break; 1242 break;
1243 case DstDI:
1244 c->dst.type = OP_MEM;
1245 c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
1246 c->dst.ptr = (unsigned long *)
1247 register_address(c, es_base(ctxt),
1248 c->regs[VCPU_REGS_RDI]);
1249 c->dst.val = 0;
1250 break;
1233 } 1251 }
1234 1252
1235done: 1253done:
@@ -2392,6 +2410,16 @@ int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
2392 return rc; 2410 return rc;
2393} 2411}
2394 2412
2413static void string_addr_inc(struct x86_emulate_ctxt *ctxt, unsigned long base,
2414 int reg, unsigned long **ptr)
2415{
2416 struct decode_cache *c = &ctxt->decode;
2417 int df = (ctxt->eflags & EFLG_DF) ? -1 : 1;
2418
2419 register_address_increment(c, &c->regs[reg], df * c->src.bytes);
2420 *ptr = (unsigned long *)register_address(c, base, c->regs[reg]);
2421}
2422
2395int 2423int
2396x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) 2424x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
2397{ 2425{
@@ -2754,89 +2782,16 @@ special_insn:
2754 c->dst.val = (unsigned long)c->regs[VCPU_REGS_RAX]; 2782 c->dst.val = (unsigned long)c->regs[VCPU_REGS_RAX];
2755 break; 2783 break;
2756 case 0xa4 ... 0xa5: /* movs */ 2784 case 0xa4 ... 0xa5: /* movs */
2757 c->dst.type = OP_MEM; 2785 goto mov;
2758 c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
2759 c->dst.ptr = (unsigned long *)register_address(c,
2760 es_base(ctxt),
2761 c->regs[VCPU_REGS_RDI]);
2762 rc = ops->read_emulated(register_address(c,
2763 seg_override_base(ctxt, c),
2764 c->regs[VCPU_REGS_RSI]),
2765 &c->dst.val,
2766 c->dst.bytes, ctxt->vcpu);
2767 if (rc != X86EMUL_CONTINUE)
2768 goto done;
2769 register_address_increment(c, &c->regs[VCPU_REGS_RSI],
2770 (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
2771 : c->dst.bytes);
2772 register_address_increment(c, &c->regs[VCPU_REGS_RDI],
2773 (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
2774 : c->dst.bytes);
2775 break;
2776 case 0xa6 ... 0xa7: /* cmps */ 2786 case 0xa6 ... 0xa7: /* cmps */
2777 c->src.type = OP_NONE; /* Disable writeback. */
2778 c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
2779 c->src.ptr = (unsigned long *)register_address(c,
2780 seg_override_base(ctxt, c),
2781 c->regs[VCPU_REGS_RSI]);
2782 rc = ops->read_emulated((unsigned long)c->src.ptr,
2783 &c->src.val,
2784 c->src.bytes,
2785 ctxt->vcpu);
2786 if (rc != X86EMUL_CONTINUE)
2787 goto done;
2788
2789 c->dst.type = OP_NONE; /* Disable writeback. */ 2787 c->dst.type = OP_NONE; /* Disable writeback. */
2790 c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
2791 c->dst.ptr = (unsigned long *)register_address(c,
2792 es_base(ctxt),
2793 c->regs[VCPU_REGS_RDI]);
2794 rc = ops->read_emulated((unsigned long)c->dst.ptr,
2795 &c->dst.val,
2796 c->dst.bytes,
2797 ctxt->vcpu);
2798 if (rc != X86EMUL_CONTINUE)
2799 goto done;
2800
2801 DPRINTF("cmps: mem1=0x%p mem2=0x%p\n", c->src.ptr, c->dst.ptr); 2788 DPRINTF("cmps: mem1=0x%p mem2=0x%p\n", c->src.ptr, c->dst.ptr);
2802 2789 goto cmp;
2803 emulate_2op_SrcV("cmp", c->src, c->dst, ctxt->eflags);
2804
2805 register_address_increment(c, &c->regs[VCPU_REGS_RSI],
2806 (ctxt->eflags & EFLG_DF) ? -c->src.bytes
2807 : c->src.bytes);
2808 register_address_increment(c, &c->regs[VCPU_REGS_RDI],
2809 (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
2810 : c->dst.bytes);
2811
2812 break;
2813 case 0xaa ... 0xab: /* stos */ 2790 case 0xaa ... 0xab: /* stos */
2814 c->dst.type = OP_MEM;
2815 c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
2816 c->dst.ptr = (unsigned long *)register_address(c,
2817 es_base(ctxt),
2818 c->regs[VCPU_REGS_RDI]);
2819 c->dst.val = c->regs[VCPU_REGS_RAX]; 2791 c->dst.val = c->regs[VCPU_REGS_RAX];
2820 register_address_increment(c, &c->regs[VCPU_REGS_RDI],
2821 (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
2822 : c->dst.bytes);
2823 break; 2792 break;
2824 case 0xac ... 0xad: /* lods */ 2793 case 0xac ... 0xad: /* lods */
2825 c->dst.type = OP_REG; 2794 goto mov;
2826 c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
2827 c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX];
2828 rc = ops->read_emulated(register_address(c,
2829 seg_override_base(ctxt, c),
2830 c->regs[VCPU_REGS_RSI]),
2831 &c->dst.val,
2832 c->dst.bytes,
2833 ctxt->vcpu);
2834 if (rc != X86EMUL_CONTINUE)
2835 goto done;
2836 register_address_increment(c, &c->regs[VCPU_REGS_RSI],
2837 (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
2838 : c->dst.bytes);
2839 break;
2840 case 0xae ... 0xaf: /* scas */ 2795 case 0xae ... 0xaf: /* scas */
2841 DPRINTF("Urk! I don't handle SCAS.\n"); 2796 DPRINTF("Urk! I don't handle SCAS.\n");
2842 goto cannot_emulate; 2797 goto cannot_emulate;
@@ -2979,6 +2934,14 @@ writeback:
2979 if (rc != X86EMUL_CONTINUE) 2934 if (rc != X86EMUL_CONTINUE)
2980 goto done; 2935 goto done;
2981 2936
2937 if ((c->d & SrcMask) == SrcSI)
2938 string_addr_inc(ctxt, seg_override_base(ctxt, c), VCPU_REGS_RSI,
2939 &c->src.ptr);
2940
2941 if ((c->d & DstMask) == DstDI)
2942 string_addr_inc(ctxt, es_base(ctxt), VCPU_REGS_RDI,
2943 &c->dst.ptr);
2944
2982 /* Commit shadow register state. */ 2945 /* Commit shadow register state. */
2983 memcpy(ctxt->vcpu->arch.regs, c->regs, sizeof c->regs); 2946 memcpy(ctxt->vcpu->arch.regs, c->regs, sizeof c->regs);
2984 kvm_rip_write(ctxt->vcpu, c->eip); 2947 kvm_rip_write(ctxt->vcpu, c->eip);