aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYang Zhang <yang.z.zhang@intel.com>2013-01-24 21:18:49 -0500
committerGleb Natapov <gleb@redhat.com>2013-01-29 03:47:54 -0500
commit83d4c286931c9d28c5be21bac3c73a2332cab681 (patch)
tree524885d4cad7e7f1d98357711eff11b8224dc01e
parentd47510e295c0f82699192a61d715351cf00f65de (diff)
x86, apicv: add APICv register virtualization support
- APIC read doesn't cause VM-Exit - APIC write becomes trap-like Reviewed-by: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Kevin Tian <kevin.tian@intel.com> Signed-off-by: Yang Zhang <yang.z.zhang@intel.com> Signed-off-by: Gleb Natapov <gleb@redhat.com>
-rw-r--r--arch/x86/include/asm/vmx.h2
-rw-r--r--arch/x86/kvm/lapic.c15
-rw-r--r--arch/x86/kvm/lapic.h2
-rw-r--r--arch/x86/kvm/vmx.c33
4 files changed, 51 insertions, 1 deletions
diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index e385df97bfdc..44c3f7eb4532 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -66,6 +66,7 @@
66#define EXIT_REASON_EPT_MISCONFIG 49 66#define EXIT_REASON_EPT_MISCONFIG 49
67#define EXIT_REASON_WBINVD 54 67#define EXIT_REASON_WBINVD 54
68#define EXIT_REASON_XSETBV 55 68#define EXIT_REASON_XSETBV 55
69#define EXIT_REASON_APIC_WRITE 56
69#define EXIT_REASON_INVPCID 58 70#define EXIT_REASON_INVPCID 58
70 71
71#define VMX_EXIT_REASONS \ 72#define VMX_EXIT_REASONS \
@@ -141,6 +142,7 @@
141#define SECONDARY_EXEC_ENABLE_VPID 0x00000020 142#define SECONDARY_EXEC_ENABLE_VPID 0x00000020
142#define SECONDARY_EXEC_WBINVD_EXITING 0x00000040 143#define SECONDARY_EXEC_WBINVD_EXITING 0x00000040
143#define SECONDARY_EXEC_UNRESTRICTED_GUEST 0x00000080 144#define SECONDARY_EXEC_UNRESTRICTED_GUEST 0x00000080
145#define SECONDARY_EXEC_APIC_REGISTER_VIRT 0x00000100
144#define SECONDARY_EXEC_PAUSE_LOOP_EXITING 0x00000400 146#define SECONDARY_EXEC_PAUSE_LOOP_EXITING 0x00000400
145#define SECONDARY_EXEC_ENABLE_INVPCID 0x00001000 147#define SECONDARY_EXEC_ENABLE_INVPCID 0x00001000
146 148
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 9392f527f107..0664c138e860 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -1212,6 +1212,21 @@ void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu)
1212} 1212}
1213EXPORT_SYMBOL_GPL(kvm_lapic_set_eoi); 1213EXPORT_SYMBOL_GPL(kvm_lapic_set_eoi);
1214 1214
1215/* emulate APIC access in a trap manner */
1216void kvm_apic_write_nodecode(struct kvm_vcpu *vcpu, u32 offset)
1217{
1218 u32 val = 0;
1219
1220 /* hw has done the conditional check and inst decode */
1221 offset &= 0xff0;
1222
1223 apic_reg_read(vcpu->arch.apic, offset, 4, &val);
1224
1225 /* TODO: optimize to just emulate side effect w/o one more write */
1226 apic_reg_write(vcpu->arch.apic, offset, val);
1227}
1228EXPORT_SYMBOL_GPL(kvm_apic_write_nodecode);
1229
1215void kvm_free_lapic(struct kvm_vcpu *vcpu) 1230void kvm_free_lapic(struct kvm_vcpu *vcpu)
1216{ 1231{
1217 struct kvm_lapic *apic = vcpu->arch.apic; 1232 struct kvm_lapic *apic = vcpu->arch.apic;
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index e5ebf9f3571f..9a8ee22bc7a3 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -64,6 +64,8 @@ int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
64u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu); 64u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu);
65void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, u64 data); 65void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, u64 data);
66 66
67void kvm_apic_write_nodecode(struct kvm_vcpu *vcpu, u32 offset);
68
67void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr); 69void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr);
68void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu); 70void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu);
69void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu); 71void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 02eeba86328d..5ad7c8531083 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -84,6 +84,9 @@ module_param(vmm_exclusive, bool, S_IRUGO);
84static bool __read_mostly fasteoi = 1; 84static bool __read_mostly fasteoi = 1;
85module_param(fasteoi, bool, S_IRUGO); 85module_param(fasteoi, bool, S_IRUGO);
86 86
87static bool __read_mostly enable_apicv_reg = 1;
88module_param(enable_apicv_reg, bool, S_IRUGO);
89
87/* 90/*
88 * If nested=1, nested virtualization is supported, i.e., guests may use 91 * If nested=1, nested virtualization is supported, i.e., guests may use
89 * VMX and be a hypervisor for its own guests. If nested=0, guests may not 92 * VMX and be a hypervisor for its own guests. If nested=0, guests may not
@@ -764,6 +767,12 @@ static inline bool cpu_has_vmx_virtualize_apic_accesses(void)
764 SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES; 767 SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
765} 768}
766 769
770static inline bool cpu_has_vmx_apic_register_virt(void)
771{
772 return vmcs_config.cpu_based_2nd_exec_ctrl &
773 SECONDARY_EXEC_APIC_REGISTER_VIRT;
774}
775
767static inline bool cpu_has_vmx_flexpriority(void) 776static inline bool cpu_has_vmx_flexpriority(void)
768{ 777{
769 return cpu_has_vmx_tpr_shadow() && 778 return cpu_has_vmx_tpr_shadow() &&
@@ -2540,7 +2549,8 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
2540 SECONDARY_EXEC_UNRESTRICTED_GUEST | 2549 SECONDARY_EXEC_UNRESTRICTED_GUEST |
2541 SECONDARY_EXEC_PAUSE_LOOP_EXITING | 2550 SECONDARY_EXEC_PAUSE_LOOP_EXITING |
2542 SECONDARY_EXEC_RDTSCP | 2551 SECONDARY_EXEC_RDTSCP |
2543 SECONDARY_EXEC_ENABLE_INVPCID; 2552 SECONDARY_EXEC_ENABLE_INVPCID |
2553 SECONDARY_EXEC_APIC_REGISTER_VIRT;
2544 if (adjust_vmx_controls(min2, opt2, 2554 if (adjust_vmx_controls(min2, opt2,
2545 MSR_IA32_VMX_PROCBASED_CTLS2, 2555 MSR_IA32_VMX_PROCBASED_CTLS2,
2546 &_cpu_based_2nd_exec_control) < 0) 2556 &_cpu_based_2nd_exec_control) < 0)
@@ -2551,6 +2561,11 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
2551 SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES)) 2561 SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES))
2552 _cpu_based_exec_control &= ~CPU_BASED_TPR_SHADOW; 2562 _cpu_based_exec_control &= ~CPU_BASED_TPR_SHADOW;
2553#endif 2563#endif
2564
2565 if (!(_cpu_based_exec_control & CPU_BASED_TPR_SHADOW))
2566 _cpu_based_2nd_exec_control &= ~(
2567 SECONDARY_EXEC_APIC_REGISTER_VIRT);
2568
2554 if (_cpu_based_2nd_exec_control & SECONDARY_EXEC_ENABLE_EPT) { 2569 if (_cpu_based_2nd_exec_control & SECONDARY_EXEC_ENABLE_EPT) {
2555 /* CR3 accesses and invlpg don't need to cause VM Exits when EPT 2570 /* CR3 accesses and invlpg don't need to cause VM Exits when EPT
2556 enabled */ 2571 enabled */
@@ -2748,6 +2763,9 @@ static __init int hardware_setup(void)
2748 if (!cpu_has_vmx_ple()) 2763 if (!cpu_has_vmx_ple())
2749 ple_gap = 0; 2764 ple_gap = 0;
2750 2765
2766 if (!cpu_has_vmx_apic_register_virt())
2767 enable_apicv_reg = 0;
2768
2751 if (nested) 2769 if (nested)
2752 nested_vmx_setup_ctls_msrs(); 2770 nested_vmx_setup_ctls_msrs();
2753 2771
@@ -3829,6 +3847,8 @@ static u32 vmx_secondary_exec_control(struct vcpu_vmx *vmx)
3829 exec_control &= ~SECONDARY_EXEC_UNRESTRICTED_GUEST; 3847 exec_control &= ~SECONDARY_EXEC_UNRESTRICTED_GUEST;
3830 if (!ple_gap) 3848 if (!ple_gap)
3831 exec_control &= ~SECONDARY_EXEC_PAUSE_LOOP_EXITING; 3849 exec_control &= ~SECONDARY_EXEC_PAUSE_LOOP_EXITING;
3850 if (!enable_apicv_reg || !irqchip_in_kernel(vmx->vcpu.kvm))
3851 exec_control &= ~SECONDARY_EXEC_APIC_REGISTER_VIRT;
3832 return exec_control; 3852 return exec_control;
3833} 3853}
3834 3854
@@ -4787,6 +4807,16 @@ static int handle_apic_access(struct kvm_vcpu *vcpu)
4787 return emulate_instruction(vcpu, 0) == EMULATE_DONE; 4807 return emulate_instruction(vcpu, 0) == EMULATE_DONE;
4788} 4808}
4789 4809
4810static int handle_apic_write(struct kvm_vcpu *vcpu)
4811{
4812 unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
4813 u32 offset = exit_qualification & 0xfff;
4814
4815 /* APIC-write VM exit is trap-like and thus no need to adjust IP */
4816 kvm_apic_write_nodecode(vcpu, offset);
4817 return 1;
4818}
4819
4790static int handle_task_switch(struct kvm_vcpu *vcpu) 4820static int handle_task_switch(struct kvm_vcpu *vcpu)
4791{ 4821{
4792 struct vcpu_vmx *vmx = to_vmx(vcpu); 4822 struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -5721,6 +5751,7 @@ static int (*const kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = {
5721 [EXIT_REASON_VMON] = handle_vmon, 5751 [EXIT_REASON_VMON] = handle_vmon,
5722 [EXIT_REASON_TPR_BELOW_THRESHOLD] = handle_tpr_below_threshold, 5752 [EXIT_REASON_TPR_BELOW_THRESHOLD] = handle_tpr_below_threshold,
5723 [EXIT_REASON_APIC_ACCESS] = handle_apic_access, 5753 [EXIT_REASON_APIC_ACCESS] = handle_apic_access,
5754 [EXIT_REASON_APIC_WRITE] = handle_apic_write,
5724 [EXIT_REASON_WBINVD] = handle_wbinvd, 5755 [EXIT_REASON_WBINVD] = handle_wbinvd,
5725 [EXIT_REASON_XSETBV] = handle_xsetbv, 5756 [EXIT_REASON_XSETBV] = handle_xsetbv,
5726 [EXIT_REASON_TASK_SWITCH] = handle_task_switch, 5757 [EXIT_REASON_TASK_SWITCH] = handle_task_switch,