From nobody Mon Feb 9 20:32:17 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=1751391201; cv=none; d=zohomail.com; s=zohoarc; b=cDvNp19cVM9l+j/acGtTROzCkpicMpl4Xtlpyr7FCRyl0QWZV3khG7KFQ4HlVYqKEL4Eeyak2juXkOBEnPCm+0brZO5T9bG/EqJJaEeowTmYKXq7fsVzTGAv2kcbVjKAoU32mvAN465VUNaojXihdurFesMBfo3uHpdI7ny3GHA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1751391201; 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=IcalwT8+xtmV9BIr8XPQRT0cWxIIe+Fs8gXDtFxzNdo=; b=W82lvdOu/cTJwxN6SUDGfAbC2V8DwwGgS8dojU9U4oRD+t/6mMzpicItRowseEMolBRBGqeZVnnjNK8FqrwBdCUTgFe+EAKcCxdeXSCmUNehoQZOCuV7eM6BjaQYa1RvthHluRli8ag/HxuezK7Z1g3mdR/5gJ4P1mXaMfoHERo= 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 1751391200827933.9561831490073; Tue, 1 Jul 2025 10:33:20 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uWeoy-0006Q6-F5; Tue, 01 Jul 2025 13:31:06 -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 1uWeob-00069F-G8 for qemu-devel@nongnu.org; Tue, 01 Jul 2025 13:30:43 -0400 Received: from linux.microsoft.com ([13.77.154.182]) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uWeoV-0007Gq-1X for qemu-devel@nongnu.org; Tue, 01 Jul 2025 13:30:41 -0400 Received: from localhost.localdomain (unknown [167.220.208.67]) by linux.microsoft.com (Postfix) with ESMTPSA id 69590211938F; Tue, 1 Jul 2025 10:30:19 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 69590211938F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1751391023; bh=IcalwT8+xtmV9BIr8XPQRT0cWxIIe+Fs8gXDtFxzNdo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bLnDudvdzHAd4amKVX1eRRBu3yY4SAcdQ+Rkz35MY0IoA9pnMsawoceWvktkUvL+m UGB+T6NBmsH71I1zxM2v0mkycTSIPr0yziVoqQUNPNSWbeTn/kHPDH96kDx9SvDJww ldOzIP1kzUR3dUy4g6B+whbgQl6jBmFt1ZXVzhO4= From: Magnus Kulke To: qemu-devel@nongnu.org Cc: Cameron Esfahani , Phil Dennis-Jordan , Roman Bolshakov , Thomas Huth , Zhao Liu , Wei Liu , Paolo Bonzini , Wei Liu , Richard Henderson , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Markus Armbruster , Cornelia Huck , Magnus Kulke , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , "Michael S. Tsirkin" , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , =?UTF-8?q?Alex=20Benn=C3=A9e?= Subject: [PATCH v2 20/27] target/i386/mshv: Register CPUID entries with MSHV Date: Tue, 1 Jul 2025 19:28:27 +0200 Message-Id: <20250701172834.44849-21-magnuskulke@linux.microsoft.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250701172834.44849-1-magnuskulke@linux.microsoft.com> References: <20250701172834.44849-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: 1751391202190116600 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 8716fe350b..210bd85e11 100644 --- a/target/i386/mshv/mshv-cpu.c +++ b/target/i386/mshv/mshv-cpu.c @@ -323,6 +323,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) { @@ -607,6 +800,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