From nobody Mon Feb 9 17:36:08 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; 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=linux.microsoft.com ARC-Seal: i=1; a=rsa-sha256; t=1758041613; cv=none; d=zohomail.com; s=zohoarc; b=Rzc8Kda4ab8ZzxoRphKqe7LF5+TtoMJcfHzy5YiSkZ5bbxVTwibY0zvkxFZoWNlm9a0LXSLgLhEDpdkhIEZg2C0sP9/ZbiJ3ivv7PALXFRkG8L5TAr22dbNGJiCrQ11q95JpQ3qw5L6nB9znQGkb8DJuaIE2Q/UDiYdgmTCL6wc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1758041613; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=+Q/G6oBPcAz/NsYtv5GdYxMdgdVn+iCcKC3nXkDG4OU=; b=ZE1acRclas8IgObTpkaLW1xY13Tt2uUSyYQWgpJwS6qamHzraFHOgBg0zOJhV4X/B4zBgI8Z4Q6a/0okvmc2FCuPkoijLgYocBcEWxCRXv0d/ONEOTFE0a4qxqMr0xp02a3OKR91Du314Nz/CyQf/9XjVdJ+2BAJqBZvOXia+BI= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; 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 1758041613816635.054747726456; Tue, 16 Sep 2025 09:53:33 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uyYth-0002jl-8V; Tue, 16 Sep 2025 12:51:17 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uyYtP-0002IL-TN for qemu-devel@nongnu.org; Tue, 16 Sep 2025 12:51:01 -0400 Received: from linux.microsoft.com ([13.77.154.182]) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uyYtM-0006qi-GX for qemu-devel@nongnu.org; Tue, 16 Sep 2025 12:50:58 -0400 Received: from localhost.localdomain (unknown [167.220.208.43]) by linux.microsoft.com (Postfix) with ESMTPSA id B23EB201551D; Tue, 16 Sep 2025 09:50:49 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com B23EB201551D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1758041454; bh=+Q/G6oBPcAz/NsYtv5GdYxMdgdVn+iCcKC3nXkDG4OU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Jwt8U/kGNzddquEcO03qf8g/Eua3UXJl469eo+Rc5roO0T82KhsZLYbtcsvJmu5++ dEJ0kmk3jdU+SWh7gBsQGr1kCSiia62oVlnl+18tlXsJwLBQGropCakuslQri4mMYW LdplVI09heXpzXZBwSJDwfWiCID7QjALQJT1Sv00= From: Magnus Kulke To: qemu-devel@nongnu.org Cc: Markus Armbruster , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Cameron Esfahani , Paolo Bonzini , Thomas Huth , Richard Henderson , Wei Liu , Cornelia Huck , "Michael S. Tsirkin" , "Dr. David Alan Gilbert" , Roman Bolshakov , Phil Dennis-Jordan , Marcel Apfelbaum , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Zhao Liu , Eduardo Habkost , Magnus Kulke , Wei Liu , Eric Blake , Yanan Wang , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , =?UTF-8?q?Alex=20Benn=C3=A9e?= Subject: [PATCH v4 18/27] target/i386/mshv: Register CPUID entries with MSHV Date: Tue, 16 Sep 2025 18:48:38 +0200 Message-Id: <20250916164847.77883-19-magnuskulke@linux.microsoft.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250916164847.77883-1-magnuskulke@linux.microsoft.com> References: <20250916164847.77883-1-magnuskulke@linux.microsoft.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=13.77.154.182; envelope-from=magnuskulke@linux.microsoft.com; helo=linux.microsoft.com X-Spam_score_int: -19 X-Spam_score: -2.0 X-Spam_bar: -- X-Spam_report: (-2.0 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 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-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.microsoft.com) X-ZM-MESSAGEID: 1758041615250116600 Content-Type: text/plain; charset="utf-8" Convert the guest CPU's CPUID model into MSHV's format and register it with the hypervisor. This ensures that the guest observes the correct CPU feature set during CPUID instructions. Signed-off-by: Magnus Kulke --- target/i386/mshv/mshv-cpu.c | 206 ++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c index daa41b92c9..54ab36e76a 100644 --- a/target/i386/mshv/mshv-cpu.c +++ b/target/i386/mshv/mshv-cpu.c @@ -402,6 +402,206 @@ int mshv_load_regs(CPUState *cpu) return 0; } =20 +static void add_cpuid_entry(GList *cpuid_entries, + uint32_t function, uint32_t index, + uint32_t eax, uint32_t ebx, + uint32_t ecx, uint32_t edx) +{ + struct hv_cpuid_entry *entry; + + entry =3D g_malloc0(sizeof(struct hv_cpuid_entry)); + entry->function =3D function; + entry->index =3D index; + entry->eax =3D eax; + entry->ebx =3D ebx; + entry->ecx =3D ecx; + entry->edx =3D edx; + + cpuid_entries =3D g_list_append(cpuid_entries, entry); +} + +static void collect_cpuid_entries(const CPUState *cpu, GList *cpuid_entrie= s) +{ + X86CPU *x86_cpu =3D X86_CPU(cpu); + CPUX86State *env =3D &x86_cpu->env; + uint32_t eax, ebx, ecx, edx; + uint32_t leaf, subleaf; + size_t max_leaf =3D 0x1F; + size_t max_subleaf =3D 0x20; + + uint32_t leaves_with_subleaves[] =3D {0x4, 0x7, 0xD, 0xF, 0x10}; + int n_subleaf_leaves =3D ARRAY_SIZE(leaves_with_subleaves); + + /* Regular leaves without subleaves */ + for (leaf =3D 0; leaf <=3D max_leaf; leaf++) { + bool has_subleaves =3D false; + for (int i =3D 0; i < n_subleaf_leaves; i++) { + if (leaf =3D=3D leaves_with_subleaves[i]) { + has_subleaves =3D true; + break; + } + } + + if (!has_subleaves) { + cpu_x86_cpuid(env, leaf, 0, &eax, &ebx, &ecx, &edx); + if (eax =3D=3D 0 && ebx =3D=3D 0 && ecx =3D=3D 0 && edx =3D=3D= 0) { + /* all zeroes indicates no more leaves */ + continue; + } + + add_cpuid_entry(cpuid_entries, leaf, 0, eax, ebx, ecx, edx); + continue; + } + + subleaf =3D 0; + while (subleaf < max_subleaf) { + cpu_x86_cpuid(env, leaf, subleaf, &eax, &ebx, &ecx, &edx); + + if (eax =3D=3D 0 && ebx =3D=3D 0 && ecx =3D=3D 0 && edx =3D=3D= 0) { + /* all zeroes indicates no more leaves */ + break; + } + add_cpuid_entry(cpuid_entries, leaf, 0, eax, ebx, ecx, edx); + subleaf++; + } + } +} + +static int register_intercept_result_cpuid_entry(const CPUState *cpu, + uint8_t subleaf_specific, + uint8_t always_override, + struct hv_cpuid_entry *en= try) +{ + int ret; + int vp_index =3D cpu->cpu_index; + int cpu_fd =3D mshv_vcpufd(cpu); + + struct hv_register_x64_cpuid_result_parameters cpuid_params =3D { + .input.eax =3D entry->function, + .input.ecx =3D entry->index, + .input.subleaf_specific =3D subleaf_specific, + .input.always_override =3D always_override, + .input.padding =3D 0, + /* + * With regard to masks - these are to specify bits to be overwrit= ten + * The current CpuidEntry structure wouldn't allow to carry the ma= sks + * in addition to the actual register values. For this reason, the + * masks are set to the exact values of the corresponding register= bits + * to be registered for an overwrite. To view resulting values the + * hypervisor would return, HvCallGetVpCpuidValues hypercall can be + * used. + */ + .result.eax =3D entry->eax, + .result.eax_mask =3D entry->eax, + .result.ebx =3D entry->ebx, + .result.ebx_mask =3D entry->ebx, + .result.ecx =3D entry->ecx, + .result.ecx_mask =3D entry->ecx, + .result.edx =3D entry->edx, + .result.edx_mask =3D entry->edx, + }; + union hv_register_intercept_result_parameters parameters =3D { + .cpuid =3D cpuid_params, + }; + + hv_input_register_intercept_result in =3D {0}; + in.vp_index =3D vp_index; + in.intercept_type =3D HV_INTERCEPT_TYPE_X64_CPUID; + in.parameters =3D parameters; + + struct mshv_root_hvcall args =3D {0}; + args.code =3D HVCALL_REGISTER_INTERCEPT_RESULT; + args.in_sz =3D sizeof(in); + args.in_ptr =3D (uint64_t)∈ + + ret =3D mshv_hvcall(cpu_fd, &args); + if (ret < 0) { + error_report("failed to register intercept result for cpuid"); + return -1; + } + + return 0; +} + +static int register_intercept_result_cpuid(const CPUState *cpu, + struct hv_cpuid *cpuid) +{ + int ret =3D 0, entry_ret; + struct hv_cpuid_entry *entry; + uint8_t subleaf_specific, always_override; + + for (size_t i =3D 0; i < cpuid->nent; i++) { + entry =3D &cpuid->entries[i]; + + /* set defaults */ + subleaf_specific =3D 0; + always_override =3D 1; + + /* Intel */ + /* 0xb - Extended Topology Enumeration Leaf */ + /* 0x1f - V2 Extended Topology Enumeration Leaf */ + /* AMD */ + /* 0x8000_001e - Processor Topology Information */ + /* 0x8000_0026 - Extended CPU Topology */ + if (entry->function =3D=3D 0xb + || entry->function =3D=3D 0x1f + || entry->function =3D=3D 0x8000001e + || entry->function =3D=3D 0x80000026) { + subleaf_specific =3D 1; + always_override =3D 1; + } else if (entry->function =3D=3D 0x00000001 + || entry->function =3D=3D 0x80000000 + || entry->function =3D=3D 0x80000001 + || entry->function =3D=3D 0x80000008) { + subleaf_specific =3D 0; + always_override =3D 1; + } + + entry_ret =3D register_intercept_result_cpuid_entry(cpu, subleaf_s= pecific, + always_override, + entry); + if ((entry_ret < 0) && (ret =3D=3D 0)) { + ret =3D entry_ret; + } + } + + return ret; +} + +static int set_cpuid2(const CPUState *cpu) +{ + int ret; + size_t n_entries, cpuid_size; + struct hv_cpuid *cpuid; + struct hv_cpuid_entry *entry; + GList *entries =3D NULL; + + collect_cpuid_entries(cpu, entries); + n_entries =3D g_list_length(entries); + + cpuid_size =3D sizeof(struct hv_cpuid) + + n_entries * sizeof(struct hv_cpuid_entry); + + cpuid =3D g_malloc0(cpuid_size); + cpuid->nent =3D n_entries; + cpuid->padding =3D 0; + + for (size_t i =3D 0; i < n_entries; i++) { + entry =3D g_list_nth_data(entries, i); + cpuid->entries[i] =3D *entry; + g_free(entry); + } + g_list_free(entries); + + ret =3D register_intercept_result_cpuid(cpu, cpuid); + g_free(cpuid); + if (ret < 0) { + return ret; + } + + return 0; +} + static inline void populate_hv_segment_reg(SegmentCache *seg, hv_x64_segment_register *hv_reg) { @@ -684,6 +884,12 @@ int mshv_configure_vcpu(const CPUState *cpu, const str= uct MshvFPU *fpu, int ret; int cpu_fd =3D mshv_vcpufd(cpu); =20 + ret =3D set_cpuid2(cpu); + if (ret < 0) { + error_report("failed to set cpuid"); + return -1; + } + ret =3D set_cpu_state(cpu, fpu, xcr0); if (ret < 0) { error_report("failed to set cpu state"); --=20 2.34.1