From nobody Tue Jun 30 13:03:36 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 96297C433FE for ; Mon, 17 Jan 2022 15:05:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240358AbiAQPF4 (ORCPT ); Mon, 17 Jan 2022 10:05:56 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]:42857 "EHLO us-smtp-delivery-124.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240342AbiAQPFz (ORCPT ); Mon, 17 Jan 2022 10:05:55 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1642431954; 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=EtCPFf36oFYoPxxwsxl3YMgvt1BmYctu8ZZbjSQQ19JUleE127ZlPc3icQbTMU6ER2hpIg 3d5gwpEW024SxxOXDQqysOYqtYQJyr4Rsavqgkc6tJCf3JT2wLmjAtjm5D39WmAwCa+x2v ONQyDlGanB77r7yuhg3NpbO7t+4ObIc= 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-593-w-OqnEp0OlS9L7wMt3HcaQ-1; Mon, 17 Jan 2022 10:05:53 -0500 X-MC-Unique: w-OqnEp0OlS9L7wMt3HcaQ-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id D0DFA1054F90; Mon, 17 Jan 2022 15:05:51 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.40.195.65]) by smtp.corp.redhat.com (Postfix) with ESMTP id A6A512B59F; Mon, 17 Jan 2022 15:05:49 +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 v2 1/4] KVM: x86: Do runtime CPUID update before updating vcpu->arch.cpuid_entries Date: Mon, 17 Jan 2022 16:05:39 +0100 Message-Id: <20220117150542.2176196-2-vkuznets@redhat.com> In-Reply-To: <20220117150542.2176196-1-vkuznets@redhat.com> References: <20220117150542.2176196-1-vkuznets@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 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 13:03:36 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 163BEC433EF for ; Mon, 17 Jan 2022 15:06:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240360AbiAQPGB (ORCPT ); Mon, 17 Jan 2022 10:06:01 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]:31243 "EHLO us-smtp-delivery-124.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240363AbiAQPF7 (ORCPT ); Mon, 17 Jan 2022 10:05:59 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1642431958; 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=XRC1So2PUXU9EUqrVYvvdmXgibZOxvXodE8fKDcbqgQ=; b=MhTc8wrr2f/NrWObAbiAGo8hCTooapoaqJ2jKlgwWpQYNckWuLikeo0gYgl/Tn7xQuf8Lx WWgL4bZm50hTsaJtvdL5jizmlWMYQKMAXBwiIVHjMOboybJ09808bPy+VrMGrm9nU5gdFm p9I4AZ9DkeoGjljfKc5bTcTgVZD9z6k= 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-518-LjKgfq4FOy2f_RT_Tq0etg-1; Mon, 17 Jan 2022 10:05:55 -0500 X-MC-Unique: LjKgfq4FOy2f_RT_Tq0etg-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 684BB1054F92; Mon, 17 Jan 2022 15:05:54 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.40.195.65]) by smtp.corp.redhat.com (Postfix) with ESMTP id 545812B59F; Mon, 17 Jan 2022 15:05:52 +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 v2 2/4] KVM: x86: Partially allow KVM_SET_CPUID{,2} after KVM_RUN Date: Mon, 17 Jan 2022 16:05:40 +0100 Message-Id: <20220117150542.2176196-3-vkuznets@redhat.com> In-Reply-To: <20220117150542.2176196-1-vkuznets@redhat.com> References: <20220117150542.2176196-1-vkuznets@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 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 | 33 +++++++++++++++++++++++++++++++++ arch/x86/kvm/x86.c | 19 ------------------- 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 812190a707f6..c2e9c860fc3f 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -119,6 +119,25 @@ 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) +{ + struct kvm_cpuid_entry2 *best; + int i; + + for (i =3D 0; i < nent; i++) { + best =3D kvm_find_cpuid_entry(vcpu, e2[i].function, e2[i].index); + if (!best) + return -EINVAL; + + if (e2[i].eax !=3D best->eax || e2[i].ebx !=3D best->ebx || + e2[i].ecx !=3D best->ecx || e2[i].edx !=3D best->edx) + return -EINVAL; + } + + return 0; +} static void kvm_update_kvm_cpuid_base(struct kvm_vcpu *vcpu) { u32 function; @@ -313,6 +332,20 @@ 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. It would've been better to forbid any + * KVM_SET_CPUID{,2} calls after KVM_RUN altogether but unfortunately + * some VMMs (e.g. QEMU) reuse vCPU fds for CPU hotplug/unplug and do + * KVM_SET_CPUID{,2} again. To support this legacy behavior, check + * whether the supplied CPUID data is equal to what's already set. + */ + 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 13:03:36 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 BFDC1C433EF for ; Mon, 17 Jan 2022 15:06:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240408AbiAQPGJ (ORCPT ); Mon, 17 Jan 2022 10:06:09 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]:24711 "EHLO us-smtp-delivery-124.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240393AbiAQPGC (ORCPT ); Mon, 17 Jan 2022 10:06:02 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1642431961; 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=TMmb+IQZ7JCs89tEbyPu3vTr85BvcTWDpDr8EgudoSzVMFpIQsd+Rq0+xQlEHe5S7p5jOv 24Bi9k9LBlpwFmv1U0s/IN6tTvxQxxx7dz3ftlhKJWkJP2gWutUE6lZjdHJunpYonMCCCa LW+p/Okn57mY4QWb8qpOQFqyQVV3oCw= 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-35-Fao2JeeiM52E4Ke-KQV5zA-1; Mon, 17 Jan 2022 10:05:58 -0500 X-MC-Unique: Fao2JeeiM52E4Ke-KQV5zA-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 141303E746; Mon, 17 Jan 2022 15:05:57 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.40.195.65]) by smtp.corp.redhat.com (Postfix) with ESMTP id C3F2D2B59F; Mon, 17 Jan 2022 15:05:54 +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 v2 3/4] KVM: selftests: Rename 'get_cpuid_test' to 'cpuid_test' Date: Mon, 17 Jan 2022 16:05:41 +0100 Message-Id: <20220117150542.2176196-4-vkuznets@redhat.com> In-Reply-To: <20220117150542.2176196-1-vkuznets@redhat.com> References: <20220117150542.2176196-1-vkuznets@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 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 13:03:36 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 5844DC433FE for ; Mon, 17 Jan 2022 15:06:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240452AbiAQPGM (ORCPT ); Mon, 17 Jan 2022 10:06:12 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]:38281 "EHLO us-smtp-delivery-124.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240409AbiAQPGE (ORCPT ); Mon, 17 Jan 2022 10:06:04 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1642431964; 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=QGtnUBJFkKpIt3/4YZ90fzwsg7++mcHSWCGWvtWiTxZEVfEUZ3bR7t8NGrGRs7ZpMrKZHn Jhg6lyqwdkbKOqyiP+8uRA1dJFiHF526WMw+kMDrr+e6FJl32ZxVqOpp+CwvPi5+GKmMhb srI262JwKrBS4trpbw8+UErAEkSaImw= 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-32-O1HyghfuMAqfNzHzVDjykw-1; Mon, 17 Jan 2022 10:06:01 -0500 X-MC-Unique: O1HyghfuMAqfNzHzVDjykw-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id D65241083F64; Mon, 17 Jan 2022 15:05:59 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.40.195.65]) by smtp.corp.redhat.com (Postfix) with ESMTP id C7D6A2B59F; Mon, 17 Jan 2022 15:05:57 +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 v2 4/4] KVM: selftests: Test KVM_SET_CPUID2 after KVM_RUN Date: Mon, 17 Jan 2022 16:05:42 +0100 Message-Id: <20220117150542.2176196-5-vkuznets@redhat.com> In-Reply-To: <20220117150542.2176196-1-vkuznets@redhat.com> References: <20220117150542.2176196-1-vkuznets@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 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