From nobody Tue Feb 10 03:36:53 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass 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=pass(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1652325877; cv=none; d=zohomail.com; s=zohoarc; b=dOVkiC7+eVZNqN0W05RpdbjztL5KAVvU4vKEvcmsQM07GmG71AJCU9+RSn+QtcJtSvEj1FS7cZroeqWnoxFjp4XHhHCds610UXvI/6aiGQgCjOnFmWv8hrDz5P15rZLgOnqNInyYSqjOP6R1VVHPF9tJ/XnQ2aRhzE1PR8qX5lw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1652325877; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=srIHm2BCG4h/za8DIjDEwpWQ5vhGfUn8X5VCqVarslg=; b=f9uVw23u8GxS5XKh6trf/Gt4XyOmN5mi4rkC2nMry2Rr52DLgGMJYbxdiJp3IvkmRP1GqK81Zwjg0FGBxnWRfsCSt71T/OeW1iQPqgS+66aOZQI2LR6NE54+W8MGZX87fOZ8+3KD6m/Qzq0uodETcRXOlywwk5l7aibJR+svu8I= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass 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=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 165232587714752.624078930569; Wed, 11 May 2022 20:24:37 -0700 (PDT) Received: from localhost ([::1]:57532 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nozRM-0002ab-3Z for importer@patchew.org; Wed, 11 May 2022 23:24:36 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:39006) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nozLz-0002Fg-2R for qemu-devel@nongnu.org; Wed, 11 May 2022 23:19:03 -0400 Received: from mga06b.intel.com ([134.134.136.31]:1459 helo=mga06.intel.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nozLw-0002rZ-P9 for qemu-devel@nongnu.org; Wed, 11 May 2022 23:19:02 -0400 Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 11 May 2022 20:18:57 -0700 Received: from lxy-dell.sh.intel.com ([10.239.159.55]) by orsmga008.jf.intel.com with ESMTP; 11 May 2022 20:18:52 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1652325540; x=1683861540; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=xXOpZyf6vx7tJv/hV11QMvvy3TYUd0GngrfsQ4GYerg=; b=CCc5sEswHNMdnd+XTC4wW+xmBu0leTpArlOpP1p/V9ul4FidAla7fnNK joW99KiGcNF7oN81hCohB9Smha1iMBIQk/mX5b2D5Z01zZS1RW2GlJN/C jjAYTPyo7xv3fzBfSq/ArBWe0Q9+cdiTta+z6/fFV/d9XC1mHdYogYmpC qzcyF2XbeAzkz2SA7o3TfzGuNSu2oY5UiPYCVJPOSFDFxwOWpoTWdxJtd 3HpRHTC4QBxU7FcfkcZ3BwAlpbUD8EM7gAD4O0fr8IYXDDuaA3vrvpG8s jYEL5/hYShAv0GWiA+37zc8fXy41a3+0QWBaQ463DTZtwd60ptYN4CRDY w==; X-IronPort-AV: E=McAfee;i="6400,9594,10344"; a="330479019" X-IronPort-AV: E=Sophos;i="5.91,218,1647327600"; d="scan'208";a="330479019" X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.91,218,1647327600"; d="scan'208";a="594455614" From: Xiaoyao Li To: Paolo Bonzini , Isaku Yamahata , isaku.yamahata@intel.com, Gerd Hoffmann , =?UTF-8?q?Daniel=20P=20=2E=20Berrang=C3=A9?= , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Richard Henderson , "Michael S . Tsirkin" , Marcel Apfelbaum , Cornelia Huck , Marcelo Tosatti , Laszlo Ersek , Eric Blake Cc: Connor Kuehl , erdemaktas@google.com, kvm@vger.kernel.org, qemu-devel@nongnu.org, seanjc@google.com, xiaoyao.li@intel.com Subject: [RFC PATCH v4 10/36] i386/kvm: Move architectural CPUID leaf generation to separate helper Date: Thu, 12 May 2022 11:17:37 +0800 Message-Id: <20220512031803.3315890-11-xiaoyao.li@intel.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20220512031803.3315890-1-xiaoyao.li@intel.com> References: <20220512031803.3315890-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=134.134.136.31; envelope-from=xiaoyao.li@intel.com; helo=mga06.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_NONE=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: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: pass (identity @intel.com) X-ZM-MESSAGEID: 1652325878886100001 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 0751e6e102cc..5be151e6499b 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -1686,8 +1686,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) { @@ -1708,115 +1706,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: { @@ -1835,7 +1739,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); @@ -1881,7 +1785,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: @@ -1901,7 +1805,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: @@ -1921,7 +1825,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; @@ -1978,7 +1882,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: @@ -1997,7 +1901,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: @@ -2024,7 +1928,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; @@ -2032,6 +1936,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