diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2009-12-08 14:14:27 +0000 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2009-12-08 14:14:27 +0000 |
commit | 7aab6d6523ecc31156d3f36f55e599e0c4f73325 (patch) | |
tree | fb60fea0540e31cd8ae66b1c044f45024b673915 | |
parent | c4a0c89b8c23b3e9f5b2ab9ad72a264b48774811 (diff) | |
download | xen-7aab6d6523ecc31156d3f36f55e599e0c4f73325.tar.gz xen-7aab6d6523ecc31156d3f36f55e599e0c4f73325.tar.bz2 xen-7aab6d6523ecc31156d3f36f55e599e0c4f73325.zip |
hvm: Share ASID logic between VMX and SVM.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
-rw-r--r-- | xen/arch/x86/hvm/asid.c | 6 | ||||
-rw-r--r-- | xen/arch/x86/hvm/hvm.c | 2 | ||||
-rw-r--r-- | xen/arch/x86/hvm/svm/svm.c | 13 | ||||
-rw-r--r-- | xen/arch/x86/hvm/svm/vmcb.c | 3 | ||||
-rw-r--r-- | xen/arch/x86/hvm/vmx/entry.S | 2 | ||||
-rw-r--r-- | xen/arch/x86/hvm/vmx/vmcs.c | 12 | ||||
-rw-r--r-- | xen/arch/x86/hvm/vmx/vmx.c | 109 | ||||
-rw-r--r-- | xen/include/asm-x86/hvm/asid.h | 6 | ||||
-rw-r--r-- | xen/include/asm-x86/hvm/hvm.h | 18 | ||||
-rw-r--r-- | xen/include/asm-x86/hvm/svm/asid.h | 2 | ||||
-rw-r--r-- | xen/include/asm-x86/hvm/vmx/vmcs.h | 2 | ||||
-rw-r--r-- | xen/include/asm-x86/hvm/vmx/vmx.h | 12 |
12 files changed, 72 insertions, 115 deletions
diff --git a/xen/arch/x86/hvm/asid.c b/xen/arch/x86/hvm/asid.c index 85754d18bb..69f3f577f8 100644 --- a/xen/arch/x86/hvm/asid.c +++ b/xen/arch/x86/hvm/asid.c @@ -20,7 +20,9 @@ #include <xen/config.h> #include <xen/init.h> #include <xen/lib.h> -#include <xen/perfc.h> +#include <xen/sched.h> +#include <xen/smp.h> +#include <xen/percpu.h> #include <asm/hvm/asid.h> /* @@ -80,7 +82,7 @@ void hvm_asid_init(int nasids) data->next_asid = 1; } -void hvm_asid_invalidate_asid(struct vcpu *v) +void hvm_asid_flush_vcpu(struct vcpu *v) { v->arch.hvm_vcpu.asid_generation = 0; } diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 42121fec80..d2e8a7162e 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -756,6 +756,8 @@ int hvm_vcpu_initialise(struct vcpu *v) { int rc; + hvm_asid_flush_vcpu(v); + if ( cpu_has_xsave ) { /* XSAVE/XRSTOR requires the save area be 64-byte-boundary aligned. */ diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index 7695f3b831..c297b0b509 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -424,7 +424,7 @@ static void svm_update_guest_cr(struct vcpu *v, unsigned int cr) break; case 3: vmcb->cr3 = v->arch.hvm_vcpu.hw_cr[3]; - hvm_asid_invalidate_asid(v); + hvm_asid_flush_vcpu(v); break; case 4: vmcb->cr4 = HVM_CR4_HOST_MASK; @@ -455,14 +455,6 @@ static void svm_update_guest_efer(struct vcpu *v) svm_intercept_msr(v, MSR_IA32_SYSENTER_EIP, lma); } -static void svm_flush_guest_tlbs(void) -{ - /* Roll over the CPU's ASID generation, so it gets a clean TLB when we - * next VMRUN. (If ASIDs are disabled, the whole TLB is flushed on - * VMRUN anyway). */ - hvm_asid_flush_core(); -} - static void svm_sync_vmcb(struct vcpu *v) { struct arch_svm_struct *arch_svm = &v->arch.hvm_svm; @@ -704,7 +696,7 @@ static void svm_do_resume(struct vcpu *v) hvm_migrate_timers(v); /* Migrating to another ASID domain. Request a new ASID. */ - hvm_asid_invalidate_asid(v); + hvm_asid_flush_vcpu(v); } /* Reflect the vlapic's TPR in the hardware vtpr */ @@ -1250,7 +1242,6 @@ static struct hvm_function_table __read_mostly svm_function_table = { .update_host_cr3 = svm_update_host_cr3, .update_guest_cr = svm_update_guest_cr, .update_guest_efer = svm_update_guest_efer, - .flush_guest_tlbs = svm_flush_guest_tlbs, .set_tsc_offset = svm_set_tsc_offset, .inject_exception = svm_inject_exception, .init_hypercall_page = svm_init_hypercall_page, diff --git a/xen/arch/x86/hvm/svm/vmcb.c b/xen/arch/x86/hvm/svm/vmcb.c index 71302cc194..9218028221 100644 --- a/xen/arch/x86/hvm/svm/vmcb.c +++ b/xen/arch/x86/hvm/svm/vmcb.c @@ -114,9 +114,6 @@ static int construct_vmcb(struct vcpu *v) struct arch_svm_struct *arch_svm = &v->arch.hvm_svm; struct vmcb_struct *vmcb = arch_svm->vmcb; - /* TLB control, and ASID assigment. */ - hvm_asid_invalidate_asid(v); - vmcb->general1_intercepts = GENERAL1_INTERCEPT_INTR | GENERAL1_INTERCEPT_NMI | GENERAL1_INTERCEPT_SMI | GENERAL1_INTERCEPT_INIT | diff --git a/xen/arch/x86/hvm/vmx/entry.S b/xen/arch/x86/hvm/vmx/entry.S index 8720efccee..9fb7ecb97c 100644 --- a/xen/arch/x86/hvm/vmx/entry.S +++ b/xen/arch/x86/hvm/vmx/entry.S @@ -142,9 +142,9 @@ vmx_asm_do_vmentry: call_with_regs(vmx_enter_realmode) .Lvmx_not_realmode: + call vmx_vmenter_helper mov VCPU_hvm_guest_cr2(r(bx)),r(ax) mov r(ax),%cr2 - call vmx_trace_vmentry lea UREGS_rip(r(sp)),r(di) mov $GUEST_RIP,%eax diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c index bcbf7ccb65..8c974b79ca 100644 --- a/xen/arch/x86/hvm/vmx/vmcs.c +++ b/xen/arch/x86/hvm/vmx/vmcs.c @@ -400,9 +400,12 @@ int vmx_cpu_up(void) BUG(); } + hvm_asid_init(cpu_has_vmx_vpid ? (1u << VMCS_VPID_WIDTH) : 0); + ept_sync_all(); - vpid_sync_all(); + if ( cpu_has_vmx_vpid ) + vpid_sync_all(); return 1; } @@ -559,6 +562,9 @@ static int construct_vmcs(struct vcpu *v) v->arch.hvm_vmx.secondary_exec_control = vmx_secondary_exec_control; + /* Disable VPID for now: we decide when to enable it on VMENTER. */ + v->arch.hvm_vmx.secondary_exec_control &= ~SECONDARY_EXEC_ENABLE_VPID; + if ( paging_mode_hap(d) ) { v->arch.hvm_vmx.exec_control &= ~(CPU_BASED_INVLPG_EXITING | @@ -736,7 +742,7 @@ static int construct_vmcs(struct vcpu *v) } if ( cpu_has_vmx_vpid ) - __vmwrite(VIRTUAL_PROCESSOR_ID, v->arch.hvm_vmx.vpid); + __vmwrite(VIRTUAL_PROCESSOR_ID, v->arch.hvm_vcpu.asid); if ( cpu_has_vmx_pat && paging_mode_hap(d) ) { @@ -946,7 +952,7 @@ void vmx_do_resume(struct vcpu *v) hvm_migrate_timers(v); hvm_migrate_pirqs(v); vmx_set_host_env(v); - vpid_sync_vcpu_all(v); + hvm_asid_flush_vcpu(v); } debug_state = v->domain->debugger_attached; diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 20c30c5612..e2b55a5a04 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -60,8 +60,6 @@ static void vmx_ctxt_switch_to(struct vcpu *v); static int vmx_alloc_vlapic_mapping(struct domain *d); static void vmx_free_vlapic_mapping(struct domain *d); -static int vmx_alloc_vpid(struct vcpu *v); -static void vmx_free_vpid(struct vcpu *v); static void vmx_install_vlapic_mapping(struct vcpu *v); static void vmx_update_guest_cr(struct vcpu *v, unsigned int cr); static void vmx_update_guest_efer(struct vcpu *v); @@ -104,9 +102,6 @@ static int vmx_vcpu_initialise(struct vcpu *v) spin_lock_init(&v->arch.hvm_vmx.vmcs_lock); - if ( (rc = vmx_alloc_vpid(v)) != 0 ) - return rc; - v->arch.schedule_tail = vmx_do_resume; v->arch.ctxt_switch_from = vmx_ctxt_switch_from; v->arch.ctxt_switch_to = vmx_ctxt_switch_to; @@ -116,7 +111,6 @@ static int vmx_vcpu_initialise(struct vcpu *v) dprintk(XENLOG_WARNING, "Failed to create VMCS for vcpu %d: err=%d.\n", v->vcpu_id, rc); - vmx_free_vpid(v); return rc; } @@ -136,7 +130,6 @@ static void vmx_vcpu_destroy(struct vcpu *v) vmx_destroy_vmcs(v); vpmu_destroy(v); passive_domain_destroy(v); - vmx_free_vpid(v); } #ifdef __x86_64__ @@ -1168,7 +1161,7 @@ static void vmx_update_guest_cr(struct vcpu *v, unsigned int cr) } __vmwrite(GUEST_CR3, v->arch.hvm_vcpu.hw_cr[3]); - vpid_sync_vcpu_all(v); + hvm_asid_flush_vcpu(v); break; case 4: v->arch.hvm_vcpu.hw_cr[4] = HVM_CR4_HOST_MASK; @@ -1214,19 +1207,6 @@ static void vmx_update_guest_efer(struct vcpu *v) (v->arch.hvm_vcpu.guest_efer & EFER_SCE)); } -static void vmx_flush_guest_tlbs(void) -{ - /* - * If VPID (i.e. tagged TLB support) is not enabled, the fact that - * we're in Xen at all means any guest will have a clean TLB when - * it's next run, because VMRESUME will flush it for us. - * - * If enabled, we invalidate all translations associated with all - * VPID values. - */ - vpid_sync_all(); -} - static void __ept_sync_domain(void *info) { struct domain *d = info; @@ -1358,7 +1338,7 @@ static void vmx_set_uc_mode(struct vcpu *v) if ( paging_mode_hap(v->domain) ) ept_change_entry_emt_with_range( v->domain, 0, v->domain->arch.p2m->max_mapped_pfn); - vpid_sync_all(); + hvm_asid_flush_vcpu(v); } static void vmx_set_info_guest(struct vcpu *v) @@ -1405,7 +1385,6 @@ static struct hvm_function_table __read_mostly vmx_function_table = { .update_host_cr3 = vmx_update_host_cr3, .update_guest_cr = vmx_update_guest_cr, .update_guest_efer = vmx_update_guest_efer, - .flush_guest_tlbs = vmx_flush_guest_tlbs, .set_tsc_offset = vmx_set_tsc_offset, .inject_exception = vmx_inject_exception, .init_hypercall_page = vmx_init_hypercall_page, @@ -1424,9 +1403,6 @@ static struct hvm_function_table __read_mostly vmx_function_table = { .set_rdtsc_exiting = vmx_set_rdtsc_exiting }; -static unsigned long *vpid_bitmap; -#define VPID_BITMAP_SIZE (1u << VMCS_VPID_WIDTH) - void start_vmx(void) { static bool_t bootstrapped; @@ -1461,17 +1437,6 @@ void start_vmx(void) if ( cpu_has_vmx_ept ) vmx_function_table.hap_supported = 1; - if ( cpu_has_vmx_vpid ) - { - vpid_bitmap = xmalloc_array( - unsigned long, BITS_TO_LONGS(VPID_BITMAP_SIZE)); - BUG_ON(vpid_bitmap == NULL); - memset(vpid_bitmap, 0, BITS_TO_LONGS(VPID_BITMAP_SIZE) * sizeof(long)); - - /* VPID 0 is used by VMX root mode (the hypervisor). */ - __set_bit(0, vpid_bitmap); - } - setup_vmcs_dump(); hvm_enable(&vmx_function_table); @@ -1584,7 +1549,7 @@ static void vmx_invlpg_intercept(unsigned long vaddr) { struct vcpu *curr = current; HVMTRACE_LONG_2D(INVLPG, /*invlpga=*/ 0, TRC_PAR_LONG(vaddr)); - if ( paging_invlpg(curr, vaddr) ) + if ( paging_invlpg(curr, vaddr) && cpu_has_vmx_vpid ) vpid_sync_vcpu_gva(curr, vaddr); } @@ -1931,36 +1896,6 @@ static void vmx_free_vlapic_mapping(struct domain *d) free_xenheap_page(mfn_to_virt(mfn)); } -static int vmx_alloc_vpid(struct vcpu *v) -{ - int idx; - - if ( !cpu_has_vmx_vpid ) - return 0; - - do { - idx = find_first_zero_bit(vpid_bitmap, VPID_BITMAP_SIZE); - if ( idx >= VPID_BITMAP_SIZE ) - { - dprintk(XENLOG_WARNING, "VMX VPID space exhausted.\n"); - return -EBUSY; - } - } - while ( test_and_set_bit(idx, vpid_bitmap) ); - - v->arch.hvm_vmx.vpid = idx; - return 0; -} - -static void vmx_free_vpid(struct vcpu *v) -{ - if ( !cpu_has_vmx_vpid ) - return; - - if ( v->arch.hvm_vmx.vpid ) - clear_bit(v->arch.hvm_vmx.vpid, vpid_bitmap); -} - static void vmx_install_vlapic_mapping(struct vcpu *v) { paddr_t virt_page_ma, apic_page_ma; @@ -2675,8 +2610,44 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs *regs) } } -asmlinkage void vmx_trace_vmentry(void) +asmlinkage void vmx_vmenter_helper(void) { + struct vcpu *curr = current; + u32 new_asid, old_asid; + bool_t need_flush; + + if ( !cpu_has_vmx_vpid ) + goto out; + + old_asid = curr->arch.hvm_vcpu.asid; + need_flush = hvm_asid_handle_vmenter(); + new_asid = curr->arch.hvm_vcpu.asid; + + if ( unlikely(new_asid != old_asid) ) + { + __vmwrite(VIRTUAL_PROCESSOR_ID, new_asid); + if ( !old_asid && new_asid ) + { + /* VPID was disabled: now enabled. */ + curr->arch.hvm_vmx.secondary_exec_control |= + SECONDARY_EXEC_ENABLE_VPID; + __vmwrite(SECONDARY_VM_EXEC_CONTROL, + curr->arch.hvm_vmx.secondary_exec_control); + } + else if ( old_asid && !new_asid ) + { + /* VPID was enabled: now disabled. */ + curr->arch.hvm_vmx.secondary_exec_control &= + ~SECONDARY_EXEC_ENABLE_VPID; + __vmwrite(SECONDARY_VM_EXEC_CONTROL, + curr->arch.hvm_vmx.secondary_exec_control); + } + } + + if ( unlikely(need_flush) ) + vpid_sync_all(); + + out: HVMTRACE_ND (VMENTRY, 1/*cycles*/, 0, 0, 0, 0, 0, 0, 0); } diff --git a/xen/include/asm-x86/hvm/asid.h b/xen/include/asm-x86/hvm/asid.h index 336e61dd54..4ee520f1db 100644 --- a/xen/include/asm-x86/hvm/asid.h +++ b/xen/include/asm-x86/hvm/asid.h @@ -21,14 +21,14 @@ #define __ASM_X86_HVM_ASID_H__ #include <xen/config.h> -#include <xen/sched.h> -#include <asm/processor.h> + +struct vcpu; /* Initialise ASID management for the current physical CPU. */ void hvm_asid_init(int nasids); /* Invalidate a VCPU's current ASID allocation: forces re-allocation. */ -void hvm_asid_invalidate_asid(struct vcpu *v); +void hvm_asid_flush_vcpu(struct vcpu *v); /* Flush all ASIDs on this processor core. */ void hvm_asid_flush_core(void); diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h index cbff2e0a0d..8643f92926 100644 --- a/xen/include/asm-x86/hvm/hvm.h +++ b/xen/include/asm-x86/hvm/hvm.h @@ -23,6 +23,7 @@ #include <asm/current.h> #include <asm/x86_emulate.h> +#include <asm/hvm/asid.h> #include <public/domctl.h> #include <public/hvm/save.h> @@ -100,13 +101,6 @@ struct hvm_function_table { void (*update_guest_cr)(struct vcpu *v, unsigned int cr); void (*update_guest_efer)(struct vcpu *v); - /* - * Called to ensure than all guest-specific mappings in a tagged TLB - * are flushed; does *not* flush Xen's TLB entries, and on - * processors without a tagged TLB it will be a noop. - */ - void (*flush_guest_tlbs)(void); - void (*set_tsc_offset)(struct vcpu *v, u64 offset); void (*inject_exception)(unsigned int trapnr, int errcode, @@ -201,11 +195,15 @@ static inline void hvm_update_guest_efer(struct vcpu *v) hvm_funcs.update_guest_efer(v); } -static inline void -hvm_flush_guest_tlbs(void) +/* + * Called to ensure than all guest-specific mappings in a tagged TLB are + * flushed; does *not* flush Xen's TLB entries, and on processors without a + * tagged TLB it will be a noop. + */ +static inline void hvm_flush_guest_tlbs(void) { if ( hvm_enabled ) - hvm_funcs.flush_guest_tlbs(); + hvm_asid_flush_core(); } void hvm_hypercall_page_initialise(struct domain *d, diff --git a/xen/include/asm-x86/hvm/svm/asid.h b/xen/include/asm-x86/hvm/svm/asid.h index 25a8835e7e..a484f3eff3 100644 --- a/xen/include/asm-x86/hvm/svm/asid.h +++ b/xen/include/asm-x86/hvm/svm/asid.h @@ -41,7 +41,7 @@ static inline void svm_asid_g_invlpg(struct vcpu *v, unsigned long g_vaddr) #endif /* Safe fallback. Take a new ASID. */ - hvm_asid_invalidate_asid(v); + hvm_asid_flush_vcpu(v); } #endif /* __ASM_X86_HVM_SVM_ASID_H__ */ diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/vmx/vmcs.h index f7c3c78cf7..a24985bd64 100644 --- a/xen/include/asm-x86/hvm/vmx/vmcs.h +++ b/xen/include/asm-x86/hvm/vmx/vmcs.h @@ -90,8 +90,6 @@ struct arch_vmx_struct { u32 exec_control; u32 secondary_exec_control; - u16 vpid; - /* PMU */ struct vpmu_struct vpmu; diff --git a/xen/include/asm-x86/hvm/vmx/vmx.h b/xen/include/asm-x86/hvm/vmx/vmx.h index ddda6c09aa..8894dbf6d8 100644 --- a/xen/include/asm-x86/hvm/vmx/vmx.h +++ b/xen/include/asm-x86/hvm/vmx/vmx.h @@ -314,20 +314,12 @@ void ept_sync_domain(struct domain *d); static inline void vpid_sync_vcpu_gva(struct vcpu *v, unsigned long gva) { - if ( cpu_has_vmx_vpid ) - __invvpid(0, v->arch.hvm_vmx.vpid, (u64)gva); -} - -static inline void vpid_sync_vcpu_all(struct vcpu *v) -{ - if ( cpu_has_vmx_vpid ) - __invvpid(1, v->arch.hvm_vmx.vpid, 0); + __invvpid(0, v->arch.hvm_vcpu.asid, (u64)gva); } static inline void vpid_sync_all(void) { - if ( cpu_has_vmx_vpid ) - __invvpid(2, 0, 0); + __invvpid(2, 0, 0); } static inline void __vmxoff(void) |