From patchwork Tue Feb 16 02:13:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Isaku Yamahata X-Patchwork-Id: 12089411 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9B02BC433DB for ; Tue, 16 Feb 2021 02:15:55 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 753A664DE8 for ; Tue, 16 Feb 2021 02:15:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229694AbhBPCPt (ORCPT ); Mon, 15 Feb 2021 21:15:49 -0500 Received: from mga06.intel.com ([134.134.136.31]:39370 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229806AbhBPCPf (ORCPT ); Mon, 15 Feb 2021 21:15:35 -0500 IronPort-SDR: XKluSLYEhQLwTj6hzt/ly3w2bBdHqjQAZABw7somKIECTftr0LmnZG6TWcFcF58uEv5YF8UZLZ kiZCSYbSn40g== X-IronPort-AV: E=McAfee;i="6000,8403,9896"; a="244270197" X-IronPort-AV: E=Sophos;i="5.81,182,1610438400"; d="scan'208";a="244270197" Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Feb 2021 18:14:50 -0800 IronPort-SDR: FiEC2/fGZjoAYFutqHwRCGeWNKn4qgtjipuWv5MvsbHi1R6hk9SWSZqZdHev5sZiSIlGj4m6Mh d7RHnAyXGmtQ== X-IronPort-AV: E=Sophos;i="5.81,182,1610438400"; d="scan'208";a="591705392" Received: from ls.sc.intel.com (HELO localhost) ([143.183.96.54]) by fmsmga005-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Feb 2021 18:14:50 -0800 From: Isaku Yamahata To: qemu-devel@nongnu.org, pbonzini@redhat.com, alistair@alistair23.me, ehabkost@redhat.com, marcel.apfelbaum@gmail.com, mst@redhat.com, cohuck@redhat.com, mtosatti@redhat.com, xiaoyao.li@intel.com, seanjc@google.com Cc: kvm@vger.kernel.org, isaku.yamahata@gmail.com, isaku.yamahata@intel.com, Sean Christopherson Subject: [RFC PATCH 04/23] i386/kvm: Move architectural CPUID leaf generation to separarte helper Date: Mon, 15 Feb 2021 18:13:00 -0800 Message-Id: <66dbf12944f81c25e3a0d3d7afac159858cb78bd.1613188118.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: References: In-Reply-To: References: Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org 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 --- target/i386/kvm/kvm.c | 170 +++++++++++++++++++------------------ target/i386/kvm/kvm_i386.h | 4 + 2 files changed, 93 insertions(+), 81 deletions(-) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 8a04cf1337..bb241d8aa1 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -1461,82 +1461,11 @@ static int hyperv_init_vcpu(X86CPU *cpu) static Error *invtsc_mig_blocker; -#define KVM_MAX_CPUID_ENTRIES 100 - -int kvm_arch_init_vcpu(CPUState *cs) +uint32_t kvm_x86_arch_cpuid(CPUX86State *env, struct kvm_cpuid_entry2 *entries, + 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) != - sizeof(struct kvm_cpuid2) + - sizeof(struct kvm_cpuid_entry2) * KVM_MAX_CPUID_ENTRIES); - - X86CPU *cpu = X86_CPU(cs); - CPUX86State *env = &cpu->env; - uint32_t limit, i, j, cpuid_i; - uint32_t unused; + uint32_t limit, i, j, unused; struct kvm_cpuid_entry2 *c; - uint32_t signature[3]; - int kvm_base = KVM_CPUID_SIGNATURE; - int max_nested_state_len; - int r; - Error *local_err = NULL; - - memset(&cpuid_data, 0, sizeof(cpuid_data)); - - cpuid_i = 0; - - r = 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 = 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 = r; - } - } - - env->apic_bus_freq = KVM_APIC_BUS_FREQUENCY; - - /* Paravirtualization CPUIDs */ - r = hyperv_handle_properties(cs, cpuid_data.entries); - if (r < 0) { - return r; - } else if (r > 0) { - cpuid_i = r; - kvm_base = KVM_CPUID_SIGNATURE_NEXT; - has_msr_hv_hypercall = true; - } - - if (cpu->expose_kvm) { - memcpy(signature, "KVMKVMKVM\0\0\0", 12); - c = &cpuid_data.entries[cpuid_i++]; - c->function = KVM_CPUID_SIGNATURE | kvm_base; - c->eax = KVM_CPUID_FEATURES | kvm_base; - c->ebx = signature[0]; - c->ecx = signature[1]; - c->edx = signature[2]; - - c = &cpuid_data.entries[cpuid_i++]; - c->function = KVM_CPUID_FEATURES | kvm_base; - c->eax = env->features[FEAT_KVM]; - c->edx = env->features[FEAT_KVM_HINTS]; - } cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused); @@ -1545,7 +1474,7 @@ int kvm_arch_init_vcpu(CPUState *cs) fprintf(stderr, "unsupported level value: 0x%x\n", limit); abort(); } - c = &cpuid_data.entries[cpuid_i++]; + c = &entries[cpuid_i++]; switch (i) { case 2: { @@ -1564,7 +1493,7 @@ int kvm_arch_init_vcpu(CPUState *cs) "cpuid(eax:2):eax & 0xf = 0x%x\n", times); abort(); } - c = &cpuid_data.entries[cpuid_i++]; + c = &entries[cpuid_i++]; c->function = i; c->flags = KVM_CPUID_FLAG_STATEFUL_FUNC; cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx); @@ -1610,7 +1539,7 @@ int kvm_arch_init_vcpu(CPUState *cs) "cpuid(eax:0x%x,ecx:0x%x)\n", i, j); abort(); } - c = &cpuid_data.entries[cpuid_i++]; + c = &entries[cpuid_i++]; } break; case 0x7: @@ -1629,7 +1558,7 @@ int kvm_arch_init_vcpu(CPUState *cs) "cpuid(eax:0x%x,ecx:0x%x)\n", i, j); abort(); } - c = &cpuid_data.entries[cpuid_i++]; + c = &entries[cpuid_i++]; c->function = i; c->index = j; c->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX; @@ -1686,7 +1615,7 @@ int kvm_arch_init_vcpu(CPUState *cs) fprintf(stderr, "unsupported xlevel value: 0x%x\n", limit); abort(); } - c = &cpuid_data.entries[cpuid_i++]; + c = &entries[cpuid_i++]; switch (i) { case 0x8000001d: @@ -1705,7 +1634,7 @@ int kvm_arch_init_vcpu(CPUState *cs) "cpuid(eax:0x%x,ecx:0x%x)\n", i, j); abort(); } - c = &cpuid_data.entries[cpuid_i++]; + c = &entries[cpuid_i++]; } break; default: @@ -1732,7 +1661,7 @@ int kvm_arch_init_vcpu(CPUState *cs) fprintf(stderr, "unsupported xlevel2 value: 0x%x\n", limit); abort(); } - c = &cpuid_data.entries[cpuid_i++]; + c = &entries[cpuid_i++]; c->function = i; c->flags = 0; @@ -1740,6 +1669,85 @@ int kvm_arch_init_vcpu(CPUState *cs) } } + 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) != + sizeof(struct kvm_cpuid2) + + sizeof(struct kvm_cpuid_entry2) * KVM_MAX_CPUID_ENTRIES); + + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + uint32_t cpuid_i; + struct kvm_cpuid_entry2 *c; + uint32_t signature[3]; + int kvm_base = KVM_CPUID_SIGNATURE; + int max_nested_state_len; + int r; + Error *local_err = NULL; + + memset(&cpuid_data, 0, sizeof(cpuid_data)); + + cpuid_i = 0; + + r = 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 = 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 = r; + } + } + + env->apic_bus_freq = KVM_APIC_BUS_FREQUENCY; + + /* Paravirtualization CPUIDs */ + r = hyperv_handle_properties(cs, cpuid_data.entries); + if (r < 0) { + return r; + } else if (r > 0) { + cpuid_i = r; + kvm_base = KVM_CPUID_SIGNATURE_NEXT; + has_msr_hv_hypercall = true; + } + + if (cpu->expose_kvm) { + memcpy(signature, "KVMKVMKVM\0\0\0", 12); + c = &cpuid_data.entries[cpuid_i++]; + c->function = KVM_CPUID_SIGNATURE | kvm_base; + c->eax = KVM_CPUID_FEATURES | kvm_base; + c->ebx = signature[0]; + c->ecx = signature[1]; + c->edx = signature[2]; + + c = &cpuid_data.entries[cpuid_i++]; + c->function = KVM_CPUID_FEATURES | kvm_base; + c->eax = env->features[FEAT_KVM]; + c->edx = env->features[FEAT_KVM_HINTS]; + } + + cpuid_i = kvm_x86_arch_cpuid(env, cpuid_data.entries, cpuid_i); cpuid_data.cpuid.nent = cpuid_i; if (((env->cpuid_version >> 8)&0xF) >= 6 diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h index dc72508389..c9a92578b1 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()) +#define KVM_MAX_CPUID_ENTRIES 100 +uint32_t kvm_x86_arch_cpuid(CPUX86State *env, struct kvm_cpuid_entry2 *entries, + uint32_t cpuid_i); + #else #define kvm_pit_in_kernel() 0