diff options
author | Sheng Yang <sheng.yang@intel.com> | 2008-01-17 02:14:33 -0500 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-04-27 04:53:17 -0400 |
commit | 2384d2b32640839a4d4d260ca7c5aa4edbf68d91 (patch) | |
tree | 812ba0ea30b2fd59553bc7064b13cc107f276e6b | |
parent | adb1ff46754a87f3f6c9e7ee0a92f9a8a183bb38 (diff) |
KVM: VMX: Enable Virtual Processor Identification (VPID)
To allow TLB entries to be retained across VM entry and VM exit, the VMM
can now identify distinct address spaces through a new virtual-processor ID
(VPID) field of the VMCS.
[avi: drop vpid_sync_all()]
[avi: add "cc" to asm constraints]
Signed-off-by: Sheng Yang <sheng.yang@intel.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
-rw-r--r-- | arch/x86/kvm/vmx.c | 80 | ||||
-rw-r--r-- | arch/x86/kvm/vmx.h | 6 | ||||
-rw-r--r-- | include/asm-x86/kvm_host.h | 1 |
3 files changed, 82 insertions, 5 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 8e1462880d1f..1157e8a4059b 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -37,6 +37,9 @@ MODULE_LICENSE("GPL"); | |||
37 | static int bypass_guest_pf = 1; | 37 | static int bypass_guest_pf = 1; |
38 | module_param(bypass_guest_pf, bool, 0); | 38 | module_param(bypass_guest_pf, bool, 0); |
39 | 39 | ||
40 | static int enable_vpid = 1; | ||
41 | module_param(enable_vpid, bool, 0); | ||
42 | |||
40 | struct vmcs { | 43 | struct vmcs { |
41 | u32 revision_id; | 44 | u32 revision_id; |
42 | u32 abort; | 45 | u32 abort; |
@@ -71,6 +74,7 @@ struct vcpu_vmx { | |||
71 | unsigned rip; | 74 | unsigned rip; |
72 | } irq; | 75 | } irq; |
73 | } rmode; | 76 | } rmode; |
77 | int vpid; | ||
74 | }; | 78 | }; |
75 | 79 | ||
76 | static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu) | 80 | static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu) |
@@ -86,6 +90,9 @@ static DEFINE_PER_CPU(struct vmcs *, current_vmcs); | |||
86 | static struct page *vmx_io_bitmap_a; | 90 | static struct page *vmx_io_bitmap_a; |
87 | static struct page *vmx_io_bitmap_b; | 91 | static struct page *vmx_io_bitmap_b; |
88 | 92 | ||
93 | static DECLARE_BITMAP(vmx_vpid_bitmap, VMX_NR_VPIDS); | ||
94 | static DEFINE_SPINLOCK(vmx_vpid_lock); | ||
95 | |||
89 | static struct vmcs_config { | 96 | static struct vmcs_config { |
90 | int size; | 97 | int size; |
91 | int order; | 98 | int order; |
@@ -204,6 +211,12 @@ static inline int vm_need_virtualize_apic_accesses(struct kvm *kvm) | |||
204 | (irqchip_in_kernel(kvm))); | 211 | (irqchip_in_kernel(kvm))); |
205 | } | 212 | } |
206 | 213 | ||
214 | static inline int cpu_has_vmx_vpid(void) | ||
215 | { | ||
216 | return (vmcs_config.cpu_based_2nd_exec_ctrl & | ||
217 | SECONDARY_EXEC_ENABLE_VPID); | ||
218 | } | ||
219 | |||
207 | static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr) | 220 | static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr) |
208 | { | 221 | { |
209 | int i; | 222 | int i; |
@@ -214,6 +227,20 @@ static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr) | |||
214 | return -1; | 227 | return -1; |
215 | } | 228 | } |
216 | 229 | ||
230 | static inline void __invvpid(int ext, u16 vpid, gva_t gva) | ||
231 | { | ||
232 | struct { | ||
233 | u64 vpid : 16; | ||
234 | u64 rsvd : 48; | ||
235 | u64 gva; | ||
236 | } operand = { vpid, 0, gva }; | ||
237 | |||
238 | asm volatile (ASM_VMX_INVVPID | ||
239 | /* CF==1 or ZF==1 --> rc = -1 */ | ||
240 | "; ja 1f ; ud2 ; 1:" | ||
241 | : : "a"(&operand), "c"(ext) : "cc", "memory"); | ||
242 | } | ||
243 | |||
217 | static struct kvm_msr_entry *find_msr_entry(struct vcpu_vmx *vmx, u32 msr) | 244 | static struct kvm_msr_entry *find_msr_entry(struct vcpu_vmx *vmx, u32 msr) |
218 | { | 245 | { |
219 | int i; | 246 | int i; |
@@ -257,6 +284,14 @@ static void vcpu_clear(struct vcpu_vmx *vmx) | |||
257 | vmx->launched = 0; | 284 | vmx->launched = 0; |
258 | } | 285 | } |
259 | 286 | ||
287 | static inline void vpid_sync_vcpu_all(struct vcpu_vmx *vmx) | ||
288 | { | ||
289 | if (vmx->vpid == 0) | ||
290 | return; | ||
291 | |||
292 | __invvpid(VMX_VPID_EXTENT_SINGLE_CONTEXT, vmx->vpid, 0); | ||
293 | } | ||
294 | |||
260 | static unsigned long vmcs_readl(unsigned long field) | 295 | static unsigned long vmcs_readl(unsigned long field) |
261 | { | 296 | { |
262 | unsigned long value; | 297 | unsigned long value; |
@@ -490,6 +525,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | |||
490 | if (vcpu->cpu != cpu) { | 525 | if (vcpu->cpu != cpu) { |
491 | vcpu_clear(vmx); | 526 | vcpu_clear(vmx); |
492 | kvm_migrate_apic_timer(vcpu); | 527 | kvm_migrate_apic_timer(vcpu); |
528 | vpid_sync_vcpu_all(vmx); | ||
493 | } | 529 | } |
494 | 530 | ||
495 | if (per_cpu(current_vmcs, cpu) != vmx->vmcs) { | 531 | if (per_cpu(current_vmcs, cpu) != vmx->vmcs) { |
@@ -971,7 +1007,8 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf) | |||
971 | if (_cpu_based_exec_control & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) { | 1007 | if (_cpu_based_exec_control & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) { |
972 | min = 0; | 1008 | min = 0; |
973 | opt = SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | | 1009 | opt = SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | |
974 | SECONDARY_EXEC_WBINVD_EXITING; | 1010 | SECONDARY_EXEC_WBINVD_EXITING | |
1011 | SECONDARY_EXEC_ENABLE_VPID; | ||
975 | if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS2, | 1012 | if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS2, |
976 | &_cpu_based_2nd_exec_control) < 0) | 1013 | &_cpu_based_2nd_exec_control) < 0) |
977 | return -EIO; | 1014 | return -EIO; |
@@ -1239,6 +1276,11 @@ static void exit_lmode(struct kvm_vcpu *vcpu) | |||
1239 | 1276 | ||
1240 | #endif | 1277 | #endif |
1241 | 1278 | ||
1279 | static void vmx_flush_tlb(struct kvm_vcpu *vcpu) | ||
1280 | { | ||
1281 | vpid_sync_vcpu_all(to_vmx(vcpu)); | ||
1282 | } | ||
1283 | |||
1242 | static void vmx_decache_cr4_guest_bits(struct kvm_vcpu *vcpu) | 1284 | static void vmx_decache_cr4_guest_bits(struct kvm_vcpu *vcpu) |
1243 | { | 1285 | { |
1244 | vcpu->arch.cr4 &= KVM_GUEST_CR4_MASK; | 1286 | vcpu->arch.cr4 &= KVM_GUEST_CR4_MASK; |
@@ -1275,6 +1317,7 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) | |||
1275 | 1317 | ||
1276 | static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) | 1318 | static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) |
1277 | { | 1319 | { |
1320 | vmx_flush_tlb(vcpu); | ||
1278 | vmcs_writel(GUEST_CR3, cr3); | 1321 | vmcs_writel(GUEST_CR3, cr3); |
1279 | if (vcpu->arch.cr0 & X86_CR0_PE) | 1322 | if (vcpu->arch.cr0 & X86_CR0_PE) |
1280 | vmx_fpu_deactivate(vcpu); | 1323 | vmx_fpu_deactivate(vcpu); |
@@ -1494,6 +1537,22 @@ out: | |||
1494 | return r; | 1537 | return r; |
1495 | } | 1538 | } |
1496 | 1539 | ||
1540 | static void allocate_vpid(struct vcpu_vmx *vmx) | ||
1541 | { | ||
1542 | int vpid; | ||
1543 | |||
1544 | vmx->vpid = 0; | ||
1545 | if (!enable_vpid || !cpu_has_vmx_vpid()) | ||
1546 | return; | ||
1547 | spin_lock(&vmx_vpid_lock); | ||
1548 | vpid = find_first_zero_bit(vmx_vpid_bitmap, VMX_NR_VPIDS); | ||
1549 | if (vpid < VMX_NR_VPIDS) { | ||
1550 | vmx->vpid = vpid; | ||
1551 | __set_bit(vpid, vmx_vpid_bitmap); | ||
1552 | } | ||
1553 | spin_unlock(&vmx_vpid_lock); | ||
1554 | } | ||
1555 | |||
1497 | /* | 1556 | /* |
1498 | * Sets up the vmcs for emulated real mode. | 1557 | * Sets up the vmcs for emulated real mode. |
1499 | */ | 1558 | */ |
@@ -1532,6 +1591,8 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) | |||
1532 | if (!vm_need_virtualize_apic_accesses(vmx->vcpu.kvm)) | 1591 | if (!vm_need_virtualize_apic_accesses(vmx->vcpu.kvm)) |
1533 | exec_control &= | 1592 | exec_control &= |
1534 | ~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES; | 1593 | ~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES; |
1594 | if (vmx->vpid == 0) | ||
1595 | exec_control &= ~SECONDARY_EXEC_ENABLE_VPID; | ||
1535 | vmcs_write32(SECONDARY_VM_EXEC_CONTROL, exec_control); | 1596 | vmcs_write32(SECONDARY_VM_EXEC_CONTROL, exec_control); |
1536 | } | 1597 | } |
1537 | 1598 | ||
@@ -1704,6 +1765,9 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu) | |||
1704 | vmcs_write64(APIC_ACCESS_ADDR, | 1765 | vmcs_write64(APIC_ACCESS_ADDR, |
1705 | page_to_phys(vmx->vcpu.kvm->arch.apic_access_page)); | 1766 | page_to_phys(vmx->vcpu.kvm->arch.apic_access_page)); |
1706 | 1767 | ||
1768 | if (vmx->vpid != 0) | ||
1769 | vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->vpid); | ||
1770 | |||
1707 | vmx->vcpu.arch.cr0 = 0x60000010; | 1771 | vmx->vcpu.arch.cr0 = 0x60000010; |
1708 | vmx_set_cr0(&vmx->vcpu, vmx->vcpu.arch.cr0); /* enter rmode */ | 1772 | vmx_set_cr0(&vmx->vcpu, vmx->vcpu.arch.cr0); /* enter rmode */ |
1709 | vmx_set_cr4(&vmx->vcpu, 0); | 1773 | vmx_set_cr4(&vmx->vcpu, 0); |
@@ -1713,6 +1777,8 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu) | |||
1713 | vmx_fpu_activate(&vmx->vcpu); | 1777 | vmx_fpu_activate(&vmx->vcpu); |
1714 | update_exception_bitmap(&vmx->vcpu); | 1778 | update_exception_bitmap(&vmx->vcpu); |
1715 | 1779 | ||
1780 | vpid_sync_vcpu_all(vmx); | ||
1781 | |||
1716 | return 0; | 1782 | return 0; |
1717 | 1783 | ||
1718 | out: | 1784 | out: |
@@ -2221,10 +2287,6 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) | |||
2221 | return 0; | 2287 | return 0; |
2222 | } | 2288 | } |
2223 | 2289 | ||
2224 | static void vmx_flush_tlb(struct kvm_vcpu *vcpu) | ||
2225 | { | ||
2226 | } | ||
2227 | |||
2228 | static void update_tpr_threshold(struct kvm_vcpu *vcpu) | 2290 | static void update_tpr_threshold(struct kvm_vcpu *vcpu) |
2229 | { | 2291 | { |
2230 | int max_irr, tpr; | 2292 | int max_irr, tpr; |
@@ -2489,6 +2551,10 @@ static void vmx_free_vcpu(struct kvm_vcpu *vcpu) | |||
2489 | { | 2551 | { |
2490 | struct vcpu_vmx *vmx = to_vmx(vcpu); | 2552 | struct vcpu_vmx *vmx = to_vmx(vcpu); |
2491 | 2553 | ||
2554 | spin_lock(&vmx_vpid_lock); | ||
2555 | if (vmx->vpid != 0) | ||
2556 | __clear_bit(vmx->vpid, vmx_vpid_bitmap); | ||
2557 | spin_unlock(&vmx_vpid_lock); | ||
2492 | vmx_free_vmcs(vcpu); | 2558 | vmx_free_vmcs(vcpu); |
2493 | kfree(vmx->host_msrs); | 2559 | kfree(vmx->host_msrs); |
2494 | kfree(vmx->guest_msrs); | 2560 | kfree(vmx->guest_msrs); |
@@ -2505,6 +2571,8 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) | |||
2505 | if (!vmx) | 2571 | if (!vmx) |
2506 | return ERR_PTR(-ENOMEM); | 2572 | return ERR_PTR(-ENOMEM); |
2507 | 2573 | ||
2574 | allocate_vpid(vmx); | ||
2575 | |||
2508 | err = kvm_vcpu_init(&vmx->vcpu, kvm, id); | 2576 | err = kvm_vcpu_init(&vmx->vcpu, kvm, id); |
2509 | if (err) | 2577 | if (err) |
2510 | goto free_vcpu; | 2578 | goto free_vcpu; |
@@ -2652,6 +2720,8 @@ static int __init vmx_init(void) | |||
2652 | memset(iova, 0xff, PAGE_SIZE); | 2720 | memset(iova, 0xff, PAGE_SIZE); |
2653 | kunmap(vmx_io_bitmap_b); | 2721 | kunmap(vmx_io_bitmap_b); |
2654 | 2722 | ||
2723 | set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */ | ||
2724 | |||
2655 | r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx), THIS_MODULE); | 2725 | r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx), THIS_MODULE); |
2656 | if (r) | 2726 | if (r) |
2657 | goto out1; | 2727 | goto out1; |
diff --git a/arch/x86/kvm/vmx.h b/arch/x86/kvm/vmx.h index d52ae8d7303d..436ce0f29092 100644 --- a/arch/x86/kvm/vmx.h +++ b/arch/x86/kvm/vmx.h | |||
@@ -49,6 +49,7 @@ | |||
49 | * Definitions of Secondary Processor-Based VM-Execution Controls. | 49 | * Definitions of Secondary Processor-Based VM-Execution Controls. |
50 | */ | 50 | */ |
51 | #define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001 | 51 | #define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001 |
52 | #define SECONDARY_EXEC_ENABLE_VPID 0x00000020 | ||
52 | #define SECONDARY_EXEC_WBINVD_EXITING 0x00000040 | 53 | #define SECONDARY_EXEC_WBINVD_EXITING 0x00000040 |
53 | 54 | ||
54 | 55 | ||
@@ -65,6 +66,7 @@ | |||
65 | 66 | ||
66 | /* VMCS Encodings */ | 67 | /* VMCS Encodings */ |
67 | enum vmcs_field { | 68 | enum vmcs_field { |
69 | VIRTUAL_PROCESSOR_ID = 0x00000000, | ||
68 | GUEST_ES_SELECTOR = 0x00000800, | 70 | GUEST_ES_SELECTOR = 0x00000800, |
69 | GUEST_CS_SELECTOR = 0x00000802, | 71 | GUEST_CS_SELECTOR = 0x00000802, |
70 | GUEST_SS_SELECTOR = 0x00000804, | 72 | GUEST_SS_SELECTOR = 0x00000804, |
@@ -321,4 +323,8 @@ enum vmcs_field { | |||
321 | 323 | ||
322 | #define APIC_ACCESS_PAGE_PRIVATE_MEMSLOT 9 | 324 | #define APIC_ACCESS_PAGE_PRIVATE_MEMSLOT 9 |
323 | 325 | ||
326 | #define VMX_NR_VPIDS (1 << 16) | ||
327 | #define VMX_VPID_EXTENT_SINGLE_CONTEXT 1 | ||
328 | #define VMX_VPID_EXTENT_ALL_CONTEXT 2 | ||
329 | |||
324 | #endif | 330 | #endif |
diff --git a/include/asm-x86/kvm_host.h b/include/asm-x86/kvm_host.h index e076790ee794..28e8177ea4a0 100644 --- a/include/asm-x86/kvm_host.h +++ b/include/asm-x86/kvm_host.h | |||
@@ -601,6 +601,7 @@ static inline void kvm_inject_gp(struct kvm_vcpu *vcpu, u32 error_code) | |||
601 | #define ASM_VMX_VMWRITE_RSP_RDX ".byte 0x0f, 0x79, 0xd4" | 601 | #define ASM_VMX_VMWRITE_RSP_RDX ".byte 0x0f, 0x79, 0xd4" |
602 | #define ASM_VMX_VMXOFF ".byte 0x0f, 0x01, 0xc4" | 602 | #define ASM_VMX_VMXOFF ".byte 0x0f, 0x01, 0xc4" |
603 | #define ASM_VMX_VMXON_RAX ".byte 0xf3, 0x0f, 0xc7, 0x30" | 603 | #define ASM_VMX_VMXON_RAX ".byte 0xf3, 0x0f, 0xc7, 0x30" |
604 | #define ASM_VMX_INVVPID ".byte 0x66, 0x0f, 0x38, 0x81, 0x08" | ||
604 | 605 | ||
605 | #define MSR_IA32_TIME_STAMP_COUNTER 0x010 | 606 | #define MSR_IA32_TIME_STAMP_COUNTER 0x010 |
606 | 607 | ||