mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Paolo Bonzini <pbonzini@redhat.com>
To: linux-kernel@vger.kernel.org
Cc: bdas@redhat.com, gleb@kernel.org
Subject: [PATCH 10/25] KVM: emulate: introduce memory_prepare callback to speed up memory access
Date: Mon,  9 Jun 2014 14:58:58 +0200	[thread overview]
Message-ID: <1402318753-23362-11-git-send-email-pbonzini@redhat.com> (raw)
In-Reply-To: <1402318753-23362-1-git-send-email-pbonzini@redhat.com>

Emulating a RMW instruction currently walks the page tables
twice.  To avoid this, store the virtual address in the host
and access it directly.

In fact, it turns out that the optimizations we can do
actually benefit all memory accesses.

Reviewed-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 arch/x86/include/asm/kvm_emulate.h | 26 +++++++++++++++
 arch/x86/kvm/x86.c                 | 67 ++++++++++++++++++++++++++++++++++++++
 include/linux/kvm_host.h           |  5 +++
 virt/kvm/kvm_main.c                |  5 ---
 4 files changed, 98 insertions(+), 5 deletions(-)

diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index 46725e8aa8cb..1aa2adf0bb1a 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -167,6 +167,32 @@ struct x86_emulate_ops {
 				const void *new,
 				unsigned int bytes,
 				struct x86_exception *fault);
