[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v5 rebased 3/4] nested vmx: optimize for bulk access of virtual VMCS
Acked-by Eddie Dong <eddie.dong@xxxxxxxxx> > -----Original Message----- > From: Xu, Dongxiao > Sent: Wednesday, January 23, 2013 10:32 PM > To: xen-devel@xxxxxxxxxxxxxxxxxxx > Cc: Dong, Eddie; Nakajima, Jun; Zhang, Xiantao; JBeulich@xxxxxxxx > Subject: [PATCH v5 rebased 3/4] nested vmx: optimize for bulk access of > virtual VMCS > > 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@xxxxxxxxx> > --- > 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 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |