Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2195172/?format=api
{ "id": 2195172, "url": "http://patchwork.ozlabs.org/api/patches/2195172/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260210135206.229528-11-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-11-peter.maydell@linaro.org>", "list_archive_url": null, "date": "2026-02-10T13:51:50", "name": "[PULL,10/26] whpx: reshuffle common code", "commit_ref": null, "pull_url": null, "state": "not-applicable", "archived": false, "hash": "63c7eb95e964f7ea4bfd41aba4034d619059be09", "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-11-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/2195172/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2195172/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=GnlS9FTS;\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 4f9NNq3yvWz1xtr\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 11 Feb 2026 00:55:07 +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 1vpoAG-0002Aj-Ch; Tue, 10 Feb 2026 08:52:28 -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 1vpoAB-00021K-HS\n for qemu-devel@nongnu.org; Tue, 10 Feb 2026 08:52:23 -0500", "from mail-wm1-x329.google.com ([2a00:1450:4864:20::329])\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 1vpoA6-0006L0-4q\n for qemu-devel@nongnu.org; Tue, 10 Feb 2026 08:52:21 -0500", "by mail-wm1-x329.google.com with SMTP id\n 5b1f17b1804b1-4806f3fc50bso47910585e9.0\n for <qemu-devel@nongnu.org>; Tue, 10 Feb 2026 05:52:17 -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.15\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:15 -0800 (PST)" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=linaro.org; s=google; t=1770731536; x=1771336336; 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=LHRt76DpiTUXu+oYqus89Ea8WBq2OqReifFSpohvo54=;\n b=GnlS9FTS4/wEEHr7DvUAjLWgX7fYT1qrH4SNi91usONZJapmr/NGS57aPuCd/jYFu8\n Otm7HnUo0Y32Z4iUJhLPOKjjkM9Znb/0mmUAmO1CFTJbZHn6610WEErGCmEYt1TRflrn\n r8dWujmSIHyMO6RcoHGZgSzDxRDTGQfQMy1nnZyB9zqlvgK+WrsoYxuzNLDaQDsLK40m\n joeHZwJlWSHgc3j6uraKC5cNNqjmEq+V6N+SSu+fzTkyOiaKK8LblWv5+25iOFJKSfq0\n Yn8meMhtqaXGEveEr8ElXGTHnud9Jfp2WbZytg/2DXjnU56rT2dmIh+TDzEt3EbjnaQs\n APpg==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20230601; t=1770731536; x=1771336336;\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=LHRt76DpiTUXu+oYqus89Ea8WBq2OqReifFSpohvo54=;\n b=FvkdYk6HpoFUSWOeJuONlEfp7a+41gc5ANbL1aepqipmz44FwYoss7rpnfc0JBrloj\n zevwp9/v497mLOyU7IaO0YYsjeh+iCmS6e8hAYqi3liBQv+8S1mxGfv9A8ztK7HwYY4u\n Qti+Kb9riwni9Wvan47br9PFtnN76tLv7xkyNKbgtptLN61Nw3oM/UpEF4ZDmCWX3ii5\n Bd47NwItbnseVS9F49NAYJoLKqWJwM2YxFGUz2C+Awcd47QNJ7EfoLgARklxgoxgKBxk\n yWDsNMTjH14D5ROfdD5tcf7YlmmGqKIsvaeoCpNQ9YCjjebpFx/N/QE8kxEaHf7DpNlm\n yW+g==", "X-Gm-Message-State": "AOJu0YxEp0mSKcvMtazlkSvjynJ3DnP1FY+QiyD4jc45+TAXbaE1pCVS\n mPF+lWBAUuNMaepFOKebLMb4xGq4uqEIZ8l/htNypZEM75663mzWfTn9xYwmgU+93X36EwYUQu1\n vV15N", "X-Gm-Gg": "AZuq6aJTKoVYLoMOnYFioLtiE+TqmRPW9M/5Mh9dGkyJe+irOjD07u3n95FgrXRkXTj\n zcW+Fl7xSeg0fPgLigcfGkRb+yZnMUJSELMRTNWKtVD5q2lQq6A6pPxCrDiJ3j2NoPVH/Qbxzd5\n +pneqYtP+z/TASjrVnigVlfUea3M3ioJBgy3Y+iAhSZddxS3w9kcJS1A50I/ODqan9SfiJVs+zS\n oCToglwJVqlvhkS+s1Kuu5/Eg7MyIpSFxtaBDDakWUtA3tF+gN2CtdHzzBNtuukezz3UDkPAL3u\n CCRJAUzg3QI/OWt3haouiDtQHzsjz5OMF5Kh3Is4U9Gqv2pS0lViVkZXRLsWA4FOhDIjrGw9dEJ\n w3k4pJi6wodRP5NXJ4aLP5U1pMPAa9fWvOxWs64NBDeB4irL6k7TDfL2IM1U37blnzZCeSuzDbO\n S8nUWLIDxwBSJyWuqY0L0hwxczqkhH/87Ir/rwS+sHLKR5m0JbDRbUMWbamd+4XCdCt9owjrA1I\n f4Jm+j15ZTp112NodH/a505bWVXhJM=", "X-Received": "by 2002:a05:600c:19c7:b0:480:1e9e:f9d with SMTP id\n 5b1f17b1804b1-483201db0bcmr222865225e9.8.1770731536144;\n Tue, 10 Feb 2026 05:52:16 -0800 (PST)", "From": "Peter Maydell <peter.maydell@linaro.org>", "To": "qemu-devel@nongnu.org", "Subject": "[PULL 10/26] whpx: reshuffle common code", "Date": "Tue, 10 Feb 2026 13:51:50 +0000", "Message-ID": "<20260210135206.229528-11-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-Transfer-Encoding": "8bit", "Received-SPF": "pass client-ip=2a00:1450:4864:20::329;\n envelope-from=peter.maydell@linaro.org; helo=mail-wm1-x329.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\nSome code can be shared between x86_64 and arm64 WHPX. Do so as much as reasonable.\n\nSigned-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>\n\nReviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>\nReviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>\nSigned-off-by: Peter Maydell <peter.maydell@linaro.org>\n---\n MAINTAINERS | 2 +\n accel/whpx/meson.build | 1 +\n accel/whpx/whpx-common.c | 558 +++++++++++++++++++++++++++++++++++\n include/system/whpx-all.h | 20 ++\n include/system/whpx-common.h | 21 ++\n target/i386/whpx/whpx-all.c | 551 +---------------------------------\n 6 files changed, 612 insertions(+), 541 deletions(-)\n create mode 100644 accel/whpx/whpx-common.c\n create mode 100644 include/system/whpx-all.h\n create mode 100644 include/system/whpx-common.h", "diff": "diff --git a/MAINTAINERS b/MAINTAINERS\nindex 3a0fe1081a..54326b1a5a 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -569,6 +569,8 @@ F: target/i386/whpx/\n F: accel/stubs/whpx-stub.c\n F: include/system/whpx.h\n F: include/system/whpx-accel-ops.h\n+F: include/system/whpx-common.h\n+F: include/system/whpx-internal.h\n \n MSHV\n M: Magnus Kulke <magnus.kulke@linux.microsoft.com>\ndiff --git a/accel/whpx/meson.build b/accel/whpx/meson.build\nindex 7b3d6f1c1c..fad28dddcb 100644\n--- a/accel/whpx/meson.build\n+++ b/accel/whpx/meson.build\n@@ -1,6 +1,7 @@\n whpx_ss = ss.source_set()\n whpx_ss.add(files(\n 'whpx-accel-ops.c',\n+ 'whpx-common.c'\n ))\n \n specific_ss.add_all(when: 'CONFIG_WHPX', if_true: whpx_ss)\ndiff --git a/accel/whpx/whpx-common.c b/accel/whpx/whpx-common.c\nnew file mode 100644\nindex 0000000000..0a6068fdde\n--- /dev/null\n+++ b/accel/whpx/whpx-common.c\n@@ -0,0 +1,558 @@\n+/* SPDX-License-Identifier: GPL-2.0-or-later */\n+/*\n+ * QEMU Windows Hypervisor Platform accelerator (WHPX)\n+ *\n+ * Copyright Microsoft Corp. 2017\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 \"hw/intc/ioapic.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 \"system/whpx-internal.h\"\n+#include \"system/whpx-accel-ops.h\"\n+#include \"system/whpx-common.h\"\n+#include \"system/whpx-all.h\"\n+\n+#include <winhvplatform.h>\n+#include <winhvplatformdefs.h>\n+\n+bool whpx_allowed;\n+static bool whp_dispatch_initialized;\n+static HMODULE hWinHvPlatform;\n+static HMODULE hWinHvEmulation;\n+\n+struct whpx_state whpx_global;\n+struct WHPDispatch whp_dispatch;\n+\n+/* Tries to find a breakpoint at the specified address. */\n+struct whpx_breakpoint *whpx_lookup_breakpoint_by_addr(uint64_t address)\n+{\n+ struct whpx_state *whpx = &whpx_global;\n+ int i;\n+\n+ if (whpx->breakpoints.breakpoints) {\n+ for (i = 0; i < whpx->breakpoints.breakpoints->used; i++) {\n+ if (address == whpx->breakpoints.breakpoints->data[i].address) {\n+ return &whpx->breakpoints.breakpoints->data[i];\n+ }\n+ }\n+ }\n+\n+ return NULL;\n+}\n+\n+/*\n+ * This function is called when the a VCPU is about to start and no other\n+ * VCPUs have been started so far. Since the VCPU start order could be\n+ * arbitrary, it doesn't have to be VCPU#0.\n+ *\n+ * It is used to commit the breakpoints into memory, and configure WHPX\n+ * to intercept debug exceptions.\n+ *\n+ * Note that whpx_set_exception_exit_bitmap() cannot be called if one or\n+ * more VCPUs are already running, so this is the best place to do it.\n+ */\n+int whpx_first_vcpu_starting(CPUState *cpu)\n+{\n+ struct whpx_state *whpx = &whpx_global;\n+\n+ g_assert(bql_locked());\n+\n+ if (!QTAILQ_EMPTY(&cpu->breakpoints) ||\n+ (whpx->breakpoints.breakpoints &&\n+ whpx->breakpoints.breakpoints->used)) {\n+ CPUBreakpoint *bp;\n+ int i = 0;\n+ bool update_pending = false;\n+\n+ QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {\n+ if (i >= whpx->breakpoints.original_address_count ||\n+ bp->pc != whpx->breakpoints.original_addresses[i]) {\n+ update_pending = true;\n+ }\n+\n+ i++;\n+ }\n+\n+ if (i != whpx->breakpoints.original_address_count) {\n+ update_pending = true;\n+ }\n+\n+ if (update_pending) {\n+ /*\n+ * The CPU breakpoints have changed since the last call to\n+ * whpx_translate_cpu_breakpoints(). WHPX breakpoints must\n+ * now be recomputed.\n+ */\n+ whpx_translate_cpu_breakpoints(&whpx->breakpoints, cpu, i);\n+ }\n+ /* Actually insert the breakpoints into the memory. */\n+ whpx_apply_breakpoints(whpx->breakpoints.breakpoints, cpu, true);\n+ }\n+ HRESULT hr;\n+ uint64_t exception_mask;\n+ if (whpx->step_pending ||\n+ (whpx->breakpoints.breakpoints &&\n+ whpx->breakpoints.breakpoints->used)) {\n+ /*\n+ * We are either attempting to single-step one or more CPUs, or\n+ * have one or more breakpoints enabled. Both require intercepting\n+ * the WHvX64ExceptionTypeBreakpointTrap exception.\n+ */\n+ exception_mask = 1UL << WHvX64ExceptionTypeDebugTrapOrFault;\n+ } else {\n+ /* Let the guest handle all exceptions. */\n+ exception_mask = 0;\n+ }\n+ hr = whpx_set_exception_exit_bitmap(exception_mask);\n+ if (!SUCCEEDED(hr)) {\n+ error_report(\"WHPX: Failed to update exception exit mask,\"\n+ \"hr=%08lx.\", hr);\n+ return 1;\n+ }\n+ return 0;\n+}\n+\n+/*\n+ * This function is called when the last VCPU has finished running.\n+ * It is used to remove any previously set breakpoints from memory.\n+ */\n+int whpx_last_vcpu_stopping(CPUState *cpu)\n+{\n+ whpx_apply_breakpoints(whpx_global.breakpoints.breakpoints, cpu, false);\n+ return 0;\n+}\n+\n+static void do_whpx_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)\n+{\n+ if (!cpu->vcpu_dirty) {\n+ whpx_get_registers(cpu);\n+ cpu->vcpu_dirty = true;\n+ }\n+}\n+\n+static void do_whpx_cpu_synchronize_post_reset(CPUState *cpu,\n+ run_on_cpu_data arg)\n+{\n+ whpx_set_registers(cpu, WHPX_SET_RESET_STATE);\n+ cpu->vcpu_dirty = false;\n+}\n+\n+static void do_whpx_cpu_synchronize_post_init(CPUState *cpu,\n+ run_on_cpu_data arg)\n+{\n+ whpx_set_registers(cpu, WHPX_SET_FULL_STATE);\n+ cpu->vcpu_dirty = false;\n+}\n+\n+static void do_whpx_cpu_synchronize_pre_loadvm(CPUState *cpu,\n+ run_on_cpu_data arg)\n+{\n+ cpu->vcpu_dirty = true;\n+}\n+\n+/*\n+ * CPU support.\n+ */\n+\n+void whpx_cpu_synchronize_state(CPUState *cpu)\n+{\n+ if (!cpu->vcpu_dirty) {\n+ run_on_cpu(cpu, do_whpx_cpu_synchronize_state, RUN_ON_CPU_NULL);\n+ }\n+}\n+\n+void whpx_cpu_synchronize_post_reset(CPUState *cpu)\n+{\n+ run_on_cpu(cpu, do_whpx_cpu_synchronize_post_reset, RUN_ON_CPU_NULL);\n+}\n+\n+void whpx_cpu_synchronize_post_init(CPUState *cpu)\n+{\n+ run_on_cpu(cpu, do_whpx_cpu_synchronize_post_init, RUN_ON_CPU_NULL);\n+}\n+\n+void whpx_cpu_synchronize_pre_loadvm(CPUState *cpu)\n+{\n+ run_on_cpu(cpu, do_whpx_cpu_synchronize_pre_loadvm, RUN_ON_CPU_NULL);\n+}\n+\n+static void whpx_pre_resume_vm(AccelState *as, bool step_pending)\n+{\n+ whpx_global.step_pending = step_pending;\n+}\n+\n+/*\n+ * Vcpu support.\n+ */\n+\n+int whpx_vcpu_exec(CPUState *cpu)\n+{\n+ int ret;\n+ int fatal;\n+\n+ for (;;) {\n+ if (cpu->exception_index >= EXCP_INTERRUPT) {\n+ ret = cpu->exception_index;\n+ cpu->exception_index = -1;\n+ break;\n+ }\n+\n+ fatal = whpx_vcpu_run(cpu);\n+\n+ if (fatal) {\n+ error_report(\"WHPX: Failed to exec a virtual processor\");\n+ abort();\n+ }\n+ }\n+\n+ return ret;\n+}\n+\n+void whpx_destroy_vcpu(CPUState *cpu)\n+{\n+ struct whpx_state *whpx = &whpx_global;\n+\n+ whp_dispatch.WHvDeleteVirtualProcessor(whpx->partition, cpu->cpu_index);\n+ AccelCPUState *vcpu = cpu->accel;\n+ whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator);\n+ g_free(cpu->accel);\n+}\n+\n+\n+void whpx_vcpu_kick(CPUState *cpu)\n+{\n+ struct whpx_state *whpx = &whpx_global;\n+ whp_dispatch.WHvCancelRunVirtualProcessor(\n+ whpx->partition, cpu->cpu_index, 0);\n+}\n+\n+/*\n+ * Memory support.\n+ */\n+\n+static void whpx_update_mapping(hwaddr start_pa, ram_addr_t size,\n+ void *host_va, int add, int rom,\n+ const char *name)\n+{\n+ struct whpx_state *whpx = &whpx_global;\n+ HRESULT hr;\n+\n+ /*\n+ if (add) {\n+ printf(\"WHPX: ADD PA:%p Size:%p, Host:%p, %s, '%s'\\n\",\n+ (void*)start_pa, (void*)size, host_va,\n+ (rom ? \"ROM\" : \"RAM\"), name);\n+ } else {\n+ printf(\"WHPX: DEL PA:%p Size:%p, Host:%p, '%s'\\n\",\n+ (void*)start_pa, (void*)size, host_va, name);\n+ }\n+ */\n+\n+ if (add) {\n+ hr = whp_dispatch.WHvMapGpaRange(whpx->partition,\n+ host_va,\n+ start_pa,\n+ size,\n+ (WHvMapGpaRangeFlagRead |\n+ WHvMapGpaRangeFlagExecute |\n+ (rom ? 0 : WHvMapGpaRangeFlagWrite)));\n+ } else {\n+ hr = whp_dispatch.WHvUnmapGpaRange(whpx->partition,\n+ start_pa,\n+ size);\n+ }\n+\n+ if (FAILED(hr)) {\n+ error_report(\"WHPX: Failed to %s GPA range '%s' PA:%p, Size:%p bytes,\"\n+ \" Host:%p, hr=%08lx\",\n+ (add ? \"MAP\" : \"UNMAP\"), name,\n+ (void *)(uintptr_t)start_pa, (void *)size, host_va, hr);\n+ }\n+}\n+\n+static void whpx_process_section(MemoryRegionSection *section, int add)\n+{\n+ MemoryRegion *mr = section->mr;\n+ hwaddr start_pa = section->offset_within_address_space;\n+ ram_addr_t size = int128_get64(section->size);\n+ unsigned int delta;\n+ uint64_t host_va;\n+\n+ if (!memory_region_is_ram(mr)) {\n+ return;\n+ }\n+\n+ delta = qemu_real_host_page_size() - (start_pa & ~qemu_real_host_page_mask());\n+ delta &= ~qemu_real_host_page_mask();\n+ if (delta > size) {\n+ return;\n+ }\n+ start_pa += delta;\n+ size -= delta;\n+ size &= qemu_real_host_page_mask();\n+ if (!size || (start_pa & ~qemu_real_host_page_mask())) {\n+ return;\n+ }\n+\n+ host_va = (uintptr_t)memory_region_get_ram_ptr(mr)\n+ + section->offset_within_region + delta;\n+\n+ whpx_update_mapping(start_pa, size, (void *)(uintptr_t)host_va, add,\n+ memory_region_is_rom(mr), mr->name);\n+}\n+\n+static void whpx_region_add(MemoryListener *listener,\n+ MemoryRegionSection *section)\n+{\n+ memory_region_ref(section->mr);\n+ whpx_process_section(section, 1);\n+}\n+\n+static void whpx_region_del(MemoryListener *listener,\n+ MemoryRegionSection *section)\n+{\n+ whpx_process_section(section, 0);\n+ memory_region_unref(section->mr);\n+}\n+\n+static void whpx_transaction_begin(MemoryListener *listener)\n+{\n+}\n+\n+static void whpx_transaction_commit(MemoryListener *listener)\n+{\n+}\n+\n+static void whpx_log_sync(MemoryListener *listener,\n+ MemoryRegionSection *section)\n+{\n+ MemoryRegion *mr = section->mr;\n+\n+ if (!memory_region_is_ram(mr)) {\n+ return;\n+ }\n+\n+ memory_region_set_dirty(mr, 0, int128_get64(section->size));\n+}\n+\n+static MemoryListener whpx_memory_listener = {\n+ .name = \"whpx\",\n+ .begin = whpx_transaction_begin,\n+ .commit = whpx_transaction_commit,\n+ .region_add = whpx_region_add,\n+ .region_del = whpx_region_del,\n+ .log_sync = whpx_log_sync,\n+ .priority = MEMORY_LISTENER_PRIORITY_ACCEL,\n+};\n+\n+void whpx_memory_init(void)\n+{\n+ memory_listener_register(&whpx_memory_listener, &address_space_memory);\n+}\n+\n+/*\n+ * Load the functions from the given library, using the given handle. If a\n+ * handle is provided, it is used, otherwise the library is opened. The\n+ * handle will be updated on return with the opened one.\n+ */\n+static bool load_whp_dispatch_fns(HMODULE *handle,\n+ WHPFunctionList function_list)\n+{\n+ HMODULE hLib = *handle;\n+\n+ #define WINHV_PLATFORM_DLL \"WinHvPlatform.dll\"\n+ #define WINHV_EMULATION_DLL \"WinHvEmulation.dll\"\n+ #define WHP_LOAD_FIELD_OPTIONAL(return_type, function_name, signature) \\\n+ whp_dispatch.function_name = \\\n+ (function_name ## _t)GetProcAddress(hLib, #function_name); \\\n+\n+ #define WHP_LOAD_FIELD(return_type, function_name, signature) \\\n+ whp_dispatch.function_name = \\\n+ (function_name ## _t)GetProcAddress(hLib, #function_name); \\\n+ if (!whp_dispatch.function_name) { \\\n+ error_report(\"Could not load function %s\", #function_name); \\\n+ goto error; \\\n+ } \\\n+\n+ #define WHP_LOAD_LIB(lib_name, handle_lib) \\\n+ if (!handle_lib) { \\\n+ handle_lib = LoadLibrary(lib_name); \\\n+ if (!handle_lib) { \\\n+ error_report(\"Could not load library %s.\", lib_name); \\\n+ goto error; \\\n+ } \\\n+ } \\\n+\n+ switch (function_list) {\n+ case WINHV_PLATFORM_FNS_DEFAULT:\n+ WHP_LOAD_LIB(WINHV_PLATFORM_DLL, hLib)\n+ LIST_WINHVPLATFORM_FUNCTIONS(WHP_LOAD_FIELD)\n+ break;\n+ case WINHV_EMULATION_FNS_DEFAULT:\n+ WHP_LOAD_LIB(WINHV_EMULATION_DLL, hLib)\n+ LIST_WINHVEMULATION_FUNCTIONS(WHP_LOAD_FIELD)\n+ break;\n+ case WINHV_PLATFORM_FNS_SUPPLEMENTAL:\n+ WHP_LOAD_LIB(WINHV_PLATFORM_DLL, hLib)\n+ LIST_WINHVPLATFORM_FUNCTIONS_SUPPLEMENTAL(WHP_LOAD_FIELD_OPTIONAL)\n+ break;\n+ }\n+\n+ *handle = hLib;\n+ return true;\n+\n+error:\n+ if (hLib) {\n+ FreeLibrary(hLib);\n+ }\n+\n+ return false;\n+}\n+\n+static void whpx_set_kernel_irqchip(Object *obj, Visitor *v,\n+ const char *name, void *opaque,\n+ Error **errp)\n+{\n+ struct whpx_state *whpx = &whpx_global;\n+ OnOffSplit mode;\n+\n+ if (!visit_type_OnOffSplit(v, name, &mode, errp)) {\n+ return;\n+ }\n+\n+ switch (mode) {\n+ case ON_OFF_SPLIT_ON:\n+ whpx->kernel_irqchip_allowed = true;\n+ whpx->kernel_irqchip_required = true;\n+ break;\n+\n+ case ON_OFF_SPLIT_OFF:\n+ whpx->kernel_irqchip_allowed = false;\n+ whpx->kernel_irqchip_required = false;\n+ break;\n+\n+ case ON_OFF_SPLIT_SPLIT:\n+ error_setg(errp, \"WHPX: split irqchip currently not supported\");\n+ error_append_hint(errp,\n+ \"Try without kernel-irqchip or with kernel-irqchip=on|off\");\n+ break;\n+\n+ default:\n+ /*\n+ * The value was checked in visit_type_OnOffSplit() above. If\n+ * we get here, then something is wrong in QEMU.\n+ */\n+ abort();\n+ }\n+}\n+\n+static void whpx_cpu_accel_class_init(ObjectClass *oc, const void *data)\n+{\n+ AccelCPUClass *acc = ACCEL_CPU_CLASS(oc);\n+\n+ acc->cpu_instance_init = whpx_cpu_instance_init;\n+}\n+\n+static const TypeInfo whpx_cpu_accel_type = {\n+ .name = ACCEL_CPU_NAME(\"whpx\"),\n+\n+ .parent = TYPE_ACCEL_CPU,\n+ .class_init = whpx_cpu_accel_class_init,\n+ .abstract = true,\n+};\n+\n+/*\n+ * Partition support\n+ */\n+\n+bool whpx_apic_in_platform(void)\n+{\n+ return whpx_global.apic_in_platform;\n+}\n+\n+static void whpx_accel_class_init(ObjectClass *oc, const void *data)\n+{\n+ AccelClass *ac = ACCEL_CLASS(oc);\n+ ac->name = \"WHPX\";\n+ ac->init_machine = whpx_accel_init;\n+ ac->pre_resume_vm = whpx_pre_resume_vm;\n+ ac->allowed = &whpx_allowed;\n+\n+ object_class_property_add(oc, \"kernel-irqchip\", \"on|off|split\",\n+ NULL, whpx_set_kernel_irqchip,\n+ NULL, NULL);\n+ object_class_property_set_description(oc, \"kernel-irqchip\",\n+ \"Configure WHPX in-kernel irqchip\");\n+}\n+\n+static void whpx_accel_instance_init(Object *obj)\n+{\n+ struct whpx_state *whpx = &whpx_global;\n+\n+ memset(whpx, 0, sizeof(struct whpx_state));\n+ /* Turn on kernel-irqchip, by default */\n+ whpx->kernel_irqchip_allowed = true;\n+}\n+\n+static const TypeInfo whpx_accel_type = {\n+ .name = ACCEL_CLASS_NAME(\"whpx\"),\n+ .parent = TYPE_ACCEL,\n+ .instance_init = whpx_accel_instance_init,\n+ .class_init = whpx_accel_class_init,\n+};\n+\n+static void whpx_type_init(void)\n+{\n+ type_register_static(&whpx_accel_type);\n+ type_register_static(&whpx_cpu_accel_type);\n+}\n+\n+bool init_whp_dispatch(void)\n+{\n+ if (whp_dispatch_initialized) {\n+ return true;\n+ }\n+\n+ if (!load_whp_dispatch_fns(&hWinHvPlatform, WINHV_PLATFORM_FNS_DEFAULT)) {\n+ goto error;\n+ }\n+\n+ if (!load_whp_dispatch_fns(&hWinHvEmulation, WINHV_EMULATION_FNS_DEFAULT)) {\n+ goto error;\n+ }\n+\n+ assert(load_whp_dispatch_fns(&hWinHvPlatform,\n+ WINHV_PLATFORM_FNS_SUPPLEMENTAL));\n+ whp_dispatch_initialized = true;\n+\n+ return true;\n+error:\n+ if (hWinHvPlatform) {\n+ FreeLibrary(hWinHvPlatform);\n+ }\n+ if (hWinHvEmulation) {\n+ FreeLibrary(hWinHvEmulation);\n+ }\n+ return false;\n+}\n+\n+type_init(whpx_type_init);\ndiff --git a/include/system/whpx-all.h b/include/system/whpx-all.h\nnew file mode 100644\nindex 0000000000..f13cdf7f66\n--- /dev/null\n+++ b/include/system/whpx-all.h\n@@ -0,0 +1,20 @@\n+/* SPDX-License-Identifier: GPL-2.0-or-later */\n+#ifndef SYSTEM_WHPX_ALL_H\n+#define SYSTEM_WHPX_ALL_H\n+\n+/* Called by whpx-common */\n+int whpx_vcpu_run(CPUState *cpu);\n+void whpx_get_registers(CPUState *cpu);\n+void whpx_set_registers(CPUState *cpu, int level);\n+int whpx_accel_init(AccelState *as, MachineState *ms);\n+void whpx_cpu_instance_init(CPUState *cs);\n+HRESULT whpx_set_exception_exit_bitmap(UINT64 exceptions);\n+void whpx_apply_breakpoints(\n+struct whpx_breakpoint_collection *breakpoints,\n+ CPUState *cpu,\n+ bool resuming);\n+void whpx_translate_cpu_breakpoints(\n+ struct whpx_breakpoints *breakpoints,\n+ CPUState *cpu,\n+ int cpu_breakpoint_count);\n+#endif\ndiff --git a/include/system/whpx-common.h b/include/system/whpx-common.h\nnew file mode 100644\nindex 0000000000..e549c7539c\n--- /dev/null\n+++ b/include/system/whpx-common.h\n@@ -0,0 +1,21 @@\n+/* SPDX-License-Identifier: GPL-2.0-or-later */\n+#ifndef SYSTEM_WHPX_COMMON_H\n+#define SYSTEM_WHPX_COMMON_H\n+\n+struct AccelCPUState {\n+ WHV_EMULATOR_HANDLE emulator;\n+ bool window_registered;\n+ bool interruptable;\n+ bool ready_for_pic_interrupt;\n+ uint64_t tpr;\n+ uint64_t apic_base;\n+ bool interruption_pending;\n+ /* Must be the last field as it may have a tail */\n+ WHV_RUN_VP_EXIT_CONTEXT exit_ctx;\n+};\n+\n+int whpx_first_vcpu_starting(CPUState *cpu);\n+int whpx_last_vcpu_stopping(CPUState *cpu);\n+void whpx_memory_init(void);\n+struct whpx_breakpoint *whpx_lookup_breakpoint_by_addr(uint64_t address);\n+#endif\ndiff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c\nindex cef31fc1a8..052cda42bf 100644\n--- a/target/i386/whpx/whpx-all.c\n+++ b/target/i386/whpx/whpx-all.c\n@@ -33,6 +33,8 @@\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 \n #include <winhvplatform.h>\n #include <winhvemulation.h>\n@@ -232,28 +234,9 @@ typedef enum WhpxStepMode {\n WHPX_STEP_EXCLUSIVE,\n } WhpxStepMode;\n \n-struct AccelCPUState {\n- WHV_EMULATOR_HANDLE emulator;\n- bool window_registered;\n- bool interruptable;\n- bool ready_for_pic_interrupt;\n- uint64_t tpr;\n- uint64_t apic_base;\n- bool interruption_pending;\n-\n- /* Must be the last field as it may have a tail */\n- WHV_RUN_VP_EXIT_CONTEXT exit_ctx;\n-};\n-\n-bool whpx_allowed;\n-static bool whp_dispatch_initialized;\n-static HMODULE hWinHvPlatform, hWinHvEmulation;\n static uint32_t max_vcpu_index;\n static WHV_PROCESSOR_XSAVE_FEATURES whpx_xsave_cap;\n \n-struct whpx_state whpx_global;\n-struct WHPDispatch whp_dispatch;\n-\n static bool whpx_has_xsave(void)\n {\n return whpx_xsave_cap.XsaveSupport;\n@@ -379,7 +362,7 @@ static uint64_t whpx_cr8_to_apic_tpr(uint64_t cr8)\n return cr8 << 4;\n }\n \n-static void whpx_set_registers(CPUState *cpu, int level)\n+void whpx_set_registers(CPUState *cpu, int level)\n {\n struct whpx_state *whpx = &whpx_global;\n AccelCPUState *vcpu = cpu->accel;\n@@ -594,7 +577,7 @@ static void whpx_get_xcrs(CPUState *cpu)\n cpu_env(cpu)->xcr0 = xcr0.Reg64;\n }\n \n-static void whpx_get_registers(CPUState *cpu)\n+void whpx_get_registers(CPUState *cpu)\n {\n struct whpx_state *whpx = &whpx_global;\n AccelCPUState *vcpu = cpu->accel;\n@@ -934,7 +917,7 @@ static int whpx_handle_portio(CPUState *cpu,\n * The 'exceptions' argument accepts a bitmask, e.g:\n * (1 << WHvX64ExceptionTypeDebugTrapOrFault) | (...)\n */\n-static HRESULT whpx_set_exception_exit_bitmap(UINT64 exceptions)\n+HRESULT whpx_set_exception_exit_bitmap(UINT64 exceptions)\n {\n struct whpx_state *whpx = &whpx_global;\n WHV_PARTITION_PROPERTY prop = { 0, };\n@@ -1084,23 +1067,6 @@ static HRESULT whpx_vcpu_configure_single_stepping(CPUState *cpu,\n return S_OK;\n }\n \n-/* Tries to find a breakpoint at the specified address. */\n-static struct whpx_breakpoint *whpx_lookup_breakpoint_by_addr(uint64_t address)\n-{\n- struct whpx_state *whpx = &whpx_global;\n- int i;\n-\n- if (whpx->breakpoints.breakpoints) {\n- for (i = 0; i < whpx->breakpoints.breakpoints->used; i++) {\n- if (address == whpx->breakpoints.breakpoints->data[i].address) {\n- return &whpx->breakpoints.breakpoints->data[i];\n- }\n- }\n- }\n-\n- return NULL;\n-}\n-\n /*\n * Linux uses int3 (0xCC) during startup (see int3_selftest()) and for\n * debugging user-mode applications. Since the WHPX API does not offer\n@@ -1136,7 +1102,7 @@ static const uint8_t whpx_breakpoint_instruction = 0xF1;\n * memory, but doesn't actually do it. The memory accessing is done in\n * whpx_apply_breakpoints().\n */\n-static void whpx_translate_cpu_breakpoints(\n+void whpx_translate_cpu_breakpoints(\n struct whpx_breakpoints *breakpoints,\n CPUState *cpu,\n int cpu_breakpoint_count)\n@@ -1230,7 +1196,7 @@ static void whpx_translate_cpu_breakpoints(\n * Passing resuming=true will try to set all previously unset breakpoints.\n * Passing resuming=false will remove all inserted ones.\n */\n-static void whpx_apply_breakpoints(\n+void whpx_apply_breakpoints(\n struct whpx_breakpoint_collection *breakpoints,\n CPUState *cpu,\n bool resuming)\n@@ -1306,93 +1272,6 @@ static void whpx_apply_breakpoints(\n }\n }\n \n-/*\n- * This function is called when the a VCPU is about to start and no other\n- * VCPUs have been started so far. Since the VCPU start order could be\n- * arbitrary, it doesn't have to be VCPU#0.\n- *\n- * It is used to commit the breakpoints into memory, and configure WHPX\n- * to intercept debug exceptions.\n- *\n- * Note that whpx_set_exception_exit_bitmap() cannot be called if one or\n- * more VCPUs are already running, so this is the best place to do it.\n- */\n-static int whpx_first_vcpu_starting(CPUState *cpu)\n-{\n- struct whpx_state *whpx = &whpx_global;\n- HRESULT hr;\n-\n- g_assert(bql_locked());\n-\n- if (!QTAILQ_EMPTY(&cpu->breakpoints) ||\n- (whpx->breakpoints.breakpoints &&\n- whpx->breakpoints.breakpoints->used)) {\n- CPUBreakpoint *bp;\n- int i = 0;\n- bool update_pending = false;\n-\n- QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {\n- if (i >= whpx->breakpoints.original_address_count ||\n- bp->pc != whpx->breakpoints.original_addresses[i]) {\n- update_pending = true;\n- }\n-\n- i++;\n- }\n-\n- if (i != whpx->breakpoints.original_address_count) {\n- update_pending = true;\n- }\n-\n- if (update_pending) {\n- /*\n- * The CPU breakpoints have changed since the last call to\n- * whpx_translate_cpu_breakpoints(). WHPX breakpoints must\n- * now be recomputed.\n- */\n- whpx_translate_cpu_breakpoints(&whpx->breakpoints, cpu, i);\n- }\n-\n- /* Actually insert the breakpoints into the memory. */\n- whpx_apply_breakpoints(whpx->breakpoints.breakpoints, cpu, true);\n- }\n-\n- uint64_t exception_mask;\n- if (whpx->step_pending ||\n- (whpx->breakpoints.breakpoints &&\n- whpx->breakpoints.breakpoints->used)) {\n- /*\n- * We are either attempting to single-step one or more CPUs, or\n- * have one or more breakpoints enabled. Both require intercepting\n- * the WHvX64ExceptionTypeBreakpointTrap exception.\n- */\n-\n- exception_mask = 1UL << WHvX64ExceptionTypeDebugTrapOrFault;\n- } else {\n- /* Let the guest handle all exceptions. */\n- exception_mask = 0;\n- }\n-\n- hr = whpx_set_exception_exit_bitmap(exception_mask);\n- if (!SUCCEEDED(hr)) {\n- error_report(\"WHPX: Failed to update exception exit mask,\"\n- \"hr=%08lx.\", hr);\n- return 1;\n- }\n-\n- return 0;\n-}\n-\n-/*\n- * This function is called when the last VCPU has finished running.\n- * It is used to remove any previously set breakpoints from memory.\n- */\n-static int whpx_last_vcpu_stopping(CPUState *cpu)\n-{\n- whpx_apply_breakpoints(whpx_global.breakpoints.breakpoints, cpu, false);\n- return 0;\n-}\n-\n /* Returns the address of the next instruction that is about to be executed. */\n static vaddr whpx_vcpu_get_pc(CPUState *cpu, bool exit_context_valid)\n {\n@@ -1634,7 +1513,7 @@ static void whpx_vcpu_process_async_events(CPUState *cpu)\n }\n }\n \n-static int whpx_vcpu_run(CPUState *cpu)\n+int whpx_vcpu_run(CPUState *cpu)\n {\n HRESULT hr;\n struct whpx_state *whpx = &whpx_global;\n@@ -2057,65 +1936,6 @@ static int whpx_vcpu_run(CPUState *cpu)\n return ret < 0;\n }\n \n-static void do_whpx_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)\n-{\n- if (!cpu->vcpu_dirty) {\n- whpx_get_registers(cpu);\n- cpu->vcpu_dirty = true;\n- }\n-}\n-\n-static void do_whpx_cpu_synchronize_post_reset(CPUState *cpu,\n- run_on_cpu_data arg)\n-{\n- whpx_set_registers(cpu, WHPX_SET_RESET_STATE);\n- cpu->vcpu_dirty = false;\n-}\n-\n-static void do_whpx_cpu_synchronize_post_init(CPUState *cpu,\n- run_on_cpu_data arg)\n-{\n- whpx_set_registers(cpu, WHPX_SET_FULL_STATE);\n- cpu->vcpu_dirty = false;\n-}\n-\n-static void do_whpx_cpu_synchronize_pre_loadvm(CPUState *cpu,\n- run_on_cpu_data arg)\n-{\n- cpu->vcpu_dirty = true;\n-}\n-\n-/*\n- * CPU support.\n- */\n-\n-void whpx_cpu_synchronize_state(CPUState *cpu)\n-{\n- if (!cpu->vcpu_dirty) {\n- run_on_cpu(cpu, do_whpx_cpu_synchronize_state, RUN_ON_CPU_NULL);\n- }\n-}\n-\n-void whpx_cpu_synchronize_post_reset(CPUState *cpu)\n-{\n- run_on_cpu(cpu, do_whpx_cpu_synchronize_post_reset, RUN_ON_CPU_NULL);\n-}\n-\n-void whpx_cpu_synchronize_post_init(CPUState *cpu)\n-{\n- run_on_cpu(cpu, do_whpx_cpu_synchronize_post_init, RUN_ON_CPU_NULL);\n-}\n-\n-void whpx_cpu_synchronize_pre_loadvm(CPUState *cpu)\n-{\n- run_on_cpu(cpu, do_whpx_cpu_synchronize_pre_loadvm, RUN_ON_CPU_NULL);\n-}\n-\n-static void whpx_pre_resume_vm(AccelState *as, bool step_pending)\n-{\n- whpx_global.step_pending = step_pending;\n-}\n-\n /*\n * Vcpu support.\n */\n@@ -2244,295 +2064,18 @@ error:\n return ret;\n }\n \n-int whpx_vcpu_exec(CPUState *cpu)\n-{\n- int ret;\n- int fatal;\n-\n- for (;;) {\n- if (cpu->exception_index >= EXCP_INTERRUPT) {\n- ret = cpu->exception_index;\n- cpu->exception_index = -1;\n- break;\n- }\n-\n- fatal = whpx_vcpu_run(cpu);\n-\n- if (fatal) {\n- error_report(\"WHPX: Failed to exec a virtual processor\");\n- abort();\n- }\n- }\n-\n- return ret;\n-}\n-\n-void whpx_destroy_vcpu(CPUState *cpu)\n-{\n- struct whpx_state *whpx = &whpx_global;\n- AccelCPUState *vcpu = cpu->accel;\n-\n- whp_dispatch.WHvDeleteVirtualProcessor(whpx->partition, cpu->cpu_index);\n- whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator);\n- g_free(cpu->accel);\n-}\n-\n-void whpx_vcpu_kick(CPUState *cpu)\n-{\n- struct whpx_state *whpx = &whpx_global;\n- whp_dispatch.WHvCancelRunVirtualProcessor(\n- whpx->partition, cpu->cpu_index, 0);\n-}\n-\n-/*\n- * Memory support.\n- */\n-\n-static void whpx_update_mapping(hwaddr start_pa, ram_addr_t size,\n- void *host_va, int add, int rom,\n- const char *name)\n-{\n- struct whpx_state *whpx = &whpx_global;\n- HRESULT hr;\n-\n- /*\n- if (add) {\n- printf(\"WHPX: ADD PA:%p Size:%p, Host:%p, %s, '%s'\\n\",\n- (void*)start_pa, (void*)size, host_va,\n- (rom ? \"ROM\" : \"RAM\"), name);\n- } else {\n- printf(\"WHPX: DEL PA:%p Size:%p, Host:%p, '%s'\\n\",\n- (void*)start_pa, (void*)size, host_va, name);\n- }\n- */\n-\n- if (add) {\n- hr = whp_dispatch.WHvMapGpaRange(whpx->partition,\n- host_va,\n- start_pa,\n- size,\n- (WHvMapGpaRangeFlagRead |\n- WHvMapGpaRangeFlagExecute |\n- (rom ? 0 : WHvMapGpaRangeFlagWrite)));\n- } else {\n- hr = whp_dispatch.WHvUnmapGpaRange(whpx->partition,\n- start_pa,\n- size);\n- }\n-\n- if (FAILED(hr)) {\n- error_report(\"WHPX: Failed to %s GPA range '%s' PA:%p, Size:%p bytes,\"\n- \" Host:%p, hr=%08lx\",\n- (add ? \"MAP\" : \"UNMAP\"), name,\n- (void *)(uintptr_t)start_pa, (void *)size, host_va, hr);\n- }\n-}\n-\n-static void whpx_process_section(MemoryRegionSection *section, int add)\n-{\n- MemoryRegion *mr = section->mr;\n- hwaddr start_pa = section->offset_within_address_space;\n- ram_addr_t size = int128_get64(section->size);\n- unsigned int delta;\n- uint64_t host_va;\n-\n- if (!memory_region_is_ram(mr)) {\n- return;\n- }\n-\n- delta = qemu_real_host_page_size() - (start_pa & ~qemu_real_host_page_mask());\n- delta &= ~qemu_real_host_page_mask();\n- if (delta > size) {\n- return;\n- }\n- start_pa += delta;\n- size -= delta;\n- size &= qemu_real_host_page_mask();\n- if (!size || (start_pa & ~qemu_real_host_page_mask())) {\n- return;\n- }\n-\n- host_va = (uintptr_t)memory_region_get_ram_ptr(mr)\n- + section->offset_within_region + delta;\n-\n- whpx_update_mapping(start_pa, size, (void *)(uintptr_t)host_va, add,\n- memory_region_is_rom(mr), mr->name);\n-}\n-\n-static void whpx_region_add(MemoryListener *listener,\n- MemoryRegionSection *section)\n-{\n- memory_region_ref(section->mr);\n- whpx_process_section(section, 1);\n-}\n-\n-static void whpx_region_del(MemoryListener *listener,\n- MemoryRegionSection *section)\n-{\n- whpx_process_section(section, 0);\n- memory_region_unref(section->mr);\n-}\n-\n-static void whpx_transaction_begin(MemoryListener *listener)\n-{\n-}\n-\n-static void whpx_transaction_commit(MemoryListener *listener)\n-{\n-}\n-\n-static void whpx_log_sync(MemoryListener *listener,\n- MemoryRegionSection *section)\n-{\n- MemoryRegion *mr = section->mr;\n-\n- if (!memory_region_is_ram(mr)) {\n- return;\n- }\n-\n- memory_region_set_dirty(mr, 0, int128_get64(section->size));\n-}\n-\n-static MemoryListener whpx_memory_listener = {\n- .name = \"whpx\",\n- .begin = whpx_transaction_begin,\n- .commit = whpx_transaction_commit,\n- .region_add = whpx_region_add,\n- .region_del = whpx_region_del,\n- .log_sync = whpx_log_sync,\n- .priority = MEMORY_LISTENER_PRIORITY_ACCEL,\n-};\n-\n-static void whpx_memory_init(void)\n-{\n- memory_listener_register(&whpx_memory_listener, &address_space_memory);\n-}\n-\n-/*\n- * Load the functions from the given library, using the given handle. If a\n- * handle is provided, it is used, otherwise the library is opened. The\n- * handle will be updated on return with the opened one.\n- */\n-static bool load_whp_dispatch_fns(HMODULE *handle,\n- WHPFunctionList function_list)\n-{\n- HMODULE hLib = *handle;\n-\n- #define WINHV_PLATFORM_DLL \"WinHvPlatform.dll\"\n- #define WINHV_EMULATION_DLL \"WinHvEmulation.dll\"\n- #define WHP_LOAD_FIELD_OPTIONAL(return_type, function_name, signature) \\\n- whp_dispatch.function_name = \\\n- (function_name ## _t)GetProcAddress(hLib, #function_name); \\\n-\n- #define WHP_LOAD_FIELD(return_type, function_name, signature) \\\n- whp_dispatch.function_name = \\\n- (function_name ## _t)GetProcAddress(hLib, #function_name); \\\n- if (!whp_dispatch.function_name) { \\\n- error_report(\"Could not load function %s\", #function_name); \\\n- goto error; \\\n- } \\\n-\n- #define WHP_LOAD_LIB(lib_name, handle_lib) \\\n- if (!handle_lib) { \\\n- handle_lib = LoadLibrary(lib_name); \\\n- if (!handle_lib) { \\\n- error_report(\"Could not load library %s.\", lib_name); \\\n- goto error; \\\n- } \\\n- } \\\n-\n- switch (function_list) {\n- case WINHV_PLATFORM_FNS_DEFAULT:\n- WHP_LOAD_LIB(WINHV_PLATFORM_DLL, hLib)\n- LIST_WINHVPLATFORM_FUNCTIONS(WHP_LOAD_FIELD)\n- break;\n-\n- case WINHV_EMULATION_FNS_DEFAULT:\n- WHP_LOAD_LIB(WINHV_EMULATION_DLL, hLib)\n- LIST_WINHVEMULATION_FUNCTIONS(WHP_LOAD_FIELD)\n- break;\n-\n- case WINHV_PLATFORM_FNS_SUPPLEMENTAL:\n- WHP_LOAD_LIB(WINHV_PLATFORM_DLL, hLib)\n- LIST_WINHVPLATFORM_FUNCTIONS_SUPPLEMENTAL(WHP_LOAD_FIELD_OPTIONAL)\n- break;\n- }\n-\n- *handle = hLib;\n- return true;\n-\n-error:\n- if (hLib) {\n- FreeLibrary(hLib);\n- }\n-\n- return false;\n-}\n-\n-static void whpx_set_kernel_irqchip(Object *obj, Visitor *v,\n- const char *name, void *opaque,\n- Error **errp)\n-{\n- struct whpx_state *whpx = &whpx_global;\n- OnOffSplit mode;\n-\n- if (!visit_type_OnOffSplit(v, name, &mode, errp)) {\n- return;\n- }\n-\n- switch (mode) {\n- case ON_OFF_SPLIT_ON:\n- whpx->kernel_irqchip_allowed = true;\n- whpx->kernel_irqchip_required = true;\n- break;\n-\n- case ON_OFF_SPLIT_OFF:\n- whpx->kernel_irqchip_allowed = false;\n- whpx->kernel_irqchip_required = false;\n- break;\n-\n- case ON_OFF_SPLIT_SPLIT:\n- error_setg(errp, \"WHPX: split irqchip currently not supported\");\n- error_append_hint(errp,\n- \"Try without kernel-irqchip or with kernel-irqchip=on|off\");\n- break;\n-\n- default:\n- /*\n- * The value was checked in visit_type_OnOffSplit() above. If\n- * we get here, then something is wrong in QEMU.\n- */\n- abort();\n- }\n-}\n-\n-static void whpx_cpu_instance_init(CPUState *cs)\n+void whpx_cpu_instance_init(CPUState *cs)\n {\n X86CPU *cpu = X86_CPU(cs);\n \n host_cpu_instance_init(cpu);\n }\n \n-static void whpx_cpu_accel_class_init(ObjectClass *oc, const void *data)\n-{\n- AccelCPUClass *acc = ACCEL_CPU_CLASS(oc);\n-\n- acc->cpu_instance_init = whpx_cpu_instance_init;\n-}\n-\n-static const TypeInfo whpx_cpu_accel_type = {\n- .name = ACCEL_CPU_NAME(\"whpx\"),\n-\n- .parent = TYPE_ACCEL_CPU,\n- .class_init = whpx_cpu_accel_class_init,\n- .abstract = true,\n-};\n-\n /*\n * Partition support\n */\n \n-static int whpx_accel_init(AccelState *as, MachineState *ms)\n+int whpx_accel_init(AccelState *as, MachineState *ms)\n {\n struct whpx_state *whpx;\n int ret;\n@@ -2715,77 +2258,3 @@ error:\n \n return ret;\n }\n-\n-bool whpx_apic_in_platform(void) {\n- return whpx_global.apic_in_platform;\n-}\n-\n-static void whpx_accel_class_init(ObjectClass *oc, const void *data)\n-{\n- AccelClass *ac = ACCEL_CLASS(oc);\n- ac->name = \"WHPX\";\n- ac->init_machine = whpx_accel_init;\n- ac->pre_resume_vm = whpx_pre_resume_vm;\n- ac->allowed = &whpx_allowed;\n-\n- object_class_property_add(oc, \"kernel-irqchip\", \"on|off|split\",\n- NULL, whpx_set_kernel_irqchip,\n- NULL, NULL);\n- object_class_property_set_description(oc, \"kernel-irqchip\",\n- \"Configure WHPX in-kernel irqchip\");\n-}\n-\n-static void whpx_accel_instance_init(Object *obj)\n-{\n- struct whpx_state *whpx = &whpx_global;\n-\n- memset(whpx, 0, sizeof(struct whpx_state));\n- /* Turn on kernel-irqchip, by default */\n- whpx->kernel_irqchip_allowed = true;\n-}\n-\n-static const TypeInfo whpx_accel_type = {\n- .name = ACCEL_CLASS_NAME(\"whpx\"),\n- .parent = TYPE_ACCEL,\n- .instance_init = whpx_accel_instance_init,\n- .class_init = whpx_accel_class_init,\n-};\n-\n-static void whpx_type_init(void)\n-{\n- type_register_static(&whpx_accel_type);\n- type_register_static(&whpx_cpu_accel_type);\n-}\n-\n-bool init_whp_dispatch(void)\n-{\n- if (whp_dispatch_initialized) {\n- return true;\n- }\n-\n- if (!load_whp_dispatch_fns(&hWinHvPlatform, WINHV_PLATFORM_FNS_DEFAULT)) {\n- goto error;\n- }\n-\n- if (!load_whp_dispatch_fns(&hWinHvEmulation, WINHV_EMULATION_FNS_DEFAULT)) {\n- goto error;\n- }\n-\n- assert(load_whp_dispatch_fns(&hWinHvPlatform,\n- WINHV_PLATFORM_FNS_SUPPLEMENTAL));\n- whp_dispatch_initialized = true;\n-\n- return true;\n-error:\n- if (hWinHvPlatform) {\n- FreeLibrary(hWinHvPlatform);\n- }\n-\n- if (hWinHvEmulation) {\n- FreeLibrary(hWinHvEmulation);\n- }\n-\n- return false;\n-}\n-\n-type_init(whpx_type_init);\n", "prefixes": [ "PULL", "10/26" ] }