From nobody Wed Dec 17 04:03:15 2025 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=1754577976; cv=none; d=zohomail.com; s=zohoarc; b=dx+7M2A040pLNkad5o3Vlqdla9soEwVjEa5+Fkroan4PZzGhT9X05xacOhSbxeCauNilf6wVyGKle7nEpX7di+YxR/+zg8tJ4EJbw7qePkKugBGh40Eina2u0EknW37jyWBNfV0wwE/LZrbHKwhRB+m4oYDABOFSYp7T2zAckmM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1754577976; 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=vU3tcvhiGXL9MoCJ+Cc+MlbXR/po3w9Bd/gpqNljl64=; b=SZ6l/tVeoQTneRw0g1QePspmJuehBvEiAZw+w4Wa1Xms3KonNWckuSnMBbAoY+xeGkPiDnW7Gd9XK0jptshdokc2affWOYRo7S+jFCd07ypFAM9EvZQNGKY57QVJcbuK4jssJ7afpPUejo8DPedyHJQ5tM3vM6KltCxZDRzPBHs= 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 1754577976456332.18757203811674; Thu, 7 Aug 2025 07:46:16 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uk1p9-0002Ca-K6; Thu, 07 Aug 2025 10:42:31 -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 1uk1oZ-0000Rr-S2 for qemu-devel@nongnu.org; Thu, 07 Aug 2025 10:42:00 -0400 Received: from linux.microsoft.com ([13.77.154.182]) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uk1oX-00013l-Du for qemu-devel@nongnu.org; Thu, 07 Aug 2025 10:41:55 -0400 Received: from localhost.localdomain (unknown [167.220.208.72]) by linux.microsoft.com (Postfix) with ESMTPSA id AFC4F201BC82; Thu, 7 Aug 2025 07:41:47 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com AFC4F201BC82 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1754577712; bh=vU3tcvhiGXL9MoCJ+Cc+MlbXR/po3w9Bd/gpqNljl64=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=AMFoRLnOR9HgKAdZlEH5HNgcmHLDltmY6nbmwfWaJr3dnMq6ydNTjTr+64m4cpPCI rKpjVBNutdJUTmnA/POMYRVW3ZNCAu1JA0lLhzZBMutsI/4gmpM/5mmBV8ISWOCHsJ jkt/p6qs1xGWux/LUpYyp8W+Tdil8ZnW2o3CqUfE= From: Magnus Kulke To: qemu-devel@nongnu.org Cc: Eric Blake , Eduardo Habkost , "Michael S. Tsirkin" , Markus Armbruster , Magnus Kulke , Paolo Bonzini , Richard Henderson , Phil Dennis-Jordan , Marcel Apfelbaum , =?UTF-8?q?Alex=20Benn=C3=A9e?= , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Magnus Kulke , Cornelia Huck , Zhao Liu , Thomas Huth , Yanan Wang , Cameron Esfahani , Wei Liu , Wei Liu , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , Roman Bolshakov , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Subject: [PATCH v3 18/26] target/i386/mshv: Register CPUID entries with MSHV Date: Thu, 7 Aug 2025 16:39:43 +0200 Message-Id: <20250807143951.1154713-19-magnuskulke@linux.microsoft.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250807143951.1154713-1-magnuskulke@linux.microsoft.com> References: <20250807143951.1154713-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_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_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: 1754577977141116600 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 | 199 ++++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c index c233d4af70..0b7350877d 100644 --- a/target/i386/mshv/mshv-cpu.c +++ b/target/i386/mshv/mshv-cpu.c @@ -324,6 +324,199 @@ 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(int cpu_fd, + uint8_t subleaf_specific, + uint8_t always_override, + struct hv_cpuid_entry *en= try) +{ + 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, + }; + struct mshv_register_intercept_result args =3D { + .intercept_type =3D HV_INTERCEPT_TYPE_X64_CPUID, + .parameters =3D parameters, + }; + int ret; + + ret =3D ioctl(cpu_fd, MSHV_VP_REGISTER_INTERCEPT_RESULT, &args); + if (ret < 0) { + error_report("failed to register intercept result for cpuid: %s", + strerror(errno)); + return -1; + } + + return 0; +} + +static int register_intercept_result_cpuid(int cpu_fd, struct hv_cpuid *cp= uid) +{ + 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_fd, + subleaf_specific, + 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; + int cpu_fd =3D mshv_vcpufd(cpu); + + 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_fd, 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) { @@ -608,6 +801,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