diff options
author | Avi Kivity <avi.kivity@gmail.com> | 2013-02-09 04:31:44 -0500 |
---|---|---|
committer | Gleb Natapov <gleb@redhat.com> | 2013-05-21 08:43:14 -0400 |
commit | fb32b1eda29f2040148b0e172f9cbbd2f07697e4 (patch) | |
tree | ce1844ae8998f70fa0bae623fd44cd793fdb28c1 /arch/x86/kvm/emulate.c | |
parent | f8b5ff2cff232df052955ef975f7219e1faa217f (diff) |
KVM: x86 emulator: add support for writing back the source operand
Some instructions write back the source operand, not just the destination.
Add support for doing this via the decode flags.
Gleb: add BUG_ON() to prevent source to be memory operand.
Signed-off-by: Avi Kivity <avi.kivity@gmail.com>
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Diffstat (limited to 'arch/x86/kvm/emulate.c')
-rw-r--r-- | arch/x86/kvm/emulate.c | 48 |
1 files changed, 27 insertions, 21 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 8db0010ed150..a4c266e99e50 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -155,6 +155,7 @@ | |||
155 | #define Avx ((u64)1 << 43) /* Advanced Vector Extensions */ | 155 | #define Avx ((u64)1 << 43) /* Advanced Vector Extensions */ |
156 | #define Fastop ((u64)1 << 44) /* Use opcode::u.fastop */ | 156 | #define Fastop ((u64)1 << 44) /* Use opcode::u.fastop */ |
157 | #define NoWrite ((u64)1 << 45) /* No writeback */ | 157 | #define NoWrite ((u64)1 << 45) /* No writeback */ |
158 | #define SrcWrite ((u64)1 << 46) /* Write back src operand */ | ||
158 | 159 | ||
159 | #define X2(x...) x, x | 160 | #define X2(x...) x, x |
160 | #define X3(x...) X2(x), x | 161 | #define X3(x...) X2(x), x |
@@ -1723,45 +1724,42 @@ static void write_register_operand(struct operand *op) | |||
1723 | } | 1724 | } |
1724 | } | 1725 | } |
1725 | 1726 | ||
1726 | static int writeback(struct x86_emulate_ctxt *ctxt) | 1727 | static int writeback(struct x86_emulate_ctxt *ctxt, struct operand *op) |
1727 | { | 1728 | { |
1728 | int rc; | 1729 | int rc; |
1729 | 1730 | ||
1730 | if (ctxt->d & NoWrite) | 1731 | switch (op->type) { |
1731 | return X86EMUL_CONTINUE; | ||
1732 | |||
1733 | switch (ctxt->dst.type) { | ||
1734 | case OP_REG: | 1732 | case OP_REG: |
1735 | write_register_operand(&ctxt->dst); | 1733 | write_register_operand(op); |
1736 | break; | 1734 | break; |
1737 | case OP_MEM: | 1735 | case OP_MEM: |
1738 | if (ctxt->lock_prefix) | 1736 | if (ctxt->lock_prefix) |
1739 | rc = segmented_cmpxchg(ctxt, | 1737 | rc = segmented_cmpxchg(ctxt, |
1740 | ctxt->dst.addr.mem, | 1738 | op->addr.mem, |
1741 | &ctxt->dst.orig_val, | 1739 | &op->orig_val, |
1742 | &ctxt->dst.val, | 1740 | &op->val, |
1743 | ctxt->dst.bytes); | 1741 | op->bytes); |
1744 | else | 1742 | else |
1745 | rc = segmented_write(ctxt, | 1743 | rc = segmented_write(ctxt, |
1746 | ctxt->dst.addr.mem, | 1744 | op->addr.mem, |
1747 | &ctxt->dst.val, | 1745 | &op->val, |
1748 | ctxt->dst.bytes); | 1746 | op->bytes); |
1749 | if (rc != X86EMUL_CONTINUE) | 1747 | if (rc != X86EMUL_CONTINUE) |
1750 | return rc; | 1748 | return rc; |
1751 | break; | 1749 | break; |
1752 | case OP_MEM_STR: | 1750 | case OP_MEM_STR: |
1753 | rc = segmented_write(ctxt, | 1751 | rc = segmented_write(ctxt, |
1754 | ctxt->dst.addr.mem, | 1752 | op->addr.mem, |
1755 | ctxt->dst.data, | 1753 | op->data, |
1756 | ctxt->dst.bytes * ctxt->dst.count); | 1754 | op->bytes * op->count); |
1757 | if (rc != X86EMUL_CONTINUE) | 1755 | if (rc != X86EMUL_CONTINUE) |
1758 | return rc; | 1756 | return rc; |
1759 | break; | 1757 | break; |
1760 | case OP_XMM: | 1758 | case OP_XMM: |
1761 | write_sse_reg(ctxt, &ctxt->dst.vec_val, ctxt->dst.addr.xmm); | 1759 | write_sse_reg(ctxt, &op->vec_val, op->addr.xmm); |
1762 | break; | 1760 | break; |
1763 | case OP_MM: | 1761 | case OP_MM: |
1764 | write_mmx_reg(ctxt, &ctxt->dst.mm_val, ctxt->dst.addr.mm); | 1762 | write_mmx_reg(ctxt, &op->mm_val, op->addr.mm); |
1765 | break; | 1763 | break; |
1766 | case OP_NONE: | 1764 | case OP_NONE: |
1767 | /* no writeback */ | 1765 | /* no writeback */ |
@@ -4769,9 +4767,17 @@ special_insn: | |||
4769 | goto done; | 4767 | goto done; |
4770 | 4768 | ||
4771 | writeback: | 4769 | writeback: |
4772 | rc = writeback(ctxt); | 4770 | if (!(ctxt->d & NoWrite)) { |
4773 | if (rc != X86EMUL_CONTINUE) | 4771 | rc = writeback(ctxt, &ctxt->dst); |
4774 | goto done; | 4772 | if (rc != X86EMUL_CONTINUE) |
4773 | goto done; | ||
4774 | } | ||
4775 | if (ctxt->d & SrcWrite) { | ||
4776 | BUG_ON(ctxt->src.type == OP_MEM || ctxt->src.type == OP_MEM_STR); | ||
4777 | rc = writeback(ctxt, &ctxt->src); | ||
4778 | if (rc != X86EMUL_CONTINUE) | ||
4779 | goto done; | ||
4780 | } | ||
4775 | 4781 | ||
4776 | /* | 4782 | /* |
4777 | * restore dst type in case the decoding will be reused | 4783 | * restore dst type in case the decoding will be reused |