diff options
author | Gleb Natapov <gleb@redhat.com> | 2010-03-18 09:20:21 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2010-05-17 05:16:21 -0400 |
commit | a682e35449abc83d260a8219015c7cb4b25ecced (patch) | |
tree | 41349e491e41f4c4c33a12534ece4d4b1cceb898 | |
parent | 69f55cb11e8d789433d111ac3a0f60be37a1ae01 (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.c | 125 |
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 | ||
1235 | done: | 1253 | done: |
@@ -2392,6 +2410,16 @@ int emulator_task_switch(struct x86_emulate_ctxt *ctxt, | |||
2392 | return rc; | 2410 | return rc; |
2393 | } | 2411 | } |
2394 | 2412 | ||
2413 | static 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 | |||
2395 | int | 2423 | int |
2396 | x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) | 2424 | x86_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); |