aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorYang, Sheng <sheng.yang@intel.com>2007-09-12 06:03:11 -0400
committerAvi Kivity <avi@qumranet.com>2007-10-13 04:18:26 -0400
commit6e5d865c0b9679b00b5e5f0754c9fc2b6b9894d6 (patch)
tree1b8133926578a16f8849143da5a7d5a6d9e67b24 /drivers
parent2a8067f17b8442ecce0b14e134823020ff33b4fa (diff)
KVM: VMX: Use shadow TPR/cr8 for 64-bits guests
This patch enables TPR shadow of VMX on CR8 access. 64bit Windows using CR8 access TPR frequently. The TPR shadow can improve the performance of access TPR by not causing vmexit. Signed-off-by: Sheng Yang <sheng.yang@intel.com> Signed-off-by: Yaozu (Eddie) Dong <eddie.dong@intel.com> Signed-off-by: Qing He <qing.he@intel.com> Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/kvm/irq.h2
-rw-r--r--drivers/kvm/lapic.c17
-rw-r--r--drivers/kvm/vmx.c65
-rw-r--r--drivers/kvm/vmx.h1
4 files changed, 81 insertions, 4 deletions
diff --git a/drivers/kvm/irq.h b/drivers/kvm/irq.h
index 24b871f9b5fc..07035e8279d4 100644
--- a/drivers/kvm/irq.h
+++ b/drivers/kvm/irq.h
@@ -152,5 +152,7 @@ int kvm_apic_set_irq(struct kvm_lapic *apic, u8 vec, u8 trig);
152void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu); 152void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu);
153int kvm_ioapic_init(struct kvm *kvm); 153int kvm_ioapic_init(struct kvm *kvm);
154void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level); 154void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);
155int kvm_lapic_enabled(struct kvm_vcpu *vcpu);
156int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
155 157
156#endif 158#endif
diff --git a/drivers/kvm/lapic.c b/drivers/kvm/lapic.c
index df636bf19798..68bbbb38edad 100644
--- a/drivers/kvm/lapic.c
+++ b/drivers/kvm/lapic.c
@@ -170,6 +170,19 @@ static inline int apic_find_highest_irr(struct kvm_lapic *apic)
170 return result; 170 return result;
171} 171}
172 172
173int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu)
174{
175 struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
176 int highest_irr;
177
178 if (!apic)
179 return 0;
180 highest_irr = apic_find_highest_irr(apic);
181
182 return highest_irr;
183}
184EXPORT_SYMBOL_GPL(kvm_lapic_find_highest_irr);
185
173int kvm_apic_set_irq(struct kvm_lapic *apic, u8 vec, u8 trig) 186int kvm_apic_set_irq(struct kvm_lapic *apic, u8 vec, u8 trig)
174{ 187{
175 if (!apic_test_and_set_irr(vec, apic)) { 188 if (!apic_test_and_set_irr(vec, apic)) {
@@ -483,6 +496,7 @@ static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset)
483 break; 496 break;
484 497
485 default: 498 default:
499 apic_update_ppr(apic);
486 val = apic_get_reg(apic, offset); 500 val = apic_get_reg(apic, offset);
487 break; 501 break;
488 } 502 }
@@ -723,6 +737,7 @@ u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu)
723 737
724 return (tpr & 0xf0) >> 4; 738 return (tpr & 0xf0) >> 4;
725} 739}
740EXPORT_SYMBOL_GPL(kvm_lapic_get_cr8);
726 741
727void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value) 742void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
728{ 743{
@@ -809,6 +824,7 @@ int kvm_lapic_enabled(struct kvm_vcpu *vcpu)
809 824
810 return ret; 825 return ret;
811} 826}
827EXPORT_SYMBOL_GPL(kvm_lapic_enabled);
812 828
813/* 829/*
814 *---------------------------------------------------------------------- 830 *----------------------------------------------------------------------
@@ -911,6 +927,7 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu)
911 if (!apic || !apic_enabled(apic)) 927 if (!apic || !apic_enabled(apic))
912 return -1; 928 return -1;
913 929
930 apic_update_ppr(apic);
914 highest_irr = apic_find_highest_irr(apic); 931 highest_irr = apic_find_highest_irr(apic);
915 if ((highest_irr == -1) || 932 if ((highest_irr == -1) ||
916 ((highest_irr & 0xF0) <= apic_get_reg(apic, APIC_PROCPRI))) 933 ((highest_irr & 0xF0) <= apic_get_reg(apic, APIC_PROCPRI)))
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index 6c371ea21046..5c2c6e71abf2 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -170,6 +170,16 @@ static inline int is_external_interrupt(u32 intr_info)
170 == (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); 170 == (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
171} 171}
172 172
173static inline int cpu_has_vmx_tpr_shadow(void)
174{
175 return (vmcs_config.cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW);
176}
177
178static inline int vm_need_tpr_shadow(struct kvm *kvm)
179{
180 return ((cpu_has_vmx_tpr_shadow()) && (irqchip_in_kernel(kvm)));
181}
182
173static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr) 183static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr)
174{ 184{
175 int i; 185 int i;
@@ -888,10 +898,19 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
888 CPU_BASED_USE_IO_BITMAPS | 898 CPU_BASED_USE_IO_BITMAPS |
889 CPU_BASED_MOV_DR_EXITING | 899 CPU_BASED_MOV_DR_EXITING |
890 CPU_BASED_USE_TSC_OFFSETING; 900 CPU_BASED_USE_TSC_OFFSETING;
901#ifdef CONFIG_X86_64
902 opt = CPU_BASED_TPR_SHADOW;
903#else
891 opt = 0; 904 opt = 0;
905#endif
892 if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS, 906 if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS,
893 &_cpu_based_exec_control) < 0) 907 &_cpu_based_exec_control) < 0)
894 return -EIO; 908 return -EIO;
909#ifdef CONFIG_X86_64
910 if ((_cpu_based_exec_control & CPU_BASED_TPR_SHADOW))
911 _cpu_based_exec_control &= ~CPU_BASED_CR8_LOAD_EXITING &
912 ~CPU_BASED_CR8_STORE_EXITING;
913#endif
895 914
896 min = 0; 915 min = 0;
897#ifdef CONFIG_X86_64 916#ifdef CONFIG_X86_64
@@ -1384,6 +1403,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
1384 int ret = 0; 1403 int ret = 0;
1385 unsigned long kvm_vmx_return; 1404 unsigned long kvm_vmx_return;
1386 u64 msr; 1405 u64 msr;
1406 u32 exec_control;
1387 1407
1388 if (!init_rmode_tss(vmx->vcpu.kvm)) { 1408 if (!init_rmode_tss(vmx->vcpu.kvm)) {
1389 ret = -ENOMEM; 1409 ret = -ENOMEM;
@@ -1459,8 +1479,16 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
1459 /* Control */ 1479 /* Control */
1460 vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, 1480 vmcs_write32(PIN_BASED_VM_EXEC_CONTROL,
1461 vmcs_config.pin_based_exec_ctrl); 1481 vmcs_config.pin_based_exec_ctrl);
1462 vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, 1482
1463 vmcs_config.cpu_based_exec_ctrl); 1483 exec_control = vmcs_config.cpu_based_exec_ctrl;
1484 if (!vm_need_tpr_shadow(vmx->vcpu.kvm)) {
1485 exec_control &= ~CPU_BASED_TPR_SHADOW;
1486#ifdef CONFIG_X86_64
1487 exec_control |= CPU_BASED_CR8_STORE_EXITING |
1488 CPU_BASED_CR8_LOAD_EXITING;
1489#endif
1490 }
1491 vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, exec_control);
1464 1492
1465 vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, 0); 1493 vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, 0);
1466 vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, 0); 1494 vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, 0);
@@ -1532,8 +1560,11 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
1532 vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); /* 22.2.1 */ 1560 vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); /* 22.2.1 */
1533 1561
1534#ifdef CONFIG_X86_64 1562#ifdef CONFIG_X86_64
1535 vmcs_writel(VIRTUAL_APIC_PAGE_ADDR, 0); 1563 vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, 0);
1536 vmcs_writel(TPR_THRESHOLD, 0); 1564 if (vm_need_tpr_shadow(vmx->vcpu.kvm))
1565 vmcs_write64(VIRTUAL_APIC_PAGE_ADDR,
1566 page_to_phys(vmx->vcpu.apic->regs_page));
1567 vmcs_write32(TPR_THRESHOLD, 0);
1537#endif 1568#endif
1538 1569
1539 vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL); 1570 vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL);
@@ -1969,6 +2000,12 @@ static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1969 return 1; 2000 return 1;
1970} 2001}
1971 2002
2003static int handle_tpr_below_threshold(struct kvm_vcpu *vcpu,
2004 struct kvm_run *kvm_run)
2005{
2006 return 1;
2007}
2008
1972static void post_kvm_run_save(struct kvm_vcpu *vcpu, 2009static void post_kvm_run_save(struct kvm_vcpu *vcpu,
1973 struct kvm_run *kvm_run) 2010 struct kvm_run *kvm_run)
1974{ 2011{
@@ -2036,6 +2073,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu,
2036 [EXIT_REASON_PENDING_INTERRUPT] = handle_interrupt_window, 2073 [EXIT_REASON_PENDING_INTERRUPT] = handle_interrupt_window,
2037 [EXIT_REASON_HLT] = handle_halt, 2074 [EXIT_REASON_HLT] = handle_halt,
2038 [EXIT_REASON_VMCALL] = handle_vmcall, 2075 [EXIT_REASON_VMCALL] = handle_vmcall,
2076 [EXIT_REASON_TPR_BELOW_THRESHOLD] = handle_tpr_below_threshold
2039}; 2077};
2040 2078
2041static const int kvm_vmx_max_exit_handlers = 2079static const int kvm_vmx_max_exit_handlers =
@@ -2083,6 +2121,23 @@ static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
2083{ 2121{
2084} 2122}
2085 2123
2124static void update_tpr_threshold(struct kvm_vcpu *vcpu)
2125{
2126 int max_irr, tpr;
2127
2128 if (!vm_need_tpr_shadow(vcpu->kvm))
2129 return;
2130
2131 if (!kvm_lapic_enabled(vcpu) ||
2132 ((max_irr = kvm_lapic_find_highest_irr(vcpu)) == -1)) {
2133 vmcs_write32(TPR_THRESHOLD, 0);
2134 return;
2135 }
2136
2137 tpr = (kvm_lapic_get_cr8(vcpu) & 0x0f) << 4;
2138 vmcs_write32(TPR_THRESHOLD, (max_irr > tpr) ? tpr >> 4 : max_irr >> 4);
2139}
2140
2086static void enable_irq_window(struct kvm_vcpu *vcpu) 2141static void enable_irq_window(struct kvm_vcpu *vcpu)
2087{ 2142{
2088 u32 cpu_based_vm_exec_control; 2143 u32 cpu_based_vm_exec_control;
@@ -2097,6 +2152,8 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu)
2097 u32 idtv_info_field, intr_info_field; 2152 u32 idtv_info_field, intr_info_field;
2098 int has_ext_irq, interrupt_window_open; 2153 int has_ext_irq, interrupt_window_open;
2099 2154
2155 update_tpr_threshold(vcpu);
2156
2100 has_ext_irq = kvm_cpu_has_interrupt(vcpu); 2157 has_ext_irq = kvm_cpu_has_interrupt(vcpu);
2101 intr_info_field = vmcs_read32(VM_ENTRY_INTR_INFO_FIELD); 2158 intr_info_field = vmcs_read32(VM_ENTRY_INTR_INFO_FIELD);
2102 idtv_info_field = vmcs_read32(IDT_VECTORING_INFO_FIELD); 2159 idtv_info_field = vmcs_read32(IDT_VECTORING_INFO_FIELD);
diff --git a/drivers/kvm/vmx.h b/drivers/kvm/vmx.h
index 35d0b58c0a0b..fd4e14666088 100644
--- a/drivers/kvm/vmx.h
+++ b/drivers/kvm/vmx.h
@@ -213,6 +213,7 @@ enum vmcs_field {
213#define EXIT_REASON_MSR_READ 31 213#define EXIT_REASON_MSR_READ 31
214#define EXIT_REASON_MSR_WRITE 32 214#define EXIT_REASON_MSR_WRITE 32
215#define EXIT_REASON_MWAIT_INSTRUCTION 36 215#define EXIT_REASON_MWAIT_INSTRUCTION 36
216#define EXIT_REASON_TPR_BELOW_THRESHOLD 43
216 217
217/* 218/*
218 * Interruption-information format 219 * Interruption-information format