From nobody Tue Jun 30 08:10:02 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 27E29C433FE for ; Fri, 21 Jan 2022 13:29:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1380736AbiAUN3N (ORCPT ); Fri, 21 Jan 2022 08:29:13 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]:35564 "EHLO us-smtp-delivery-124.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1380702AbiAUN3E (ORCPT ); Fri, 21 Jan 2022 08:29:04 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1642771743; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=vT5SFyPQwf3C5QU0HD+SeNKojUWOi+souCVxIuzr4TU=; b=K27TMnB8IKJOf8VLChOQ50fwiftg9erVnYQjpoSr5win/4vwQI0k4qNvZs0Sgmh4E8M6f4 7WYXjcPvWbtq8JADJl6n8sQ/UycBVEMvh2JDpUgRcelyRusxZoFw57CUzZxpyLkP8Vfdfp 2A7UmC80/3NItNB2V/cljyD2VaCqJZQ= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-473-LrFnqQEZOO-W6veRAg67-w-1; Fri, 21 Jan 2022 08:29:00 -0500 X-MC-Unique: LrFnqQEZOO-W6veRAg67-w-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id CD11418A0F1C; Fri, 21 Jan 2022 13:28:58 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.40.195.38]) by smtp.corp.redhat.com (Postfix) with ESMTP id 6DF107E213; Fri, 21 Jan 2022 13:28:56 +0000 (UTC) From: Vitaly Kuznetsov To: kvm@vger.kernel.org, Paolo Bonzini Cc: Sean Christopherson , Wanpeng Li , Jim Mattson , Igor Mammedov , linux-kernel@vger.kernel.org Subject: [PATCH v4 1/5] KVM: x86: Do runtime CPUID update before updating vcpu->arch.cpuid_entries Date: Fri, 21 Jan 2022 14:28:48 +0100 Message-Id: <20220121132852.2482355-2-vkuznets@redhat.com> In-Reply-To: <20220121132852.2482355-1-vkuznets@redhat.com> References: <20220121132852.2482355-1-vkuznets@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" kvm_update_cpuid_runtime() mangles CPUID data coming from userspace VMM after updating 'vcpu->arch.cpuid_entries', this makes it impossible to compare an update with what was previously supplied. Introduce __kvm_update_cpuid_runtime() version which can be used to tweak the input before it goes to 'vcpu->arch.cpuid_entries' so the upcoming update check can compare tweaked data. No functional change intended. Signed-off-by: Vitaly Kuznetsov --- arch/x86/kvm/cpuid.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index c55e57b30e81..812190a707f6 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -145,14 +145,21 @@ static void kvm_update_kvm_cpuid_base(struct kvm_vcpu= *vcpu) } } =20 -static struct kvm_cpuid_entry2 *kvm_find_kvm_cpuid_features(struct kvm_vcp= u *vcpu) +static struct kvm_cpuid_entry2 *__kvm_find_kvm_cpuid_features(struct kvm_v= cpu *vcpu, + struct kvm_cpuid_entry2 *entries, int nent) { u32 base =3D vcpu->arch.kvm_cpuid_base; =20 if (!base) return NULL; =20 - return kvm_find_cpuid_entry(vcpu, base | KVM_CPUID_FEATURES, 0); + return cpuid_entry2_find(entries, nent, base | KVM_CPUID_FEATURES, 0); +} + +static struct kvm_cpuid_entry2 *kvm_find_kvm_cpuid_features(struct kvm_vcp= u *vcpu) +{ + return __kvm_find_kvm_cpuid_features(vcpu, vcpu->arch.cpuid_entries, + vcpu->arch.cpuid_nent); } =20 void kvm_update_pv_runtime(struct kvm_vcpu *vcpu) @@ -167,11 +174,12 @@ void kvm_update_pv_runtime(struct kvm_vcpu *vcpu) vcpu->arch.pv_cpuid.features =3D best->eax; } =20 -void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu) +static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_c= puid_entry2 *entries, + int nent) { struct kvm_cpuid_entry2 *best; =20 - best =3D kvm_find_cpuid_entry(vcpu, 1, 0); + best =3D cpuid_entry2_find(entries, nent, 1, 0); if (best) { /* Update OSXSAVE bit */ if (boot_cpu_has(X86_FEATURE_XSAVE)) @@ -182,33 +190,38 @@ void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu) vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE); } =20 - best =3D kvm_find_cpuid_entry(vcpu, 7, 0); + best =3D cpuid_entry2_find(entries, nent, 7, 0); if (best && boot_cpu_has(X86_FEATURE_PKU) && best->function =3D=3D 0x7) cpuid_entry_change(best, X86_FEATURE_OSPKE, kvm_read_cr4_bits(vcpu, X86_CR4_PKE)); =20 - best =3D kvm_find_cpuid_entry(vcpu, 0xD, 0); + best =3D cpuid_entry2_find(entries, nent, 0xD, 0); if (best) best->ebx =3D xstate_required_size(vcpu->arch.xcr0, false); =20 - best =3D kvm_find_cpuid_entry(vcpu, 0xD, 1); + best =3D cpuid_entry2_find(entries, nent, 0xD, 1); if (best && (cpuid_entry_has(best, X86_FEATURE_XSAVES) || cpuid_entry_has(best, X86_FEATURE_XSAVEC))) best->ebx =3D xstate_required_size(vcpu->arch.xcr0, true); =20 - best =3D kvm_find_kvm_cpuid_features(vcpu); + best =3D __kvm_find_kvm_cpuid_features(vcpu, entries, nent); if (kvm_hlt_in_guest(vcpu->kvm) && best && (best->eax & (1 << KVM_FEATURE_PV_UNHALT))) best->eax &=3D ~(1 << KVM_FEATURE_PV_UNHALT); =20 if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT)) { - best =3D kvm_find_cpuid_entry(vcpu, 0x1, 0); + best =3D cpuid_entry2_find(entries, nent, 0x1, 0); if (best) cpuid_entry_change(best, X86_FEATURE_MWAIT, vcpu->arch.ia32_misc_enable_msr & MSR_IA32_MISC_ENABLE_MWAIT); } } + +void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu) +{ + __kvm_update_cpuid_runtime(vcpu, vcpu->arch.cpuid_entries, vcpu->arch.cpu= id_nent); +} EXPORT_SYMBOL_GPL(kvm_update_cpuid_runtime); =20 static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) @@ -298,6 +311,8 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct = kvm_cpuid_entry2 *e2, { int r; =20 + __kvm_update_cpuid_runtime(vcpu, e2, nent); + r =3D kvm_check_cpuid(vcpu, e2, nent); if (r) return r; @@ -307,7 +322,6 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct = kvm_cpuid_entry2 *e2, vcpu->arch.cpuid_nent =3D nent; =20 kvm_update_kvm_cpuid_base(vcpu); - kvm_update_cpuid_runtime(vcpu); kvm_vcpu_after_set_cpuid(vcpu); =20 return 0; --=20 2.34.1 From nobody Tue Jun 30 08:10:02 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 468B9C433EF for ; Fri, 21 Jan 2022 13:29:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1380749AbiAUN3P (ORCPT ); Fri, 21 Jan 2022 08:29:15 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]:46612 "EHLO us-smtp-delivery-124.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1380708AbiAUN3G (ORCPT ); Fri, 21 Jan 2022 08:29:06 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1642771746; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ph7iuiqAyH7LAtbQMxXscX0QTvPI7Az7INEqaoOkdQY=; b=CBnpFW36xLHnYWsa1dXCzWri3TCIPb+J5Cy/oHtA9FogB0niV78cVJCbMN7x8GywyzmpuQ QjEPJjapS3XNA6oB3b5PU1Z0MP7dFhraiLhVVgh9u/6G1KEt22u9IyQRrJfyp2Q8XbGaNT CBEzUZj2CwlWgNr+XrzR0HNVv0rES6U= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-330-6akO12oFNImxNxCzy0XgZA-1; Fri, 21 Jan 2022 08:29:03 -0500 X-MC-Unique: 6akO12oFNImxNxCzy0XgZA-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 9362E1091DA1; Fri, 21 Jan 2022 13:29:01 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.40.195.38]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3514E7E213; Fri, 21 Jan 2022 13:28:59 +0000 (UTC) From: Vitaly Kuznetsov To: kvm@vger.kernel.org, Paolo Bonzini Cc: Sean Christopherson , Wanpeng Li , Jim Mattson , Igor Mammedov , linux-kernel@vger.kernel.org Subject: [PATCH v4 2/5] KVM: x86: Move CPUID.(EAX=0x12,ECX=1) mangling to __kvm_update_cpuid_runtime() Date: Fri, 21 Jan 2022 14:28:49 +0100 Message-Id: <20220121132852.2482355-3-vkuznets@redhat.com> In-Reply-To: <20220121132852.2482355-1-vkuznets@redhat.com> References: <20220121132852.2482355-1-vkuznets@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" To support comparing CPUID data update with what's already set for a vCPU all mangling needs to happen in __kvm_update_cpuid_runtime(), before 'vcpu->arch.cpuid_entries' is updated. CPUID.(EAX=3D0x12,ECX=3D1) is curren= tly being mangled in kvm_vcpu_after_set_cpuid(), move it to __kvm_update_cpuid_runtime(). Split off cpuid_get_supported_xcr0() helper as 'vcpu->arch.guest_supported_xcr0' update needs (logically) to stay in kvm_vcpu_after_set_cpuid(). No functional change intended. Signed-off-by: Vitaly Kuznetsov --- arch/x86/kvm/cpuid.c | 54 +++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 812190a707f6..7c48daee6670 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -174,10 +174,26 @@ void kvm_update_pv_runtime(struct kvm_vcpu *vcpu) vcpu->arch.pv_cpuid.features =3D best->eax; } =20 +/* + * Calculate guest's supported XCR0 taking into account guest CPUID data a= nd + * supported_xcr0 (comprised of host configuration and KVM_SUPPORTED_XCR0). + */ +static u64 cpuid_get_supported_xcr0(struct kvm_cpuid_entry2 *entries, int = nent) +{ + struct kvm_cpuid_entry2 *best; + + best =3D cpuid_entry2_find(entries, nent, 0xd, 0); + if (!best) + return 0; + + return (best->eax | ((u64)best->edx << 32)) & supported_xcr0; +} + static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_c= puid_entry2 *entries, int nent) { struct kvm_cpuid_entry2 *best; + u64 guest_supported_xcr0 =3D cpuid_get_supported_xcr0(entries, nent); =20 best =3D cpuid_entry2_find(entries, nent, 1, 0); if (best) { @@ -216,6 +232,21 @@ static void __kvm_update_cpuid_runtime(struct kvm_vcpu= *vcpu, struct kvm_cpuid_e vcpu->arch.ia32_misc_enable_msr & MSR_IA32_MISC_ENABLE_MWAIT); } + + /* + * Bits 127:0 of the allowed SECS.ATTRIBUTES (CPUID.0x12.0x1) enumerate + * the supported XSAVE Feature Request Mask (XFRM), i.e. the enclave's + * requested XCR0 value. The enclave's XFRM must be a subset of XCRO + * at the time of EENTER, thus adjust the allowed XFRM by the guest's + * supported XCR0. Similar to XCR0 handling, FP and SSE are forced to + * '1' even on CPUs that don't support XSAVE. + */ + best =3D cpuid_entry2_find(entries, nent, 0x12, 0x1); + if (best) { + best->ecx &=3D guest_supported_xcr0 & 0xffffffff; + best->edx &=3D guest_supported_xcr0 >> 32; + best->ecx |=3D XFEATURE_MASK_FPSSE; + } } =20 void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu) @@ -239,27 +270,8 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *= vcpu) kvm_apic_set_version(vcpu); } =20 - best =3D kvm_find_cpuid_entry(vcpu, 0xD, 0); - if (!best) - vcpu->arch.guest_supported_xcr0 =3D 0; - else - vcpu->arch.guest_supported_xcr0 =3D - (best->eax | ((u64)best->edx << 32)) & supported_xcr0; - - /* - * Bits 127:0 of the allowed SECS.ATTRIBUTES (CPUID.0x12.0x1) enumerate - * the supported XSAVE Feature Request Mask (XFRM), i.e. the enclave's - * requested XCR0 value. The enclave's XFRM must be a subset of XCRO - * at the time of EENTER, thus adjust the allowed XFRM by the guest's - * supported XCR0. Similar to XCR0 handling, FP and SSE are forced to - * '1' even on CPUs that don't support XSAVE. - */ - best =3D kvm_find_cpuid_entry(vcpu, 0x12, 0x1); - if (best) { - best->ecx &=3D vcpu->arch.guest_supported_xcr0 & 0xffffffff; - best->edx &=3D vcpu->arch.guest_supported_xcr0 >> 32; - best->ecx |=3D XFEATURE_MASK_FPSSE; - } + vcpu->arch.guest_supported_xcr0 =3D + cpuid_get_supported_xcr0(vcpu->arch.cpuid_entries, vcpu->arch.cpuid_nent= ); =20 kvm_update_pv_runtime(vcpu); =20 --=20 2.34.1 From nobody Tue Jun 30 08:10:02 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7C069C433F5 for ; Fri, 21 Jan 2022 13:30:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1380772AbiAUNaZ (ORCPT ); Fri, 21 Jan 2022 08:30:25 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]:58109 "EHLO us-smtp-delivery-124.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1380720AbiAUNaJ (ORCPT ); Fri, 21 Jan 2022 08:30:09 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1642771753; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=XcWu6s4pN5jlEkVju4/UBrdbowSjhtmAIaPpgML9RtY=; b=ZnC5+vWiGV/Kw8yLG3xYgG4xIgcVl7ZADpwPkjiCxt8AC5EacPWHMxNJd61tB69Oe652ph QsSz+0N8eQ029QJ83H1+KSgLjistYECI2yIYD5tYloc7ygll2ZHhBtP/bmKTeH/Le3qKgB I4pAI7220ZWFRaDpIBvjukIYusEToWI= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-325-HZhNq7LqNTe5hEetPfEeuQ-1; Fri, 21 Jan 2022 08:29:05 -0500 X-MC-Unique: HZhNq7LqNTe5hEetPfEeuQ-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 3FC6084DA41; Fri, 21 Jan 2022 13:29:04 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.40.195.38]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1E8457E228; Fri, 21 Jan 2022 13:29:01 +0000 (UTC) From: Vitaly Kuznetsov To: kvm@vger.kernel.org, Paolo Bonzini Cc: Sean Christopherson , Wanpeng Li , Jim Mattson , Igor Mammedov , linux-kernel@vger.kernel.org Subject: [PATCH v4 3/5] KVM: x86: Partially allow KVM_SET_CPUID{,2} after KVM_RUN Date: Fri, 21 Jan 2022 14:28:50 +0100 Message-Id: <20220121132852.2482355-4-vkuznets@redhat.com> In-Reply-To: <20220121132852.2482355-1-vkuznets@redhat.com> References: <20220121132852.2482355-1-vkuznets@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Commit feb627e8d6f6 ("KVM: x86: Forbid KVM_SET_CPUID{,2} after KVM_RUN") forbade changing CPUID altogether but unfortunately this is not fully compatible with existing VMMs. In particular, QEMU reuses vCPU fds for CPU hotplug after unplug and it calls KVM_SET_CPUID2. Instead of full ban, check whether the supplied CPUID data is equal to what was previously set. Reported-by: Igor Mammedov Fixes: feb627e8d6f6 ("KVM: x86: Forbid KVM_SET_CPUID{,2} after KVM_RUN") Signed-off-by: Vitaly Kuznetsov --- arch/x86/kvm/cpuid.c | 31 +++++++++++++++++++++++++++++++ arch/x86/kvm/x86.c | 19 ------------------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 7c48daee6670..96556bf494fc 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -119,6 +119,19 @@ static int kvm_check_cpuid(struct kvm_vcpu *vcpu, return fpu_enable_guest_xfd_features(&vcpu->arch.guest_fpu, xfeatures); } =20 +/* Check whether the supplied CPUID data is equal to what is already set f= or the vCPU. */ +static int kvm_cpuid_check_equal(struct kvm_vcpu *vcpu, struct kvm_cpuid_e= ntry2 *e2, + int nent) +{ + if (nent !=3D vcpu->arch.cpuid_nent) + return -EINVAL; + + if (memcmp(e2, vcpu->arch.cpuid_entries, nent * sizeof(*e2))) + return -EINVAL; + + return 0; +} + static void kvm_update_kvm_cpuid_base(struct kvm_vcpu *vcpu) { u32 function; @@ -325,6 +338,24 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct= kvm_cpuid_entry2 *e2, =20 __kvm_update_cpuid_runtime(vcpu, e2, nent); =20 + /* + * KVM does not correctly handle changing guest CPUID after KVM_RUN, as + * MAXPHYADDR, GBPAGES support, AMD reserved bit behavior, etc.. aren't + * tracked in kvm_mmu_page_role. As a result, KVM may miss guest page + * faults due to reusing SPs/SPTEs. In practice no sane VMM mucks with + * the core vCPU model on the fly. To avoid potential hard to debug + * problems, forbid changing CPUID data after successfully entering the + * guest. Banning KVM_SET_CPUID{,2} altogether is incompatible with + * certain VMMs (e.g. QEMU) which reuse vCPU fds for CPU hotplug as + * KVM_SET_CPUID{,2} call (with the same CPUID data) may be issued again + * upon hotplug. + * Note, there are other problematic scenarios which are currently not + * being handled, e.g. supplying different CPUID data for different + * vCPUs also won't be handled correctly by KVM MMU. + */ + if (vcpu->arch.last_vmentry_cpu !=3D -1) + return kvm_cpuid_check_equal(vcpu, e2, nent); + r =3D kvm_check_cpuid(vcpu, e2, nent); if (r) return r; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 76b4803dd3bd..ff1416010728 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -5230,17 +5230,6 @@ long kvm_arch_vcpu_ioctl(struct file *filp, struct kvm_cpuid __user *cpuid_arg =3D argp; struct kvm_cpuid cpuid; =20 - /* - * KVM does not correctly handle changing guest CPUID after KVM_RUN, as - * MAXPHYADDR, GBPAGES support, AMD reserved bit behavior, etc.. aren't - * tracked in kvm_mmu_page_role. As a result, KVM may miss guest page - * faults due to reusing SPs/SPTEs. In practice no sane VMM mucks with - * the core vCPU model on the fly, so fail. - */ - r =3D -EINVAL; - if (vcpu->arch.last_vmentry_cpu !=3D -1) - goto out; - r =3D -EFAULT; if (copy_from_user(&cpuid, cpuid_arg, sizeof(cpuid))) goto out; @@ -5251,14 +5240,6 @@ long kvm_arch_vcpu_ioctl(struct file *filp, struct kvm_cpuid2 __user *cpuid_arg =3D argp; struct kvm_cpuid2 cpuid; =20 - /* - * KVM_SET_CPUID{,2} after KVM_RUN is forbidded, see the comment in - * KVM_SET_CPUID case above. - */ - r =3D -EINVAL; - if (vcpu->arch.last_vmentry_cpu !=3D -1) - goto out; - r =3D -EFAULT; if (copy_from_user(&cpuid, cpuid_arg, sizeof(cpuid))) goto out; --=20 2.34.1 From nobody Tue Jun 30 08:10:02 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AB72AC433F5 for ; Fri, 21 Jan 2022 13:29:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1380789AbiAUN3Z (ORCPT ); Fri, 21 Jan 2022 08:29:25 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]:58733 "EHLO us-smtp-delivery-124.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1380727AbiAUN3L (ORCPT ); Fri, 21 Jan 2022 08:29:11 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1642771750; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=2PBE8349W+pORnjnNy3WMgm07NQBV8dZAmx6X3HKn1A=; b=Mb9EXCGIA9pJC3LS6zt7QyDxSypyObPwqeoWTAQaXZ+0qtYLvUXpwptiWecxLJxbXnJfNg /YNcKK30n7oCy2rdp2ByVsCbRfQsvkeGEajuoZ+KATroYv4TowBOImPm3xtC654UhD5b4z uyeB1n+fV3eGTWb9E6cfoOp57E/9oFI= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-36-DsspPE7UO0aD9UtMTOEkmQ-1; Fri, 21 Jan 2022 08:29:07 -0500 X-MC-Unique: DsspPE7UO0aD9UtMTOEkmQ-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id B05A884DA41; Fri, 21 Jan 2022 13:29:06 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.40.195.38]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9D9637E213; Fri, 21 Jan 2022 13:29:04 +0000 (UTC) From: Vitaly Kuznetsov To: kvm@vger.kernel.org, Paolo Bonzini Cc: Sean Christopherson , Wanpeng Li , Jim Mattson , Igor Mammedov , linux-kernel@vger.kernel.org Subject: [PATCH v4 4/5] KVM: selftests: Rename 'get_cpuid_test' to 'cpuid_test' Date: Fri, 21 Jan 2022 14:28:51 +0100 Message-Id: <20220121132852.2482355-5-vkuznets@redhat.com> In-Reply-To: <20220121132852.2482355-1-vkuznets@redhat.com> References: <20220121132852.2482355-1-vkuznets@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" In preparation to reusing the existing 'get_cpuid_test' for testing "KVM_SET_CPUID{,2} after KVM_RUN" rename it to 'cpuid_test' to avoid the confusion. No functional change intended. Signed-off-by: Vitaly Kuznetsov --- tools/testing/selftests/kvm/.gitignore | 2 +- tools/testing/selftests/kvm/Makefile | 4 ++-- .../selftests/kvm/x86_64/{get_cpuid_test.c =3D> cpuid_test.c} | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename tools/testing/selftests/kvm/x86_64/{get_cpuid_test.c =3D> cpuid_tes= t.c} (100%) diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftes= ts/kvm/.gitignore index 8c129961accf..20b4c921c9a2 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -8,11 +8,11 @@ /s390x/memop /s390x/resets /s390x/sync_regs_test +/x86_64/cpuid_test /x86_64/cr4_cpuid_sync_test /x86_64/debug_regs /x86_64/evmcs_test /x86_64/emulator_error_test -/x86_64/get_cpuid_test /x86_64/get_msr_index_features /x86_64/kvm_clock_test /x86_64/kvm_pv_test diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests= /kvm/Makefile index ee8cf2149824..ec78a8692899 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -43,11 +43,11 @@ LIBKVM_aarch64 =3D lib/aarch64/processor.c lib/aarch64/= ucall.c lib/aarch64/handler LIBKVM_s390x =3D lib/s390x/processor.c lib/s390x/ucall.c lib/s390x/diag318= _test_handler.c LIBKVM_riscv =3D lib/riscv/processor.c lib/riscv/ucall.c =20 -TEST_GEN_PROGS_x86_64 =3D x86_64/cr4_cpuid_sync_test +TEST_GEN_PROGS_x86_64 =3D x86_64/cpuid_test +TEST_GEN_PROGS_x86_64 +=3D x86_64/cr4_cpuid_sync_test TEST_GEN_PROGS_x86_64 +=3D x86_64/get_msr_index_features TEST_GEN_PROGS_x86_64 +=3D x86_64/evmcs_test TEST_GEN_PROGS_x86_64 +=3D x86_64/emulator_error_test -TEST_GEN_PROGS_x86_64 +=3D x86_64/get_cpuid_test TEST_GEN_PROGS_x86_64 +=3D x86_64/hyperv_clock TEST_GEN_PROGS_x86_64 +=3D x86_64/hyperv_cpuid TEST_GEN_PROGS_x86_64 +=3D x86_64/hyperv_features diff --git a/tools/testing/selftests/kvm/x86_64/get_cpuid_test.c b/tools/te= sting/selftests/kvm/x86_64/cpuid_test.c similarity index 100% rename from tools/testing/selftests/kvm/x86_64/get_cpuid_test.c rename to tools/testing/selftests/kvm/x86_64/cpuid_test.c --=20 2.34.1 From nobody Tue Jun 30 08:10:02 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 98A5DC433F5 for ; Fri, 21 Jan 2022 13:30:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1380716AbiAUNan (ORCPT ); Fri, 21 Jan 2022 08:30:43 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]:55440 "EHLO us-smtp-delivery-124.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1380711AbiAUN3M (ORCPT ); Fri, 21 Jan 2022 08:29:12 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1642771752; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=bLFvUw5OiL0PwWN1RfLYJMbRWgda2rw0vcjqVwdGBw4=; b=PCGxNfBDEkbuH7jmCMu1LoY+eeCJn9jLHxSTXa9Se31MN76xS+yHC6Yb3HY0JJ1fab0sRJ BloTCSWPUHkWRvBVzAvA1HIJG5OHKRhwGktF1EdDOqNywVW/2GrirXe70so4H/G2h4JoZY A4NN2lcwjvVELPhL+7mrV8wH1LWHwo8= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-283-xBGI9zUhPLiwzszKkmMBMQ-1; Fri, 21 Jan 2022 08:29:10 -0500 X-MC-Unique: xBGI9zUhPLiwzszKkmMBMQ-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 74258A0BE4; Fri, 21 Jan 2022 13:29:09 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.40.195.38]) by smtp.corp.redhat.com (Postfix) with ESMTP id 189497E228; Fri, 21 Jan 2022 13:29:06 +0000 (UTC) From: Vitaly Kuznetsov To: kvm@vger.kernel.org, Paolo Bonzini Cc: Sean Christopherson , Wanpeng Li , Jim Mattson , Igor Mammedov , linux-kernel@vger.kernel.org Subject: [PATCH v4 5/5] KVM: selftests: Test KVM_SET_CPUID2 after KVM_RUN Date: Fri, 21 Jan 2022 14:28:52 +0100 Message-Id: <20220121132852.2482355-6-vkuznets@redhat.com> In-Reply-To: <20220121132852.2482355-1-vkuznets@redhat.com> References: <20220121132852.2482355-1-vkuznets@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" KVM forbids KVM_SET_CPUID2 after KVM_RUN was performed on a vCPU unless the supplied CPUID data is equal to what was previously set. Test this. Signed-off-by: Vitaly Kuznetsov --- .../selftests/kvm/include/x86_64/processor.h | 7 ++++ .../selftests/kvm/lib/x86_64/processor.c | 33 ++++++++++++++++--- .../testing/selftests/kvm/x86_64/cpuid_test.c | 30 +++++++++++++++++ 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools= /testing/selftests/kvm/include/x86_64/processor.h index e94ba0fc67d8..bb013d101c14 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -375,6 +375,8 @@ uint64_t kvm_get_feature_msr(uint64_t msr_index); struct kvm_cpuid2 *kvm_get_supported_cpuid(void); =20 struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vm *vm, uint32_t vcpuid); +int __vcpu_set_cpuid(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_cpuid2 *cpuid); void vcpu_set_cpuid(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_cpuid2 *cpuid); =20 @@ -418,6 +420,11 @@ uint64_t vm_get_page_table_entry(struct kvm_vm *vm, in= t vcpuid, uint64_t vaddr); void vm_set_page_table_entry(struct kvm_vm *vm, int vcpuid, uint64_t vaddr, uint64_t pte); =20 +/* + * get_cpuid() - find matching CPUID entry and return pointer to it. + */ +struct kvm_cpuid_entry2 *get_cpuid(struct kvm_cpuid2 *cpuid, uint32_t func= tion, + uint32_t index); /* * set_cpuid() - overwrites a matching cpuid entry with the provided value. * matches based on ent->function && ent->index. returns true diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/tes= ting/selftests/kvm/lib/x86_64/processor.c index babb0f28575c..d61e2326dc85 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -886,6 +886,17 @@ kvm_get_supported_cpuid_index(uint32_t function, uint3= 2_t index) return entry; } =20 + +int __vcpu_set_cpuid(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_cpuid2 *cpuid) +{ + struct vcpu *vcpu =3D vcpu_find(vm, vcpuid); + + TEST_ASSERT(vcpu !=3D NULL, "vcpu not found, vcpuid: %u", vcpuid); + + return ioctl(vcpu->fd, KVM_SET_CPUID2, cpuid); +} + /* * VM VCPU CPUID Set * @@ -903,12 +914,9 @@ kvm_get_supported_cpuid_index(uint32_t function, uint3= 2_t index) void vcpu_set_cpuid(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_cpuid2 *cpuid) { - struct vcpu *vcpu =3D vcpu_find(vm, vcpuid); int rc; =20 - TEST_ASSERT(vcpu !=3D NULL, "vcpu not found, vcpuid: %u", vcpuid); - - rc =3D ioctl(vcpu->fd, KVM_SET_CPUID2, cpuid); + rc =3D __vcpu_set_cpuid(vm, vcpuid, cpuid); TEST_ASSERT(rc =3D=3D 0, "KVM_SET_CPUID2 failed, rc: %i errno: %i", rc, errno); =20 @@ -1384,6 +1392,23 @@ void assert_on_unhandled_exception(struct kvm_vm *vm= , uint32_t vcpuid) } } =20 +struct kvm_cpuid_entry2 *get_cpuid(struct kvm_cpuid2 *cpuid, uint32_t func= tion, + uint32_t index) +{ + int i; + + for (i =3D 0; i < cpuid->nent; i++) { + struct kvm_cpuid_entry2 *cur =3D &cpuid->entries[i]; + + if (cur->function =3D=3D function && cur->index =3D=3D index) + return cur; + } + + TEST_FAIL("CPUID function 0x%x index 0x%x not found ", function, index); + + return NULL; +} + bool set_cpuid(struct kvm_cpuid2 *cpuid, struct kvm_cpuid_entry2 *ent) { diff --git a/tools/testing/selftests/kvm/x86_64/cpuid_test.c b/tools/testin= g/selftests/kvm/x86_64/cpuid_test.c index a711f83749ea..16d2465c5634 100644 --- a/tools/testing/selftests/kvm/x86_64/cpuid_test.c +++ b/tools/testing/selftests/kvm/x86_64/cpuid_test.c @@ -154,6 +154,34 @@ struct kvm_cpuid2 *vcpu_alloc_cpuid(struct kvm_vm *vm,= vm_vaddr_t *p_gva, struct return guest_cpuids; } =20 +static void set_cpuid_after_run(struct kvm_vm *vm, struct kvm_cpuid2 *cpui= d) +{ + struct kvm_cpuid_entry2 *ent; + int rc; + u32 eax, ebx, x; + + /* Setting unmodified CPUID is allowed */ + rc =3D __vcpu_set_cpuid(vm, VCPU_ID, cpuid); + TEST_ASSERT(!rc, "Setting unmodified CPUID after KVM_RUN failed: %d", rc); + + /* Changing CPU features is forbidden */ + ent =3D get_cpuid(cpuid, 0x7, 0); + ebx =3D ent->ebx; + ent->ebx--; + rc =3D __vcpu_set_cpuid(vm, VCPU_ID, cpuid); + TEST_ASSERT(rc, "Changing CPU features should fail"); + ent->ebx =3D ebx; + + /* Changing MAXPHYADDR is forbidden */ + ent =3D get_cpuid(cpuid, 0x80000008, 0); + eax =3D ent->eax; + x =3D eax & 0xff; + ent->eax =3D (eax & ~0xffu) | (x - 1); + rc =3D __vcpu_set_cpuid(vm, VCPU_ID, cpuid); + TEST_ASSERT(rc, "Changing MAXPHYADDR should fail"); + ent->eax =3D eax; +} + int main(void) { struct kvm_cpuid2 *supp_cpuid, *cpuid2; @@ -175,5 +203,7 @@ int main(void) for (stage =3D 0; stage < 3; stage++) run_vcpu(vm, VCPU_ID, stage); =20 + set_cpuid_after_run(vm, cpuid2); + kvm_vm_free(vm); } --=20 2.34.1