diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2014-05-06 07:05:25 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2014-07-11 03:14:03 -0400 |
commit | 9506d57de3bc8277a4e306e0d439976862f68c6d (patch) | |
tree | aac16beac03ddc018f7ffec0d453d1a89d4a11f0 /arch/x86/kvm/emulate.c | |
parent | 5cfc7e0f5e5e1adf998df94f8e36edaf5d30d38e (diff) |
KVM: emulate: avoid per-byte copying in instruction fetches
We do not need a memory copying loop anymore in insn_fetch; we
can use a byte-aligned pointer to access instruction fields directly
from the fetch_cache. This eliminates 50-150 cycles (corresponding to
a 5-10% improvement in performance) from each instruction.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/x86/kvm/emulate.c')
-rw-r--r-- | arch/x86/kvm/emulate.c | 46 |
1 files changed, 22 insertions, 24 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index ca82ec9c5ffe..02c668aca2b6 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -708,7 +708,7 @@ static int segmented_read_std(struct x86_emulate_ctxt *ctxt, | |||
708 | * Prefetch the remaining bytes of the instruction without crossing page | 708 | * Prefetch the remaining bytes of the instruction without crossing page |
709 | * boundary if they are not in fetch_cache yet. | 709 | * boundary if they are not in fetch_cache yet. |
710 | */ | 710 | */ |
711 | static int do_insn_fetch_bytes(struct x86_emulate_ctxt *ctxt, int op_size) | 711 | static int __do_insn_fetch_bytes(struct x86_emulate_ctxt *ctxt, int op_size) |
712 | { | 712 | { |
713 | struct fetch_cache *fc = &ctxt->fetch; | 713 | struct fetch_cache *fc = &ctxt->fetch; |
714 | int rc; | 714 | int rc; |
@@ -740,41 +740,39 @@ static int do_insn_fetch_bytes(struct x86_emulate_ctxt *ctxt, int op_size) | |||
740 | return X86EMUL_CONTINUE; | 740 | return X86EMUL_CONTINUE; |
741 | } | 741 | } |
742 | 742 | ||
743 | static int do_insn_fetch(struct x86_emulate_ctxt *ctxt, | 743 | static __always_inline int do_insn_fetch_bytes(struct x86_emulate_ctxt *ctxt, |
744 | void *__dest, unsigned size) | 744 | unsigned size) |
745 | { | 745 | { |
746 | struct fetch_cache *fc = &ctxt->fetch; | ||
747 | u8 *dest = __dest; | ||
748 | u8 *src = &fc->data[ctxt->_eip - fc->start]; | ||
749 | |||
750 | /* We have to be careful about overflow! */ | 746 | /* We have to be careful about overflow! */ |
751 | if (unlikely(ctxt->_eip > fc->end - size)) { | 747 | if (unlikely(ctxt->_eip > ctxt->fetch.end - size)) |
752 | int rc = do_insn_fetch_bytes(ctxt, size); | 748 | return __do_insn_fetch_bytes(ctxt, size); |
753 | if (rc != X86EMUL_CONTINUE) | 749 | else |
754 | return rc; | 750 | return X86EMUL_CONTINUE; |
755 | } | ||
756 | |||
757 | while (size--) { | ||
758 | *dest++ = *src++; | ||
759 | ctxt->_eip++; | ||
760 | continue; | ||
761 | } | ||
762 | return X86EMUL_CONTINUE; | ||
763 | } | 751 | } |
764 | 752 | ||
765 | /* Fetch next part of the instruction being emulated. */ | 753 | /* Fetch next part of the instruction being emulated. */ |
766 | #define insn_fetch(_type, _ctxt) \ | 754 | #define insn_fetch(_type, _ctxt) \ |
767 | ({ unsigned long _x; \ | 755 | ({ _type _x; \ |
768 | rc = do_insn_fetch(_ctxt, &_x, sizeof(_type)); \ | 756 | struct fetch_cache *_fc; \ |
757 | \ | ||
758 | rc = do_insn_fetch_bytes(_ctxt, sizeof(_type)); \ | ||
769 | if (rc != X86EMUL_CONTINUE) \ | 759 | if (rc != X86EMUL_CONTINUE) \ |
770 | goto done; \ | 760 | goto done; \ |
771 | (_type)_x; \ | 761 | _fc = &ctxt->fetch; \ |
762 | _x = *(_type __aligned(1) *) &_fc->data[ctxt->_eip - _fc->start]; \ | ||
763 | ctxt->_eip += sizeof(_type); \ | ||
764 | _x; \ | ||
772 | }) | 765 | }) |
773 | 766 | ||
774 | #define insn_fetch_arr(_arr, _size, _ctxt) \ | 767 | #define insn_fetch_arr(_arr, _size, _ctxt) \ |
775 | ({ rc = do_insn_fetch(_ctxt, _arr, (_size)); \ | 768 | ({ \ |
769 | struct fetch_cache *_fc; \ | ||
770 | rc = do_insn_fetch_bytes(_ctxt, _size); \ | ||
776 | if (rc != X86EMUL_CONTINUE) \ | 771 | if (rc != X86EMUL_CONTINUE) \ |
777 | goto done; \ | 772 | goto done; \ |
773 | _fc = &ctxt->fetch; \ | ||
774 | memcpy(_arr, &_fc->data[ctxt->_eip - _fc->start], _size); \ | ||
775 | ctxt->_eip += (_size); \ | ||
778 | }) | 776 | }) |
779 | 777 | ||
780 | /* | 778 | /* |
@@ -4236,7 +4234,7 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) | |||
4236 | if (insn_len > 0) | 4234 | if (insn_len > 0) |
4237 | memcpy(ctxt->fetch.data, insn, insn_len); | 4235 | memcpy(ctxt->fetch.data, insn, insn_len); |
4238 | else { | 4236 | else { |
4239 | rc = do_insn_fetch_bytes(ctxt, 1); | 4237 | rc = __do_insn_fetch_bytes(ctxt, 1); |
4240 | if (rc != X86EMUL_CONTINUE) | 4238 | if (rc != X86EMUL_CONTINUE) |
4241 | return rc; | 4239 | return rc; |
4242 | } | 4240 | } |