From: Dongxiao Xu <dongxiao.xu@intel.com>
To: xen-devel@lists.xensource.com
Cc: JBeulich@suse.com, eddie.dong@intel.com, xiantao.zhang@intel.com,
jun.nakajima@intel.com
Subject: [PATCH v5 rebased 3/4] nested vmx: optimize for bulk access of virtual VMCS
Date: Wed, 23 Jan 2013 22:32:11 +0800 [thread overview]
Message-ID: <1358951532-20302-4-git-send-email-dongxiao.xu@intel.com> (raw)
In-Reply-To: <1358951532-20302-1-git-send-email-dongxiao.xu@intel.com>
After we use the VMREAD/VMWRITE to build up the virtual VMCS, each
access to the virtual VMCS needs two VMPTRLD and one VMCLEAR to
switch the environment, which might be an overhead to performance.
This commit tries to handle multiple virtual VMCS access together
to improve the performance.
Signed-off-by: Dongxiao Xu <dongxiao.xu@intel.com>
---
xen/arch/x86/hvm/vmx/vmcs.c | 10 +++
xen/arch/x86/hvm/vmx/vvmx.c | 126 +++++++++++++++++++++++++++++++-----
xen/include/asm-x86/hvm/vmx/vvmx.h | 2 +
3 files changed, 122 insertions(+), 16 deletions(-)
diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c
index 82a8d91..f89ea93 100644
--- a/xen/arch/x86/hvm/vmx/vmcs.c
+++ b/xen/arch/x86/hvm/vmx/vmcs.c
@@ -31,6 +31,7 @@
#include <asm/hvm/io.h>
#include <asm/hvm/support.h>
#include <asm/hvm/vmx/vmx.h>
+#include <asm/hvm/vmx/vvmx.h>
#include <asm/hvm/vmx/vmcs.h>
#include <asm/flushtlb.h>
#include <xen/event.h>
@@ -423,6 +424,13 @@ static void vmx_load_vmcs(struct vcpu *v)
int vmx_cpu_up_prepare(unsigned int cpu)
{
+ /*
+ * If nvmx_cpu_up_prepare() failed, do not return failure and just fallback
+ * to legacy mode for vvmcs synchronization.
+ */
+ if ( nvmx_cpu_up_prepare(cpu) != 0 )
+ printk("CPU%d: Could not allocate virtual VMCS buffer.\n", cpu);
+
if ( per_cpu(vmxon_region, cpu) != NULL )
return 0;
@@ -431,6 +439,7 @@ int vmx_cpu_up_prepare(unsigned int cpu)
return 0;
printk("CPU%d: Could not allocate host VMCS\n", cpu);
+ nvmx_cpu_dead(cpu);
return -ENOMEM;
}
@@ -438,6 +447,7 @@ void vmx_cpu_dead(unsigned int cpu)
{
vmx_free_vmcs(per_cpu(vmxon_region, cpu));
per_cpu(vmxon_region, cpu) = NULL;
+ nvmx_cpu_dead(cpu);
}
int vmx_cpu_up(void)
diff --git a/xen/arch/x86/hvm/vmx/vvmx.c b/xen/arch/x86/hvm/vmx/vvmx.c
index 8000f84..1e1ad56 100644
--- a/xen/arch/x86/hvm/vmx/vvmx.c
+++ b/xen/arch/x86/hvm/vmx/vvmx.c
@@ -28,8 +28,31 @@
#include <asm/hvm/vmx/vvmx.h>
#include <asm/hvm/nestedhvm.h>
+static DEFINE_PER_CPU(u64 *, vvmcs_buf);
+
static void nvmx_purge_vvmcs(struct vcpu *v);
+#define VMCS_BUF_SIZE 100
+
+int nvmx_cpu_up_prepare(unsigned int cpu)
+{
+ if ( per_cpu(vvmcs_buf, cpu) != NULL )
+ return 0;
+
+ per_cpu(vvmcs_buf, cpu) = xzalloc_array(u64, VMCS_BUF_SIZE);
+
+ if ( per_cpu(vvmcs_buf, cpu) != NULL )
+ return 0;
+
+ return -ENOMEM;
+}
+
+void nvmx_cpu_dead(unsigned int cpu)
+{
+ xfree(per_cpu(vvmcs_buf, cpu));
+ per_cpu(vvmcs_buf, cpu) = NULL;
+}
+
int nvmx_vcpu_initialise(struct vcpu *v)
{
struct nestedvmx *nvmx = &vcpu_2_nvmx(v);
@@ -834,6 +857,40 @@ static void vvmcs_to_shadow(void *vvmcs, unsigned int field)
__vmwrite(field, value);
}
+static void vvmcs_to_shadow_bulk(struct vcpu *v, unsigned int n,
+ const u16 *field)
+{
+ struct nestedvcpu *nvcpu = &vcpu_nestedhvm(v);
+ void *vvmcs = nvcpu->nv_vvmcx;
+ u64 *value = this_cpu(vvmcs_buf);
+ unsigned int i;
+
+ if ( !cpu_has_vmx_vmcs_shadowing )
+ goto fallback;
+
+ if ( !value || n > VMCS_BUF_SIZE )
+ {
+ gdprintk(XENLOG_DEBUG, "vmcs sync fall back to non-bulk mode, \
+ buffer: %p, buffer size: %d, fields number: %d.\n",
+ value, VMCS_BUF_SIZE, n);
+ goto fallback;
+ }
+
+ virtual_vmcs_enter(vvmcs);
+ for ( i = 0; i < n; i++ )
+ value[i] = __vmread(field[i]);
+ virtual_vmcs_exit(vvmcs);
+
+ for ( i = 0; i < n; i++ )
+ __vmwrite(field[i], value[i]);
+
+ return;
+
+fallback:
+ for ( i = 0; i < n; i++ )
+ vvmcs_to_shadow(vvmcs, field[i]);
+}
+
static void shadow_to_vvmcs(void *vvmcs, unsigned int field)
{
u64 value;
@@ -844,6 +901,40 @@ static void shadow_to_vvmcs(void *vvmcs, unsigned int field)
__set_vvmcs(vvmcs, field, value);
}
+static void shadow_to_vvmcs_bulk(struct vcpu *v, unsigned int n,
+ const u16 *field)
+{
+ struct nestedvcpu *nvcpu = &vcpu_nestedhvm(v);
+ void *vvmcs = nvcpu->nv_vvmcx;
+ u64 *value = this_cpu(vvmcs_buf);
+ unsigned int i;
+
+ if ( !cpu_has_vmx_vmcs_shadowing )
+ goto fallback;
+
+ if ( !value || n > VMCS_BUF_SIZE )
+ {
+ gdprintk(XENLOG_DEBUG, "vmcs sync fall back to non-bulk mode, \
+ buffer: %p, buffer size: %d, fields number: %d.\n",
+ value, VMCS_BUF_SIZE, n);
+ goto fallback;
+ }
+
+ for ( i = 0; i < n; i++ )
+ value[i] = __vmread(field[i]);
+
+ virtual_vmcs_enter(vvmcs);
+ for ( i = 0; i < n; i++ )
+ __vmwrite(field[i], value[i]);
+ virtual_vmcs_exit(vvmcs);
+
+ return;
+
+fallback:
+ for ( i = 0; i < n; i++ )
+ shadow_to_vvmcs(vvmcs, field[i]);
+}
+
static void load_shadow_control(struct vcpu *v)
{
/*
@@ -867,13 +958,18 @@ static void load_shadow_guest_state(struct vcpu *v)
{
struct nestedvcpu *nvcpu = &vcpu_nestedhvm(v);
void *vvmcs = nvcpu->nv_vvmcx;
- int i;
u32 control;
u64 cr_gh_mask, cr_read_shadow;
+ static const u16 vmentry_fields[] = {
+ VM_ENTRY_INTR_INFO,
+ VM_ENTRY_EXCEPTION_ERROR_CODE,
+ VM_ENTRY_INSTRUCTION_LEN,
+ };
+
/* vvmcs.gstate to shadow vmcs.gstate */
- for ( i = 0; i < ARRAY_SIZE(vmcs_gstate_field); i++ )
- vvmcs_to_shadow(vvmcs, vmcs_gstate_field[i]);
+ vvmcs_to_shadow_bulk(v, ARRAY_SIZE(vmcs_gstate_field),
+ vmcs_gstate_field);
hvm_set_cr0(__get_vvmcs(vvmcs, GUEST_CR0));
hvm_set_cr4(__get_vvmcs(vvmcs, GUEST_CR4));
@@ -887,9 +983,7 @@ static void load_shadow_guest_state(struct vcpu *v)
hvm_funcs.set_tsc_offset(v, v->arch.hvm_vcpu.cache_tsc_offset);
- vvmcs_to_shadow(vvmcs, VM_ENTRY_INTR_INFO);
- vvmcs_to_shadow(vvmcs, VM_ENTRY_EXCEPTION_ERROR_CODE);
- vvmcs_to_shadow(vvmcs, VM_ENTRY_INSTRUCTION_LEN);
+ vvmcs_to_shadow_bulk(v, ARRAY_SIZE(vmentry_fields), vmentry_fields);
/*
* While emulate CR0 and CR4 for nested virtualization, set the CR0/CR4
@@ -909,10 +1003,13 @@ static void load_shadow_guest_state(struct vcpu *v)
if ( nvmx_ept_enabled(v) && hvm_pae_enabled(v) &&
(v->arch.hvm_vcpu.guest_efer & EFER_LMA) )
{
- vvmcs_to_shadow(vvmcs, GUEST_PDPTR0);
- vvmcs_to_shadow(vvmcs, GUEST_PDPTR1);
- vvmcs_to_shadow(vvmcs, GUEST_PDPTR2);
- vvmcs_to_shadow(vvmcs, GUEST_PDPTR3);
+ static const u16 gpdptr_fields[] = {
+ GUEST_PDPTR0,
+ GUEST_PDPTR1,
+ GUEST_PDPTR2,
+ GUEST_PDPTR3,
+ };
+ vvmcs_to_shadow_bulk(v, ARRAY_SIZE(gpdptr_fields), gpdptr_fields);
}
/* TODO: CR3 target control */
@@ -1003,13 +1100,12 @@ static void virtual_vmentry(struct cpu_user_regs *regs)
static void sync_vvmcs_guest_state(struct vcpu *v, struct cpu_user_regs *regs)
{
- int i;
struct nestedvcpu *nvcpu = &vcpu_nestedhvm(v);
void *vvmcs = nvcpu->nv_vvmcx;
/* copy shadow vmcs.gstate back to vvmcs.gstate */
- for ( i = 0; i < ARRAY_SIZE(vmcs_gstate_field); i++ )
- shadow_to_vvmcs(vvmcs, vmcs_gstate_field[i]);
+ shadow_to_vvmcs_bulk(v, ARRAY_SIZE(vmcs_gstate_field),
+ vmcs_gstate_field);
/* RIP, RSP are in user regs */
__set_vvmcs(vvmcs, GUEST_RIP, regs->eip);
__set_vvmcs(vvmcs, GUEST_RSP, regs->esp);
@@ -1021,13 +1117,11 @@ static void sync_vvmcs_guest_state(struct vcpu *v, struct cpu_user_regs *regs)
static void sync_vvmcs_ro(struct vcpu *v)
{
- int i;
struct nestedvcpu *nvcpu = &vcpu_nestedhvm(v);
struct nestedvmx *nvmx = &vcpu_2_nvmx(v);
void *vvmcs = nvcpu->nv_vvmcx;
- for ( i = 0; i < ARRAY_SIZE(vmcs_ro_field); i++ )
- shadow_to_vvmcs(nvcpu->nv_vvmcx, vmcs_ro_field[i]);
+ shadow_to_vvmcs_bulk(v, ARRAY_SIZE(vmcs_ro_field), vmcs_ro_field);
/* Adjust exit_reason/exit_qualifciation for violation case */
if ( __get_vvmcs(vvmcs, VM_EXIT_REASON) == EXIT_REASON_EPT_VIOLATION )
diff --git a/xen/include/asm-x86/hvm/vmx/vvmx.h b/xen/include/asm-x86/hvm/vmx/vvmx.h
index 73a67cc..3874525 100644
--- a/xen/include/asm-x86/hvm/vmx/vvmx.h
+++ b/xen/include/asm-x86/hvm/vmx/vvmx.h
@@ -229,5 +229,7 @@ int nept_translate_l2ga(struct vcpu *v, paddr_t l2ga,
unsigned int *page_order, uint32_t rwx_acc,
unsigned long *l1gfn, uint8_t *p2m_acc,
uint64_t *exit_qual, uint32_t *exit_reason);
+int nvmx_cpu_up_prepare(unsigned int cpu);
+void nvmx_cpu_dead(unsigned int cpu);
#endif /* __ASM_X86_HVM_VVMX_H__ */
--
1.7.1
next prev parent reply other threads:[~2013-01-23 14:32 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-01-23 14:32 [PATCH v5 rebased 0/4] nested vmx: enable VMCS shadowing feature Dongxiao Xu
2013-01-23 14:32 ` [PATCH v5 rebased 1/4] nested vmx: Use a list to store the launched vvmcs for L1 VMM Dongxiao Xu
2013-01-25 2:13 ` Dong, Eddie
2013-01-23 14:32 ` [PATCH v5 rebased 2/4] nested vmx: use VMREAD/VMWRITE to construct vVMCS if enabled VMCS shadowing Dongxiao Xu
2013-01-25 2:26 ` Dong, Eddie
2013-01-23 14:32 ` Dongxiao Xu [this message]
2013-01-25 2:27 ` [PATCH v5 rebased 3/4] nested vmx: optimize for bulk access of virtual VMCS Dong, Eddie
2013-01-23 14:32 ` [PATCH v5 rebased 4/4] nested vmx: enable VMCS shadowing feature Dongxiao Xu
2013-01-23 14:55 ` Nakajima, Jun
2013-01-25 2:28 ` Dong, Eddie
2013-01-29 10:19 ` [PATCH v5 rebased 0/4] " Joerg Roedel
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=1358951532-20302-4-git-send-email-dongxiao.xu@intel.com \
--to=dongxiao.xu@intel.com \
--cc=JBeulich@suse.com \
--cc=eddie.dong@intel.com \
--cc=jun.nakajima@intel.com \
--cc=xen-devel@lists.xensource.com \
--cc=xiantao.zhang@intel.com \
/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;
as well as URLs for NNTP newsgroup(s).