aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/kvm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/kvm')
-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