From nobody Tue Feb 10 16:44:25 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail header.i=@intel.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=intel.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1647526376921869.2171214195835; Thu, 17 Mar 2022 07:12:56 -0700 (PDT) Received: from localhost ([::1]:37184 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nUqs3-00069S-Rk for importer@patchew.org; Thu, 17 Mar 2022 10:12:55 -0400 Received: from eggs.gnu.org ([209.51.188.92]:56858) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nUqfg-0000Ah-QC for qemu-devel@nongnu.org; Thu, 17 Mar 2022 10:00:08 -0400 Received: from mga12.intel.com ([192.55.52.136]:24917) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nUqfe-0004Bw-8A for qemu-devel@nongnu.org; Thu, 17 Mar 2022 10:00:08 -0400 Received: from orsmga007.jf.intel.com ([10.7.209.58]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Mar 2022 07:00:03 -0700 Received: from lxy-dell.sh.intel.com ([10.239.159.55]) by orsmga007.jf.intel.com with ESMTP; 17 Mar 2022 06:59:58 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1647525606; x=1679061606; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=AYOAw9w3AvRO/Oo5ijkmZDkDQHU5tFoA/V/doyQ6WHA=; b=FRHVXcyl4DNDhoushopywkbw2TLAQCP0J173LgI33crU5yIiUMqi+eR1 neXcRnENTpA2BeQlEAuwXeGj4juWEsPe8cnIAPeaWxO2T6Mg2fwXrONyZ hu1lRu4QWDCFyCyxs+7mQuVnYorcb1x2bArocusUDrzVwyYNk2C+UqMmc Stc4EGpWRnnxASdylyrxOjvuom+ZBgrPkDdW33YJqCuGGA/a7DipP/sbV YBk/4y8ZZJ71OdshZQ5QfYBJYfc3ivg8+OAoYhpFHpg/nCGChrf8ekc0V fXCycw8+hICyVu9lE4+iLT4Gc9lzVYjg1kZJJoCaCApRks0I3F9ocS2hU g==; X-IronPort-AV: E=McAfee;i="6200,9189,10288"; a="236816747" X-IronPort-AV: E=Sophos;i="5.90,188,1643702400"; d="scan'208";a="236816747" X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.90,188,1643702400"; d="scan'208";a="541378008" From: Xiaoyao Li To: Paolo Bonzini , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Richard Henderson , "Michael S. Tsirkin" , Marcel Apfelbaum , Cornelia Huck , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Marcelo Tosatti , Laszlo Ersek , Gerd Hoffmann , Eric Blake Subject: [RFC PATCH v3 10/36] i386/kvm: Move architectural CPUID leaf generation to separate helper Date: Thu, 17 Mar 2022 21:58:47 +0800 Message-Id: <20220317135913.2166202-11-xiaoyao.li@intel.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20220317135913.2166202-1-xiaoyao.li@intel.com> References: <20220317135913.2166202-1-xiaoyao.li@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=192.55.52.136; envelope-from=xiaoyao.li@intel.com; helo=mga12.intel.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.082, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, HK_RANDOM_ENVFROM=0.998, HK_RANDOM_FROM=0.998, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: isaku.yamahata@intel.com, kvm@vger.kernel.org, Connor Kuehl , seanjc@google.com, xiaoyao.li@intel.com, qemu-devel@nongnu.org, erdemaktas@google.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1647526379365100001 Content-Type: text/plain; charset="utf-8" From: Sean Christopherson Move the architectural (for lack of a better term) CPUID leaf generation to a separate helper so that the generation code can be reused by TDX, which needs to generate a canonical VM-scoped configuration. Signed-off-by: Sean Christopherson Signed-off-by: Xiaoyao Li --- target/i386/kvm/kvm.c | 222 +++++++++++++++++++------------------ target/i386/kvm/kvm_i386.h | 4 + 2 files changed, 119 insertions(+), 107 deletions(-) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 7bd5589e1e6c..02849f6ef142 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -1621,8 +1621,6 @@ static int hyperv_init_vcpu(X86CPU *cpu) =20 static Error *invtsc_mig_blocker; =20 -#define KVM_MAX_CPUID_ENTRIES 100 - static void kvm_init_xsave(CPUX86State *env) { if (has_xsave2) { @@ -1643,115 +1641,21 @@ static void kvm_init_xsave(CPUX86State *env) env->xsave_buf_len); } =20 -int kvm_arch_init_vcpu(CPUState *cs) +uint32_t kvm_x86_arch_cpuid(CPUX86State *env, struct kvm_cpuid_entry2 *ent= ries, + uint32_t cpuid_i) { - struct { - struct kvm_cpuid2 cpuid; - struct kvm_cpuid_entry2 entries[KVM_MAX_CPUID_ENTRIES]; - } cpuid_data; - /* - * The kernel defines these structs with padding fields so there - * should be no extra padding in our cpuid_data struct. - */ - QEMU_BUILD_BUG_ON(sizeof(cpuid_data) !=3D - sizeof(struct kvm_cpuid2) + - sizeof(struct kvm_cpuid_entry2) * KVM_MAX_CPUID_ENTR= IES); - - X86CPU *cpu =3D X86_CPU(cs); - CPUX86State *env =3D &cpu->env; - uint32_t limit, i, j, cpuid_i; + uint32_t limit, i, j; uint32_t unused; struct kvm_cpuid_entry2 *c; - uint32_t signature[3]; - int kvm_base =3D KVM_CPUID_SIGNATURE; - int max_nested_state_len; - int r; - Error *local_err =3D NULL; - - memset(&cpuid_data, 0, sizeof(cpuid_data)); - - cpuid_i =3D 0; - - has_xsave2 =3D kvm_check_extension(cs->kvm_state, KVM_CAP_XSAVE2); - - r =3D kvm_arch_set_tsc_khz(cs); - if (r < 0) { - return r; - } - - /* vcpu's TSC frequency is either specified by user, or following - * the value used by KVM if the former is not present. In the - * latter case, we query it from KVM and record in env->tsc_khz, - * so that vcpu's TSC frequency can be migrated later via this field. - */ - if (!env->tsc_khz) { - r =3D kvm_check_extension(cs->kvm_state, KVM_CAP_GET_TSC_KHZ) ? - kvm_vcpu_ioctl(cs, KVM_GET_TSC_KHZ) : - -ENOTSUP; - if (r > 0) { - env->tsc_khz =3D r; - } - } - - env->apic_bus_freq =3D KVM_APIC_BUS_FREQUENCY; - - /* - * kvm_hyperv_expand_features() is called here for the second time in = case - * KVM_CAP_SYS_HYPERV_CPUID is not supported. While we can't possibly = handle - * 'query-cpu-model-expansion' in this case as we don't have a KVM vCP= U to - * check which Hyper-V enlightenments are supported and which are not,= we - * can still proceed and check/expand Hyper-V enlightenments here so l= egacy - * behavior is preserved. - */ - if (!kvm_hyperv_expand_features(cpu, &local_err)) { - error_report_err(local_err); - return -ENOSYS; - } - - if (hyperv_enabled(cpu)) { - r =3D hyperv_init_vcpu(cpu); - if (r) { - return r; - } - - cpuid_i =3D hyperv_fill_cpuids(cs, cpuid_data.entries); - kvm_base =3D KVM_CPUID_SIGNATURE_NEXT; - has_msr_hv_hypercall =3D true; - } - - if (cpu->expose_kvm) { - memcpy(signature, "KVMKVMKVM\0\0\0", 12); - c =3D &cpuid_data.entries[cpuid_i++]; - c->function =3D KVM_CPUID_SIGNATURE | kvm_base; - c->eax =3D KVM_CPUID_FEATURES | kvm_base; - c->ebx =3D signature[0]; - c->ecx =3D signature[1]; - c->edx =3D signature[2]; - - c =3D &cpuid_data.entries[cpuid_i++]; - c->function =3D KVM_CPUID_FEATURES | kvm_base; - c->eax =3D env->features[FEAT_KVM]; - c->edx =3D env->features[FEAT_KVM_HINTS]; - } =20 cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused); =20 - if (cpu->kvm_pv_enforce_cpuid) { - r =3D kvm_vcpu_enable_cap(cs, KVM_CAP_ENFORCE_PV_FEATURE_CPUID, 0,= 1); - if (r < 0) { - fprintf(stderr, - "failed to enable KVM_CAP_ENFORCE_PV_FEATURE_CPUID: %s= ", - strerror(-r)); - abort(); - } - } - for (i =3D 0; i <=3D limit; i++) { if (cpuid_i =3D=3D KVM_MAX_CPUID_ENTRIES) { fprintf(stderr, "unsupported level value: 0x%x\n", limit); abort(); } - c =3D &cpuid_data.entries[cpuid_i++]; + c =3D &entries[cpuid_i++]; =20 switch (i) { case 2: { @@ -1770,7 +1674,7 @@ int kvm_arch_init_vcpu(CPUState *cs) "cpuid(eax:2):eax & 0xf =3D 0x%x\n", times); abort(); } - c =3D &cpuid_data.entries[cpuid_i++]; + c =3D &entries[cpuid_i++]; c->function =3D i; c->flags =3D KVM_CPUID_FLAG_STATEFUL_FUNC; cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->ed= x); @@ -1816,7 +1720,7 @@ int kvm_arch_init_vcpu(CPUState *cs) "cpuid(eax:0x%x,ecx:0x%x)\n", i, j); abort(); } - c =3D &cpuid_data.entries[cpuid_i++]; + c =3D &entries[cpuid_i++]; } break; case 0x7: @@ -1836,7 +1740,7 @@ int kvm_arch_init_vcpu(CPUState *cs) "cpuid(eax:0x12,ecx:0x%x)\n", j); abort(); } - c =3D &cpuid_data.entries[cpuid_i++]; + c =3D &entries[cpuid_i++]; } break; case 0x14: @@ -1856,7 +1760,7 @@ int kvm_arch_init_vcpu(CPUState *cs) "cpuid(eax:0x%x,ecx:0x%x)\n", i, j); abort(); } - c =3D &cpuid_data.entries[cpuid_i++]; + c =3D &entries[cpuid_i++]; c->function =3D i; c->index =3D j; c->flags =3D KVM_CPUID_FLAG_SIGNIFCANT_INDEX; @@ -1913,7 +1817,7 @@ int kvm_arch_init_vcpu(CPUState *cs) fprintf(stderr, "unsupported xlevel value: 0x%x\n", limit); abort(); } - c =3D &cpuid_data.entries[cpuid_i++]; + c =3D &entries[cpuid_i++]; =20 switch (i) { case 0x8000001d: @@ -1932,7 +1836,7 @@ int kvm_arch_init_vcpu(CPUState *cs) "cpuid(eax:0x%x,ecx:0x%x)\n", i, j); abort(); } - c =3D &cpuid_data.entries[cpuid_i++]; + c =3D &entries[cpuid_i++]; } break; default: @@ -1959,7 +1863,7 @@ int kvm_arch_init_vcpu(CPUState *cs) fprintf(stderr, "unsupported xlevel2 value: 0x%x\n", limit= ); abort(); } - c =3D &cpuid_data.entries[cpuid_i++]; + c =3D &entries[cpuid_i++]; =20 c->function =3D i; c->flags =3D 0; @@ -1967,6 +1871,110 @@ int kvm_arch_init_vcpu(CPUState *cs) } } =20 + return cpuid_i; +} + +int kvm_arch_init_vcpu(CPUState *cs) +{ + struct { + struct kvm_cpuid2 cpuid; + struct kvm_cpuid_entry2 entries[KVM_MAX_CPUID_ENTRIES]; + } cpuid_data; + /* + * The kernel defines these structs with padding fields so there + * should be no extra padding in our cpuid_data struct. + */ + QEMU_BUILD_BUG_ON(sizeof(cpuid_data) !=3D + sizeof(struct kvm_cpuid2) + + sizeof(struct kvm_cpuid_entry2) * KVM_MAX_CPUID_ENTR= IES); + + X86CPU *cpu =3D X86_CPU(cs); + CPUX86State *env =3D &cpu->env; + uint32_t cpuid_i; + struct kvm_cpuid_entry2 *c; + uint32_t signature[3]; + int kvm_base =3D KVM_CPUID_SIGNATURE; + int max_nested_state_len; + int r; + Error *local_err =3D NULL; + + memset(&cpuid_data, 0, sizeof(cpuid_data)); + + cpuid_i =3D 0; + + has_xsave2 =3D kvm_check_extension(cs->kvm_state, KVM_CAP_XSAVE2); + + r =3D kvm_arch_set_tsc_khz(cs); + if (r < 0) { + return r; + } + + /* vcpu's TSC frequency is either specified by user, or following + * the value used by KVM if the former is not present. In the + * latter case, we query it from KVM and record in env->tsc_khz, + * so that vcpu's TSC frequency can be migrated later via this field. + */ + if (!env->tsc_khz) { + r =3D kvm_check_extension(cs->kvm_state, KVM_CAP_GET_TSC_KHZ) ? + kvm_vcpu_ioctl(cs, KVM_GET_TSC_KHZ) : + -ENOTSUP; + if (r > 0) { + env->tsc_khz =3D r; + } + } + + env->apic_bus_freq =3D KVM_APIC_BUS_FREQUENCY; + + /* + * kvm_hyperv_expand_features() is called here for the second time in = case + * KVM_CAP_SYS_HYPERV_CPUID is not supported. While we can't possibly = handle + * 'query-cpu-model-expansion' in this case as we don't have a KVM vCP= U to + * check which Hyper-V enlightenments are supported and which are not,= we + * can still proceed and check/expand Hyper-V enlightenments here so l= egacy + * behavior is preserved. + */ + if (!kvm_hyperv_expand_features(cpu, &local_err)) { + error_report_err(local_err); + return -ENOSYS; + } + + if (hyperv_enabled(cpu)) { + r =3D hyperv_init_vcpu(cpu); + if (r) { + return r; + } + + cpuid_i =3D hyperv_fill_cpuids(cs, cpuid_data.entries); + kvm_base =3D KVM_CPUID_SIGNATURE_NEXT; + has_msr_hv_hypercall =3D true; + } + + if (cpu->expose_kvm) { + memcpy(signature, "KVMKVMKVM\0\0\0", 12); + c =3D &cpuid_data.entries[cpuid_i++]; + c->function =3D KVM_CPUID_SIGNATURE | kvm_base; + c->eax =3D KVM_CPUID_FEATURES | kvm_base; + c->ebx =3D signature[0]; + c->ecx =3D signature[1]; + c->edx =3D signature[2]; + + c =3D &cpuid_data.entries[cpuid_i++]; + c->function =3D KVM_CPUID_FEATURES | kvm_base; + c->eax =3D env->features[FEAT_KVM]; + c->edx =3D env->features[FEAT_KVM_HINTS]; + } + + if (cpu->kvm_pv_enforce_cpuid) { + r =3D kvm_vcpu_enable_cap(cs, KVM_CAP_ENFORCE_PV_FEATURE_CPUID, 0,= 1); + if (r < 0) { + fprintf(stderr, + "failed to enable KVM_CAP_ENFORCE_PV_FEATURE_CPUID: %s= ", + strerror(-r)); + abort(); + } + } + + cpuid_i =3D kvm_x86_arch_cpuid(env, cpuid_data.entries, cpuid_i); cpuid_data.cpuid.nent =3D cpuid_i; =20 if (((env->cpuid_version >> 8)&0xF) >=3D 6 diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h index b434feaa6b1d..5c7972f617e8 100644 --- a/target/i386/kvm/kvm_i386.h +++ b/target/i386/kvm/kvm_i386.h @@ -24,6 +24,10 @@ #define kvm_ioapic_in_kernel() \ (kvm_irqchip_in_kernel() && !kvm_irqchip_is_split()) =20 +#define KVM_MAX_CPUID_ENTRIES 100 +uint32_t kvm_x86_arch_cpuid(CPUX86State *env, struct kvm_cpuid_entry2 *ent= ries, + uint32_t cpuid_i); + #else =20 #define kvm_pit_in_kernel() 0 --=20 2.27.0