diff options
author | Sheng Yang <sheng.yang@intel.com> | 2007-10-28 21:40:42 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-01-30 10:52:58 -0500 |
commit | f78e0e2ee498e8f847500b565792c7d7634dcf54 (patch) | |
tree | dfd8f35883b40939a1ec013e27e6303af06d3e77 /drivers/kvm/vmx.c | |
parent | a03490ed29d2771c675d4d9c0ffe22e19a1757f3 (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.c | 117 |
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 | ||
183 | static 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 | |||
189 | static inline int vm_need_secondary_exec_ctrls(struct kvm *kvm) | ||
190 | { | ||
191 | return ((cpu_has_secondary_exec_ctrls()) && (irqchip_in_kernel(kvm))); | ||
192 | } | ||
193 | |||
194 | static 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 | |||
200 | static 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 | |||
182 | static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr) | 206 | static 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 | ||
1465 | static 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); | ||
1481 | out: | ||
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 | ||
2167 | static 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 | ||
2119 | static const int kvm_vmx_max_exit_handlers = | 2210 | static const int kvm_vmx_max_exit_handlers = |