diff options
Diffstat (limited to 'drivers/kvm')
-rw-r--r-- | drivers/kvm/irq.h | 2 | ||||
-rw-r--r-- | drivers/kvm/lapic.c | 17 | ||||
-rw-r--r-- | drivers/kvm/vmx.c | 65 | ||||
-rw-r--r-- | drivers/kvm/vmx.h | 1 |
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); | |||
152 | void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu); | 152 | void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu); |
153 | int kvm_ioapic_init(struct kvm *kvm); | 153 | int kvm_ioapic_init(struct kvm *kvm); |
154 | void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level); | 154 | void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level); |
155 | int kvm_lapic_enabled(struct kvm_vcpu *vcpu); | ||
156 | int 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 | ||
173 | int 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 | } | ||
184 | EXPORT_SYMBOL_GPL(kvm_lapic_find_highest_irr); | ||
185 | |||
173 | int kvm_apic_set_irq(struct kvm_lapic *apic, u8 vec, u8 trig) | 186 | int 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 | } |
740 | EXPORT_SYMBOL_GPL(kvm_lapic_get_cr8); | ||
726 | 741 | ||
727 | void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value) | 742 | void 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 | } |
827 | EXPORT_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 | ||
173 | static inline int cpu_has_vmx_tpr_shadow(void) | ||
174 | { | ||
175 | return (vmcs_config.cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW); | ||
176 | } | ||
177 | |||
178 | static inline int vm_need_tpr_shadow(struct kvm *kvm) | ||
179 | { | ||
180 | return ((cpu_has_vmx_tpr_shadow()) && (irqchip_in_kernel(kvm))); | ||
181 | } | ||
182 | |||
173 | static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr) | 183 | static 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 | ||
2003 | static int handle_tpr_below_threshold(struct kvm_vcpu *vcpu, | ||
2004 | struct kvm_run *kvm_run) | ||
2005 | { | ||
2006 | return 1; | ||
2007 | } | ||
2008 | |||
1972 | static void post_kvm_run_save(struct kvm_vcpu *vcpu, | 2009 | static 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 | ||
2041 | static const int kvm_vmx_max_exit_handlers = | 2079 | static 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 | ||
2124 | static 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 | |||
2086 | static void enable_irq_window(struct kvm_vcpu *vcpu) | 2141 | static 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 |