Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.1/patches/2225091/?format=api
{ "id": 2225091, "url": "http://patchwork.ozlabs.org/api/1.1/patches/2225091/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260420104248.86702-32-mohamed@unpredictable.fr/", "project": { "id": 14, "url": "http://patchwork.ozlabs.org/api/1.1/projects/14/?format=api", "name": "QEMU Development", "link_name": "qemu-devel", "list_id": "qemu-devel.nongnu.org", "list_email": "qemu-devel@nongnu.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20260420104248.86702-32-mohamed@unpredictable.fr>", "date": "2026-04-20T10:42:41", "name": "[v2,31/38] whpx: xsave support", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "c55216a00f1b1cc999a27d96ab7b149ea8f81de8", "submitter": { "id": 91318, "url": "http://patchwork.ozlabs.org/api/1.1/people/91318/?format=api", "name": "Mohamed Mediouni", "email": "mohamed@unpredictable.fr" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260420104248.86702-32-mohamed@unpredictable.fr/mbox/", "series": [ { "id": 500592, "url": "http://patchwork.ozlabs.org/api/1.1/series/500592/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=500592", "date": "2026-04-20T10:42:10", "name": "WHPX x86 updates for QEMU 11.1", "version": 2, "mbox": "http://patchwork.ozlabs.org/series/500592/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2225091/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2225091/checks/", "tags": {}, "headers": { "Return-Path": "<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@legolas.ozlabs.org", "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=unpredictable.fr header.i=@unpredictable.fr\n header.a=rsa-sha256 header.s=sig1 header.b=V7XdVDc1;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists1p.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=patchwork.ozlabs.org)" ], "Received": [ "from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fzhzg1p70z1yCv\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 20 Apr 2026 20:48:31 +1000 (AEST)", "from localhost ([::1] helo=lists1p.gnu.org)\n\tby lists1p.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces@nongnu.org>)\n\tid 1wEm71-0008LP-5Q; Mon, 20 Apr 2026 06:44:19 -0400", "from eggs.gnu.org ([2001:470:142:3::10])\n by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <mohamed@unpredictable.fr>)\n id 1wEm70-0008Ko-6p\n for qemu-devel@nongnu.org; Mon, 20 Apr 2026 06:44:18 -0400", "from p-west3-cluster4-host11-snip4-10.eps.apple.com ([57.103.74.221]\n helo=outbound.ms.icloud.com)\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <mohamed@unpredictable.fr>)\n id 1wEm6w-0000m2-7s\n for qemu-devel@nongnu.org; Mon, 20 Apr 2026 06:44:17 -0400", "from outbound.ms.icloud.com (unknown [127.0.0.2])\n by p00-icloudmta-asmtp-us-west-3a-100-percent-1 (Postfix) with ESMTPS id\n 251371800451; Mon, 20 Apr 2026 10:44:11 +0000 (UTC)", "from localhost.localdomain (unknown [17.57.154.37])\n by p00-icloudmta-asmtp-us-west-3a-100-percent-1 (Postfix) with ESMTPSA id\n 9669D1800159; Mon, 20 Apr 2026 10:44:08 +0000 (UTC)" ], "Dkim-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=unpredictable.fr;\n s=sig1; t=1776681853; x=1779273853;\n bh=tbMliXtkqk8dPHBK0hLkGecREvcpTdLtake6KyI3WL8=;\n h=From:To:Subject:Date:Message-ID:MIME-Version:x-icloud-hme;\n b=V7XdVDc1+XTOwx6v5+f57H3xAUMNtmfBwphIFmv8pOhEmEaS3VOHBOTJSsrpaxAUdzwQdaEJqqEtgbl/3L+kCJ+qOXlbuxzfznTqfMLomzEAITFM7eJzEgGEhvaoHOLJC07l7/mbVymCgzqfcxy7Acfkva859Dp+6sjusij+lOcVgLF+6BLHKEjRLovxmnRzICOL/F//ffvmYFQa9b7vENBb8jECvYJ0wGGfeXtGrqFGVvddcvkr4VgxBOcmoHNMellPPzCTotMoiQfDdt0rioRXzGxlAH8UMrQiW4swZ1zVzenYu6wX5/xPhS/7lJUO6PalDSbBApTfG2j3ylkR8A==", "mail-alias-created-date": "1752046281608", "From": "Mohamed Mediouni <mohamed@unpredictable.fr>", "To": "qemu-devel@nongnu.org", "Cc": "qemu-arm@nongnu.org, Mohamed Mediouni <mohamed@unpredictable.fr>,\n Paolo Bonzini <pbonzini@redhat.com>,\n Phil Dennis-Jordan <phil@philjordan.eu>,\n Roman Bolshakov <rbolshakov@ddn.com>,\n Pierrick Bouvier <pierrick.bouvier@linaro.org>,\n Pedro Barbuda <pbarbuda@microsoft.com>, Wei Liu <wei.liu@kernel.org>,\n \"Michael S. Tsirkin\" <mst@redhat.com>,\n Peter Maydell <peter.maydell@linaro.org>, Zhao Liu <zhao1.liu@intel.com>", "Subject": "[PATCH v2 31/38] whpx: xsave support", "Date": "Mon, 20 Apr 2026 12:42:41 +0200", "Message-ID": "<20260420104248.86702-32-mohamed@unpredictable.fr>", "X-Mailer": "git-send-email 2.50.1", "In-Reply-To": "<20260420104248.86702-1-mohamed@unpredictable.fr>", "References": "<20260420104248.86702-1-mohamed@unpredictable.fr>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "X-Proofpoint-ORIG-GUID": "bO-wrEJn44fpQzUefPwBq6egDJYePCFq", "X-Proofpoint-GUID": "bO-wrEJn44fpQzUefPwBq6egDJYePCFq", "X-Authority-Info-Out": "v=2.4 cv=cKftc1eN c=1 sm=1 tr=0 ts=69e6037b\n cx=c_apl:c_pps:t_out a=qkKslKyYc0ctBTeLUVfTFg==:117 a=A5OVakUREuEA:10\n a=VkNPw1HP01LnGYTKEx00:22 a=pIzSZyhXsI4QXQPOM_AA:9", "X-Proofpoint-Spam-Details-Enc": "AW1haW4tMjYwNDIwMDEwNCBTYWx0ZWRfXxELx/m+9X/Ic\n Q9UioB4ugv0c07Qj2JgxzQUo2Z4YKyEy7nycL/uX3WjK2YSzB3OGfJmr+hcO9xVnhLwsjOLcIIs\n m2vdwg2jcrun/33wLp3ImmdhNuIcT2K37wLIzGNjnu1ohal5ws6/2aJOZgZ9AZZSUwA0vp53pAA\n MHofpj2BzA4nkmXWSu8lTkGOtuNHIS2z2XTO/UxRKPs3ULb/ZItADrA1QEtbH16Eb/diBdUKNIQ\n +4qFlzlhhufIioUO5rd9SMC7155sRVR1P3KK0S/aIFQaLY5GNJqUhmymIXyDH05C1zoV6M1DSYa\n XxqVAB5UX5C6t9vgffnGvc1NpH6T+xNX5bAHc7jwszu0oE1s8o655zQ8XevM2Y=", "X-Proofpoint-Virus-Version": "vendor=baseguard\n engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.51,FMLib:17.12.100.49\n definitions=2026-04-20_02,2026-04-17_04,2025-10-01_01", "X-Proofpoint-Spam-Details": "rule=notspam policy=default score=0 suspectscore=0\n lowpriorityscore=0 malwarescore=0 clxscore=1030\n mlxlogscore=999 adultscore=0\n mlxscore=0 bulkscore=0 phishscore=0 spamscore=0 classifier=spam authscore=0\n adjust=0 reason=mlx scancount=1 engine=8.22.0-2601150000\n definitions=main-2604200104", "Received-SPF": "pass client-ip=57.103.74.221;\n envelope-from=mohamed@unpredictable.fr; helo=outbound.ms.icloud.com", "X-Spam_score_int": "-27", "X-Spam_score": "-2.8", "X-Spam_bar": "--", "X-Spam_report": "(-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,\n DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1,\n RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001,\n 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 <qemu-devel.nongnu.org>", "List-Unsubscribe": "<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>", "List-Archive": "<https://lists.nongnu.org/archive/html/qemu-devel>", "List-Post": "<mailto:qemu-devel@nongnu.org>", "List-Help": "<mailto:qemu-devel-request@nongnu.org?subject=help>", "List-Subscribe": "<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>", "Errors-To": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org", "Sender": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org" }, "content": "Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>\n---\n include/system/whpx-internal.h | 16 ++\n target/i386/whpx/whpx-all.c | 379 ++++++++++++++++++++++++---------\n 2 files changed, 292 insertions(+), 103 deletions(-)", "diff": "diff --git a/include/system/whpx-internal.h b/include/system/whpx-internal.h\nindex 86639627b3..0aae83bd7c 100644\n--- a/include/system/whpx-internal.h\n+++ b/include/system/whpx-internal.h\n@@ -99,6 +99,22 @@ void whpx_apic_get(APICCommonState *s);\n UINT32 StateSize)) \\\n X(HRESULT, WHvResetPartition, \\\n (WHV_PARTITION_HANDLE Partition)) \\\n+ X(HRESULT, WHvGetVirtualProcessorXsaveState, \\\n+ (WHV_PARTITION_HANDLE Partition, UINT32 VpIndex, \\\n+ PVOID Buffer, \\\n+ UINT32 BufferSizeInBytes, UINT32 *BytesWritten)) \\\n+ X(HRESULT, WHvSetVirtualProcessorXsaveState, \\\n+ (WHV_PARTITION_HANDLE Partition, UINT32 VpIndex, \\\n+ PVOID Buffer, \\\n+ UINT32 BufferSizeInBytes)) \\\n+ X(HRESULT, WHvGetVirtualProcessorState, \\\n+ (WHV_PARTITION_HANDLE Partition, UINT32 VpIndex, \\\n+ WHV_VIRTUAL_PROCESSOR_STATE_TYPE StateType, PVOID Buffer, \\\n+ UINT32 BufferSizeInBytes, UINT32 *BytesWritten)) \\\n+ X(HRESULT, WHvSetVirtualProcessorState, \\\n+ (WHV_PARTITION_HANDLE Partition, UINT32 VpIndex, \\\n+ WHV_VIRTUAL_PROCESSOR_STATE_TYPE StateType, PVOID Buffer, \\\n+ UINT32 BufferSizeInBytes)) \\\n LIST_WINHVPLATFORM_FUNCTIONS_SUPPLEMENTAL_ARCH(X)\n \n #define WHP_DEFINE_TYPE(return_type, function_name, signature) \\\ndiff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c\nindex 045dbdfdc8..9b2488b801 100644\n--- a/target/i386/whpx/whpx-all.c\n+++ b/target/i386/whpx/whpx-all.c\n@@ -10,6 +10,7 @@\n \n #include \"qemu/osdep.h\"\n #include \"cpu.h\"\n+#include \"qemu/typedefs.h\"\n #include \"system/address-spaces.h\"\n #include \"system/ioport.h\"\n #include \"gdbstub/helpers.h\"\n@@ -20,6 +21,7 @@\n #include \"system/cpus.h\"\n #include \"system/runstate.h\"\n #include \"qemu/main-loop.h\"\n+#include \"qemu/memalign.h\"\n #include \"hw/core/boards.h\"\n #include \"hw/intc/ioapic.h\"\n #include \"hw/intc/i8259.h\"\n@@ -108,34 +110,6 @@ static const WHV_REGISTER_NAME whpx_register_names[] = {\n * WHvX64RegisterDr7,\n */\n \n- /* X64 Floating Point and Vector Registers */\n- WHvX64RegisterXmm0,\n- WHvX64RegisterXmm1,\n- WHvX64RegisterXmm2,\n- WHvX64RegisterXmm3,\n- WHvX64RegisterXmm4,\n- WHvX64RegisterXmm5,\n- WHvX64RegisterXmm6,\n- WHvX64RegisterXmm7,\n- WHvX64RegisterXmm8,\n- WHvX64RegisterXmm9,\n- WHvX64RegisterXmm10,\n- WHvX64RegisterXmm11,\n- WHvX64RegisterXmm12,\n- WHvX64RegisterXmm13,\n- WHvX64RegisterXmm14,\n- WHvX64RegisterXmm15,\n- WHvX64RegisterFpMmx0,\n- WHvX64RegisterFpMmx1,\n- WHvX64RegisterFpMmx2,\n- WHvX64RegisterFpMmx3,\n- WHvX64RegisterFpMmx4,\n- WHvX64RegisterFpMmx5,\n- WHvX64RegisterFpMmx6,\n- WHvX64RegisterFpMmx7,\n- WHvX64RegisterFpControlStatus,\n- WHvX64RegisterXmmControlStatus,\n-\n /* X64 MSRs */\n WHvX64RegisterEfer,\n #ifdef TARGET_X86_64\n@@ -182,6 +156,36 @@ static const WHV_REGISTER_NAME whpx_register_names_for_vmexit[] = {\n WHvX64RegisterR15,\n };\n \n+static const WHV_REGISTER_NAME whpx_register_names_legacy_fp[] = {\n+ /* X64 Floating Point and Vector Registers (non-xsave) */\n+ WHvX64RegisterXmm0,\n+ WHvX64RegisterXmm1,\n+ WHvX64RegisterXmm2,\n+ WHvX64RegisterXmm3,\n+ WHvX64RegisterXmm4,\n+ WHvX64RegisterXmm5,\n+ WHvX64RegisterXmm6,\n+ WHvX64RegisterXmm7,\n+ WHvX64RegisterXmm8,\n+ WHvX64RegisterXmm9,\n+ WHvX64RegisterXmm10,\n+ WHvX64RegisterXmm11,\n+ WHvX64RegisterXmm12,\n+ WHvX64RegisterXmm13,\n+ WHvX64RegisterXmm14,\n+ WHvX64RegisterXmm15,\n+ WHvX64RegisterFpMmx0,\n+ WHvX64RegisterFpMmx1,\n+ WHvX64RegisterFpMmx2,\n+ WHvX64RegisterFpMmx3,\n+ WHvX64RegisterFpMmx4,\n+ WHvX64RegisterFpMmx5,\n+ WHvX64RegisterFpMmx6,\n+ WHvX64RegisterFpMmx7,\n+ WHvX64RegisterFpControlStatus,\n+ WHvX64RegisterXmmControlStatus,\n+};\n+\n struct whpx_register_set {\n WHV_REGISTER_VALUE values[RTL_NUMBER_OF(whpx_register_names)];\n };\n@@ -392,6 +396,123 @@ static int whpx_set_tsc(CPUState *cpu)\n return 0;\n }\n \n+static bool whpx_is_xsave_enabled(CPUState *cpu)\n+{\n+ CPUX86State *env = &X86_CPU(cpu)->env;\n+ return env->cr[4] & CR4_OSXSAVE_MASK;\n+}\n+\n+static size_t whpx_get_xsave_max_len(void)\n+{\n+ return whpx_get_supported_cpuid(0xd, 0, R_ECX);\n+}\n+\n+static int whpx_set_xsave_state(const CPUState *cpu)\n+{\n+ struct whpx_state *whpx = &whpx_global;\n+ X86CPU *x86cpu = X86_CPU(cpu);\n+ CPUX86State *env = &x86cpu->env;\n+ HRESULT hr;\n+ void *xsavec_buf;\n+ size_t page = qemu_real_host_page_size();\n+ size_t xsavec_buf_len;\n+\n+ /* allocate and populate compacted buffer */\n+ xsavec_buf_len = whpx_get_xsave_max_len();\n+ xsavec_buf = qemu_memalign(page, xsavec_buf_len);\n+\n+ /* save registers to standard format buffer */\n+ x86_cpu_xsave_all_areas(x86cpu, env->xsave_buf, env->xsave_buf_len);\n+\n+ /* store compacted version of xsave area in xsavec_buf */\n+ compact_xsave_area(env, xsavec_buf, xsavec_buf_len);\n+\n+ if (!whpx_is_legacy_os()) {\n+ hr = whp_dispatch.WHvSetVirtualProcessorState(\n+ whpx->partition, cpu->cpu_index,\n+ WHvVirtualProcessorStateTypeXsaveState,\n+ xsavec_buf,\n+ xsavec_buf_len);\n+ } else {\n+ hr = whp_dispatch.WHvSetVirtualProcessorXsaveState(\n+ whpx->partition, cpu->cpu_index,\n+ xsavec_buf,\n+ xsavec_buf_len);\n+ }\n+\n+ qemu_vfree(xsavec_buf);\n+ if (FAILED(hr)) {\n+ error_report(\"WHPX: Failed to get virtual processor context, hr=%08lx\",\n+ hr);\n+ }\n+\n+ return 0;\n+}\n+\n+static void whpx_set_legacy_fp_registers(CPUState *cpu, WHPXStateLevel level)\n+{\n+ struct whpx_state *whpx = &whpx_global;\n+ X86CPU *x86_cpu = X86_CPU(cpu);\n+ CPUX86State *env = &x86_cpu->env;\n+ struct whpx_register_set vcxt;\n+ HRESULT hr;\n+ int idx = 0;\n+ int i;\n+ int idx_next;\n+\n+ assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));\n+\n+ /* 16 XMM registers */\n+ assert(whpx_register_names_legacy_fp[idx] == WHvX64RegisterXmm0);\n+ idx_next = idx + 16;\n+ for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i += 1, idx += 1) {\n+ vcxt.values[idx].Reg128.Low64 = env->xmm_regs[i].ZMM_Q(0);\n+ vcxt.values[idx].Reg128.High64 = env->xmm_regs[i].ZMM_Q(1);\n+ }\n+ idx = idx_next;\n+\n+ /* 8 FP registers */\n+ assert(whpx_register_names_legacy_fp[idx] == WHvX64RegisterFpMmx0);\n+ for (i = 0; i < 8; i += 1, idx += 1) {\n+ vcxt.values[idx].Fp.AsUINT128.Low64 = env->fpregs[i].mmx.MMX_Q(0);\n+ /* vcxt.values[idx].Fp.AsUINT128.High64 =\n+ env->fpregs[i].mmx.MMX_Q(1);\n+ */\n+ }\n+\n+ /* FP control status register */\n+ assert(whpx_register_names_legacy_fp[idx] == WHvX64RegisterFpControlStatus);\n+ vcxt.values[idx].FpControlStatus.FpControl = env->fpuc;\n+ vcxt.values[idx].FpControlStatus.FpStatus =\n+ (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;\n+ vcxt.values[idx].FpControlStatus.FpTag = 0;\n+ for (i = 0; i < 8; ++i) {\n+ vcxt.values[idx].FpControlStatus.FpTag |= (!env->fptags[i]) << i;\n+ }\n+ vcxt.values[idx].FpControlStatus.Reserved = 0;\n+ vcxt.values[idx].FpControlStatus.LastFpOp = env->fpop;\n+ vcxt.values[idx].FpControlStatus.LastFpRip = env->fpip;\n+ idx += 1;\n+\n+ /* XMM control status register */\n+ assert(whpx_register_names_legacy_fp[idx] == WHvX64RegisterXmmControlStatus);\n+ vcxt.values[idx].XmmControlStatus.LastFpRdp = 0;\n+ vcxt.values[idx].XmmControlStatus.XmmStatusControl = env->mxcsr;\n+ vcxt.values[idx].XmmControlStatus.XmmStatusControlMask = 0x0000ffff;\n+ idx += 1;\n+\n+ hr = whp_dispatch.WHvSetVirtualProcessorRegisters(\n+ whpx->partition, cpu->cpu_index,\n+ whpx_register_names_legacy_fp,\n+ idx,\n+ &vcxt.values[0]);\n+\n+ if (FAILED(hr)) {\n+ error_report(\"WHPX: Failed to set virtual processor context, hr=%08lx\",\n+ hr);\n+ }\n+}\n+\n void whpx_set_registers(CPUState *cpu, WHPXStateLevel level)\n {\n struct whpx_state *whpx = &whpx_global;\n@@ -491,45 +612,11 @@ void whpx_set_registers(CPUState *cpu, WHPXStateLevel level)\n */\n whpx_set_xcrs(cpu);\n \n- /* 16 XMM registers */\n- assert(whpx_register_names[idx] == WHvX64RegisterXmm0);\n- idx_next = idx + 16;\n- for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i += 1, idx += 1) {\n- vcxt.values[idx].Reg128.Low64 = env->xmm_regs[i].ZMM_Q(0);\n- vcxt.values[idx].Reg128.High64 = env->xmm_regs[i].ZMM_Q(1);\n- }\n- idx = idx_next;\n-\n- /* 8 FP registers */\n- assert(whpx_register_names[idx] == WHvX64RegisterFpMmx0);\n- for (i = 0; i < 8; i += 1, idx += 1) {\n- vcxt.values[idx].Fp.AsUINT128.Low64 = env->fpregs[i].mmx.MMX_Q(0);\n- /* vcxt.values[idx].Fp.AsUINT128.High64 =\n- env->fpregs[i].mmx.MMX_Q(1);\n- */\n- }\n-\n- /* FP control status register */\n- assert(whpx_register_names[idx] == WHvX64RegisterFpControlStatus);\n- vcxt.values[idx].FpControlStatus.FpControl = env->fpuc;\n- vcxt.values[idx].FpControlStatus.FpStatus =\n- (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;\n- vcxt.values[idx].FpControlStatus.FpTag = 0;\n- for (i = 0; i < 8; ++i) {\n- vcxt.values[idx].FpControlStatus.FpTag |= (!env->fptags[i]) << i;\n+ if (whpx_is_xsave_enabled(cpu)) {\n+ whpx_set_xsave_state(cpu);\n+ } else {\n+ whpx_set_legacy_fp_registers(cpu, level);\n }\n- vcxt.values[idx].FpControlStatus.Reserved = 0;\n- vcxt.values[idx].FpControlStatus.LastFpOp = env->fpop;\n- vcxt.values[idx].FpControlStatus.LastFpRip = env->fpip;\n- idx += 1;\n-\n- /* XMM control status register */\n- assert(whpx_register_names[idx] == WHvX64RegisterXmmControlStatus);\n- vcxt.values[idx].XmmControlStatus.LastFpRdp = 0;\n- vcxt.values[idx].XmmControlStatus.XmmStatusControl = env->mxcsr;\n- vcxt.values[idx].XmmControlStatus.XmmStatusControlMask = 0x0000ffff;\n- idx += 1;\n-\n /* MSRs */\n assert(whpx_register_names[idx] == WHvX64RegisterEfer);\n vcxt.values[idx++].Reg64 = env->efer;\n@@ -662,6 +749,110 @@ static void whpx_get_registers_for_vmexit(CPUState *cpu, WHPXStateLevel level)\n x86_update_hflags(env);\n }\n \n+static void whpx_get_legacy_fp_registers(CPUState *cpu, WHPXStateLevel level)\n+{\n+ struct whpx_state *whpx = &whpx_global;\n+ X86CPU *x86_cpu = X86_CPU(cpu);\n+ CPUX86State *env = &x86_cpu->env;\n+ struct whpx_register_set vcxt;\n+ HRESULT hr;\n+ int i;\n+ int idx;\n+ int idx_next;\n+\n+ assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));\n+\n+ hr = whp_dispatch.WHvGetVirtualProcessorRegisters(\n+ whpx->partition, cpu->cpu_index,\n+ whpx_register_names_legacy_fp,\n+ RTL_NUMBER_OF(whpx_register_names_legacy_fp),\n+ &vcxt.values[0]);\n+\n+ if (FAILED(hr)) {\n+ error_report(\"WHPX: Failed to get virtual processor context, hr=%08lx\",\n+ hr);\n+ }\n+\n+ idx = 0;\n+ /* 16 XMM registers */\n+ assert(whpx_register_names_legacy_fp[idx] == WHvX64RegisterXmm0);\n+ idx_next = idx + 16;\n+ for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i += 1, idx += 1) {\n+ env->xmm_regs[i].ZMM_Q(0) = vcxt.values[idx].Reg128.Low64;\n+ env->xmm_regs[i].ZMM_Q(1) = vcxt.values[idx].Reg128.High64;\n+ }\n+ idx = idx_next;\n+\n+ /* 8 FP registers */\n+ assert(whpx_register_names_legacy_fp[idx] == WHvX64RegisterFpMmx0);\n+ for (i = 0; i < 8; i += 1, idx += 1) {\n+ env->fpregs[i].mmx.MMX_Q(0) = vcxt.values[idx].Fp.AsUINT128.Low64;\n+ /* env->fpregs[i].mmx.MMX_Q(1) =\n+ vcxt.values[idx].Fp.AsUINT128.High64;\n+ */\n+ }\n+\n+ /* FP control status register */\n+ assert(whpx_register_names_legacy_fp[idx] == WHvX64RegisterFpControlStatus);\n+ env->fpuc = vcxt.values[idx].FpControlStatus.FpControl;\n+ env->fpstt = (vcxt.values[idx].FpControlStatus.FpStatus >> 11) & 0x7;\n+ env->fpus = vcxt.values[idx].FpControlStatus.FpStatus & ~0x3800;\n+ for (i = 0; i < 8; ++i) {\n+ env->fptags[i] = !((vcxt.values[idx].FpControlStatus.FpTag >> i) & 1);\n+ }\n+ env->fpop = vcxt.values[idx].FpControlStatus.LastFpOp;\n+ env->fpip = vcxt.values[idx].FpControlStatus.LastFpRip;\n+ idx += 1;\n+\n+ /* XMM control status register */\n+ assert(whpx_register_names_legacy_fp[idx] == WHvX64RegisterXmmControlStatus);\n+ env->mxcsr = vcxt.values[idx].XmmControlStatus.XmmStatusControl;\n+ idx += 1;\n+}\n+\n+static int whpx_get_xsave_state(CPUState *cpu)\n+{\n+ struct whpx_state *whpx = &whpx_global;\n+ X86CPU *x86cpu = X86_CPU(cpu);\n+ CPUX86State *env = &x86cpu->env;\n+ int ret;\n+ HRESULT hr;\n+ void *xsavec_buf;\n+ const size_t page = qemu_real_host_page_size();\n+ size_t xsavec_buf_len = whpx_get_xsave_max_len();\n+ UINT32 bytes_written;\n+\n+ xsavec_buf = qemu_memalign(page, xsavec_buf_len);\n+ memset(xsavec_buf, 0, xsavec_buf_len);\n+\n+ if (!whpx_is_legacy_os()) {\n+ hr = whp_dispatch.WHvGetVirtualProcessorState(\n+ whpx->partition, cpu->cpu_index,\n+ WHvVirtualProcessorStateTypeXsaveState,\n+ xsavec_buf,\n+ xsavec_buf_len, &bytes_written);\n+ } else {\n+ hr = whp_dispatch.WHvGetVirtualProcessorXsaveState(\n+ whpx->partition, cpu->cpu_index,\n+ xsavec_buf,\n+ xsavec_buf_len, &bytes_written);\n+ }\n+ if (FAILED(hr) || bytes_written == 0) {\n+ error_report(\"failed to get xsave state: %s\", strerror(errno));\n+ return -errno;\n+ }\n+\n+ ret = decompact_xsave_area(xsavec_buf, xsavec_buf_len, env);\n+ qemu_vfree(xsavec_buf);\n+ if (ret < 0) {\n+ error_report(\"failed to decompact xsave area\");\n+ return ret;\n+ }\n+ x86_cpu_xrstor_all_areas(x86cpu, env->xsave_buf, env->xsave_buf_len);\n+\n+ return 0;\n+}\n+\n void whpx_get_registers(CPUState *cpu, WHPXStateLevel level)\n {\n struct whpx_state *whpx = &whpx_global;\n@@ -758,40 +949,11 @@ void whpx_get_registers(CPUState *cpu, WHPXStateLevel level)\n */\n whpx_get_xcrs(cpu);\n \n- /* 16 XMM registers */\n- assert(whpx_register_names[idx] == WHvX64RegisterXmm0);\n- idx_next = idx + 16;\n- for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i += 1, idx += 1) {\n- env->xmm_regs[i].ZMM_Q(0) = vcxt.values[idx].Reg128.Low64;\n- env->xmm_regs[i].ZMM_Q(1) = vcxt.values[idx].Reg128.High64;\n- }\n- idx = idx_next;\n-\n- /* 8 FP registers */\n- assert(whpx_register_names[idx] == WHvX64RegisterFpMmx0);\n- for (i = 0; i < 8; i += 1, idx += 1) {\n- env->fpregs[i].mmx.MMX_Q(0) = vcxt.values[idx].Fp.AsUINT128.Low64;\n- /* env->fpregs[i].mmx.MMX_Q(1) =\n- vcxt.values[idx].Fp.AsUINT128.High64;\n- */\n- }\n-\n- /* FP control status register */\n- assert(whpx_register_names[idx] == WHvX64RegisterFpControlStatus);\n- env->fpuc = vcxt.values[idx].FpControlStatus.FpControl;\n- env->fpstt = (vcxt.values[idx].FpControlStatus.FpStatus >> 11) & 0x7;\n- env->fpus = vcxt.values[idx].FpControlStatus.FpStatus & ~0x3800;\n- for (i = 0; i < 8; ++i) {\n- env->fptags[i] = !((vcxt.values[idx].FpControlStatus.FpTag >> i) & 1);\n+ if (whpx_is_xsave_enabled(cpu)) {\n+ whpx_get_xsave_state(cpu);\n+ } else {\n+ whpx_get_legacy_fp_registers(cpu, level);\n }\n- env->fpop = vcxt.values[idx].FpControlStatus.LastFpOp;\n- env->fpip = vcxt.values[idx].FpControlStatus.LastFpRip;\n- idx += 1;\n-\n- /* XMM control status register */\n- assert(whpx_register_names[idx] == WHvX64RegisterXmmControlStatus);\n- env->mxcsr = vcxt.values[idx].XmmControlStatus.XmmStatusControl;\n- idx += 1;\n \n /* MSRs */\n assert(whpx_register_names[idx] == WHvX64RegisterEfer);\n@@ -1525,6 +1687,9 @@ void whpx_arch_destroy_vcpu(CPUState *cpu)\n X86CPU *x86cpu = X86_CPU(cpu);\n CPUX86State *env = &x86cpu->env;\n g_free(env->emu_mmio_buf);\n+ qemu_vfree(env->xsave_buf);\n+ env->xsave_buf = NULL;\n+ env->xsave_buf_len = 0;\n }\n \n /* Returns the address of the next instruction that is about to be executed. */\n@@ -2393,6 +2558,9 @@ int whpx_init_vcpu(CPUState *cpu)\n Error *local_error = NULL;\n X86CPU *x86_cpu = X86_CPU(cpu);\n CPUX86State *env = &x86_cpu->env;\n+ X86XSaveHeader *header;\n+ size_t page_size = qemu_real_host_page_size();\n+ size_t xsave_len;\n UINT64 freq = 0;\n int ret;\n \n@@ -2469,6 +2637,15 @@ int whpx_init_vcpu(CPUState *cpu)\n qemu_add_vm_change_state_handler(whpx_cpu_update_state, env);\n \n env->emu_mmio_buf = g_new(char, 4096);\n+ /* Initialize XSAVE buffer page-aligned */\n+ xsave_len = whpx_get_xsave_max_len();\n+ env->xsave_buf = qemu_memalign(page_size, xsave_len);\n+ env->xsave_buf_len = xsave_len;\n+ memset(env->xsave_buf, 0, env->xsave_buf_len);\n+\n+ /* we need to set the compacted format bit in xsave header for Hyper-V */\n+ header = (X86XSaveHeader *)(env->xsave_buf + sizeof(X86LegacyXSaveArea));\n+ header->xcomp_bv = header->xstate_bv | (1ULL << 63);\n \n return 0;\n \n@@ -2628,10 +2805,6 @@ int whpx_accel_init(AccelState *as, MachineState *ms)\n error_report(\"WHPX: Failed to query XSAVE capability, hr=%08lx\", hr);\n }\n \n- if (!whpx_has_xsave()) {\n- printf(\"WHPX: Partition is not XSAVE capable\\n\");\n- }\n-\n memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY));\n prop.ProcessorCount = ms->smp.cpus;\n hr = whp_dispatch.WHvSetPartitionProperty(\n", "prefixes": [ "v2", "31/38" ] }