get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/2195175/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2195175,
    "url": "http://patchwork.ozlabs.org/api/patches/2195175/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260210135206.229528-15-peter.maydell@linaro.org/",
    "project": {
        "id": 14,
        "url": "http://patchwork.ozlabs.org/api/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": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20260210135206.229528-15-peter.maydell@linaro.org>",
    "list_archive_url": null,
    "date": "2026-02-10T13:51:54",
    "name": "[PULL,14/26] whpx: add arm64 support",
    "commit_ref": null,
    "pull_url": null,
    "state": "not-applicable",
    "archived": false,
    "hash": "a1b1256892919705d3b66dc2c38922bc84f8059d",
    "submitter": {
        "id": 5111,
        "url": "http://patchwork.ozlabs.org/api/people/5111/?format=api",
        "name": "Peter Maydell",
        "email": "peter.maydell@linaro.org"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260210135206.229528-15-peter.maydell@linaro.org/mbox/",
    "series": [
        {
            "id": 491680,
            "url": "http://patchwork.ozlabs.org/api/series/491680/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=491680",
            "date": "2026-02-10T13:51:40",
            "name": "[PULL,01/26] target/arm/kvm: add constants for new PSCI versions",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/491680/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2195175/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2195175/checks/",
    "tags": {},
    "related": [],
    "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=linaro.org header.i=@linaro.org header.a=rsa-sha256\n header.s=google header.b=fdcfF5Re;\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=lists.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=patchwork.ozlabs.org)"
        ],
        "Received": [
            "from lists.gnu.org (lists.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 4f9NPW2bCWz1xtr\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 11 Feb 2026 00:55:43 +1100 (AEDT)",
            "from localhost ([::1] helo=lists1p.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces@nongnu.org>)\n\tid 1vpoAH-0002Bs-QC; Tue, 10 Feb 2026 08:52:29 -0500",
            "from eggs.gnu.org ([2001:470:142:3::10])\n by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <peter.maydell@linaro.org>)\n id 1vpoAG-0002Ah-73\n for qemu-devel@nongnu.org; Tue, 10 Feb 2026 08:52:28 -0500",
            "from mail-wm1-x332.google.com ([2a00:1450:4864:20::332])\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)\n (Exim 4.90_1) (envelope-from <peter.maydell@linaro.org>)\n id 1vpoAB-0006Ll-A7\n for qemu-devel@nongnu.org; Tue, 10 Feb 2026 08:52:27 -0500",
            "by mail-wm1-x332.google.com with SMTP id\n 5b1f17b1804b1-4801eb2c0a5so53543395e9.3\n for <qemu-devel@nongnu.org>; Tue, 10 Feb 2026 05:52:21 -0800 (PST)",
            "from lanath.. (wildly.archaic.org.uk. [81.2.115.145])\n by smtp.gmail.com with ESMTPSA id\n 5b1f17b1804b1-4834d5d77f9sm64344875e9.3.2026.02.10.05.52.18\n for <qemu-devel@nongnu.org>\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Tue, 10 Feb 2026 05:52:18 -0800 (PST)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=linaro.org; s=google; t=1770731540; x=1771336340; darn=nongnu.org;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:to:from:from:to:cc:subject:date:message-id\n :reply-to; bh=+XOcY+AOu+OcMbkxBTIZN3ikLAl892hSxYanbSLcRcg=;\n b=fdcfF5RelNQ+39FGG0QB1Qb97q/hk7IduHRTOsneUqq4PxPB29xFNIuIGbtCNnvk5T\n oopT6zMOup3rhKfs1jwaEzEDVVrtzF75pZsfNZ3pg8HYViEUzpNpynrLS0R6gyzJLgut\n DoLFBliNmhvg6swf6GbxDtu8JWSxiscvIya6CFQZn4FpkjEbdoorXo7y2FjV1twNWGal\n iW75UvhKFNKWjlqpt8SUHY1zvi4QR+9RKuP7z/C+FoukEiVMLvjD/lbTvMEcS/jXx8jX\n UXDhnZhwTPGsbRrzTadSVtZby2mZjC3ERtZH1kO+52CgC4e9Z6wS5Rn1PqfNFGzuHInh\n xCXg==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20230601; t=1770731540; x=1771336340;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to\n :cc:subject:date:message-id:reply-to;\n bh=+XOcY+AOu+OcMbkxBTIZN3ikLAl892hSxYanbSLcRcg=;\n b=FS8TBlT7fC+7Rc/05uo3NOXeMtUsmG4By+OyVpSM8d4K8vM4R4U2sYkgLjiEcItOdV\n +vXrbD2wMOBQn3LOqEnlLCUA/zQ4EKBRkeIBx8OJUljuonMs+Foyttyh7pNxQI6eHorW\n tM2k9OVJhOaVqOfmQdCnsxwKDddUPTFRSugjjRpERTW7HvYaWK9pmKwQjmVgGna3r5N8\n xhJN5pFrS4kuViiDYENUf+Jrq/L0nTU2jX29OH5PaTSbr0GTkE2SCSXIV3Kg8HS/2tWi\n oGDmxh4hXKcqojjkfoIWPlWgf7qtplFQzvxiZu791moL+I9+AsNr9w0MJTiOlJsJyVJ4\n k2aQ==",
        "X-Gm-Message-State": "AOJu0YwArxM+VZZbR4PTEWc0WTv6A8kfu6RcY7IsgHf7HO5ABkogVWOD\n O7lP2BY2Ti8o/2p2P2+5EWypT9Ema4D6w0XzthrTNYnYaVLuFDlb8C/KMl2iRxnWotwjowadocs\n TdQuy",
        "X-Gm-Gg": "AZuq6aKqwEs++E/MHTDOnuHwjk5rcAjn4wZJS+JQ/7eTZ2yPZzeD0WBFDKBJjcWZVnH\n WhxjwTIuUT0tmNBzxA0/BNn9YiGylpMshbf871NIP/piklUqMxzMMUSUTnnc54TLGBc+JUgDk45\n WUP3XSGyvnZCEibb2P2y7iTy9ZMOaT3F0zH2TVLX6cIj0UgLbbv0nKyAQHDyApxWf7Zcyr6Cqr1\n ab5+rLyd2uDVJu1EUCx9njy3o8puEec9YpaZq9E0IL/L4sCiTgAcoMPcf21AbPhScMb/S2xdnY7\n VTr/viz7AKsgvFaOZEf4GcXIiOp1o13I3WZYEXYoyDzT8MX9py9WqBr8ZWFJewlybpP8TTw+dxh\n 0j02B2d0PFQnyd3JP3KLH4BcHRQrJ3WJBa6mDTUs/CfdKbe6qXtGzAXLr4iMtehW4Bkkn78s5g6\n /Diwujyc348Bxr3iww7r5lVZHtX/kxPNG6OxghILqV3FvhXadpq/17CMmA4gDHS+guLfhSJJj5J\n kv8p/e1RatPJjeEblZ4PISOByb41VQ=",
        "X-Received": "by 2002:a05:600c:3b1e:b0:483:3380:ca0c with SMTP id\n 5b1f17b1804b1-4835083456cmr33318915e9.35.1770731539716;\n Tue, 10 Feb 2026 05:52:19 -0800 (PST)",
        "From": "Peter Maydell <peter.maydell@linaro.org>",
        "To": "qemu-devel@nongnu.org",
        "Subject": "[PULL 14/26] whpx: add arm64 support",
        "Date": "Tue, 10 Feb 2026 13:51:54 +0000",
        "Message-ID": "<20260210135206.229528-15-peter.maydell@linaro.org>",
        "X-Mailer": "git-send-email 2.43.0",
        "In-Reply-To": "<20260210135206.229528-1-peter.maydell@linaro.org>",
        "References": "<20260210135206.229528-1-peter.maydell@linaro.org>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=UTF-8",
        "Content-Transfer-Encoding": "8bit",
        "Received-SPF": "pass client-ip=2a00:1450:4864:20::332;\n envelope-from=peter.maydell@linaro.org; helo=mail-wm1-x332.google.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,\n DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1,\n RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,\n 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": "From: Mohamed Mediouni <mohamed@unpredictable.fr>\n\nSigned-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>\nReviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>\nSigned-off-by: Peter Maydell <peter.maydell@linaro.org>\n---\n MAINTAINERS                 |   1 +\n accel/whpx/whpx-common.c    |   1 +\n target/arm/meson.build      |   1 +\n target/arm/whpx/meson.build |   3 +\n target/arm/whpx/whpx-all.c  | 810 ++++++++++++++++++++++++++++++++++++\n 5 files changed, 816 insertions(+)\n create mode 100644 target/arm/whpx/meson.build\n create mode 100644 target/arm/whpx/whpx-all.c",
    "diff": "diff --git a/MAINTAINERS b/MAINTAINERS\nindex c6af6e10bb..5cdfea7e11 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -566,6 +566,7 @@ M: Mohamed Mediouni <mohamed@unpredictable.fr>\n S: Supported\n F: accel/whpx/\n F: target/i386/whpx/\n+F: target/arm/whpx/\n F: hw/intc/arm_gicv3_whpx.c\n F: accel/stubs/whpx-stub.c\n F: include/system/whpx.h\ndiff --git a/accel/whpx/whpx-common.c b/accel/whpx/whpx-common.c\nindex 05f9e520b7..827f50f3e0 100644\n--- a/accel/whpx/whpx-common.c\n+++ b/accel/whpx/whpx-common.c\n@@ -12,6 +12,7 @@\n #include \"gdbstub/helpers.h\"\n #include \"qemu/accel.h\"\n #include \"accel/accel-ops.h\"\n+#include \"system/memory.h\"\n #include \"system/whpx.h\"\n #include \"system/cpus.h\"\n #include \"system/runstate.h\"\ndiff --git a/target/arm/meson.build b/target/arm/meson.build\nindex 1a1bcde260..fe396c4318 100644\n--- a/target/arm/meson.build\n+++ b/target/arm/meson.build\n@@ -59,6 +59,7 @@ arm_common_system_ss.add(files(\n ))\n \n subdir('hvf')\n+subdir('whpx')\n \n if 'CONFIG_TCG' in config_all_accel\n    subdir('tcg')\ndiff --git a/target/arm/whpx/meson.build b/target/arm/whpx/meson.build\nnew file mode 100644\nindex 0000000000..1de2ef0283\n--- /dev/null\n+++ b/target/arm/whpx/meson.build\n@@ -0,0 +1,3 @@\n+arm_system_ss.add(when: 'CONFIG_WHPX', if_true: files(\n+  'whpx-all.c',\n+))\ndiff --git a/target/arm/whpx/whpx-all.c b/target/arm/whpx/whpx-all.c\nnew file mode 100644\nindex 0000000000..192d7ec7a8\n--- /dev/null\n+++ b/target/arm/whpx/whpx-all.c\n@@ -0,0 +1,810 @@\n+/* SPDX-License-Identifier: GPL-2.0-or-later */\n+/*\n+ * QEMU Windows Hypervisor Platform accelerator (WHPX)\n+ *\n+ * Copyright (c) 2025 Mohamed Mediouni\n+ *\n+ */\n+\n+#include \"qemu/osdep.h\"\n+#include \"cpu.h\"\n+#include \"system/address-spaces.h\"\n+#include \"system/ioport.h\"\n+#include \"gdbstub/helpers.h\"\n+#include \"qemu/accel.h\"\n+#include \"accel/accel-ops.h\"\n+#include \"system/whpx.h\"\n+#include \"system/cpus.h\"\n+#include \"system/runstate.h\"\n+#include \"qemu/main-loop.h\"\n+#include \"hw/core/boards.h\"\n+#include \"qemu/error-report.h\"\n+#include \"qapi/error.h\"\n+#include \"qapi/qapi-types-common.h\"\n+#include \"qapi/qapi-visit-common.h\"\n+#include \"migration/blocker.h\"\n+#include \"accel/accel-cpu-target.h\"\n+#include <winerror.h>\n+\n+#include \"syndrome.h\"\n+#include \"cpu.h\"\n+#include \"target/arm/cpregs.h\"\n+#include \"internals.h\"\n+\n+#include \"system/whpx-internal.h\"\n+#include \"system/whpx-accel-ops.h\"\n+#include \"system/whpx-all.h\"\n+#include \"system/whpx-common.h\"\n+#include \"hw/arm/bsa.h\"\n+#include \"arm-powerctl.h\"\n+\n+#include <winhvplatform.h>\n+#include <winhvplatformdefs.h>\n+\n+typedef struct WHPXRegMatch {\n+   WHV_REGISTER_NAME reg;\n+   uint64_t offset;\n+} WHPXRegMatch;\n+\n+static const WHPXRegMatch whpx_reg_match[] = {\n+    { WHvArm64RegisterX0,   offsetof(CPUARMState, xregs[0]) },\n+    { WHvArm64RegisterX1,   offsetof(CPUARMState, xregs[1]) },\n+    { WHvArm64RegisterX2,   offsetof(CPUARMState, xregs[2]) },\n+    { WHvArm64RegisterX3,   offsetof(CPUARMState, xregs[3]) },\n+    { WHvArm64RegisterX4,   offsetof(CPUARMState, xregs[4]) },\n+    { WHvArm64RegisterX5,   offsetof(CPUARMState, xregs[5]) },\n+    { WHvArm64RegisterX6,   offsetof(CPUARMState, xregs[6]) },\n+    { WHvArm64RegisterX7,   offsetof(CPUARMState, xregs[7]) },\n+    { WHvArm64RegisterX8,   offsetof(CPUARMState, xregs[8]) },\n+    { WHvArm64RegisterX9,   offsetof(CPUARMState, xregs[9]) },\n+    { WHvArm64RegisterX10,  offsetof(CPUARMState, xregs[10]) },\n+    { WHvArm64RegisterX11,  offsetof(CPUARMState, xregs[11]) },\n+    { WHvArm64RegisterX12,  offsetof(CPUARMState, xregs[12]) },\n+    { WHvArm64RegisterX13,  offsetof(CPUARMState, xregs[13]) },\n+    { WHvArm64RegisterX14,  offsetof(CPUARMState, xregs[14]) },\n+    { WHvArm64RegisterX15,  offsetof(CPUARMState, xregs[15]) },\n+    { WHvArm64RegisterX16,  offsetof(CPUARMState, xregs[16]) },\n+    { WHvArm64RegisterX17,  offsetof(CPUARMState, xregs[17]) },\n+    { WHvArm64RegisterX18,  offsetof(CPUARMState, xregs[18]) },\n+    { WHvArm64RegisterX19,  offsetof(CPUARMState, xregs[19]) },\n+    { WHvArm64RegisterX20,  offsetof(CPUARMState, xregs[20]) },\n+    { WHvArm64RegisterX21,  offsetof(CPUARMState, xregs[21]) },\n+    { WHvArm64RegisterX22,  offsetof(CPUARMState, xregs[22]) },\n+    { WHvArm64RegisterX23,  offsetof(CPUARMState, xregs[23]) },\n+    { WHvArm64RegisterX24,  offsetof(CPUARMState, xregs[24]) },\n+    { WHvArm64RegisterX25,  offsetof(CPUARMState, xregs[25]) },\n+    { WHvArm64RegisterX26,  offsetof(CPUARMState, xregs[26]) },\n+    { WHvArm64RegisterX27,  offsetof(CPUARMState, xregs[27]) },\n+    { WHvArm64RegisterX28,  offsetof(CPUARMState, xregs[28]) },\n+    { WHvArm64RegisterFp,   offsetof(CPUARMState, xregs[29]) },\n+    { WHvArm64RegisterLr,   offsetof(CPUARMState, xregs[30]) },\n+    { WHvArm64RegisterPc,   offsetof(CPUARMState, pc) },\n+};\n+\n+static const WHPXRegMatch whpx_fpreg_match[] = {\n+    { WHvArm64RegisterQ0,  offsetof(CPUARMState, vfp.zregs[0]) },\n+    { WHvArm64RegisterQ1,  offsetof(CPUARMState, vfp.zregs[1]) },\n+    { WHvArm64RegisterQ2,  offsetof(CPUARMState, vfp.zregs[2]) },\n+    { WHvArm64RegisterQ3,  offsetof(CPUARMState, vfp.zregs[3]) },\n+    { WHvArm64RegisterQ4,  offsetof(CPUARMState, vfp.zregs[4]) },\n+    { WHvArm64RegisterQ5,  offsetof(CPUARMState, vfp.zregs[5]) },\n+    { WHvArm64RegisterQ6,  offsetof(CPUARMState, vfp.zregs[6]) },\n+    { WHvArm64RegisterQ7,  offsetof(CPUARMState, vfp.zregs[7]) },\n+    { WHvArm64RegisterQ8,  offsetof(CPUARMState, vfp.zregs[8]) },\n+    { WHvArm64RegisterQ9,  offsetof(CPUARMState, vfp.zregs[9]) },\n+    { WHvArm64RegisterQ10, offsetof(CPUARMState, vfp.zregs[10]) },\n+    { WHvArm64RegisterQ11, offsetof(CPUARMState, vfp.zregs[11]) },\n+    { WHvArm64RegisterQ12, offsetof(CPUARMState, vfp.zregs[12]) },\n+    { WHvArm64RegisterQ13, offsetof(CPUARMState, vfp.zregs[13]) },\n+    { WHvArm64RegisterQ14, offsetof(CPUARMState, vfp.zregs[14]) },\n+    { WHvArm64RegisterQ15, offsetof(CPUARMState, vfp.zregs[15]) },\n+    { WHvArm64RegisterQ16, offsetof(CPUARMState, vfp.zregs[16]) },\n+    { WHvArm64RegisterQ17, offsetof(CPUARMState, vfp.zregs[17]) },\n+    { WHvArm64RegisterQ18, offsetof(CPUARMState, vfp.zregs[18]) },\n+    { WHvArm64RegisterQ19, offsetof(CPUARMState, vfp.zregs[19]) },\n+    { WHvArm64RegisterQ20, offsetof(CPUARMState, vfp.zregs[20]) },\n+    { WHvArm64RegisterQ21, offsetof(CPUARMState, vfp.zregs[21]) },\n+    { WHvArm64RegisterQ22, offsetof(CPUARMState, vfp.zregs[22]) },\n+    { WHvArm64RegisterQ23, offsetof(CPUARMState, vfp.zregs[23]) },\n+    { WHvArm64RegisterQ24, offsetof(CPUARMState, vfp.zregs[24]) },\n+    { WHvArm64RegisterQ25, offsetof(CPUARMState, vfp.zregs[25]) },\n+    { WHvArm64RegisterQ26, offsetof(CPUARMState, vfp.zregs[26]) },\n+    { WHvArm64RegisterQ27, offsetof(CPUARMState, vfp.zregs[27]) },\n+    { WHvArm64RegisterQ28, offsetof(CPUARMState, vfp.zregs[28]) },\n+    { WHvArm64RegisterQ29, offsetof(CPUARMState, vfp.zregs[29]) },\n+    { WHvArm64RegisterQ30, offsetof(CPUARMState, vfp.zregs[30]) },\n+    { WHvArm64RegisterQ31, offsetof(CPUARMState, vfp.zregs[31]) },\n+};\n+\n+struct whpx_sreg_match {\n+    WHV_REGISTER_NAME reg;\n+    uint32_t key;\n+    bool global;\n+    uint32_t cp_idx;\n+};\n+\n+static struct whpx_sreg_match whpx_sreg_match[] = {\n+    { WHvArm64RegisterDbgbvr0El1, ENCODE_AA64_CP_REG(0, 0, 2, 0, 4) },\n+    { WHvArm64RegisterDbgbcr0El1, ENCODE_AA64_CP_REG(0, 0, 2, 0, 5) },\n+    { WHvArm64RegisterDbgwvr0El1, ENCODE_AA64_CP_REG(0, 0, 2, 0, 6) },\n+    { WHvArm64RegisterDbgwcr0El1, ENCODE_AA64_CP_REG(0, 0, 2, 0, 7) },\n+\n+    { WHvArm64RegisterDbgbvr0El1, ENCODE_AA64_CP_REG(0, 1, 2, 0, 4) },\n+    { WHvArm64RegisterDbgbcr0El1, ENCODE_AA64_CP_REG(0, 1, 2, 0, 5) },\n+    { WHvArm64RegisterDbgwvr0El1, ENCODE_AA64_CP_REG(0, 1, 2, 0, 6) },\n+    { WHvArm64RegisterDbgwcr0El1, ENCODE_AA64_CP_REG(0, 1, 2, 0, 7) },\n+\n+    { WHvArm64RegisterDbgbvr2El1, ENCODE_AA64_CP_REG(0, 2, 2, 0, 4) },\n+    { WHvArm64RegisterDbgbcr2El1, ENCODE_AA64_CP_REG(0, 2, 2, 0, 5) },\n+    { WHvArm64RegisterDbgwvr2El1, ENCODE_AA64_CP_REG(0, 2, 2, 0, 6) },\n+    { WHvArm64RegisterDbgwcr2El1, ENCODE_AA64_CP_REG(0, 2, 2, 0, 7) },\n+\n+    { WHvArm64RegisterDbgbvr3El1, ENCODE_AA64_CP_REG(0, 3, 2, 0, 4) },\n+    { WHvArm64RegisterDbgbcr3El1, ENCODE_AA64_CP_REG(0, 3, 2, 0, 5) },\n+    { WHvArm64RegisterDbgwvr3El1, ENCODE_AA64_CP_REG(0, 3, 2, 0, 6) },\n+    { WHvArm64RegisterDbgwcr3El1, ENCODE_AA64_CP_REG(0, 3, 2, 0, 7) },\n+\n+    { WHvArm64RegisterDbgbvr4El1, ENCODE_AA64_CP_REG(0, 4, 2, 0, 4) },\n+    { WHvArm64RegisterDbgbcr4El1, ENCODE_AA64_CP_REG(0, 4, 2, 0, 5) },\n+    { WHvArm64RegisterDbgwvr4El1, ENCODE_AA64_CP_REG(0, 4, 2, 0, 6) },\n+    { WHvArm64RegisterDbgwcr4El1, ENCODE_AA64_CP_REG(0, 4, 2, 0, 7) },\n+\n+    { WHvArm64RegisterDbgbvr5El1, ENCODE_AA64_CP_REG(0, 5, 2, 0, 4) },\n+    { WHvArm64RegisterDbgbcr5El1, ENCODE_AA64_CP_REG(0, 5, 2, 0, 5) },\n+    { WHvArm64RegisterDbgwvr5El1, ENCODE_AA64_CP_REG(0, 5, 2, 0, 6) },\n+    { WHvArm64RegisterDbgwcr5El1, ENCODE_AA64_CP_REG(0, 5, 2, 0, 7) },\n+\n+    { WHvArm64RegisterDbgbvr6El1, ENCODE_AA64_CP_REG(0, 6, 2, 0, 4) },\n+    { WHvArm64RegisterDbgbcr6El1, ENCODE_AA64_CP_REG(0, 6, 2, 0, 5) },\n+    { WHvArm64RegisterDbgwvr6El1, ENCODE_AA64_CP_REG(0, 6, 2, 0, 6) },\n+    { WHvArm64RegisterDbgwcr6El1, ENCODE_AA64_CP_REG(0, 6, 2, 0, 7) },\n+\n+    { WHvArm64RegisterDbgbvr7El1, ENCODE_AA64_CP_REG(0, 7, 2, 0, 4) },\n+    { WHvArm64RegisterDbgbcr7El1, ENCODE_AA64_CP_REG(0, 7, 2, 0, 5) },\n+    { WHvArm64RegisterDbgwvr7El1, ENCODE_AA64_CP_REG(0, 7, 2, 0, 6) },\n+    { WHvArm64RegisterDbgwcr7El1, ENCODE_AA64_CP_REG(0, 7, 2, 0, 7) },\n+\n+    { WHvArm64RegisterDbgbvr8El1, ENCODE_AA64_CP_REG(0, 8, 2, 0, 4) },\n+    { WHvArm64RegisterDbgbcr8El1, ENCODE_AA64_CP_REG(0, 8, 2, 0, 5) },\n+    { WHvArm64RegisterDbgwvr8El1, ENCODE_AA64_CP_REG(0, 8, 2, 0, 6) },\n+    { WHvArm64RegisterDbgwcr8El1, ENCODE_AA64_CP_REG(0, 8, 2, 0, 7) },\n+\n+    { WHvArm64RegisterDbgbvr9El1, ENCODE_AA64_CP_REG(0, 9, 2, 0, 4) },\n+    { WHvArm64RegisterDbgbcr9El1, ENCODE_AA64_CP_REG(0, 9, 2, 0, 5) },\n+    { WHvArm64RegisterDbgwvr9El1, ENCODE_AA64_CP_REG(0, 9, 2, 0, 6) },\n+    { WHvArm64RegisterDbgwcr9El1, ENCODE_AA64_CP_REG(0, 9, 2, 0, 7) },\n+\n+    { WHvArm64RegisterDbgbvr10El1, ENCODE_AA64_CP_REG(0, 10, 2, 0, 4) },\n+    { WHvArm64RegisterDbgbcr10El1, ENCODE_AA64_CP_REG(0, 10, 2, 0, 5) },\n+    { WHvArm64RegisterDbgwvr10El1, ENCODE_AA64_CP_REG(0, 10, 2, 0, 6) },\n+    { WHvArm64RegisterDbgwcr10El1, ENCODE_AA64_CP_REG(0, 10, 2, 0, 7) },\n+\n+    { WHvArm64RegisterDbgbvr11El1, ENCODE_AA64_CP_REG(0, 11, 2, 0, 4) },\n+    { WHvArm64RegisterDbgbcr11El1, ENCODE_AA64_CP_REG(0, 11, 2, 0, 5) },\n+    { WHvArm64RegisterDbgwvr11El1, ENCODE_AA64_CP_REG(0, 11, 2, 0, 6) },\n+    { WHvArm64RegisterDbgwcr11El1, ENCODE_AA64_CP_REG(0, 11, 2, 0, 7) },\n+\n+    { WHvArm64RegisterDbgbvr12El1, ENCODE_AA64_CP_REG(0, 12, 2, 0, 4) },\n+    { WHvArm64RegisterDbgbcr12El1, ENCODE_AA64_CP_REG(0, 12, 2, 0, 5) },\n+    { WHvArm64RegisterDbgwvr12El1, ENCODE_AA64_CP_REG(0, 12, 2, 0, 6) },\n+    { WHvArm64RegisterDbgwcr12El1, ENCODE_AA64_CP_REG(0, 12, 2, 0, 7) },\n+\n+    { WHvArm64RegisterDbgbvr13El1, ENCODE_AA64_CP_REG(0, 13, 2, 0, 4) },\n+    { WHvArm64RegisterDbgbcr13El1, ENCODE_AA64_CP_REG(0, 13, 2, 0, 5) },\n+    { WHvArm64RegisterDbgwvr13El1, ENCODE_AA64_CP_REG(0, 13, 2, 0, 6) },\n+    { WHvArm64RegisterDbgwcr13El1, ENCODE_AA64_CP_REG(0, 13, 2, 0, 7) },\n+\n+    { WHvArm64RegisterDbgbvr14El1, ENCODE_AA64_CP_REG(0, 14, 2, 0, 4) },\n+    { WHvArm64RegisterDbgbcr14El1, ENCODE_AA64_CP_REG(0, 14, 2, 0, 5) },\n+    { WHvArm64RegisterDbgwvr14El1, ENCODE_AA64_CP_REG(0, 14, 2, 0, 6) },\n+    { WHvArm64RegisterDbgwcr14El1, ENCODE_AA64_CP_REG(0, 14, 2, 0, 7) },\n+\n+    { WHvArm64RegisterDbgbvr15El1, ENCODE_AA64_CP_REG(0, 15, 2, 0, 4) },\n+    { WHvArm64RegisterDbgbcr15El1, ENCODE_AA64_CP_REG(0, 15, 2, 0, 5) },\n+    { WHvArm64RegisterDbgwvr15El1, ENCODE_AA64_CP_REG(0, 15, 2, 0, 6) },\n+    { WHvArm64RegisterDbgwcr15El1, ENCODE_AA64_CP_REG(0, 15, 2, 0, 7) },\n+#ifdef SYNC_NO_RAW_REGS\n+    /*\n+     * The registers below are manually synced on init because they are\n+     * marked as NO_RAW. We still list them to make number space sync easier.\n+     */\n+    { WHvArm64RegisterMidrEl1, ENCODE_AA64_CP_REG(0, 0, 3, 0, 0) },\n+    { WHvArm64RegisterMpidrEl1, ENCODE_AA64_CP_REG(0, 0, 3, 0, 5) },\n+    { WHvArm64RegisterIdPfr0El1, ENCODE_AA64_CP_REG(0, 4, 3, 0, 0) },\n+#endif\n+    { WHvArm64RegisterIdAa64Pfr1El1, ENCODE_AA64_CP_REG(0, 4, 3, 0, 1), true },\n+    { WHvArm64RegisterIdAa64Dfr0El1, ENCODE_AA64_CP_REG(0, 5, 3, 0, 0), true },\n+    { WHvArm64RegisterIdAa64Dfr1El1, ENCODE_AA64_CP_REG(0, 5, 3, 0, 1), true },\n+    { WHvArm64RegisterIdAa64Isar0El1, ENCODE_AA64_CP_REG(0, 6, 3, 0, 0), true },\n+    { WHvArm64RegisterIdAa64Isar1El1, ENCODE_AA64_CP_REG(0, 6, 3, 0, 1), true },\n+#ifdef SYNC_NO_MMFR0\n+    /* We keep the hardware MMFR0 around. HW limits are there anyway */\n+    { WHvArm64RegisterIdAa64Mmfr0El1, ENCODE_AA64_CP_REG(0, 7, 3, 0, 0) },\n+#endif\n+    { WHvArm64RegisterIdAa64Mmfr1El1, ENCODE_AA64_CP_REG(0, 7, 3, 0, 1), true },\n+    { WHvArm64RegisterIdAa64Mmfr2El1, ENCODE_AA64_CP_REG(0, 7, 3, 0, 2), true },\n+    { WHvArm64RegisterIdAa64Mmfr3El1, ENCODE_AA64_CP_REG(0, 7, 3, 0, 3), true },\n+\n+    { WHvArm64RegisterMdscrEl1, ENCODE_AA64_CP_REG(0, 2, 2, 0, 2) },\n+    { WHvArm64RegisterSctlrEl1, ENCODE_AA64_CP_REG(1, 0, 3, 0, 0) },\n+    { WHvArm64RegisterCpacrEl1, ENCODE_AA64_CP_REG(1, 0, 3, 0, 2) },\n+    { WHvArm64RegisterTtbr0El1, ENCODE_AA64_CP_REG(2, 0, 3, 0, 0) },\n+    { WHvArm64RegisterTtbr1El1, ENCODE_AA64_CP_REG(2, 0, 3, 0, 1) },\n+    { WHvArm64RegisterTcrEl1, ENCODE_AA64_CP_REG(2, 0, 3, 0, 2) },\n+\n+    { WHvArm64RegisterApiAKeyLoEl1, ENCODE_AA64_CP_REG(2, 1, 3, 0, 0) },\n+    { WHvArm64RegisterApiAKeyHiEl1, ENCODE_AA64_CP_REG(2, 1, 3, 0, 1) },\n+    { WHvArm64RegisterApiBKeyLoEl1, ENCODE_AA64_CP_REG(2, 1, 3, 0, 2) },\n+    { WHvArm64RegisterApiBKeyHiEl1, ENCODE_AA64_CP_REG(2, 1, 3, 0, 3) },\n+    { WHvArm64RegisterApdAKeyLoEl1, ENCODE_AA64_CP_REG(2, 2, 3, 0, 0) },\n+    { WHvArm64RegisterApdAKeyHiEl1, ENCODE_AA64_CP_REG(2, 2, 3, 0, 1) },\n+    { WHvArm64RegisterApdBKeyLoEl1, ENCODE_AA64_CP_REG(2, 2, 3, 0, 2) },\n+    { WHvArm64RegisterApdBKeyHiEl1, ENCODE_AA64_CP_REG(2, 2, 3, 0, 3) },\n+    { WHvArm64RegisterApgAKeyLoEl1, ENCODE_AA64_CP_REG(2, 3, 3, 0, 0) },\n+    { WHvArm64RegisterApgAKeyHiEl1, ENCODE_AA64_CP_REG(2, 3, 3, 0, 1) },\n+\n+    { WHvArm64RegisterSpsrEl1, ENCODE_AA64_CP_REG(4, 0, 3, 0, 0) },\n+    { WHvArm64RegisterElrEl1, ENCODE_AA64_CP_REG(4, 0, 3, 0, 1) },\n+    { WHvArm64RegisterSpEl1, ENCODE_AA64_CP_REG(4, 1, 3, 0, 0) },\n+    { WHvArm64RegisterEsrEl1, ENCODE_AA64_CP_REG(5, 2, 3, 0, 0) },\n+    { WHvArm64RegisterFarEl1, ENCODE_AA64_CP_REG(6, 0, 3, 0, 0) },\n+    { WHvArm64RegisterParEl1, ENCODE_AA64_CP_REG(7, 4, 3, 0, 0) },\n+    { WHvArm64RegisterMairEl1, ENCODE_AA64_CP_REG(10, 2, 3, 0, 0) },\n+    { WHvArm64RegisterVbarEl1, ENCODE_AA64_CP_REG(12, 0, 3, 0, 0) },\n+    { WHvArm64RegisterContextidrEl1, ENCODE_AA64_CP_REG(13, 0, 3, 0, 1) },\n+    { WHvArm64RegisterTpidrEl1, ENCODE_AA64_CP_REG(13, 0, 3, 0, 4) },\n+    { WHvArm64RegisterCntkctlEl1, ENCODE_AA64_CP_REG(14, 1, 3, 0, 0) },\n+    { WHvArm64RegisterCsselrEl1, ENCODE_AA64_CP_REG(0, 0, 3, 2, 0) },\n+    { WHvArm64RegisterTpidrEl0, ENCODE_AA64_CP_REG(13, 0, 3, 3, 2) },\n+    { WHvArm64RegisterTpidrroEl0, ENCODE_AA64_CP_REG(13, 0, 3, 3, 3) },\n+    { WHvArm64RegisterCntvCtlEl0, ENCODE_AA64_CP_REG(14, 3, 3, 3, 1) },\n+    { WHvArm64RegisterCntvCvalEl0, ENCODE_AA64_CP_REG(14, 3, 3, 3, 2) },\n+    { WHvArm64RegisterSpEl1, ENCODE_AA64_CP_REG(4, 1, 3, 4, 0) },\n+};\n+\n+static void flush_cpu_state(CPUState *cpu)\n+{\n+    if (cpu->vcpu_dirty) {\n+        whpx_set_registers(cpu, WHPX_SET_RUNTIME_STATE);\n+        cpu->vcpu_dirty = false;\n+    }\n+}\n+\n+HRESULT whpx_set_exception_exit_bitmap(UINT64 exceptions)\n+{\n+    if (exceptions != 0) {\n+        return E_NOTIMPL;\n+    }\n+    return ERROR_SUCCESS;\n+}\n+void whpx_apply_breakpoints(\n+    struct whpx_breakpoint_collection *breakpoints,\n+    CPUState *cpu,\n+    bool resuming)\n+{\n+    /* Breakpoints aren’t supported on this platform */\n+}\n+void whpx_translate_cpu_breakpoints(\n+    struct whpx_breakpoints *breakpoints,\n+    CPUState *cpu,\n+    int cpu_breakpoint_count)\n+{\n+    /* Breakpoints aren’t supported on this platform */\n+}\n+\n+static void whpx_get_reg(CPUState *cpu, WHV_REGISTER_NAME reg, WHV_REGISTER_VALUE* val)\n+{\n+    struct whpx_state *whpx = &whpx_global;\n+    HRESULT hr;\n+\n+    flush_cpu_state(cpu);\n+\n+    hr = whp_dispatch.WHvGetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index,\n+         &reg, 1, val);\n+\n+    if (FAILED(hr)) {\n+        error_report(\"WHPX: Failed to get register %08x, hr=%08lx\", reg, hr);\n+    }\n+}\n+\n+static void whpx_set_reg(CPUState *cpu, WHV_REGISTER_NAME reg, WHV_REGISTER_VALUE val)\n+{\n+    struct whpx_state *whpx = &whpx_global;\n+    HRESULT hr;\n+    hr = whp_dispatch.WHvSetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index,\n+         &reg, 1, &val);\n+\n+    if (FAILED(hr)) {\n+        error_report(\"WHPX: Failed to set register %08x, hr=%08lx\", reg, hr);\n+    }\n+}\n+\n+static void whpx_get_global_reg(WHV_REGISTER_NAME reg, WHV_REGISTER_VALUE *val)\n+{\n+    struct whpx_state *whpx = &whpx_global;\n+    HRESULT hr;\n+\n+    hr = whp_dispatch.WHvGetVirtualProcessorRegisters(whpx->partition, WHV_ANY_VP,\n+         &reg, 1, val);\n+\n+    if (FAILED(hr)) {\n+        error_report(\"WHPX: Failed to get register %08x, hr=%08lx\", reg, hr);\n+    }\n+}\n+\n+static void whpx_set_global_reg(WHV_REGISTER_NAME reg, WHV_REGISTER_VALUE val)\n+{\n+    struct whpx_state *whpx = &whpx_global;\n+    HRESULT hr;\n+    hr = whp_dispatch.WHvSetVirtualProcessorRegisters(whpx->partition, WHV_ANY_VP,\n+         &reg, 1, &val);\n+\n+    if (FAILED(hr)) {\n+        error_report(\"WHPX: Failed to set register %08x, hr=%08lx\", reg, hr);\n+    }\n+}\n+\n+static uint64_t whpx_get_gp_reg(CPUState *cpu, int rt)\n+{\n+    assert(rt <= 31);\n+    if (rt == 31) {\n+        return 0;\n+    }\n+    WHV_REGISTER_NAME reg = WHvArm64RegisterX0 + rt;\n+    WHV_REGISTER_VALUE val;\n+    whpx_get_reg(cpu, reg, &val);\n+\n+    return val.Reg64;\n+}\n+\n+static void whpx_set_gp_reg(CPUState *cpu, int rt, uint64_t val)\n+{\n+    assert(rt < 31);\n+    WHV_REGISTER_NAME reg = WHvArm64RegisterX0 + rt;\n+    WHV_REGISTER_VALUE reg_val = {.Reg64 = val};\n+\n+    whpx_set_reg(cpu, reg, reg_val);\n+}\n+\n+static int whpx_handle_mmio(CPUState *cpu, WHV_MEMORY_ACCESS_CONTEXT *ctx)\n+{\n+    uint64_t syndrome = ctx->Syndrome;\n+\n+    bool isv = syndrome & ARM_EL_ISV;\n+    bool iswrite = (syndrome >> 6) & 1;\n+    bool sse = (syndrome >> 21) & 1;\n+    uint32_t sas = (syndrome >> 22) & 3;\n+    uint32_t len = 1 << sas;\n+    uint32_t srt = (syndrome >> 16) & 0x1f;\n+    uint32_t cm = (syndrome >> 8) & 0x1;\n+    uint64_t val = 0;\n+\n+    assert(!cm);\n+    assert(isv);\n+\n+    if (iswrite) {\n+        val = whpx_get_gp_reg(cpu, srt);\n+        address_space_write(&address_space_memory,\n+                            ctx->Gpa,\n+                            MEMTXATTRS_UNSPECIFIED, &val, len);\n+    } else {\n+        address_space_read(&address_space_memory,\n+                           ctx->Gpa,\n+                           MEMTXATTRS_UNSPECIFIED, &val, len);\n+        if (sse) {\n+            val = sextract64(val, 0, len * 8);\n+        }\n+        whpx_set_gp_reg(cpu, srt, val);\n+    }\n+\n+    return 0;\n+}\n+\n+static void whpx_psci_cpu_off(ARMCPU *arm_cpu)\n+{\n+    int32_t ret = arm_set_cpu_off(arm_cpu_mp_affinity(arm_cpu));\n+    assert(ret == QEMU_ARM_POWERCTL_RET_SUCCESS);\n+}\n+\n+int whpx_vcpu_run(CPUState *cpu)\n+{\n+    HRESULT hr;\n+    struct whpx_state *whpx = &whpx_global;\n+    ARMCPU *arm_cpu = ARM_CPU(cpu);\n+    AccelCPUState *vcpu = cpu->accel;\n+    int ret;\n+\n+\n+    g_assert(bql_locked());\n+\n+    if (whpx->running_cpus++ == 0) {\n+        ret = whpx_first_vcpu_starting(cpu);\n+        if (ret != 0) {\n+            return ret;\n+        }\n+    }\n+\n+    bql_unlock();\n+\n+\n+    cpu_exec_start(cpu);\n+    do {\n+        bool advance_pc = false;\n+        if (cpu->vcpu_dirty) {\n+            whpx_set_registers(cpu, WHPX_SET_RUNTIME_STATE);\n+            cpu->vcpu_dirty = false;\n+        }\n+\n+        if (qatomic_read(&cpu->exit_request)) {\n+            whpx_vcpu_kick(cpu);\n+        }\n+\n+        hr = whp_dispatch.WHvRunVirtualProcessor(\n+            whpx->partition, cpu->cpu_index,\n+            &vcpu->exit_ctx, sizeof(vcpu->exit_ctx));\n+\n+        if (FAILED(hr)) {\n+            error_report(\"WHPX: Failed to exec a virtual processor,\"\n+                         \" hr=%08lx\", hr);\n+            ret = -1;\n+            break;\n+        }\n+\n+        switch (vcpu->exit_ctx.ExitReason) {\n+        case WHvRunVpExitReasonGpaIntercept:\n+        case WHvRunVpExitReasonUnmappedGpa:\n+            advance_pc = true;\n+\n+            if (vcpu->exit_ctx.MemoryAccess.Syndrome & BIT(8)) {\n+                error_report(\"WHPX: cached access to unmapped memory\"\n+                \"Pc = 0x%llx Gva = 0x%llx Gpa = 0x%llx\",\n+                vcpu->exit_ctx.MemoryAccess.Header.Pc,\n+                vcpu->exit_ctx.MemoryAccess.Gpa,\n+                vcpu->exit_ctx.MemoryAccess.Gva);\n+                break;\n+            }\n+\n+            ret = whpx_handle_mmio(cpu, &vcpu->exit_ctx.MemoryAccess);\n+            break;\n+        case WHvRunVpExitReasonCanceled:\n+            cpu->exception_index = EXCP_INTERRUPT;\n+            ret = 1;\n+            break;\n+        case WHvRunVpExitReasonArm64Reset:\n+            switch (vcpu->exit_ctx.Arm64Reset.ResetType) {\n+            case WHvArm64ResetTypePowerOff:\n+                qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);\n+                break;\n+            case WHvArm64ResetTypeReboot:\n+                qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);\n+                break;\n+            default:\n+                g_assert_not_reached();\n+            }\n+            bql_lock();\n+            if (arm_cpu->power_state != PSCI_OFF) {\n+                whpx_psci_cpu_off(arm_cpu);\n+            }\n+            bql_unlock();\n+            break;\n+        case WHvRunVpExitReasonNone:\n+        case WHvRunVpExitReasonUnrecoverableException:\n+        case WHvRunVpExitReasonInvalidVpRegisterValue:\n+        case WHvRunVpExitReasonUnsupportedFeature:\n+        default:\n+            error_report(\"WHPX: Unexpected VP exit code 0x%08x\",\n+                         vcpu->exit_ctx.ExitReason);\n+            whpx_get_registers(cpu);\n+            bql_lock();\n+            qemu_system_guest_panicked(cpu_get_crash_info(cpu));\n+            bql_unlock();\n+            break;\n+        }\n+        if (advance_pc) {\n+            WHV_REGISTER_VALUE pc;\n+\n+            flush_cpu_state(cpu);\n+            pc.Reg64 = vcpu->exit_ctx.MemoryAccess.Header.Pc + 4;\n+            whpx_set_reg(cpu, WHvArm64RegisterPc, pc);\n+        }\n+    } while (!ret);\n+\n+    cpu_exec_end(cpu);\n+\n+    bql_lock();\n+    current_cpu = cpu;\n+\n+    if (--whpx->running_cpus == 0) {\n+        whpx_last_vcpu_stopping(cpu);\n+    }\n+\n+    qatomic_set(&cpu->exit_request, false);\n+\n+    return ret < 0;\n+}\n+\n+static void clean_whv_register_value(WHV_REGISTER_VALUE *val)\n+{\n+    memset(val, 0, sizeof(WHV_REGISTER_VALUE));\n+}\n+\n+void whpx_get_registers(CPUState *cpu)\n+{\n+    ARMCPU *arm_cpu = ARM_CPU(cpu);\n+    CPUARMState *env = &arm_cpu->env;\n+    WHV_REGISTER_VALUE val;\n+    int i;\n+\n+    for (i = 0; i < ARRAY_SIZE(whpx_reg_match); i++) {\n+        whpx_get_reg(cpu, whpx_reg_match[i].reg, &val);\n+        *(uint64_t *)((char *)env + whpx_reg_match[i].offset) = val.Reg64;\n+    }\n+\n+    for (i = 0; i < ARRAY_SIZE(whpx_fpreg_match); i++) {\n+        whpx_get_reg(cpu, whpx_reg_match[i].reg, &val);\n+        memcpy((char *)env + whpx_fpreg_match[i].offset, &val, sizeof(val.Reg128));\n+    }\n+\n+    whpx_get_reg(cpu, WHvArm64RegisterPc, &val);\n+    env->pc = val.Reg64;\n+\n+    whpx_get_reg(cpu, WHvArm64RegisterFpcr, &val);\n+    vfp_set_fpcr(env, val.Reg32);\n+\n+    whpx_get_reg(cpu, WHvArm64RegisterFpsr, &val);\n+    vfp_set_fpsr(env, val.Reg32);\n+\n+    whpx_get_reg(cpu, WHvArm64RegisterPstate, &val);\n+    pstate_write(env, val.Reg32);\n+\n+    for (i = 0; i < ARRAY_SIZE(whpx_sreg_match); i++) {\n+        if (whpx_sreg_match[i].cp_idx == -1) {\n+            continue;\n+        }\n+\n+        if (whpx_sreg_match[i].global) {\n+            /* WHP disallows us from accessing global regs as a vCPU */\n+            whpx_get_global_reg(whpx_sreg_match[i].reg, &val);\n+        } else {\n+            whpx_get_reg(cpu, whpx_sreg_match[i].reg, &val);\n+        }\n+        arm_cpu->cpreg_values[whpx_sreg_match[i].cp_idx] = val.Reg64;\n+    }\n+\n+    assert(write_list_to_cpustate(arm_cpu));\n+    aarch64_restore_sp(env, arm_current_el(env));\n+}\n+\n+void whpx_set_registers(CPUState *cpu, int level)\n+{\n+    ARMCPU *arm_cpu = ARM_CPU(cpu);\n+    CPUARMState *env = &arm_cpu->env;\n+    WHV_REGISTER_VALUE val;\n+    clean_whv_register_value(&val);\n+    int i;\n+\n+    assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));\n+\n+    for (i = 0; i < ARRAY_SIZE(whpx_reg_match); i++) {\n+        val.Reg64 = *(uint64_t *)((char *)env + whpx_reg_match[i].offset);\n+        whpx_set_reg(cpu, whpx_reg_match[i].reg, val);\n+    }\n+\n+    for (i = 0; i < ARRAY_SIZE(whpx_fpreg_match); i++) {\n+        memcpy(&val.Reg128, (char *)env + whpx_fpreg_match[i].offset, sizeof(val.Reg128));\n+        whpx_set_reg(cpu, whpx_reg_match[i].reg, val);\n+    }\n+\n+    clean_whv_register_value(&val);\n+    val.Reg64 = env->pc;\n+    whpx_set_reg(cpu, WHvArm64RegisterPc, val);\n+\n+    clean_whv_register_value(&val);\n+    val.Reg32 = vfp_get_fpcr(env);\n+    whpx_set_reg(cpu, WHvArm64RegisterFpcr, val);\n+    val.Reg32 = vfp_get_fpsr(env);\n+    whpx_set_reg(cpu, WHvArm64RegisterFpsr, val);\n+    val.Reg32 = pstate_read(env);\n+    whpx_set_reg(cpu, WHvArm64RegisterPstate, val);\n+\n+    aarch64_save_sp(env, arm_current_el(env));\n+\n+    assert(write_cpustate_to_list(arm_cpu, false));\n+\n+    /* Currently set global regs every time. */\n+    for (i = 0; i < ARRAY_SIZE(whpx_sreg_match); i++) {\n+        if (whpx_sreg_match[i].cp_idx == -1) {\n+            continue;\n+        }\n+\n+        val.Reg64 = arm_cpu->cpreg_values[whpx_sreg_match[i].cp_idx];\n+        if (whpx_sreg_match[i].global) {\n+            /* WHP disallows us from accessing global regs as a vCPU */\n+            whpx_set_global_reg(whpx_sreg_match[i].reg, val);\n+        } else {\n+            whpx_set_reg(cpu, whpx_sreg_match[i].reg, val);\n+        }\n+    }\n+}\n+\n+static uint32_t max_vcpu_index;\n+\n+static void whpx_cpu_update_state(void *opaque, bool running, RunState state)\n+{\n+}\n+\n+int whpx_init_vcpu(CPUState *cpu)\n+{\n+    HRESULT hr;\n+    struct whpx_state *whpx = &whpx_global;\n+    ARMCPU *arm_cpu = ARM_CPU(cpu);\n+    CPUARMState *env = &arm_cpu->env;\n+\n+    uint32_t sregs_match_len = ARRAY_SIZE(whpx_sreg_match);\n+    uint32_t sregs_cnt = 0;\n+    WHV_REGISTER_VALUE val;\n+    int i;\n+\n+    hr = whp_dispatch.WHvCreateVirtualProcessor(\n+        whpx->partition, cpu->cpu_index, 0);\n+    if (FAILED(hr)) {\n+        error_report(\"WHPX: Failed to create a virtual processor,\"\n+                     \" hr=%08lx\", hr);\n+        return -EINVAL;\n+    }\n+\n+    /* Assumption that CNTFRQ_EL0 is the same between the VMM and the partition. */\n+    asm volatile(\"mrs %0, cntfrq_el0\" : \"=r\"(arm_cpu->gt_cntfrq_hz));\n+\n+    cpu->vcpu_dirty = true;\n+    cpu->accel = g_new0(AccelCPUState, 1);\n+    max_vcpu_index = MAX(max_vcpu_index, cpu->cpu_index);\n+    qemu_add_vm_change_state_handler(whpx_cpu_update_state, env);\n+\n+    env->aarch64 = true;\n+\n+    /* Allocate enough space for our sysreg sync */\n+    arm_cpu->cpreg_indexes = g_renew(uint64_t, arm_cpu->cpreg_indexes,\n+                                     sregs_match_len);\n+    arm_cpu->cpreg_values = g_renew(uint64_t, arm_cpu->cpreg_values,\n+                                    sregs_match_len);\n+    arm_cpu->cpreg_vmstate_indexes = g_renew(uint64_t,\n+                                             arm_cpu->cpreg_vmstate_indexes,\n+                                             sregs_match_len);\n+    arm_cpu->cpreg_vmstate_values = g_renew(uint64_t,\n+                                            arm_cpu->cpreg_vmstate_values,\n+                                            sregs_match_len);\n+\n+    memset(arm_cpu->cpreg_values, 0, sregs_match_len * sizeof(uint64_t));\n+\n+    /* Populate cp list for all known sysregs */\n+    for (i = 0; i < sregs_match_len; i++) {\n+        const ARMCPRegInfo *ri;\n+        uint32_t key = whpx_sreg_match[i].key;\n+\n+        ri = get_arm_cp_reginfo(arm_cpu->cp_regs, key);\n+        if (ri) {\n+            assert(!(ri->type & ARM_CP_NO_RAW));\n+            whpx_sreg_match[i].cp_idx = sregs_cnt;\n+            arm_cpu->cpreg_indexes[sregs_cnt++] = cpreg_to_kvm_id(key);\n+        } else {\n+            whpx_sreg_match[i].cp_idx = -1;\n+        }\n+    }\n+    arm_cpu->cpreg_array_len = sregs_cnt;\n+    arm_cpu->cpreg_vmstate_array_len = sregs_cnt;\n+\n+    assert(write_cpustate_to_list(arm_cpu, false));\n+\n+    /* Set CP_NO_RAW system registers on init */\n+    val.Reg64 = arm_cpu->midr;\n+    whpx_set_reg(cpu, WHvArm64RegisterMidrEl1,\n+                              val);\n+\n+    clean_whv_register_value(&val);\n+\n+    val.Reg64 = deposit64(arm_cpu->mp_affinity, 31, 1, 1 /* RES1 */);\n+    whpx_set_reg(cpu, WHvArm64RegisterMpidrEl1, val);\n+\n+    return 0;\n+}\n+\n+void whpx_cpu_instance_init(CPUState *cs)\n+{\n+}\n+\n+int whpx_accel_init(AccelState *as, MachineState *ms)\n+{\n+    struct whpx_state *whpx;\n+    int ret;\n+    HRESULT hr;\n+    WHV_CAPABILITY whpx_cap;\n+    UINT32 whpx_cap_size;\n+    WHV_PARTITION_PROPERTY prop;\n+    WHV_CAPABILITY_FEATURES features;\n+\n+    whpx = &whpx_global;\n+    /* on arm64 Windows Hypervisor Platform, vGICv3 always used */\n+    whpx_irqchip_in_kernel = true;\n+\n+    if (!init_whp_dispatch()) {\n+        ret = -ENOSYS;\n+        goto error;\n+    }\n+\n+    whpx->mem_quota = ms->ram_size;\n+\n+    hr = whp_dispatch.WHvGetCapability(\n+        WHvCapabilityCodeHypervisorPresent, &whpx_cap,\n+        sizeof(whpx_cap), &whpx_cap_size);\n+    if (FAILED(hr) || !whpx_cap.HypervisorPresent) {\n+        error_report(\"WHPX: No accelerator found, hr=%08lx\", hr);\n+        ret = -ENOSPC;\n+        goto error;\n+    }\n+\n+    memset(&features, 0, sizeof(features));\n+    hr = whp_dispatch.WHvGetCapability(\n+        WHvCapabilityCodeFeatures, &features, sizeof(features), NULL);\n+    if (FAILED(hr)) {\n+        error_report(\"WHPX: Failed to query capabilities, hr=%08lx\", hr);\n+        ret = -EINVAL;\n+        goto error;\n+    }\n+\n+    if (!features.Arm64Support) {\n+        error_report(\"WHPX: host OS exposing pre-release WHPX implementation. \"\n+            \"Please update your operating system to at least build 26100.3915\");\n+        ret = -EINVAL;\n+        goto error;\n+    }\n+\n+    hr = whp_dispatch.WHvCreatePartition(&whpx->partition);\n+    if (FAILED(hr)) {\n+        error_report(\"WHPX: Failed to create partition, hr=%08lx\", hr);\n+        ret = -EINVAL;\n+        goto error;\n+    }\n+\n+    memset(&prop, 0, sizeof(prop));\n+    prop.ProcessorCount = ms->smp.cpus;\n+    hr = whp_dispatch.WHvSetPartitionProperty(\n+        whpx->partition,\n+        WHvPartitionPropertyCodeProcessorCount,\n+        &prop,\n+        sizeof(prop));\n+\n+    if (FAILED(hr)) {\n+        error_report(\"WHPX: Failed to set partition processor count to %u,\"\n+                     \" hr=%08lx\", prop.ProcessorCount, hr);\n+        ret = -EINVAL;\n+        goto error;\n+    }\n+\n+    if (!whpx->kernel_irqchip_allowed) {\n+        error_report(\"WHPX: on Arm, only kernel-irqchip=on is currently supported\");\n+        ret = -EINVAL;\n+        goto error;\n+    }\n+\n+    memset(&prop, 0, sizeof(prop));\n+\n+    hr = whp_dispatch.WHvSetupPartition(whpx->partition);\n+    if (FAILED(hr)) {\n+        error_report(\"WHPX: Failed to setup partition, hr=%08lx\", hr);\n+        ret = -EINVAL;\n+        goto error;\n+    }\n+\n+    whpx_memory_init();\n+\n+    return 0;\n+\n+error:\n+    if (whpx->partition != NULL) {\n+        whp_dispatch.WHvDeletePartition(whpx->partition);\n+        whpx->partition = NULL;\n+    }\n+\n+    return ret;\n+}\n",
    "prefixes": [
        "PULL",
        "14/26"
    ]
}