Received: by 2002:ac0:a5a6:0:0:0:0:0 with SMTP id m35-v6csp947454imm; Thu, 13 Sep 2018 10:07:06 -0700 (PDT) X-Google-Smtp-Source: ANB0VdbjDypTrXStO1c4xA4MA7uPLUXTte1oAqhZhtmIO1VNjkGbn4OpPEBGx2lnZYlv1FaZGwv3 X-Received: by 2002:a17:902:d917:: with SMTP id c23-v6mr8141134plz.65.1536858426564; Thu, 13 Sep 2018 10:07:06 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1536858426; cv=none; d=google.com; s=arc-20160816; b=py20f5GpLgHaBdFw+XZJYdcVygqEn9sU1tmqKY8lPmQAUEwclI8z+wyg5c3wADdm1h ZkHp5FhHZUfBps5V/7/cj4i+LW/mkPY1r5ZQRNiaQsd9hwZU4lC9lU450nmazXs0QBlw ZWq1o5/4haQvGOmHBA4deF97xkQ3nz7j+BNLJc5HC0ngmJwDxdYFzht/kExTTxZGAktO YGmxn78POBFB3kor21a97vihug0Q4rN0NpIPiktfJKYGA2DhpPUJCBoLss/XNRJOVH12 +B53fLxtB3LSmvm0XlrX17lfhzeQ1OsAzV6UXx0t9HMsRS62z1J9VDP6007RYyxVp5tX CnBQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from; bh=xNnpsih5u5yf1TN0/Yr5EHY/JHOmigA//CmJPs3YdBg=; b=vShAI9a1njxFNaDCMBgFjnkmo6UFm+Y595+T5rET48STQ32L8wicuQF9yO7ZXVn4WT ytoEoUyjkujcwSN/K8xSaxFTJrWm1XiGPbmOuY8ywJJ5Y3aY9BYtMLhpAVEYhrqDoqiq IQGy0XfwUmvpJ4HnwTKYfgQOntyWDR5BUuOfqdanjUkbdvKOKGG+z0KeZAza4UQVU1tf A3WrwUkicmaDWQvV79E2nPTGzK2Is6kE5k5jiCHEGcyISyHkEyPOzFZsmXdQy0o9CwPF 7VG/MSr7z77LN9iGnuSJolneJd52zSVL50XhOn7c/sokD05+K84aJUQsVuKZ035H9Qaw bOqQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id d70-v6si4750773pfd.114.2018.09.13.10.06.50; Thu, 13 Sep 2018 10:07:06 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728566AbeIMWQP (ORCPT + 99 others); Thu, 13 Sep 2018 18:16:15 -0400 Received: from mx1.redhat.com ([209.132.183.28]:47272 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728544AbeIMWQP (ORCPT ); Thu, 13 Sep 2018 18:16:15 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 7FA5C3082B64; Thu, 13 Sep 2018 17:05:53 +0000 (UTC) Received: from vitty.brq.redhat.com (unknown [10.43.2.155]) by smtp.corp.redhat.com (Postfix) with ESMTP id 28325608E0; Thu, 13 Sep 2018 17:05:50 +0000 (UTC) From: Vitaly Kuznetsov To: kvm@vger.kernel.org Cc: Paolo Bonzini , =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= , Roman Kagan , "K. Y. Srinivasan" , Haiyang Zhang , Stephen Hemminger , "Michael Kelley (EOSG)" , Jim Mattson , Liran Alon , linux-kernel@vger.kernel.org Subject: [PATCH v5 10/12] x86/kvm/nVMX: nested state migration for Enlightened VMCS Date: Thu, 13 Sep 2018 19:05:20 +0200 Message-Id: <20180913170522.24876-11-vkuznets@redhat.com> In-Reply-To: <20180913170522.24876-1-vkuznets@redhat.com> References: <20180913170522.24876-1-vkuznets@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.45]); Thu, 13 Sep 2018 17:05:53 +0000 (UTC) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add support for get/set of nested state when Enlightened VMCS is in use. A new KVM_STATE_NESTED_EVMCS flag to indicate eVMCS on the vCPU was enabled is added. Signed-off-by: Vitaly Kuznetsov --- arch/x86/include/uapi/asm/kvm.h | 1 + arch/x86/kvm/vmx.c | 82 +++++++++++++++++++++++++++++++---------- arch/x86/kvm/x86.c | 6 ++- 3 files changed, 67 insertions(+), 22 deletions(-) diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index 86299efa804a..0b45bd0ea13b 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -380,6 +380,7 @@ struct kvm_sync_regs { #define KVM_STATE_NESTED_GUEST_MODE 0x00000001 #define KVM_STATE_NESTED_RUN_PENDING 0x00000002 +#define KVM_STATE_NESTED_EVMCS 0x00000004 #define KVM_STATE_NESTED_SMM_GUEST_MODE 0x00000001 #define KVM_STATE_NESTED_SMM_VMXON 0x00000002 diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 25a25fff8dd9..04d23aebbb17 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -1603,7 +1603,8 @@ static int nested_enable_evmcs(struct kvm_vcpu *vcpu, * maximum supported version. KVM supports versions from 1 to * KVM_EVMCS_VERSION. */ - *vmcs_version = (KVM_EVMCS_VERSION << 8) | 1; + if (vmcs_version) + *vmcs_version = (KVM_EVMCS_VERSION << 8) | 1; vmx->nested.msrs.pinbased_ctls_high &= ~EVMCS1_UNSUPPORTED_PINCTRL; vmx->nested.msrs.entry_ctls_high &= ~EVMCS1_UNSUPPORTED_VMENTRY_CTRL; @@ -9353,7 +9354,8 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu) * This is an equivalent of the nested hypervisor executing the vmptrld * instruction. */ -static int nested_vmx_handle_enlightened_vmptrld(struct kvm_vcpu *vcpu) +static int nested_vmx_handle_enlightened_vmptrld(struct kvm_vcpu *vcpu, + bool from_launch) { struct vcpu_vmx *vmx = to_vmx(vcpu); struct hv_vp_assist_page assist_page; @@ -9404,8 +9406,9 @@ static int nested_vmx_handle_enlightened_vmptrld(struct kvm_vcpu *vcpu) * present in struct hv_enlightened_vmcs, ...). Make sure there * are no leftovers. */ - memset(vmx->nested.cached_vmcs12, 0, - sizeof(*vmx->nested.cached_vmcs12)); + if (from_launch) + memset(vmx->nested.cached_vmcs12, 0, + sizeof(*vmx->nested.cached_vmcs12)); } return 1; @@ -11142,6 +11145,15 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) } if (vmx->nested.need_vmcs12_sync) { + /* + * hv_evmcs may end up being not mapped after migration (when + * L2 was running), map it here to make sure vmcs12 changes are + * properly reflected. + */ + if (vmx->nested.enlightened_vmcs_enabled && + !vmx->nested.hv_evmcs) + nested_vmx_handle_enlightened_vmptrld(vcpu, false); + if (vmx->nested.hv_evmcs) { copy_vmcs12_to_enlightened(vmx); /* All fields are clean */ @@ -13155,7 +13167,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) if (!nested_vmx_check_permission(vcpu)) return 1; - if (!nested_vmx_handle_enlightened_vmptrld(vcpu)) + if (!nested_vmx_handle_enlightened_vmptrld(vcpu, true)) return 1; if (!vmx->nested.hv_evmcs && !nested_vmx_check_vmcs12(vcpu)) @@ -14366,6 +14378,20 @@ static int enable_smi_window(struct kvm_vcpu *vcpu) return 0; } +static inline int vmx_has_valid_vmcs12(struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + + /* + * In case we do two consecutive get/set_nested_state()s while L2 was + * running hv_evmcs may end up not being mapped (we map it from + * nested_vmx_run()/vmx_vcpu_run()). Check is_guest_mode() as we always + * have vmcs12 if it is true. + */ + return is_guest_mode(vcpu) || vmx->nested.current_vmptr != -1ull || + vmx->nested.hv_evmcs; +} + static int vmx_get_nested_state(struct kvm_vcpu *vcpu, struct kvm_nested_state __user *user_kvm_nested_state, u32 user_data_size) @@ -14386,16 +14412,15 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu, vmx = to_vmx(vcpu); vmcs12 = get_vmcs12(vcpu); - /* FIXME: Enlightened VMCS is currently unsupported */ - if (vmx->nested.hv_evmcs) - return -ENOTSUPP; + if (nested_vmx_allowed(vcpu) && vmx->nested.enlightened_vmcs_enabled) + kvm_state.flags |= KVM_STATE_NESTED_EVMCS; if (nested_vmx_allowed(vcpu) && (vmx->nested.vmxon || vmx->nested.smm.vmxon)) { kvm_state.vmx.vmxon_pa = vmx->nested.vmxon_ptr; kvm_state.vmx.vmcs_pa = vmx->nested.current_vmptr; - if (vmx->nested.current_vmptr != -1ull) { + if (vmx_has_valid_vmcs12(vcpu)) { kvm_state.size += VMCS12_SIZE; if (is_guest_mode(vcpu) && @@ -14424,20 +14449,24 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu, if (copy_to_user(user_kvm_nested_state, &kvm_state, sizeof(kvm_state))) return -EFAULT; - if (vmx->nested.current_vmptr == -1ull) + if (!vmx_has_valid_vmcs12(vcpu)) goto out; /* * When running L2, the authoritative vmcs12 state is in the * vmcs02. When running L1, the authoritative vmcs12 state is - * in the shadow vmcs linked to vmcs01, unless - * sync_shadow_vmcs is set, in which case, the authoritative - * vmcs12 state is in the vmcs12 already. + * in the shadow or enlightened vmcs linked to vmcs01. In case + * need_vmcs12_sync is set the authoritative vmcs12 state is in + * the vmcs12 already. */ - if (is_guest_mode(vcpu)) + if (is_guest_mode(vcpu)) { sync_vmcs12(vcpu, vmcs12); - else if (enable_shadow_vmcs && !vmx->nested.need_vmcs12_sync) - copy_shadow_to_vmcs12(vmx); + } else if (!vmx->nested.need_vmcs12_sync) { + if (vmx->nested.hv_evmcs) + copy_enlightened_to_vmcs12(vmx); + else if (enable_shadow_vmcs) + copy_shadow_to_vmcs12(vmx); + } if (copy_to_user(user_kvm_nested_state->data, vmcs12, sizeof(*vmcs12))) return -EFAULT; @@ -14465,6 +14494,9 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu, if (kvm_state->format != 0) return -EINVAL; + if (kvm_state->flags & KVM_STATE_NESTED_EVMCS) + nested_enable_evmcs(vcpu, NULL); + if (!nested_vmx_allowed(vcpu)) return kvm_state->vmx.vmxon_pa == -1ull ? 0 : -EINVAL; @@ -14507,11 +14539,21 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu, if (kvm_state->size < sizeof(kvm_state) + sizeof(*vmcs12)) return 0; - if (kvm_state->vmx.vmcs_pa == kvm_state->vmx.vmxon_pa || - !page_address_valid(vcpu, kvm_state->vmx.vmcs_pa)) - return -EINVAL; + if (kvm_state->vmx.vmcs_pa != -1ull) { + if (kvm_state->vmx.vmcs_pa == kvm_state->vmx.vmxon_pa || + !page_address_valid(vcpu, kvm_state->vmx.vmcs_pa)) + return -EINVAL; - set_current_vmptr(vmx, kvm_state->vmx.vmcs_pa); + set_current_vmptr(vmx, kvm_state->vmx.vmcs_pa); + } else if (kvm_state->flags & KVM_STATE_NESTED_EVMCS) { + /* + * Sync eVMCS upon entry as we may not have + * HV_X64_MSR_VP_ASSIST_PAGE set up yet. + */ + vmx->nested.need_vmcs12_sync = true; + } else { + return -EINVAL; + } if (kvm_state->vmx.smm.flags & KVM_STATE_NESTED_SMM_VMXON) { vmx->nested.smm.vmxon = true; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 0157f480d4ad..8c180fbb9e1d 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4053,11 +4053,13 @@ long kvm_arch_vcpu_ioctl(struct file *filp, return -EINVAL; if (kvm_state.flags & - ~(KVM_STATE_NESTED_RUN_PENDING | KVM_STATE_NESTED_GUEST_MODE)) + ~(KVM_STATE_NESTED_RUN_PENDING | KVM_STATE_NESTED_GUEST_MODE + | KVM_STATE_NESTED_EVMCS)) return -EINVAL; /* nested_run_pending implies guest_mode. */ - if (kvm_state.flags == KVM_STATE_NESTED_RUN_PENDING) + if ((kvm_state.flags & KVM_STATE_NESTED_RUN_PENDING) + && !(kvm_state.flags & KVM_STATE_NESTED_GUEST_MODE)) return -EINVAL; r = kvm_x86_ops->set_nested_state(vcpu, user_kvm_nested_state, &kvm_state); -- 2.14.4