diff options
author | Wanpeng Li <wanpeng.li@linux.intel.com> | 2014-08-21 07:46:50 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2014-08-29 08:02:48 -0400 |
commit | a7c0b07d570848e50fce4d31ac01313484d6b844 (patch) | |
tree | 2a63548b81b2c1d6bdfbe3c68b8b4c3989d5e700 | |
parent | a2bcba5035bb3d7fb3099e1893026316365f4b5d (diff) |
KVM: nVMX: nested TPR shadow/threshold emulation
This patch fix bug https://bugzilla.kernel.org/show_bug.cgi?id=61411
TPR shadow/threshold feature is important to speed up the Windows guest.
Besides, it is a must feature for certain VMM.
We map virtual APIC page address and TPR threshold from L1 VMCS. If
TPR_BELOW_THRESHOLD VM exit is triggered by L2 guest and L1 interested
in, we inject it into L1 VMM for handling.
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Wanpeng Li <wanpeng.li@linux.intel.com>
[Add PAGE_ALIGNED check, do not write useless virtual APIC page address
if TPR shadowing is disabled. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r-- | arch/x86/kvm/vmx.c | 54 |
1 files changed, 51 insertions, 3 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 70516e11f051..73ba2a265f85 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -397,6 +397,7 @@ struct nested_vmx { | |||
397 | * we must keep them pinned while L2 runs. | 397 | * we must keep them pinned while L2 runs. |
398 | */ | 398 | */ |
399 | struct page *apic_access_page; | 399 | struct page *apic_access_page; |
400 | struct page *virtual_apic_page; | ||
400 | u64 msr_ia32_feature_control; | 401 | u64 msr_ia32_feature_control; |
401 | 402 | ||
402 | struct hrtimer preemption_timer; | 403 | struct hrtimer preemption_timer; |
@@ -555,6 +556,7 @@ static int max_shadow_read_only_fields = | |||
555 | ARRAY_SIZE(shadow_read_only_fields); | 556 | ARRAY_SIZE(shadow_read_only_fields); |
556 | 557 | ||
557 | static unsigned long shadow_read_write_fields[] = { | 558 | static unsigned long shadow_read_write_fields[] = { |
559 | TPR_THRESHOLD, | ||
558 | GUEST_RIP, | 560 | GUEST_RIP, |
559 | GUEST_RSP, | 561 | GUEST_RSP, |
560 | GUEST_CR0, | 562 | GUEST_CR0, |
@@ -2352,7 +2354,7 @@ static __init void nested_vmx_setup_ctls_msrs(void) | |||
2352 | CPU_BASED_MOV_DR_EXITING | CPU_BASED_UNCOND_IO_EXITING | | 2354 | CPU_BASED_MOV_DR_EXITING | CPU_BASED_UNCOND_IO_EXITING | |
2353 | CPU_BASED_USE_IO_BITMAPS | CPU_BASED_MONITOR_EXITING | | 2355 | CPU_BASED_USE_IO_BITMAPS | CPU_BASED_MONITOR_EXITING | |
2354 | CPU_BASED_RDPMC_EXITING | CPU_BASED_RDTSC_EXITING | | 2356 | CPU_BASED_RDPMC_EXITING | CPU_BASED_RDTSC_EXITING | |
2355 | CPU_BASED_PAUSE_EXITING | | 2357 | CPU_BASED_PAUSE_EXITING | CPU_BASED_TPR_SHADOW | |
2356 | CPU_BASED_ACTIVATE_SECONDARY_CONTROLS; | 2358 | CPU_BASED_ACTIVATE_SECONDARY_CONTROLS; |
2357 | /* | 2359 | /* |
2358 | * We can allow some features even when not supported by the | 2360 | * We can allow some features even when not supported by the |
@@ -6246,6 +6248,10 @@ static void free_nested(struct vcpu_vmx *vmx) | |||
6246 | nested_release_page(vmx->nested.apic_access_page); | 6248 | nested_release_page(vmx->nested.apic_access_page); |
6247 | vmx->nested.apic_access_page = 0; | 6249 | vmx->nested.apic_access_page = 0; |
6248 | } | 6250 | } |
6251 | if (vmx->nested.virtual_apic_page) { | ||
6252 | nested_release_page(vmx->nested.virtual_apic_page); | ||
6253 | vmx->nested.virtual_apic_page = 0; | ||
6254 | } | ||
6249 | 6255 | ||
6250 | nested_free_all_saved_vmcss(vmx); | 6256 | nested_free_all_saved_vmcss(vmx); |
6251 | } | 6257 | } |
@@ -7034,7 +7040,7 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu) | |||
7034 | case EXIT_REASON_MCE_DURING_VMENTRY: | 7040 | case EXIT_REASON_MCE_DURING_VMENTRY: |
7035 | return 0; | 7041 | return 0; |
7036 | case EXIT_REASON_TPR_BELOW_THRESHOLD: | 7042 | case EXIT_REASON_TPR_BELOW_THRESHOLD: |
7037 | return 1; | 7043 | return nested_cpu_has(vmcs12, CPU_BASED_TPR_SHADOW); |
7038 | case EXIT_REASON_APIC_ACCESS: | 7044 | case EXIT_REASON_APIC_ACCESS: |
7039 | return nested_cpu_has2(vmcs12, | 7045 | return nested_cpu_has2(vmcs12, |
7040 | SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES); | 7046 | SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES); |
@@ -7155,6 +7161,12 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu) | |||
7155 | 7161 | ||
7156 | static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr) | 7162 | static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr) |
7157 | { | 7163 | { |
7164 | struct vmcs12 *vmcs12 = get_vmcs12(vcpu); | ||
7165 | |||
7166 | if (is_guest_mode(vcpu) && | ||
7167 | nested_cpu_has(vmcs12, CPU_BASED_TPR_SHADOW)) | ||
7168 | return; | ||
7169 | |||
7158 | if (irr == -1 || tpr < irr) { | 7170 | if (irr == -1 || tpr < irr) { |
7159 | vmcs_write32(TPR_THRESHOLD, 0); | 7171 | vmcs_write32(TPR_THRESHOLD, 0); |
7160 | return; | 7172 | return; |
@@ -7933,8 +7945,8 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu, | |||
7933 | struct vcpu_vmx *vmx = to_vmx(vcpu); | 7945 | struct vcpu_vmx *vmx = to_vmx(vcpu); |
7934 | 7946 | ||
7935 | if (nested_cpu_has2(vmcs12, SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES)) { | 7947 | if (nested_cpu_has2(vmcs12, SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES)) { |
7948 | /* TODO: Also verify bits beyond physical address width are 0 */ | ||
7936 | if (!PAGE_ALIGNED(vmcs12->apic_access_addr)) | 7949 | if (!PAGE_ALIGNED(vmcs12->apic_access_addr)) |
7937 | /*TODO: Also verify bits beyond physical address width are 0*/ | ||
7938 | return false; | 7950 | return false; |
7939 | 7951 | ||
7940 | /* | 7952 | /* |
@@ -7948,6 +7960,31 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu, | |||
7948 | vmx->nested.apic_access_page = | 7960 | vmx->nested.apic_access_page = |
7949 | nested_get_page(vcpu, vmcs12->apic_access_addr); | 7961 | nested_get_page(vcpu, vmcs12->apic_access_addr); |
7950 | } | 7962 | } |
7963 | |||
7964 | if (nested_cpu_has(vmcs12, CPU_BASED_TPR_SHADOW)) { | ||
7965 | /* TODO: Also verify bits beyond physical address width are 0 */ | ||
7966 | if (!PAGE_ALIGNED(vmcs12->virtual_apic_page_addr)) | ||
7967 | return false; | ||
7968 | |||
7969 | if (vmx->nested.virtual_apic_page) /* shouldn't happen */ | ||
7970 | nested_release_page(vmx->nested.virtual_apic_page); | ||
7971 | vmx->nested.virtual_apic_page = | ||
7972 | nested_get_page(vcpu, vmcs12->virtual_apic_page_addr); | ||
7973 | |||
7974 | /* | ||
7975 | * Failing the vm entry is _not_ what the processor does | ||
7976 | * but it's basically the only possibility we have. | ||
7977 | * We could still enter the guest if CR8 load exits are | ||
7978 | * enabled, CR8 store exits are enabled, and virtualize APIC | ||
7979 | * access is disabled; in this case the processor would never | ||
7980 | * use the TPR shadow and we could simply clear the bit from | ||
7981 | * the execution control. But such a configuration is useless, | ||
7982 | * so let's keep the code simple. | ||
7983 | */ | ||
7984 | if (!vmx->nested.virtual_apic_page) | ||
7985 | return false; | ||
7986 | } | ||
7987 | |||
7951 | return true; | 7988 | return true; |
7952 | } | 7989 | } |
7953 | 7990 | ||
@@ -8141,6 +8178,13 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) | |||
8141 | exec_control &= ~CPU_BASED_VIRTUAL_NMI_PENDING; | 8178 | exec_control &= ~CPU_BASED_VIRTUAL_NMI_PENDING; |
8142 | exec_control &= ~CPU_BASED_TPR_SHADOW; | 8179 | exec_control &= ~CPU_BASED_TPR_SHADOW; |
8143 | exec_control |= vmcs12->cpu_based_vm_exec_control; | 8180 | exec_control |= vmcs12->cpu_based_vm_exec_control; |
8181 | |||
8182 | if (exec_control & CPU_BASED_TPR_SHADOW) { | ||
8183 | vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, | ||
8184 | page_to_phys(vmx->nested.virtual_apic_page)); | ||
8185 | vmcs_write32(TPR_THRESHOLD, vmcs12->tpr_threshold); | ||
8186 | } | ||
8187 | |||
8144 | /* | 8188 | /* |
8145 | * Merging of IO and MSR bitmaps not currently supported. | 8189 | * Merging of IO and MSR bitmaps not currently supported. |
8146 | * Rather, exit every time. | 8190 | * Rather, exit every time. |
@@ -8908,6 +8952,10 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason, | |||
8908 | nested_release_page(vmx->nested.apic_access_page); | 8952 | nested_release_page(vmx->nested.apic_access_page); |
8909 | vmx->nested.apic_access_page = 0; | 8953 | vmx->nested.apic_access_page = 0; |
8910 | } | 8954 | } |
8955 | if (vmx->nested.virtual_apic_page) { | ||
8956 | nested_release_page(vmx->nested.virtual_apic_page); | ||
8957 | vmx->nested.virtual_apic_page = 0; | ||
8958 | } | ||
8911 | 8959 | ||
8912 | /* | 8960 | /* |
8913 | * Exiting from L2 to L1, we're now back to L1 which thinks it just | 8961 | * Exiting from L2 to L1, we're now back to L1 which thinks it just |