aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiran Alon <liran.alon@oracle.com>2019-06-26 09:09:27 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2019-07-02 13:02:45 -0400
commit323d73a8ecad22bf3284f11112a7cce576ade6af (patch)
treeccf5fcf87d98ceada68d8af3f9b6b8b23e0f7d45
parent65b712f1560abdd9ebec005e9bd17c21ecacc849 (diff)
KVM: nVMX: Change KVM_STATE_NESTED_EVMCS to signal vmcs12 is copied from eVMCS
Currently KVM_STATE_NESTED_EVMCS is used to signal that eVMCS capability is enabled on vCPU. As indicated by vmx->nested.enlightened_vmcs_enabled. This is quite bizarre as userspace VMM should make sure to expose same vCPU with same CPUID values in both source and destination. In case vCPU is exposed with eVMCS support on CPUID, it is also expected to enable KVM_CAP_HYPERV_ENLIGHTENED_VMCS capability. Therefore, KVM_STATE_NESTED_EVMCS is redundant. KVM_STATE_NESTED_EVMCS is currently used on restore path (vmx_set_nested_state()) only to enable eVMCS capability in KVM and to signal need_vmcs12_sync such that on next VMEntry to guest nested_sync_from_vmcs12() will be called to sync vmcs12 content into eVMCS in guest memory. However, because restore nested-state is rare enough, we could have just modified vmx_set_nested_state() to always signal need_vmcs12_sync. From all the above, it seems that we could have just removed the usage of KVM_STATE_NESTED_EVMCS. However, in order to preserve backwards migration compatibility, we cannot do that. (vmx_get_nested_state() needs to signal flag when migrating from new kernel to old kernel). Returning KVM_STATE_NESTED_EVMCS when just vCPU have eVMCS enabled have a bad side-effect of userspace VMM having to send nested-state from source to destination as part of migration stream. Even if guest have never used eVMCS as it doesn't even run a nested hypervisor workload. This requires destination userspace VMM and KVM to support setting nested-state. Which make it more difficult to migrate from new host to older host. To avoid this, change KVM_STATE_NESTED_EVMCS to signal eVMCS is not only enabled but also active. i.e. Guest have made some eVMCS active via an enlightened VMEntry. i.e. vmcs12 is copied from eVMCS and therefore should be restored into eVMCS resident in memory (by copy_vmcs12_to_enlightened()). Reviewed-by: Vitaly Kuznetsov <vkuznets@redhat.com> Reviewed-by: Maran Wilson <maran.wilson@oracle.com> Reviewed-by: Krish Sadhukhan <krish.sadhukhan@oracle.com> Signed-off-by: Liran Alon <liran.alon@oracle.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--arch/x86/kvm/vmx/nested.c25
-rw-r--r--tools/testing/selftests/kvm/x86_64/evmcs_test.c1
2 files changed, 17 insertions, 9 deletions
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index adbf4fc77ad8..46af3a5e9209 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -5240,9 +5240,6 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu,
5240 vmx = to_vmx(vcpu); 5240 vmx = to_vmx(vcpu);
5241 vmcs12 = get_vmcs12(vcpu); 5241 vmcs12 = get_vmcs12(vcpu);
5242 5242
5243 if (nested_vmx_allowed(vcpu) && vmx->nested.enlightened_vmcs_enabled)
5244 kvm_state.flags |= KVM_STATE_NESTED_EVMCS;
5245
5246 if (nested_vmx_allowed(vcpu) && 5243 if (nested_vmx_allowed(vcpu) &&
5247 (vmx->nested.vmxon || vmx->nested.smm.vmxon)) { 5244 (vmx->nested.vmxon || vmx->nested.smm.vmxon)) {
5248 kvm_state.hdr.vmx.vmxon_pa = vmx->nested.vmxon_ptr; 5245 kvm_state.hdr.vmx.vmxon_pa = vmx->nested.vmxon_ptr;
@@ -5251,6 +5248,9 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu,
5251 if (vmx_has_valid_vmcs12(vcpu)) { 5248 if (vmx_has_valid_vmcs12(vcpu)) {
5252 kvm_state.size += sizeof(user_vmx_nested_state->vmcs12); 5249 kvm_state.size += sizeof(user_vmx_nested_state->vmcs12);
5253 5250
5251 if (vmx->nested.hv_evmcs)
5252 kvm_state.flags |= KVM_STATE_NESTED_EVMCS;
5253
5254 if (is_guest_mode(vcpu) && 5254 if (is_guest_mode(vcpu) &&
5255 nested_cpu_has_shadow_vmcs(vmcs12) && 5255 nested_cpu_has_shadow_vmcs(vmcs12) &&
5256 vmcs12->vmcs_link_pointer != -1ull) 5256 vmcs12->vmcs_link_pointer != -1ull)
@@ -5350,6 +5350,15 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
5350 if (kvm_state->hdr.vmx.vmcs12_pa != -1ull) 5350 if (kvm_state->hdr.vmx.vmcs12_pa != -1ull)
5351 return -EINVAL; 5351 return -EINVAL;
5352 5352
5353 /*
5354 * KVM_STATE_NESTED_EVMCS used to signal that KVM should
5355 * enable eVMCS capability on vCPU. However, since then
5356 * code was changed such that flag signals vmcs12 should
5357 * be copied into eVMCS in guest memory.
5358 *
5359 * To preserve backwards compatability, allow user
5360 * to set this flag even when there is no VMXON region.
5361 */
5353 if (kvm_state->flags & ~KVM_STATE_NESTED_EVMCS) 5362 if (kvm_state->flags & ~KVM_STATE_NESTED_EVMCS)
5354 return -EINVAL; 5363 return -EINVAL;
5355 } else { 5364 } else {
@@ -5358,7 +5367,7 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
5358 5367
5359 if (!page_address_valid(vcpu, kvm_state->hdr.vmx.vmxon_pa)) 5368 if (!page_address_valid(vcpu, kvm_state->hdr.vmx.vmxon_pa))
5360 return -EINVAL; 5369 return -EINVAL;
5361 } 5370 }
5362 5371
5363 if ((kvm_state->hdr.vmx.smm.flags & KVM_STATE_NESTED_SMM_GUEST_MODE) && 5372 if ((kvm_state->hdr.vmx.smm.flags & KVM_STATE_NESTED_SMM_GUEST_MODE) &&
5364 (kvm_state->flags & KVM_STATE_NESTED_GUEST_MODE)) 5373 (kvm_state->flags & KVM_STATE_NESTED_GUEST_MODE))
@@ -5383,13 +5392,11 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
5383 !(kvm_state->hdr.vmx.smm.flags & KVM_STATE_NESTED_SMM_VMXON)) 5392 !(kvm_state->hdr.vmx.smm.flags & KVM_STATE_NESTED_SMM_VMXON))
5384 return -EINVAL; 5393 return -EINVAL;
5385 5394
5386 vmx_leave_nested(vcpu); 5395 if ((kvm_state->flags & KVM_STATE_NESTED_EVMCS) &&
5387 if (kvm_state->flags & KVM_STATE_NESTED_EVMCS) { 5396 (!nested_vmx_allowed(vcpu) || !vmx->nested.enlightened_vmcs_enabled))
5388 if (!nested_vmx_allowed(vcpu))
5389 return -EINVAL; 5397 return -EINVAL;
5390 5398
5391 nested_enable_evmcs(vcpu, NULL); 5399 vmx_leave_nested(vcpu);
5392 }
5393 5400
5394 if (kvm_state->hdr.vmx.vmxon_pa == -1ull) 5401 if (kvm_state->hdr.vmx.vmxon_pa == -1ull)
5395 return 0; 5402 return 0;
diff --git a/tools/testing/selftests/kvm/x86_64/evmcs_test.c b/tools/testing/selftests/kvm/x86_64/evmcs_test.c
index b38260e29775..241919ef1eac 100644
--- a/tools/testing/selftests/kvm/x86_64/evmcs_test.c
+++ b/tools/testing/selftests/kvm/x86_64/evmcs_test.c
@@ -146,6 +146,7 @@ int main(int argc, char *argv[])
146 kvm_vm_restart(vm, O_RDWR); 146 kvm_vm_restart(vm, O_RDWR);
147 vm_vcpu_add(vm, VCPU_ID, 0, 0); 147 vm_vcpu_add(vm, VCPU_ID, 0, 0);
148 vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); 148 vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());
149 vcpu_ioctl(vm, VCPU_ID, KVM_ENABLE_CAP, &enable_evmcs_cap);
149 vcpu_load_state(vm, VCPU_ID, state); 150 vcpu_load_state(vm, VCPU_ID, state);
150 run = vcpu_state(vm, VCPU_ID); 151 run = vcpu_state(vm, VCPU_ID);
151 free(state); 152 free(state);