aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/kvm/vmx.c
diff options
context:
space:
mode:
authorSheng Yang <sheng.yang@intel.com>2007-10-28 21:40:42 -0400
committerAvi Kivity <avi@qumranet.com>2008-01-30 10:52:58 -0500
commitf78e0e2ee498e8f847500b565792c7d7634dcf54 (patch)
treedfd8f35883b40939a1ec013e27e6303af06d3e77 /drivers/kvm/vmx.c
parenta03490ed29d2771c675d4d9c0ffe22e19a1757f3 (diff)
KVM: VMX: Enable memory mapped TPR shadow (FlexPriority)
This patch based on CR8/TPR patch, and enable the TPR shadow (FlexPriority) for 32bit Windows. Since TPR is accessed very frequently by 32bit Windows, especially SMP guest, with FlexPriority enabled, we saw significant performance gain. Signed-off-by: Sheng Yang <sheng.yang@intel.com> Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm/vmx.c')
-rw-r--r--drivers/kvm/vmx.c117
1 files changed, 104 insertions, 13 deletions
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index 7fe834cb0d81..eca422e9506d 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -86,6 +86,7 @@ static struct vmcs_config {
86 u32 revision_id; 86 u32 revision_id;
87 u32 pin_based_exec_ctrl; 87 u32 pin_based_exec_ctrl;
88 u32 cpu_based_exec_ctrl; 88 u32 cpu_based_exec_ctrl;
89 u32 cpu_based_2nd_exec_ctrl;
89 u32 vmexit_ctrl; 90 u32 vmexit_ctrl;
90 u32 vmentry_ctrl; 91 u32 vmentry_ctrl;
91} vmcs_config; 92} vmcs_config;
@@ -179,6 +180,29 @@ static inline int vm_need_tpr_shadow(struct kvm *kvm)
179 return ((cpu_has_vmx_tpr_shadow()) && (irqchip_in_kernel(kvm))); 180 return ((cpu_has_vmx_tpr_shadow()) && (irqchip_in_kernel(kvm)));
180} 181}
181 182
183static inline int cpu_has_secondary_exec_ctrls(void)
184{
185 return (vmcs_config.cpu_based_exec_ctrl &
186 CPU_BASED_ACTIVATE_SECONDARY_CONTROLS);
187}
188
189static inline int vm_need_secondary_exec_ctrls(struct kvm *kvm)
190{
191 return ((cpu_has_secondary_exec_ctrls()) && (irqchip_in_kernel(kvm)));
192}
193
194static inline int cpu_has_vmx_virtualize_apic_accesses(void)
195{
196 return (vmcs_config.cpu_based_2nd_exec_ctrl &
197 SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES);
198}
199
200static inline int vm_need_virtualize_apic_accesses(struct kvm *kvm)
201{
202 return ((cpu_has_vmx_virtualize_apic_accesses()) &&
203 (irqchip_in_kernel(kvm)));
204}
205
182static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr) 206static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr)
183{ 207{
184 int i; 208 int i;
@@ -918,6 +942,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
918 u32 min, opt; 942 u32 min, opt;
919 u32 _pin_based_exec_control = 0; 943 u32 _pin_based_exec_control = 0;
920 u32 _cpu_based_exec_control = 0; 944 u32 _cpu_based_exec_control = 0;
945 u32 _cpu_based_2nd_exec_control = 0;
921 u32 _vmexit_control = 0; 946 u32 _vmexit_control = 0;
922 u32 _vmentry_control = 0; 947 u32 _vmentry_control = 0;
923 948
@@ -935,11 +960,8 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
935 CPU_BASED_USE_IO_BITMAPS | 960 CPU_BASED_USE_IO_BITMAPS |
936 CPU_BASED_MOV_DR_EXITING | 961 CPU_BASED_MOV_DR_EXITING |
937 CPU_BASED_USE_TSC_OFFSETING; 962 CPU_BASED_USE_TSC_OFFSETING;
938#ifdef CONFIG_X86_64 963 opt = CPU_BASED_TPR_SHADOW |
939 opt = CPU_BASED_TPR_SHADOW; 964 CPU_BASED_ACTIVATE_SECONDARY_CONTROLS;
940#else
941 opt = 0;
942#endif
943 if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS, 965 if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS,
944 &_cpu_based_exec_control) < 0) 966 &_cpu_based_exec_control) < 0)
945 return -EIO; 967 return -EIO;
@@ -948,6 +970,18 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
948 _cpu_based_exec_control &= ~CPU_BASED_CR8_LOAD_EXITING & 970 _cpu_based_exec_control &= ~CPU_BASED_CR8_LOAD_EXITING &
949 ~CPU_BASED_CR8_STORE_EXITING; 971 ~CPU_BASED_CR8_STORE_EXITING;
950#endif 972#endif
973 if (_cpu_based_exec_control & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) {
974 min = 0;
975 opt = SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
976 if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS2,
977 &_cpu_based_2nd_exec_control) < 0)
978 return -EIO;
979 }
980#ifndef CONFIG_X86_64
981 if (!(_cpu_based_2nd_exec_control &
982 SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES))
983 _cpu_based_exec_control &= ~CPU_BASED_TPR_SHADOW;
984#endif
951 985
952 min = 0; 986 min = 0;
953#ifdef CONFIG_X86_64 987#ifdef CONFIG_X86_64
@@ -985,6 +1019,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
985 1019
986 vmcs_conf->pin_based_exec_ctrl = _pin_based_exec_control; 1020 vmcs_conf->pin_based_exec_ctrl = _pin_based_exec_control;
987 vmcs_conf->cpu_based_exec_ctrl = _cpu_based_exec_control; 1021 vmcs_conf->cpu_based_exec_ctrl = _cpu_based_exec_control;
1022 vmcs_conf->cpu_based_2nd_exec_ctrl = _cpu_based_2nd_exec_control;
988 vmcs_conf->vmexit_ctrl = _vmexit_control; 1023 vmcs_conf->vmexit_ctrl = _vmexit_control;
989 vmcs_conf->vmentry_ctrl = _vmentry_control; 1024 vmcs_conf->vmentry_ctrl = _vmentry_control;
990 1025
@@ -1427,6 +1462,27 @@ static void seg_setup(int seg)
1427 vmcs_write32(sf->ar_bytes, 0x93); 1462 vmcs_write32(sf->ar_bytes, 0x93);
1428} 1463}
1429 1464
1465static int alloc_apic_access_page(struct kvm *kvm)
1466{
1467 struct kvm_userspace_memory_region kvm_userspace_mem;
1468 int r = 0;
1469
1470 mutex_lock(&kvm->lock);
1471 if (kvm->apic_access_page)
1472 goto out;
1473 kvm_userspace_mem.slot = APIC_ACCESS_PAGE_PRIVATE_MEMSLOT;
1474 kvm_userspace_mem.flags = 0;
1475 kvm_userspace_mem.guest_phys_addr = 0xfee00000ULL;
1476 kvm_userspace_mem.memory_size = PAGE_SIZE;
1477 r = __kvm_set_memory_region(kvm, &kvm_userspace_mem, 0);
1478 if (r)
1479 goto out;
1480 kvm->apic_access_page = gfn_to_page(kvm, 0xfee00);
1481out:
1482 mutex_unlock(&kvm->lock);
1483 return r;
1484}
1485
1430/* 1486/*
1431 * Sets up the vmcs for emulated real mode. 1487 * Sets up the vmcs for emulated real mode.
1432 */ 1488 */
@@ -1458,8 +1514,14 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
1458 CPU_BASED_CR8_LOAD_EXITING; 1514 CPU_BASED_CR8_LOAD_EXITING;
1459#endif 1515#endif
1460 } 1516 }
1517 if (!vm_need_secondary_exec_ctrls(vmx->vcpu.kvm))
1518 exec_control &= ~CPU_BASED_ACTIVATE_SECONDARY_CONTROLS;
1461 vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, exec_control); 1519 vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, exec_control);
1462 1520
1521 if (vm_need_secondary_exec_ctrls(vmx->vcpu.kvm))
1522 vmcs_write32(SECONDARY_VM_EXEC_CONTROL,
1523 vmcs_config.cpu_based_2nd_exec_ctrl);
1524
1463 vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, !!bypass_guest_pf); 1525 vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, !!bypass_guest_pf);
1464 vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, !!bypass_guest_pf); 1526 vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, !!bypass_guest_pf);
1465 vmcs_write32(CR3_TARGET_COUNT, 0); /* 22.2.1 */ 1527 vmcs_write32(CR3_TARGET_COUNT, 0); /* 22.2.1 */
@@ -1528,6 +1590,10 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
1528 vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL); 1590 vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL);
1529 vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK); 1591 vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK);
1530 1592
1593 if (vm_need_virtualize_apic_accesses(vmx->vcpu.kvm))
1594 if (alloc_apic_access_page(vmx->vcpu.kvm) != 0)
1595 return -ENOMEM;
1596
1531 return 0; 1597 return 0;
1532} 1598}
1533 1599
@@ -1616,13 +1682,17 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
1616 1682
1617 vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); /* 22.2.1 */ 1683 vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); /* 22.2.1 */
1618 1684
1619#ifdef CONFIG_X86_64 1685 if (cpu_has_vmx_tpr_shadow()) {
1620 vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, 0); 1686 vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, 0);
1621 if (vm_need_tpr_shadow(vmx->vcpu.kvm)) 1687 if (vm_need_tpr_shadow(vmx->vcpu.kvm))
1622 vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, 1688 vmcs_write64(VIRTUAL_APIC_PAGE_ADDR,
1623 page_to_phys(vmx->vcpu.apic->regs_page)); 1689 page_to_phys(vmx->vcpu.apic->regs_page));
1624 vmcs_write32(TPR_THRESHOLD, 0); 1690 vmcs_write32(TPR_THRESHOLD, 0);
1625#endif 1691 }
1692
1693 if (vm_need_virtualize_apic_accesses(vmx->vcpu.kvm))
1694 vmcs_write64(APIC_ACCESS_ADDR,
1695 page_to_phys(vmx->vcpu.kvm->apic_access_page));
1626 1696
1627 vmx->vcpu.cr0 = 0x60000010; 1697 vmx->vcpu.cr0 = 0x60000010;
1628 vmx_set_cr0(&vmx->vcpu, vmx->vcpu.cr0); /* enter rmode */ 1698 vmx_set_cr0(&vmx->vcpu, vmx->vcpu.cr0); /* enter rmode */
@@ -2094,6 +2164,26 @@ static int handle_vmcall(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
2094 return 1; 2164 return 1;
2095} 2165}
2096 2166
2167static int handle_apic_access(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
2168{
2169 u64 exit_qualification;
2170 enum emulation_result er;
2171 unsigned long offset;
2172
2173 exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
2174 offset = exit_qualification & 0xffful;
2175
2176 er = emulate_instruction(vcpu, kvm_run, 0, 0, 0);
2177
2178 if (er != EMULATE_DONE) {
2179 printk(KERN_ERR
2180 "Fail to handle apic access vmexit! Offset is 0x%lx\n",
2181 offset);
2182 return -ENOTSUPP;
2183 }
2184 return 1;
2185}
2186
2097/* 2187/*
2098 * The exit handlers return 1 if the exit was handled fully and guest execution 2188 * The exit handlers return 1 if the exit was handled fully and guest execution
2099 * may resume. Otherwise they set the kvm_run parameter to indicate what needs 2189 * may resume. Otherwise they set the kvm_run parameter to indicate what needs
@@ -2113,7 +2203,8 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu,
2113 [EXIT_REASON_PENDING_INTERRUPT] = handle_interrupt_window, 2203 [EXIT_REASON_PENDING_INTERRUPT] = handle_interrupt_window,
2114 [EXIT_REASON_HLT] = handle_halt, 2204 [EXIT_REASON_HLT] = handle_halt,
2115 [EXIT_REASON_VMCALL] = handle_vmcall, 2205 [EXIT_REASON_VMCALL] = handle_vmcall,
2116 [EXIT_REASON_TPR_BELOW_THRESHOLD] = handle_tpr_below_threshold 2206 [EXIT_REASON_TPR_BELOW_THRESHOLD] = handle_tpr_below_threshold,
2207 [EXIT_REASON_APIC_ACCESS] = handle_apic_access,
2117}; 2208};
2118 2209
2119static const int kvm_vmx_max_exit_handlers = 2210static const int kvm_vmx_max_exit_handlers =