From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 7E0D5F34C65 for ; Mon, 13 Apr 2026 16:54:53 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wCKX3-0006oq-Pg; Mon, 13 Apr 2026 12:53:05 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wCKX2-0006oX-Gs for qemu-devel@nongnu.org; Mon, 13 Apr 2026 12:53:04 -0400 Received: from p-west2-cluster3-host4-snip4-2.eps.apple.com ([57.103.69.15] helo=outbound.mr.icloud.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wCKX0-0005SA-Kr for qemu-devel@nongnu.org; Mon, 13 Apr 2026 12:53:04 -0400 Received: from outbound.mr.icloud.com (unknown [127.0.0.2]) by p00-icloudmta-asmtp-us-west-2a-10-percent-1 (Postfix) with ESMTPS id ABD091800370; Mon, 13 Apr 2026 16:53:00 +0000 (UTC) Dkim-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=unpredictable.fr; s=sig1; t=1776099181; x=1778691181; bh=Ash1yi3VlTyxdP0Aar5CNwwUDY+XErFVJjyfbU7EpDA=; h=From:To:Subject:Date:Message-ID:MIME-Version:x-icloud-hme; b=UZWHVG5hnJedSxcqc0hme5ybL6ZWwZXrh2emqg/H9B+iCxbJLATLQ72Rz7yD7PKmSSkXN6HbrTM/8uoFy2+23ayugTPS8s3JqhcWlHER+Hw+U/NK1kJXdFQkMxMcBCOdAEQCXS1cNfsR6cI0dvI23xpZ/pRcPE6R80FbL5lAjE1MJTnBVazL7y9LyFMyAebV63aUrgokVe1IJNUXugKyxTBA3hGmHJeRD4/kB0+nKA6dRrfge0We/oDeNeo2Ul1OAWuiu27h2wbhL2Jg2WX1RlksAX0DrGSWcKTC2OPExeAAUwOLxGFJL0BiJbrgwqwGsm8L5GqIqTAo8MX5tmBhgw== mail-alias-created-date: 1752046281608 Received: from localhost.localdomain (unknown [17.57.152.38]) by p00-icloudmta-asmtp-us-west-2a-10-percent-1 (Postfix) with ESMTPSA id 071891803BA1; Mon, 13 Apr 2026 16:52:43 +0000 (UTC) From: Mohamed Mediouni To: qemu-devel@nongnu.org Cc: "Michael S. Tsirkin" , Pedro Barbuda , Mohamed Mediouni , Paolo Bonzini , Zhao Liu , Roman Bolshakov , Wei Liu , Phil Dennis-Jordan Subject: [PATCH v11 03/15] whpx: i386: wire up feature probing Date: Mon, 13 Apr 2026 18:52:05 +0200 Message-ID: <20260413165217.47105-4-mohamed@unpredictable.fr> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260413165217.47105-1-mohamed@unpredictable.fr> References: <20260413165217.47105-1-mohamed@unpredictable.fr> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Proofpoint-ORIG-GUID: BTPwP6TZV_ChDQcQlcJkz6Y9GTT-WQAE X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNDEzMDE2NiBTYWx0ZWRfX/wECH8Lvq1SH vc0anSawCkv/rZY2x35ff9eLf+Qhhm52RTcLZfMz6gNjuA1kA8wpSGSpDFYbo4+PNbXBar4dG+6 B136jKZyOWC8/GnFWAdJV6wNepDO9UJ3LVj4NHcDEK8Xyfb85NwcECuw6XxzwOtuBkLOgt0KAyR c+rrvRu5GmjaHCZ3h0XxPHI4kGJwk1yVVwUU6947abuEqTklTx/ow+PuwSOUBo1dwumrIf3UdIF qhmRUd0o+aSjhQHRdraS6W9YMmjjhdr6ZJpUaXtJUdmW1NkQhtXUeVKaIMwBVINL0PUpYj3PFL/ WUrF+xS5nCPWvRCW6Nhb+TO7TneneFa6LOn9+C3lUNxZYDu7bWUvHGvp59LgIo= X-Authority-Info-Out: v=2.4 cv=Cu2ys34D c=1 sm=1 tr=0 ts=69dd1f6d cx=c_apl:c_pps:t_out a=9OgfyREA4BUYbbCgc0Y0oA==:117 a=9OgfyREA4BUYbbCgc0Y0oA==:17 a=A5OVakUREuEA:10 a=VkNPw1HP01LnGYTKEx00:22 a=Gr33WSPopR-aU8k7cJUA:9 X-Proofpoint-GUID: BTPwP6TZV_ChDQcQlcJkz6Y9GTT-WQAE X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-04-13_03,2026-04-13_04,2025-10-01_01 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 spamscore=0 mlxscore=0 phishscore=0 suspectscore=0 clxscore=1030 adultscore=0 malwarescore=0 mlxlogscore=985 bulkscore=0 lowpriorityscore=0 classifier=spam authscore=0 adjust=0 reason=mlx scancount=1 engine=8.22.0-2601150000 definitions=main-2604130166 Received-SPF: pass client-ip=57.103.69.15; envelope-from=mohamed@unpredictable.fr; helo=outbound.mr.icloud.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-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: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Windows 10 doesn't have the API for this, so using this only for Windows 11. Signed-off-by: Mohamed Mediouni --- include/system/whpx-internal.h | 9 ++++ target/i386/cpu.c | 25 ++++++++++++ target/i386/whpx/whpx-all.c | 75 ++++++++++++++++++++++++++++++++-- target/i386/whpx/whpx-i386.h | 4 ++ 4 files changed, 109 insertions(+), 4 deletions(-) create mode 100644 target/i386/whpx/whpx-i386.h diff --git a/include/system/whpx-internal.h b/include/system/whpx-internal.h index 8482901f71..5902124b63 100644 --- a/include/system/whpx-internal.h +++ b/include/system/whpx-internal.h @@ -73,6 +73,14 @@ void whpx_apic_get(APICCommonState *s); X(HRESULT, WHvGetVirtualProcessorRegisters, (WHV_PARTITION_HANDLE Partition, UINT32 VpIndex, const WHV_REGISTER_NAME* RegisterNames, UINT32 RegisterCount, WHV_REGISTER_VALUE* RegisterValues)) \ X(HRESULT, WHvSetVirtualProcessorRegisters, (WHV_PARTITION_HANDLE Partition, UINT32 VpIndex, const WHV_REGISTER_NAME* RegisterNames, UINT32 RegisterCount, const WHV_REGISTER_VALUE* RegisterValues)) \ +#ifdef __x86_64__ +#define LIST_WINHVPLATFORM_FUNCTIONS_SUPPLEMENTAL_ARCH(X) \ + X(HRESULT, WHvGetVirtualProcessorCpuidOutput, \ + (WHV_PARTITION_HANDLE Partition, UINT32 VpIndex, UINT32 Eax, \ + UINT32 Ecx, WHV_CPUID_OUTPUT *CpuidOutput)) +#else +#define LIST_WINHVPLATFORM_FUNCTIONS_SUPPLEMENTAL_ARCH(X) +#endif /* * These are supplemental functions that may not be present * on all versions and are not critical for basic functionality. @@ -89,6 +97,7 @@ void whpx_apic_get(APICCommonState *s); UINT32 StateSize)) \ X(HRESULT, WHvResetPartition, \ (WHV_PARTITION_HANDLE Partition)) \ + LIST_WINHVPLATFORM_FUNCTIONS_SUPPLEMENTAL_ARCH(X) #define WHP_DEFINE_TYPE(return_type, function_name, signature) \ typedef return_type (WINAPI *function_name ## _t) signature; diff --git a/target/i386/cpu.c b/target/i386/cpu.c index c6fd1dc00e..0000093fa3 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -26,6 +26,8 @@ #include "tcg/helper-tcg.h" #include "exec/translation-block.h" #include "system/hvf.h" +#include "system/whpx.h" +#include "whpx/whpx-i386.h" #include "hvf/hvf-i386.h" #include "kvm/kvm_i386.h" #include "kvm/tdx.h" @@ -8087,6 +8089,17 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w) r = hvf_get_supported_cpuid(wi->cpuid.eax, wi->cpuid.ecx, wi->cpuid.reg); + } else if (whpx_enabled()) { + if (wi->type != CPUID_FEATURE_WORD) { + return 0; + } + if (whpx_is_legacy_os()) { + r = wi->tcg_features; + } else { + r = whpx_get_supported_cpuid(wi->cpuid.eax, + wi->cpuid.ecx, + wi->cpuid.reg); + } } else if (tcg_enabled() || qtest_enabled()) { r = wi->tcg_features; } else { @@ -8168,6 +8181,18 @@ static void x86_cpu_get_supported_cpuid(uint32_t func, uint32_t index, *ebx = hvf_get_supported_cpuid(func, index, R_EBX); *ecx = hvf_get_supported_cpuid(func, index, R_ECX); *edx = hvf_get_supported_cpuid(func, index, R_EDX); + } else if (whpx_enabled()) { + if (whpx_is_legacy_os()) { + *eax = 0; + *ebx = 0; + *ecx = 0; + *edx = 0; + } else { + *eax = whpx_get_supported_cpuid(func, index, R_EAX); + *ebx = whpx_get_supported_cpuid(func, index, R_EBX); + *ecx = whpx_get_supported_cpuid(func, index, R_ECX); + *edx = whpx_get_supported_cpuid(func, index, R_EDX); + } } else { *eax = 0; *ebx = 0; diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c index 4127440c0c..2d527b90dd 100644 --- a/target/i386/whpx/whpx-all.c +++ b/target/i386/whpx/whpx-all.c @@ -36,6 +36,7 @@ #include "system/whpx-accel-ops.h" #include "system/whpx-all.h" #include "system/whpx-common.h" +#include "whpx-i386.h" #include "emulate/x86_decode.h" #include "emulate/x86_emu.h" @@ -49,6 +50,8 @@ /* for kernel-irqchip=off */ #define HV_X64_MSR_APIC_FREQUENCY 0x40000023 +static bool is_modern_os = true; + static const WHV_REGISTER_NAME whpx_register_names[] = { /* X64 General purpose registers */ @@ -1062,6 +1065,71 @@ static void whpx_init_emu(void) init_emu(&whpx_x86_emul_ops); } +bool whpx_is_legacy_os(void) +{ + return !is_modern_os; +} + +uint32_t whpx_get_supported_cpuid(uint32_t func, uint32_t idx, int reg) +{ + WHV_CPUID_OUTPUT output; + uint32_t eax, ebx, ecx, edx; + uint32_t cpu_index = 0; + bool temp_cpu = true; + HRESULT hr; + + hr = whp_dispatch.WHvCreateVirtualProcessor( + whpx_global.partition, cpu_index, 0); + + /* This means that the CPU already exists... */ + if (FAILED(hr)) { + temp_cpu = false; + } + + hr = whp_dispatch.WHvGetVirtualProcessorCpuidOutput(whpx_global.partition, + cpu_index, func, idx, &output); + + if (FAILED(hr)) { + abort(); + } + + if (temp_cpu) { + hr = whp_dispatch.WHvDeleteVirtualProcessor(whpx_global.partition, cpu_index); + if (FAILED(hr)) { + abort(); + } + } + + eax = output.Eax; + ebx = output.Ebx; + ecx = output.Ecx; + edx = output.Edx; + + /* + * We can emulate X2APIC even for the kernel-irqchip=off case. + * CPUID_EXT_HYPERVISOR and CPUID_HT should be considered present + * always, so report them as unconditionally supported here. + */ + if (func == 1) { + ecx |= CPUID_EXT_X2APIC; + ecx |= CPUID_EXT_HYPERVISOR; + edx |= CPUID_HT; + } + + switch (reg) { + case R_EAX: + return eax; + case R_EBX: + return ebx; + case R_ECX: + return ecx; + case R_EDX: + return edx; + default: + return 0; + } +} + /* * Controls whether we should intercept various exceptions on the guest, * namely breakpoint/single-step events. @@ -2235,7 +2303,6 @@ int whpx_accel_init(AccelState *as, MachineState *ms) WHV_CAPABILITY_FEATURES features = {0}; WHV_PROCESSOR_FEATURES_BANKS processor_features; WHV_PROCESSOR_PERFMON_FEATURES perfmon_features; - bool is_legacy_os = false; UINT32 cpuidExitList[] = {1}; whpx = &whpx_global; @@ -2395,7 +2462,7 @@ int whpx_accel_init(AccelState *as, MachineState *ms) if (FAILED(hr)) { warn_report("WHPX: Failed to get performance " "monitoring features, hr=%08lx", hr); - is_legacy_os = true; + is_modern_os = false; } else { hr = whp_dispatch.WHvSetPartitionProperty( whpx->partition, @@ -2435,7 +2502,7 @@ int whpx_accel_init(AccelState *as, MachineState *ms) synthetic_features.Bank0.DirectSyntheticTimers = 1; } - if (!is_legacy_os && whpx->hyperv_enlightenments_allowed) { + if (is_modern_os && whpx->hyperv_enlightenments_allowed) { hr = whp_dispatch.WHvSetPartitionProperty( whpx->partition, WHvPartitionPropertyCodeSyntheticProcessorFeaturesBanks, @@ -2446,7 +2513,7 @@ int whpx_accel_init(AccelState *as, MachineState *ms) ret = -EINVAL; goto error; } - } else if (is_legacy_os && whpx->hyperv_enlightenments_required) { + } else if (!is_modern_os && whpx->hyperv_enlightenments_required) { error_report("Hyper-V enlightenments not available on legacy Windows"); ret = -EINVAL; goto error; diff --git a/target/i386/whpx/whpx-i386.h b/target/i386/whpx/whpx-i386.h new file mode 100644 index 0000000000..6db9a75d39 --- /dev/null +++ b/target/i386/whpx/whpx-i386.h @@ -0,0 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +uint32_t whpx_get_supported_cpuid(uint32_t func, uint32_t idx, int reg); +bool whpx_is_legacy_os(void); -- 2.50.1 (Apple Git-155)