+
+	/*
+	 * memory_prepare: Prepare userspace access fastpath.
+	 *   @addr:     [IN ] Linear address to access.
+	 *   @bytes:    [IN ] Number of bytes to access.
+	 *   @write:    [IN ] True if *p_hva will be written to.
+	 *   @p_opaque: [OUT] Value passed back to memory_finish.
+	 *   @p_hva:    [OUT] Host virtual address for __copy_from/to_user.
+	 */
+	int (*memory_prepare)(struct x86_emulate_ctxt *ctxt,
+			      unsigned long addr,
+			      unsigned int bytes,
+			      struct x86_exception *exception,
+			      bool write,
+			      void **p_opaque,
+			      unsigned long *p_hva);
+
+	/*
+	 * memory_finish: Complete userspace access fastpath.
+	 *   @opaque: [OUT] Value passed back from memory_prepare.
+	 *   @hva:    [OUT] Host virtual address computed in memory_prepare.
+	 */
+	void (*memory_finish)(struct x86_emulate_ctxt *ctxt,
+			      void *p_opaque,
+			      unsigned long p_hva);
+
 	void (*invlpg)(struct x86_emulate_ctxt *ctxt, ulong addr);
 
 	int (*pio_in_emulated)(struct x86_emulate_ctxt *ctxt,
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index e64b8b5cb6cd..02678c2f3721 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4279,6 +4279,71 @@ static const struct read_write_emulator_ops write_emultor = {
 	.write = true,
 };
 
+static int emulator_memory_prepare(struct x86_emulate_ctxt *ctxt,
+				   unsigned long addr,
+				   unsigned int bytes,
+				   struct x86_exception *exception,
+				   bool write,
+				   void **p_opaque,
+				   unsigned long *p_hva)
+{
+	struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
+	struct kvm_memory_slot *memslot;
+	int ret;
+	gpa_t gpa;
+	gfn_t gfn;
+	unsigned long hva;
+	
+	if (unlikely(((addr + bytes - 1) ^ addr) & PAGE_MASK))
+		goto no_hva;
+
+	ret = vcpu_mmio_gva_to_gpa(vcpu, addr, &gpa, exception, true);
+	if (ret != 0) {
+		if (ret < 0)
+			return X86EMUL_PROPAGATE_FAULT;
+		goto no_hva;
+	}
+
+	/* A (heavily) simplified version of kvm_gfn_to_hva_cache_init.  */
+	gfn = gpa >> PAGE_SHIFT;
+	memslot = gfn_to_memslot(vcpu->kvm, gfn);
+	if (!memslot)
+		goto no_hva;
+
+	if (write) {
+		if (memslot_is_readonly(memslot))
+			goto no_hva;
+
+		*p_opaque = memslot->dirty_bitmap ? memslot : NULL;
+	}
+
+	hva = __gfn_to_hva_memslot(memslot, gfn);
+	if (kvm_is_error_hva(hva))
+		goto no_hva;
+
+	*p_hva = hva + offset_in_page(gpa);
+	return X86EMUL_CONTINUE;
+
+no_hva:
+	*p_hva = KVM_HVA_ERR_BAD;
+	return X86EMUL_CONTINUE;
+}
+
+static void emulator_memory_finish(struct x86_emulate_ctxt *ctxt,
+				   void *opaque,
+				   unsigned long hva)
+{
+	struct kvm_memory_slot *memslot;
+	gfn_t gfn;
+
+	if (!opaque)
+		return;
+
+	memslot = opaque;
+	gfn = hva_to_gfn_memslot(hva, memslot);
+	mark_page_dirty_in_slot(memslot, gfn);
+}
+
 static int emulator_read_write_onepage(unsigned long addr, void *val,
 				       unsigned int bytes,
 				       struct x86_exception *exception,
@@ -4823,6 +4888,8 @@ static const struct x86_emulate_ops emulate_ops = {
 	.read_std            = kvm_read_guest_virt_system,
 	.write_std           = kvm_write_guest_virt_system,
 	.fetch               = kvm_fetch_guest_virt,
+	.memory_prepare      = emulator_memory_prepare,
+	.memory_finish       = emulator_memory_finish,
 	.read_emulated       = emulator_read_emulated,
 	.write_emulated      = emulator_write_emulated,
 	.cmpxchg_emulated    = emulator_cmpxchg_emulated,
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 5be9805b0aeb..91f303dd0fe5 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -842,6 +842,11 @@ search_memslots(struct kvm_memslots *slots, gfn_t gfn)
 	return NULL;
 }
 
+static inline bool memslot_is_readonly(struct kvm_memory_slot *slot)
+{
+	return slot->flags & KVM_MEM_READONLY;
+}
+
 static inline struct kvm_memory_slot *
 __gfn_to_memslot(struct kvm_memslots *slots, gfn_t gfn)
 {
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 2f9bc20ae2a7..09b19afb2c11 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1028,11 +1028,6 @@ out:
 	return size;
 }
 
-static bool memslot_is_readonly(struct kvm_memory_slot *slot)
-{
-	return slot->flags & KVM_MEM_READONLY;
-}
-
 static unsigned long __gfn_to_hva_many(struct kvm_memory_slot *slot, gfn_t gfn,
 				       gfn_t *nr_pages, bool write)
 {
-- 
1.8.3.1



  parent reply	other threads:[~2014-06-09 12:59 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-06-09 12:58 [PATCH 00/25] KVM: x86: Speed up emulation of invalid state Paolo Bonzini
2014-06-09 12:58 ` [PATCH 01/25] KVM: vmx: speed up emulation of invalid guest state Paolo Bonzini
2014-06-09 12:58 ` [PATCH 02/25] KVM: x86: return all bits from get_interrupt_shadow Paolo Bonzini
2014-06-09 12:58 ` [PATCH 03/25] KVM: x86: avoid useless set of KVM_REQ_EVENT after emulation Paolo Bonzini
2014-06-09 12:58 ` [PATCH 04/25] KVM: emulate: move around some checks Paolo Bonzini
2014-06-09 12:58 ` [PATCH 05/25] KVM: emulate: protect checks on ctxt->d by a common "if (unlikely())" Paolo Bonzini
2014-06-09 12:58 ` [PATCH 06/25] KVM: emulate: speed up emulated moves Paolo Bonzini
2014-06-09 12:58 ` [PATCH 07/25] KVM: emulate: simplify writeback Paolo Bonzini
2014-06-09 12:58 ` [PATCH 08/25] KVM: emulate: abstract handling of memory operands Paolo Bonzini
2014-06-09 12:58 ` [PATCH 09/25] KVM: export mark_page_dirty_in_slot Paolo Bonzini
2014-06-09 12:58 ` Paolo Bonzini [this message]
2014-06-09 12:58 ` [PATCH 11/25] KVM: emulate: activate memory access optimization Paolo Bonzini
2014-06-09 12:59 ` [PATCH 12/25] KVM: emulate: extend memory access optimization to stores Paolo Bonzini
2014-06-09 18:40   ` Bandan Das
2014-06-19 11:37     ` Paolo Bonzini
2014-06-09 12:59 ` [PATCH 13/25] KVM: emulate: move init_decode_cache to emulate.c Paolo Bonzini
2014-06-09 12:59 ` [PATCH 14/25] KVM: emulate: Remove ctxt->intercept and ctxt->check_perm checks Paolo Bonzini
2014-06-09 12:59 ` [PATCH 15/25] KVM: emulate: cleanup decode_modrm Paolo Bonzini
2014-06-09 12:59 ` [PATCH 16/25] KVM: emulate: clean up initializations in init_decode_cache Paolo Bonzini
2014-06-09 12:59 ` [PATCH 17/25] KVM: emulate: rework seg_override Paolo Bonzini
2014-06-09 12:59 ` [PATCH 18/25] KVM: emulate: do not initialize memopp Paolo Bonzini
2014-06-09 12:59 ` [PATCH 19/25] KVM: emulate: speed up do_insn_fetch Paolo Bonzini
2014-06-09 12:59 ` [PATCH 20/25] KVM: emulate: avoid repeated calls to do_insn_fetch_bytes Paolo Bonzini
2014-06-09 12:59 ` [PATCH 21/25] KVM: emulate: avoid per-byte copying in instruction fetches Paolo Bonzini
2014-06-09 12:59 ` [PATCH 22/25] KVM: emulate: put pointers in the fetch_cache Paolo Bonzini
2014-06-09 12:59 ` [PATCH 23/25] KVM: x86: use kvm_read_guest_page for emulator accesses Paolo Bonzini
2014-06-09 12:59 ` [PATCH 24/25] KVM: emulate: simplify BitOp handling Paolo Bonzini
2014-06-09 12:59 ` [PATCH 25/25] KVM: emulate: fix harmless typo in MMX decoding Paolo Bonzini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1402318753-23362-11-git-send-email-pbonzini@redhat.com \
    --to=pbonzini@redhat.com \
    --cc=bdas@redhat.com \
    --cc=gleb@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®