* [PATCH v3 00/14] WHPX support for Arm
@ 2025-08-02 8:17 Mohamed Mediouni
2025-08-02 8:17 ` [PATCH v3 01/14] hw/arm: virt: add GICv2m for the case when ITS is not available Mohamed Mediouni
` (13 more replies)
0 siblings, 14 replies; 32+ messages in thread
From: Mohamed Mediouni @ 2025-08-02 8:17 UTC (permalink / raw)
To: qemu-devel
Cc: Richard Henderson, Zhao Liu, Yanan Wang, qemu-arm,
Sunil Muthuswamy, Daniel P. Berrangé, Igor Mammedov,
Peter Maydell, Shannon Zhao, Michael S. Tsirkin,
Marc-André Lureau, Eduardo Habkost, Marcel Apfelbaum,
Mohamed Mediouni, Paolo Bonzini, Philippe Mathieu-Daudé,
Ani Sinha
Link to branch: https://github.com/mediouni-m/qemu whpx (tag for this submission: whpx-v3)
Missing features:
- PSCI state sync with Hyper-V: notably breaks reboots when multiple cores are enabled
- Interrupt controller save-restore
- Debug register sync
- SVE register sync
- Adding a migration blocker because of the items above.
Updates since v2:
- Fixed up a rebase screwup for whpx-internal.h
- Fixed ID_AA64ISAR1_EL1 and ID_AA64ISAR2_EL1 feature probe for -cpu host
- Switched to ID_AA64PFR1_EL1/ID_AA64DFR0_EL1 instead of their non-AA64 variant
Updates since v1:
- Shutdowns and reboots
- MPIDR_EL1 register sync
- Fixing GICD_TYPER_LPIS value
- IPA size clamping
- -cpu host now implemented
Mohamed Mediouni (14):
hw/arm: virt: add GICv2m for the case when ITS is not available
whpx: Move around files before introducing AArch64 support
whpx: reshuffle common code
whpx: ifdef out some x86-only code paths
hw, target, accel: whpx: change apic_in_platform to kernel_irqchip
whpx: interrupt controller support
whpx: add arm64 support
whpx: copy over memory management logic from hvf
target/arm: cpu: mark WHPX as supporting PSCI 1.1
hw/arm: virt: cleanly fail on attempt to use the platform vGIC
together with ITS
whpx: arm64: clamp down IPA size
whpx: arm64: implement -cpu host
target/arm: whpx: instantiate GIC early
MAINTAINERS: Add myself as a maintainer for WHPX
MAINTAINERS | 9 +-
accel/meson.build | 1 +
accel/whpx/meson.build | 7 +
{target/i386 => accel}/whpx/whpx-accel-ops.c | 6 +-
accel/whpx/whpx-common.c | 674 +++++++++++
hw/arm/virt-acpi-build.c | 4 +-
hw/arm/virt.c | 55 +-
hw/i386/x86-cpu.c | 4 +-
hw/intc/arm_gicv3_common.c | 3 +
hw/intc/arm_gicv3_whpx.c | 261 +++++
hw/intc/meson.build | 1 +
include/hw/arm/virt.h | 2 +
include/hw/boards.h | 1 +
include/hw/intc/arm_gicv3_common.h | 3 +
.../whpx => include/system}/whpx-accel-ops.h | 4 +-
include/system/whpx-all.h | 14 +
include/system/whpx-common.h | 23 +
.../whpx => include/system}/whpx-internal.h | 14 +-
include/system/whpx.h | 4 +-
meson.build | 21 +-
target/arm/cpu.c | 3 +-
target/arm/cpu64.c | 14 +-
target/arm/meson.build | 1 +
target/arm/whpx/meson.build | 5 +
target/arm/whpx/whpx-all.c | 1029 +++++++++++++++++
target/arm/whpx/whpx-stub.c | 15 +
target/arm/whpx_arm.h | 17 +
target/i386/cpu-apic.c | 2 +-
target/i386/whpx/meson.build | 1 -
target/i386/whpx/whpx-all.c | 540 +--------
target/i386/whpx/whpx-apic.c | 2 +-
31 files changed, 2183 insertions(+), 557 deletions(-)
create mode 100644 accel/whpx/meson.build
rename {target/i386 => accel}/whpx/whpx-accel-ops.c (96%)
create mode 100644 accel/whpx/whpx-common.c
create mode 100644 hw/intc/arm_gicv3_whpx.c
rename {target/i386/whpx => include/system}/whpx-accel-ops.h (92%)
create mode 100644 include/system/whpx-all.h
create mode 100644 include/system/whpx-common.h
rename {target/i386/whpx => include/system}/whpx-internal.h (96%)
create mode 100644 target/arm/whpx/meson.build
create mode 100644 target/arm/whpx/whpx-all.c
create mode 100644 target/arm/whpx/whpx-stub.c
create mode 100644 target/arm/whpx_arm.h
--
2.39.5 (Apple Git-154)
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v3 01/14] hw/arm: virt: add GICv2m for the case when ITS is not available
2025-08-02 8:17 [PATCH v3 00/14] WHPX support for Arm Mohamed Mediouni
@ 2025-08-02 8:17 ` Mohamed Mediouni
2025-08-02 8:17 ` [PATCH v3 02/14] whpx: Move around files before introducing AArch64 support Mohamed Mediouni
` (12 subsequent siblings)
13 siblings, 0 replies; 32+ messages in thread
From: Mohamed Mediouni @ 2025-08-02 8:17 UTC (permalink / raw)
To: qemu-devel
Cc: Richard Henderson, Zhao Liu, Yanan Wang, qemu-arm,
Sunil Muthuswamy, Daniel P. Berrangé, Igor Mammedov,
Peter Maydell, Shannon Zhao, Michael S. Tsirkin,
Marc-André Lureau, Eduardo Habkost, Marcel Apfelbaum,
Mohamed Mediouni, Paolo Bonzini, Philippe Mathieu-Daudé,
Ani Sinha
On Hypervisor.framework for macOS and WHPX for Windows, the provided environment is a GICv3 without ITS.
As such, support a GICv3 w/ GICv2m for that scenario.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
hw/arm/virt-acpi-build.c | 4 +++-
hw/arm/virt.c | 8 ++++++++
include/hw/arm/virt.h | 2 ++
3 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index b01fc4f8ef..969fa3f686 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -848,7 +848,9 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
build_append_int_noprefix(table_data, memmap[VIRT_GIC_ITS].base, 8);
build_append_int_noprefix(table_data, 0, 4); /* Reserved */
}
- } else {
+ }
+
+ if (!vms->its && !vms->no_gicv3_with_gicv2m) {
const uint16_t spi_base = vms->irqmap[VIRT_GIC_V2M] + ARM_SPI_BASE;
/* 5.2.12.16 GIC MSI Frame Structure */
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index ef6be3660f..5951b331f3 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -953,6 +953,8 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
if (vms->gic_version != VIRT_GIC_VERSION_2 && vms->its) {
create_its(vms);
+ } else if (vms->gic_version != VIRT_GIC_VERSION_2 && !vms->no_gicv3_with_gicv2m) {
+ create_v2m(vms);
} else if (vms->gic_version == VIRT_GIC_VERSION_2) {
create_v2m(vms);
}
@@ -2402,6 +2404,8 @@ static void machvirt_init(MachineState *machine)
vms->ns_el2_virt_timer_irq = ns_el2_virt_timer_present() &&
!vmc->no_ns_el2_virt_timer_irq;
+ vms->no_gicv3_with_gicv2m = vmc->no_gicv3_with_gicv2m;
+
fdt_add_timer_nodes(vms);
fdt_add_cpu_nodes(vms);
@@ -3410,6 +3414,7 @@ static void virt_instance_init(Object *obj)
vms->its = true;
/* Allow ITS emulation if the machine version supports it */
vms->tcg_its = !vmc->no_tcg_its;
+ vms->no_gicv3_with_gicv2m = false;
/* Default disallows iommu instantiation */
vms->iommu = VIRT_IOMMU_NONE;
@@ -3462,8 +3467,11 @@ DEFINE_VIRT_MACHINE_AS_LATEST(10, 1)
static void virt_machine_10_0_options(MachineClass *mc)
{
+ VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
+
virt_machine_10_1_options(mc);
compat_props_add(mc->compat_props, hw_compat_10_0, hw_compat_10_0_len);
+ vmc->no_gicv3_with_gicv2m = true;
}
DEFINE_VIRT_MACHINE(10, 0)
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 365a28b082..725ec18fd2 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -131,6 +131,7 @@ struct VirtMachineClass {
bool no_cpu_topology;
bool no_tcg_lpa2;
bool no_ns_el2_virt_timer_irq;
+ bool no_gicv3_with_gicv2m;
bool no_nested_smmu;
};
@@ -178,6 +179,7 @@ struct VirtMachineState {
char *oem_id;
char *oem_table_id;
bool ns_el2_virt_timer_irq;
+ bool no_gicv3_with_gicv2m;
CXLState cxl_devices_state;
};
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 02/14] whpx: Move around files before introducing AArch64 support
2025-08-02 8:17 [PATCH v3 00/14] WHPX support for Arm Mohamed Mediouni
2025-08-02 8:17 ` [PATCH v3 01/14] hw/arm: virt: add GICv2m for the case when ITS is not available Mohamed Mediouni
@ 2025-08-02 8:17 ` Mohamed Mediouni
2025-08-02 8:53 ` Mohamed Mediouni
2025-08-03 0:03 ` Richard Henderson
2025-08-02 8:17 ` [PATCH v3 03/14] whpx: reshuffle common code Mohamed Mediouni
` (11 subsequent siblings)
13 siblings, 2 replies; 32+ messages in thread
From: Mohamed Mediouni @ 2025-08-02 8:17 UTC (permalink / raw)
To: qemu-devel
Cc: Richard Henderson, Zhao Liu, Yanan Wang, qemu-arm,
Sunil Muthuswamy, Daniel P. Berrangé, Igor Mammedov,
Peter Maydell, Shannon Zhao, Michael S. Tsirkin,
Marc-André Lureau, Eduardo Habkost, Marcel Apfelbaum,
Mohamed Mediouni, Paolo Bonzini, Philippe Mathieu-Daudé,
Ani Sinha
Switch to a design where we can share whpx code between x86 and AArch64 when it makes sense to do so.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
MAINTAINERS | 2 ++
accel/meson.build | 1 +
accel/whpx/meson.build | 6 ++++++
{target/i386 => accel}/whpx/whpx-accel-ops.c | 4 ++--
{target/i386/whpx => include/system}/whpx-accel-ops.h | 0
target/i386/whpx/meson.build | 1 -
target/i386/whpx/whpx-all.c | 4 ++--
target/i386/whpx/whpx-internal.h | 1 +
8 files changed, 14 insertions(+), 5 deletions(-)
create mode 100644 accel/whpx/meson.build
rename {target/i386 => accel}/whpx/whpx-accel-ops.c (97%)
rename {target/i386/whpx => include/system}/whpx-accel-ops.h (100%)
diff --git a/MAINTAINERS b/MAINTAINERS
index 28cea34271..238065e1c9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -542,9 +542,11 @@ F: include/system/hvf_int.h
WHPX CPUs
M: Sunil Muthuswamy <sunilmut@microsoft.com>
S: Supported
+F: accel/whpx/
F: target/i386/whpx/
F: accel/stubs/whpx-stub.c
F: include/system/whpx.h
+F: include/system/whpx-accel-ops.h
X86 Instruction Emulator
M: Cameron Esfahani <dirty@apple.com>
diff --git a/accel/meson.build b/accel/meson.build
index 25b0f100b5..de927a3b37 100644
--- a/accel/meson.build
+++ b/accel/meson.build
@@ -6,6 +6,7 @@ user_ss.add(files('accel-user.c'))
subdir('tcg')
if have_system
subdir('hvf')
+ subdir('whpx')
subdir('qtest')
subdir('kvm')
subdir('xen')
diff --git a/accel/whpx/meson.build b/accel/whpx/meson.build
new file mode 100644
index 0000000000..7b3d6f1c1c
--- /dev/null
+++ b/accel/whpx/meson.build
@@ -0,0 +1,6 @@
+whpx_ss = ss.source_set()
+whpx_ss.add(files(
+ 'whpx-accel-ops.c',
+))
+
+specific_ss.add_all(when: 'CONFIG_WHPX', if_true: whpx_ss)
diff --git a/target/i386/whpx/whpx-accel-ops.c b/accel/whpx/whpx-accel-ops.c
similarity index 97%
rename from target/i386/whpx/whpx-accel-ops.c
rename to accel/whpx/whpx-accel-ops.c
index da58805b1a..18488421bc 100644
--- a/target/i386/whpx/whpx-accel-ops.c
+++ b/accel/whpx/whpx-accel-ops.c
@@ -16,8 +16,8 @@
#include "qemu/guest-random.h"
#include "system/whpx.h"
-#include "whpx-internal.h"
-#include "whpx-accel-ops.h"
+#include "system/whpx-internal.h"
+#include "system/whpx-accel-ops.h"
static void *whpx_cpu_thread_fn(void *arg)
{
diff --git a/target/i386/whpx/whpx-accel-ops.h b/include/system/whpx-accel-ops.h
similarity index 100%
rename from target/i386/whpx/whpx-accel-ops.h
rename to include/system/whpx-accel-ops.h
diff --git a/target/i386/whpx/meson.build b/target/i386/whpx/meson.build
index 9c54aaad39..c3aaaff9fd 100644
--- a/target/i386/whpx/meson.build
+++ b/target/i386/whpx/meson.build
@@ -1,5 +1,4 @@
i386_system_ss.add(when: 'CONFIG_WHPX', if_true: files(
'whpx-all.c',
'whpx-apic.c',
- 'whpx-accel-ops.c',
))
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index b72dcff3c8..5a431fc3c7 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -31,8 +31,8 @@
#include "accel/accel-cpu-target.h"
#include <winerror.h>
-#include "whpx-internal.h"
-#include "whpx-accel-ops.h"
+#include "system/whpx-internal.h"
+#include "system/whpx-accel-ops.h"
#include <winhvplatform.h>
#include <winhvemulation.h>
diff --git a/target/i386/whpx/whpx-internal.h b/target/i386/whpx/whpx-internal.h
index 6633e9c4ca..435e0c5046 100644
--- a/target/i386/whpx/whpx-internal.h
+++ b/target/i386/whpx/whpx-internal.h
@@ -117,3 +117,4 @@ typedef enum WHPFunctionList {
} WHPFunctionList;
#endif /* TARGET_I386_WHPX_INTERNAL_H */
+
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 03/14] whpx: reshuffle common code
2025-08-02 8:17 [PATCH v3 00/14] WHPX support for Arm Mohamed Mediouni
2025-08-02 8:17 ` [PATCH v3 01/14] hw/arm: virt: add GICv2m for the case when ITS is not available Mohamed Mediouni
2025-08-02 8:17 ` [PATCH v3 02/14] whpx: Move around files before introducing AArch64 support Mohamed Mediouni
@ 2025-08-02 8:17 ` Mohamed Mediouni
2025-08-03 0:15 ` Richard Henderson
2025-08-02 8:17 ` [PATCH v3 04/14] whpx: ifdef out some x86-only code paths Mohamed Mediouni
` (10 subsequent siblings)
13 siblings, 1 reply; 32+ messages in thread
From: Mohamed Mediouni @ 2025-08-02 8:17 UTC (permalink / raw)
To: qemu-devel
Cc: Richard Henderson, Zhao Liu, Yanan Wang, qemu-arm,
Sunil Muthuswamy, Daniel P. Berrangé, Igor Mammedov,
Peter Maydell, Shannon Zhao, Michael S. Tsirkin,
Marc-André Lureau, Eduardo Habkost, Marcel Apfelbaum,
Mohamed Mediouni, Paolo Bonzini, Philippe Mathieu-Daudé,
Ani Sinha
Some code can be shared between x86_64 and arm64 WHPX. Do so as much as reasonable.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
MAINTAINERS | 2 +
accel/whpx/meson.build | 1 +
accel/whpx/whpx-common.c | 564 ++++++++++++++++++
include/system/whpx-accel-ops.h | 4 +-
include/system/whpx-all.h | 12 +
include/system/whpx-common.h | 21 +
.../whpx => include/system}/whpx-internal.h | 6 +-
target/i386/whpx/whpx-all.c | 522 +---------------
target/i386/whpx/whpx-apic.c | 2 +-
9 files changed, 611 insertions(+), 523 deletions(-)
create mode 100644 accel/whpx/whpx-common.c
create mode 100644 include/system/whpx-all.h
create mode 100644 include/system/whpx-common.h
rename {target/i386/whpx => include/system}/whpx-internal.h (98%)
diff --git a/MAINTAINERS b/MAINTAINERS
index 238065e1c9..259b010f55 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -547,6 +547,8 @@ F: target/i386/whpx/
F: accel/stubs/whpx-stub.c
F: include/system/whpx.h
F: include/system/whpx-accel-ops.h
+F: include/system/whpx-common.h
+F: include/system/whpx-internal.h
X86 Instruction Emulator
M: Cameron Esfahani <dirty@apple.com>
diff --git a/accel/whpx/meson.build b/accel/whpx/meson.build
index 7b3d6f1c1c..fad28dddcb 100644
--- a/accel/whpx/meson.build
+++ b/accel/whpx/meson.build
@@ -1,6 +1,7 @@
whpx_ss = ss.source_set()
whpx_ss.add(files(
'whpx-accel-ops.c',
+ 'whpx-common.c'
))
specific_ss.add_all(when: 'CONFIG_WHPX', if_true: whpx_ss)
diff --git a/accel/whpx/whpx-common.c b/accel/whpx/whpx-common.c
new file mode 100644
index 0000000000..b5e5fda696
--- /dev/null
+++ b/accel/whpx/whpx-common.c
@@ -0,0 +1,564 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU Windows Hypervisor Platform accelerator (WHPX)
+ *
+ * Copyright Microsoft Corp. 2017
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "system/address-spaces.h"
+#include "system/ioport.h"
+#include "gdbstub/helpers.h"
+#include "qemu/accel.h"
+#include "accel/accel-ops.h"
+#include "system/whpx.h"
+#include "system/cpus.h"
+#include "system/runstate.h"
+#include "qemu/main-loop.h"
+#include "hw/boards.h"
+#include "hw/intc/ioapic.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "qapi/qapi-types-common.h"
+#include "qapi/qapi-visit-common.h"
+#include "migration/blocker.h"
+#include "accel/accel-cpu-target.h"
+#include <winerror.h>
+
+#include "system/whpx-internal.h"
+#include "system/whpx-accel-ops.h"
+#include "system/whpx-common.h"
+#include "system/whpx-all.h"
+
+#include <winhvplatform.h>
+#include <winhvplatformdefs.h>
+
+bool whpx_allowed;
+static bool whp_dispatch_initialized;
+static HMODULE hWinHvPlatform;
+static HMODULE hWinHvEmulation;
+
+struct whpx_state whpx_global;
+struct WHPDispatch whp_dispatch;
+
+/* Tries to find a breakpoint at the specified address. */
+struct whpx_breakpoint *whpx_lookup_breakpoint_by_addr(uint64_t address)
+{
+ struct whpx_state *whpx = &whpx_global;
+ int i;
+
+ if (whpx->breakpoints.breakpoints) {
+ for (i = 0; i < whpx->breakpoints.breakpoints->used; i++) {
+ if (address == whpx->breakpoints.breakpoints->data[i].address) {
+ return &whpx->breakpoints.breakpoints->data[i];
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * This function is called when the a VCPU is about to start and no other
+ * VCPUs have been started so far. Since the VCPU start order could be
+ * arbitrary, it doesn't have to be VCPU#0.
+ *
+ * It is used to commit the breakpoints into memory, and configure WHPX
+ * to intercept debug exceptions.
+ *
+ * Note that whpx_set_exception_exit_bitmap() cannot be called if one or
+ * more VCPUs are already running, so this is the best place to do it.
+ */
+int whpx_first_vcpu_starting(CPUState *cpu)
+{
+ struct whpx_state *whpx = &whpx_global;
+
+ g_assert(bql_locked());
+
+ if (!QTAILQ_EMPTY(&cpu->breakpoints) ||
+ (whpx->breakpoints.breakpoints &&
+ whpx->breakpoints.breakpoints->used)) {
+ CPUBreakpoint *bp;
+ int i = 0;
+ bool update_pending = false;
+
+ QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
+ if (i >= whpx->breakpoints.original_address_count ||
+ bp->pc != whpx->breakpoints.original_addresses[i]) {
+ update_pending = true;
+ }
+
+ i++;
+ }
+
+ if (i != whpx->breakpoints.original_address_count) {
+ update_pending = true;
+ }
+
+ if (update_pending) {
+ /*
+ * The CPU breakpoints have changed since the last call to
+ * whpx_translate_cpu_breakpoints(). WHPX breakpoints must
+ * now be recomputed.
+ */
+ whpx_translate_cpu_breakpoints(&whpx->breakpoints, cpu, i);
+ }
+ /* Actually insert the breakpoints into the memory. */
+ whpx_apply_breakpoints(whpx->breakpoints.breakpoints, cpu, true);
+ }
+ HRESULT hr;
+ uint64_t exception_mask;
+ if (whpx->step_pending ||
+ (whpx->breakpoints.breakpoints &&
+ whpx->breakpoints.breakpoints->used)) {
+ /*
+ * We are either attempting to single-step one or more CPUs, or
+ * have one or more breakpoints enabled. Both require intercepting
+ * the WHvX64ExceptionTypeBreakpointTrap exception.
+ */
+ exception_mask = 1UL << WHvX64ExceptionTypeDebugTrapOrFault;
+ } else {
+ /* Let the guest handle all exceptions. */
+ exception_mask = 0;
+ }
+ hr = whpx_set_exception_exit_bitmap(exception_mask);
+ if (!SUCCEEDED(hr)) {
+ error_report("WHPX: Failed to update exception exit mask,"
+ "hr=%08lx.", hr);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * This function is called when the last VCPU has finished running.
+ * It is used to remove any previously set breakpoints from memory.
+ */
+int whpx_last_vcpu_stopping(CPUState *cpu)
+{
+#ifdef __x86_64__
+ whpx_apply_breakpoints(whpx_global.breakpoints.breakpoints, cpu, false);
+#endif
+ return 0;
+}
+
+static void do_whpx_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
+{
+ if (!cpu->vcpu_dirty) {
+ whpx_get_registers(cpu);
+ cpu->vcpu_dirty = true;
+ }
+}
+
+static void do_whpx_cpu_synchronize_post_reset(CPUState *cpu,
+ run_on_cpu_data arg)
+{
+ whpx_set_registers(cpu, WHPX_SET_RESET_STATE);
+ cpu->vcpu_dirty = false;
+}
+
+static void do_whpx_cpu_synchronize_post_init(CPUState *cpu,
+ run_on_cpu_data arg)
+{
+ whpx_set_registers(cpu, WHPX_SET_FULL_STATE);
+ cpu->vcpu_dirty = false;
+}
+
+static void do_whpx_cpu_synchronize_pre_loadvm(CPUState *cpu,
+ run_on_cpu_data arg)
+{
+ cpu->vcpu_dirty = true;
+}
+
+/*
+ * CPU support.
+ */
+
+void whpx_cpu_synchronize_state(CPUState *cpu)
+{
+ if (!cpu->vcpu_dirty) {
+ run_on_cpu(cpu, do_whpx_cpu_synchronize_state, RUN_ON_CPU_NULL);
+ }
+}
+
+void whpx_cpu_synchronize_post_reset(CPUState *cpu)
+{
+ run_on_cpu(cpu, do_whpx_cpu_synchronize_post_reset, RUN_ON_CPU_NULL);
+}
+
+void whpx_cpu_synchronize_post_init(CPUState *cpu)
+{
+ run_on_cpu(cpu, do_whpx_cpu_synchronize_post_init, RUN_ON_CPU_NULL);
+}
+
+void whpx_cpu_synchronize_pre_loadvm(CPUState *cpu)
+{
+ run_on_cpu(cpu, do_whpx_cpu_synchronize_pre_loadvm, RUN_ON_CPU_NULL);
+}
+
+static void whpx_pre_resume_vm(AccelState *as, bool step_pending)
+{
+ whpx_global.step_pending = step_pending;
+}
+
+/*
+ * Vcpu support.
+ */
+
+int whpx_vcpu_exec(CPUState *cpu)
+{
+ int ret;
+ int fatal;
+
+ for (;;) {
+ if (cpu->exception_index >= EXCP_INTERRUPT) {
+ ret = cpu->exception_index;
+ cpu->exception_index = -1;
+ break;
+ }
+
+ fatal = whpx_vcpu_run(cpu);
+
+ if (fatal) {
+ error_report("WHPX: Failed to exec a virtual processor");
+ abort();
+ }
+ }
+
+ return ret;
+}
+
+void whpx_destroy_vcpu(CPUState *cpu)
+{
+ struct whpx_state *whpx = &whpx_global;
+
+ whp_dispatch.WHvDeleteVirtualProcessor(whpx->partition, cpu->cpu_index);
+ AccelCPUState *vcpu = cpu->accel;
+ whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator);
+ g_free(cpu->accel);
+}
+
+
+void whpx_vcpu_kick(CPUState *cpu)
+{
+ struct whpx_state *whpx = &whpx_global;
+ whp_dispatch.WHvCancelRunVirtualProcessor(
+ whpx->partition, cpu->cpu_index, 0);
+}
+
+/*
+ * Memory support.
+ */
+
+static void whpx_update_mapping(hwaddr start_pa, ram_addr_t size,
+ void *host_va, int add, int rom,
+ const char *name)
+{
+ struct whpx_state *whpx = &whpx_global;
+ HRESULT hr;
+
+ /*
+ if (add) {
+ printf("WHPX: ADD PA:%p Size:%p, Host:%p, %s, '%s'\n",
+ (void*)start_pa, (void*)size, host_va,
+ (rom ? "ROM" : "RAM"), name);
+ } else {
+ printf("WHPX: DEL PA:%p Size:%p, Host:%p, '%s'\n",
+ (void*)start_pa, (void*)size, host_va, name);
+ }
+ */
+
+ if (add) {
+ hr = whp_dispatch.WHvMapGpaRange(whpx->partition,
+ host_va,
+ start_pa,
+ size,
+ (WHvMapGpaRangeFlagRead |
+ WHvMapGpaRangeFlagExecute |
+ (rom ? 0 : WHvMapGpaRangeFlagWrite)));
+ } else {
+ hr = whp_dispatch.WHvUnmapGpaRange(whpx->partition,
+ start_pa,
+ size);
+ }
+
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to %s GPA range '%s' PA:%p, Size:%p bytes,"
+ " Host:%p, hr=%08lx",
+ (add ? "MAP" : "UNMAP"), name,
+ (void *)(uintptr_t)start_pa, (void *)size, host_va, hr);
+ }
+}
+
+static void whpx_process_section(MemoryRegionSection *section, int add)
+{
+ MemoryRegion *mr = section->mr;
+ hwaddr start_pa = section->offset_within_address_space;
+ ram_addr_t size = int128_get64(section->size);
+ unsigned int delta;
+ uint64_t host_va;
+
+ if (!memory_region_is_ram(mr)) {
+ return;
+ }
+
+ delta = qemu_real_host_page_size() - (start_pa & ~qemu_real_host_page_mask());
+ delta &= ~qemu_real_host_page_mask();
+ if (delta > size) {
+ return;
+ }
+ start_pa += delta;
+ size -= delta;
+ size &= qemu_real_host_page_mask();
+ if (!size || (start_pa & ~qemu_real_host_page_mask())) {
+ return;
+ }
+
+ host_va = (uintptr_t)memory_region_get_ram_ptr(mr)
+ + section->offset_within_region + delta;
+
+ whpx_update_mapping(start_pa, size, (void *)(uintptr_t)host_va, add,
+ memory_region_is_rom(mr), mr->name);
+}
+
+static void whpx_region_add(MemoryListener *listener,
+ MemoryRegionSection *section)
+{
+ memory_region_ref(section->mr);
+ whpx_process_section(section, 1);
+}
+
+static void whpx_region_del(MemoryListener *listener,
+ MemoryRegionSection *section)
+{
+ whpx_process_section(section, 0);
+ memory_region_unref(section->mr);
+}
+
+static void whpx_transaction_begin(MemoryListener *listener)
+{
+}
+
+static void whpx_transaction_commit(MemoryListener *listener)
+{
+}
+
+static void whpx_log_sync(MemoryListener *listener,
+ MemoryRegionSection *section)
+{
+ MemoryRegion *mr = section->mr;
+
+ if (!memory_region_is_ram(mr)) {
+ return;
+ }
+
+ memory_region_set_dirty(mr, 0, int128_get64(section->size));
+}
+
+static MemoryListener whpx_memory_listener = {
+ .name = "whpx",
+ .begin = whpx_transaction_begin,
+ .commit = whpx_transaction_commit,
+ .region_add = whpx_region_add,
+ .region_del = whpx_region_del,
+ .log_sync = whpx_log_sync,
+ .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
+};
+
+void whpx_memory_init(void)
+{
+ memory_listener_register(&whpx_memory_listener, &address_space_memory);
+}
+
+/*
+ * Load the functions from the given library, using the given handle. If a
+ * handle is provided, it is used, otherwise the library is opened. The
+ * handle will be updated on return with the opened one.
+ */
+static bool load_whp_dispatch_fns(HMODULE *handle,
+ WHPFunctionList function_list)
+{
+ HMODULE hLib = *handle;
+
+ #define WINHV_PLATFORM_DLL "WinHvPlatform.dll"
+ #define WINHV_EMULATION_DLL "WinHvEmulation.dll"
+ #define WHP_LOAD_FIELD_OPTIONAL(return_type, function_name, signature) \
+ whp_dispatch.function_name = \
+ (function_name ## _t)GetProcAddress(hLib, #function_name); \
+
+ #define WHP_LOAD_FIELD(return_type, function_name, signature) \
+ whp_dispatch.function_name = \
+ (function_name ## _t)GetProcAddress(hLib, #function_name); \
+ if (!whp_dispatch.function_name) { \
+ error_report("Could not load function %s", #function_name); \
+ goto error; \
+ } \
+
+ #define WHP_LOAD_LIB(lib_name, handle_lib) \
+ if (!handle_lib) { \
+ handle_lib = LoadLibrary(lib_name); \
+ if (!handle_lib) { \
+ error_report("Could not load library %s.", lib_name); \
+ goto error; \
+ } \
+ } \
+
+ switch (function_list) {
+ case WINHV_PLATFORM_FNS_DEFAULT:
+ WHP_LOAD_LIB(WINHV_PLATFORM_DLL, hLib)
+ LIST_WINHVPLATFORM_FUNCTIONS(WHP_LOAD_FIELD)
+ break;
+ case WINHV_EMULATION_FNS_DEFAULT:
+ WHP_LOAD_LIB(WINHV_EMULATION_DLL, hLib)
+ LIST_WINHVEMULATION_FUNCTIONS(WHP_LOAD_FIELD)
+ break;
+ case WINHV_PLATFORM_FNS_SUPPLEMENTAL:
+ WHP_LOAD_LIB(WINHV_PLATFORM_DLL, hLib)
+ LIST_WINHVPLATFORM_FUNCTIONS_SUPPLEMENTAL(WHP_LOAD_FIELD_OPTIONAL)
+ break;
+ }
+
+ *handle = hLib;
+ return true;
+
+error:
+ if (hLib) {
+ FreeLibrary(hLib);
+ }
+
+ return false;
+}
+
+static void whpx_set_kernel_irqchip(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ struct whpx_state *whpx = &whpx_global;
+ OnOffSplit mode;
+
+ if (!visit_type_OnOffSplit(v, name, &mode, errp)) {
+ return;
+ }
+
+ switch (mode) {
+ case ON_OFF_SPLIT_ON:
+ whpx->kernel_irqchip_allowed = true;
+ whpx->kernel_irqchip_required = true;
+ break;
+
+ case ON_OFF_SPLIT_OFF:
+ whpx->kernel_irqchip_allowed = false;
+ whpx->kernel_irqchip_required = false;
+ break;
+
+ case ON_OFF_SPLIT_SPLIT:
+ error_setg(errp, "WHPX: split irqchip currently not supported");
+ error_append_hint(errp,
+ "Try without kernel-irqchip or with kernel-irqchip=on|off");
+ break;
+
+ default:
+ /*
+ * The value was checked in visit_type_OnOffSplit() above. If
+ * we get here, then something is wrong in QEMU.
+ */
+ abort();
+ }
+}
+
+static void whpx_cpu_accel_class_init(ObjectClass *oc, const void *data)
+{
+ AccelCPUClass *acc = ACCEL_CPU_CLASS(oc);
+
+ acc->cpu_instance_init = whpx_cpu_instance_init;
+}
+
+static const TypeInfo whpx_cpu_accel_type = {
+ .name = ACCEL_CPU_NAME("whpx"),
+
+ .parent = TYPE_ACCEL_CPU,
+ .class_init = whpx_cpu_accel_class_init,
+ .abstract = true,
+};
+
+/*
+ * Partition support
+ */
+
+bool whpx_apic_in_platform(void)
+{
+ return whpx_global.apic_in_platform;
+}
+
+static void whpx_accel_class_init(ObjectClass *oc, const void *data)
+{
+ AccelClass *ac = ACCEL_CLASS(oc);
+ ac->name = "WHPX";
+ ac->init_machine = whpx_accel_init;
+ ac->pre_resume_vm = whpx_pre_resume_vm;
+ ac->allowed = &whpx_allowed;
+
+ object_class_property_add(oc, "kernel-irqchip", "on|off|split",
+ NULL, whpx_set_kernel_irqchip,
+ NULL, NULL);
+ object_class_property_set_description(oc, "kernel-irqchip",
+ "Configure WHPX in-kernel irqchip");
+}
+
+static void whpx_accel_instance_init(Object *obj)
+{
+ struct whpx_state *whpx = &whpx_global;
+
+ memset(whpx, 0, sizeof(struct whpx_state));
+ /* Turn on kernel-irqchip, by default */
+ whpx->kernel_irqchip_allowed = true;
+}
+
+static const TypeInfo whpx_accel_type = {
+ .name = ACCEL_CLASS_NAME("whpx"),
+ .parent = TYPE_ACCEL,
+ .instance_init = whpx_accel_instance_init,
+ .class_init = whpx_accel_class_init,
+};
+
+static void whpx_type_init(void)
+{
+ type_register_static(&whpx_accel_type);
+ type_register_static(&whpx_cpu_accel_type);
+}
+
+bool init_whp_dispatch(void)
+{
+ if (whp_dispatch_initialized) {
+ return true;
+ }
+
+ if (!load_whp_dispatch_fns(&hWinHvPlatform, WINHV_PLATFORM_FNS_DEFAULT)) {
+ goto error;
+ }
+
+ if (!load_whp_dispatch_fns(&hWinHvEmulation, WINHV_EMULATION_FNS_DEFAULT)) {
+ goto error;
+ }
+
+ assert(load_whp_dispatch_fns(&hWinHvPlatform,
+ WINHV_PLATFORM_FNS_SUPPLEMENTAL));
+ whp_dispatch_initialized = true;
+
+ return true;
+error:
+ if (hWinHvPlatform) {
+ FreeLibrary(hWinHvPlatform);
+ }
+ if (hWinHvEmulation) {
+ FreeLibrary(hWinHvEmulation);
+ }
+ return false;
+}
+
+type_init(whpx_type_init);
diff --git a/include/system/whpx-accel-ops.h b/include/system/whpx-accel-ops.h
index 54cfc25a14..ed9d4c49f4 100644
--- a/include/system/whpx-accel-ops.h
+++ b/include/system/whpx-accel-ops.h
@@ -7,8 +7,8 @@
* See the COPYING file in the top-level directory.
*/
-#ifndef TARGET_I386_WHPX_ACCEL_OPS_H
-#define TARGET_I386_WHPX_ACCEL_OPS_H
+#ifndef SYSTEM_WHPX_ACCEL_OPS_H
+#define SYSTEM_WHPX_ACCEL_OPS_H
#include "system/cpus.h"
diff --git a/include/system/whpx-all.h b/include/system/whpx-all.h
new file mode 100644
index 0000000000..a82b083284
--- /dev/null
+++ b/include/system/whpx-all.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef SYSTEM_WHPX_ALL_H
+#define SYSTEM_WHPX_ALL_H
+
+/* Called by whpx-common */
+int whpx_vcpu_run(CPUState *cpu);
+void whpx_get_registers(CPUState *cpu);
+void whpx_set_registers(CPUState *cpu, int level);
+int whpx_accel_init(AccelState *as, MachineState *ms);
+void whpx_cpu_instance_init(CPUState *cs);
+HRESULT whpx_set_exception_exit_bitmap(UINT64 exceptions);
+#endif
diff --git a/include/system/whpx-common.h b/include/system/whpx-common.h
new file mode 100644
index 0000000000..e549c7539c
--- /dev/null
+++ b/include/system/whpx-common.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef SYSTEM_WHPX_COMMON_H
+#define SYSTEM_WHPX_COMMON_H
+
+struct AccelCPUState {
+ WHV_EMULATOR_HANDLE emulator;
+ bool window_registered;
+ bool interruptable;
+ bool ready_for_pic_interrupt;
+ uint64_t tpr;
+ uint64_t apic_base;
+ bool interruption_pending;
+ /* Must be the last field as it may have a tail */
+ WHV_RUN_VP_EXIT_CONTEXT exit_ctx;
+};
+
+int whpx_first_vcpu_starting(CPUState *cpu);
+int whpx_last_vcpu_stopping(CPUState *cpu);
+void whpx_memory_init(void);
+struct whpx_breakpoint *whpx_lookup_breakpoint_by_addr(uint64_t address);
+#endif
diff --git a/target/i386/whpx/whpx-internal.h b/include/system/whpx-internal.h
similarity index 98%
rename from target/i386/whpx/whpx-internal.h
rename to include/system/whpx-internal.h
index 435e0c5046..e61375d554 100644
--- a/target/i386/whpx/whpx-internal.h
+++ b/include/system/whpx-internal.h
@@ -1,5 +1,6 @@
-#ifndef TARGET_I386_WHPX_INTERNAL_H
-#define TARGET_I386_WHPX_INTERNAL_H
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef SYSTEM_WHPX_INTERNAL_H
+#define SYSTEM_WHPX_INTERNAL_H
#include <windows.h>
#include <winhvplatform.h>
@@ -117,4 +118,3 @@ typedef enum WHPFunctionList {
} WHPFunctionList;
#endif /* TARGET_I386_WHPX_INTERNAL_H */
-
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index 5a431fc3c7..4b4be67773 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -33,6 +33,8 @@
#include "system/whpx-internal.h"
#include "system/whpx-accel-ops.h"
+#include "system/whpx-all.h"
+#include "system/whpx-common.h"
#include <winhvplatform.h>
#include <winhvemulation.h>
@@ -931,7 +933,7 @@ static int whpx_handle_portio(CPUState *cpu,
* The 'exceptions' argument accepts a bitmask, e.g:
* (1 << WHvX64ExceptionTypeDebugTrapOrFault) | (...)
*/
-static HRESULT whpx_set_exception_exit_bitmap(UINT64 exceptions)
+HRESULT whpx_set_exception_exit_bitmap(UINT64 exceptions)
{
struct whpx_state *whpx = &whpx_global;
WHV_PARTITION_PROPERTY prop = { 0, };
@@ -1081,23 +1083,6 @@ static HRESULT whpx_vcpu_configure_single_stepping(CPUState *cpu,
return S_OK;
}
-/* Tries to find a breakpoint at the specified address. */
-static struct whpx_breakpoint *whpx_lookup_breakpoint_by_addr(uint64_t address)
-{
- struct whpx_state *whpx = &whpx_global;
- int i;
-
- if (whpx->breakpoints.breakpoints) {
- for (i = 0; i < whpx->breakpoints.breakpoints->used; i++) {
- if (address == whpx->breakpoints.breakpoints->data[i].address) {
- return &whpx->breakpoints.breakpoints->data[i];
- }
- }
- }
-
- return NULL;
-}
-
/*
* Linux uses int3 (0xCC) during startup (see int3_selftest()) and for
* debugging user-mode applications. Since the WHPX API does not offer
@@ -1303,93 +1288,6 @@ static void whpx_apply_breakpoints(
}
}
-/*
- * This function is called when the a VCPU is about to start and no other
- * VCPUs have been started so far. Since the VCPU start order could be
- * arbitrary, it doesn't have to be VCPU#0.
- *
- * It is used to commit the breakpoints into memory, and configure WHPX
- * to intercept debug exceptions.
- *
- * Note that whpx_set_exception_exit_bitmap() cannot be called if one or
- * more VCPUs are already running, so this is the best place to do it.
- */
-static int whpx_first_vcpu_starting(CPUState *cpu)
-{
- struct whpx_state *whpx = &whpx_global;
- HRESULT hr;
-
- g_assert(bql_locked());
-
- if (!QTAILQ_EMPTY(&cpu->breakpoints) ||
- (whpx->breakpoints.breakpoints &&
- whpx->breakpoints.breakpoints->used)) {
- CPUBreakpoint *bp;
- int i = 0;
- bool update_pending = false;
-
- QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
- if (i >= whpx->breakpoints.original_address_count ||
- bp->pc != whpx->breakpoints.original_addresses[i]) {
- update_pending = true;
- }
-
- i++;
- }
-
- if (i != whpx->breakpoints.original_address_count) {
- update_pending = true;
- }
-
- if (update_pending) {
- /*
- * The CPU breakpoints have changed since the last call to
- * whpx_translate_cpu_breakpoints(). WHPX breakpoints must
- * now be recomputed.
- */
- whpx_translate_cpu_breakpoints(&whpx->breakpoints, cpu, i);
- }
-
- /* Actually insert the breakpoints into the memory. */
- whpx_apply_breakpoints(whpx->breakpoints.breakpoints, cpu, true);
- }
-
- uint64_t exception_mask;
- if (whpx->step_pending ||
- (whpx->breakpoints.breakpoints &&
- whpx->breakpoints.breakpoints->used)) {
- /*
- * We are either attempting to single-step one or more CPUs, or
- * have one or more breakpoints enabled. Both require intercepting
- * the WHvX64ExceptionTypeBreakpointTrap exception.
- */
-
- exception_mask = 1UL << WHvX64ExceptionTypeDebugTrapOrFault;
- } else {
- /* Let the guest handle all exceptions. */
- exception_mask = 0;
- }
-
- hr = whpx_set_exception_exit_bitmap(exception_mask);
- if (!SUCCEEDED(hr)) {
- error_report("WHPX: Failed to update exception exit mask,"
- "hr=%08lx.", hr);
- return 1;
- }
-
- return 0;
-}
-
-/*
- * This function is called when the last VCPU has finished running.
- * It is used to remove any previously set breakpoints from memory.
- */
-static int whpx_last_vcpu_stopping(CPUState *cpu)
-{
- whpx_apply_breakpoints(whpx_global.breakpoints.breakpoints, cpu, false);
- return 0;
-}
-
/* Returns the address of the next instruction that is about to be executed. */
static vaddr whpx_vcpu_get_pc(CPUState *cpu, bool exit_context_valid)
{
@@ -2054,65 +1952,6 @@ static int whpx_vcpu_run(CPUState *cpu)
return ret < 0;
}
-static void do_whpx_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
-{
- if (!cpu->vcpu_dirty) {
- whpx_get_registers(cpu);
- cpu->vcpu_dirty = true;
- }
-}
-
-static void do_whpx_cpu_synchronize_post_reset(CPUState *cpu,
- run_on_cpu_data arg)
-{
- whpx_set_registers(cpu, WHPX_SET_RESET_STATE);
- cpu->vcpu_dirty = false;
-}
-
-static void do_whpx_cpu_synchronize_post_init(CPUState *cpu,
- run_on_cpu_data arg)
-{
- whpx_set_registers(cpu, WHPX_SET_FULL_STATE);
- cpu->vcpu_dirty = false;
-}
-
-static void do_whpx_cpu_synchronize_pre_loadvm(CPUState *cpu,
- run_on_cpu_data arg)
-{
- cpu->vcpu_dirty = true;
-}
-
-/*
- * CPU support.
- */
-
-void whpx_cpu_synchronize_state(CPUState *cpu)
-{
- if (!cpu->vcpu_dirty) {
- run_on_cpu(cpu, do_whpx_cpu_synchronize_state, RUN_ON_CPU_NULL);
- }
-}
-
-void whpx_cpu_synchronize_post_reset(CPUState *cpu)
-{
- run_on_cpu(cpu, do_whpx_cpu_synchronize_post_reset, RUN_ON_CPU_NULL);
-}
-
-void whpx_cpu_synchronize_post_init(CPUState *cpu)
-{
- run_on_cpu(cpu, do_whpx_cpu_synchronize_post_init, RUN_ON_CPU_NULL);
-}
-
-void whpx_cpu_synchronize_pre_loadvm(CPUState *cpu)
-{
- run_on_cpu(cpu, do_whpx_cpu_synchronize_pre_loadvm, RUN_ON_CPU_NULL);
-}
-
-static void whpx_pre_resume_vm(AccelState *as, bool step_pending)
-{
- whpx_global.step_pending = step_pending;
-}
-
/*
* Vcpu support.
*/
@@ -2241,295 +2080,18 @@ error:
return ret;
}
-int whpx_vcpu_exec(CPUState *cpu)
-{
- int ret;
- int fatal;
-
- for (;;) {
- if (cpu->exception_index >= EXCP_INTERRUPT) {
- ret = cpu->exception_index;
- cpu->exception_index = -1;
- break;
- }
-
- fatal = whpx_vcpu_run(cpu);
-
- if (fatal) {
- error_report("WHPX: Failed to exec a virtual processor");
- abort();
- }
- }
-
- return ret;
-}
-
-void whpx_destroy_vcpu(CPUState *cpu)
-{
- struct whpx_state *whpx = &whpx_global;
- AccelCPUState *vcpu = cpu->accel;
-
- whp_dispatch.WHvDeleteVirtualProcessor(whpx->partition, cpu->cpu_index);
- whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator);
- g_free(cpu->accel);
-}
-
-void whpx_vcpu_kick(CPUState *cpu)
-{
- struct whpx_state *whpx = &whpx_global;
- whp_dispatch.WHvCancelRunVirtualProcessor(
- whpx->partition, cpu->cpu_index, 0);
-}
-
-/*
- * Memory support.
- */
-
-static void whpx_update_mapping(hwaddr start_pa, ram_addr_t size,
- void *host_va, int add, int rom,
- const char *name)
-{
- struct whpx_state *whpx = &whpx_global;
- HRESULT hr;
-
- /*
- if (add) {
- printf("WHPX: ADD PA:%p Size:%p, Host:%p, %s, '%s'\n",
- (void*)start_pa, (void*)size, host_va,
- (rom ? "ROM" : "RAM"), name);
- } else {
- printf("WHPX: DEL PA:%p Size:%p, Host:%p, '%s'\n",
- (void*)start_pa, (void*)size, host_va, name);
- }
- */
-
- if (add) {
- hr = whp_dispatch.WHvMapGpaRange(whpx->partition,
- host_va,
- start_pa,
- size,
- (WHvMapGpaRangeFlagRead |
- WHvMapGpaRangeFlagExecute |
- (rom ? 0 : WHvMapGpaRangeFlagWrite)));
- } else {
- hr = whp_dispatch.WHvUnmapGpaRange(whpx->partition,
- start_pa,
- size);
- }
-
- if (FAILED(hr)) {
- error_report("WHPX: Failed to %s GPA range '%s' PA:%p, Size:%p bytes,"
- " Host:%p, hr=%08lx",
- (add ? "MAP" : "UNMAP"), name,
- (void *)(uintptr_t)start_pa, (void *)size, host_va, hr);
- }
-}
-
-static void whpx_process_section(MemoryRegionSection *section, int add)
-{
- MemoryRegion *mr = section->mr;
- hwaddr start_pa = section->offset_within_address_space;
- ram_addr_t size = int128_get64(section->size);
- unsigned int delta;
- uint64_t host_va;
-
- if (!memory_region_is_ram(mr)) {
- return;
- }
-
- delta = qemu_real_host_page_size() - (start_pa & ~qemu_real_host_page_mask());
- delta &= ~qemu_real_host_page_mask();
- if (delta > size) {
- return;
- }
- start_pa += delta;
- size -= delta;
- size &= qemu_real_host_page_mask();
- if (!size || (start_pa & ~qemu_real_host_page_mask())) {
- return;
- }
-
- host_va = (uintptr_t)memory_region_get_ram_ptr(mr)
- + section->offset_within_region + delta;
-
- whpx_update_mapping(start_pa, size, (void *)(uintptr_t)host_va, add,
- memory_region_is_rom(mr), mr->name);
-}
-
-static void whpx_region_add(MemoryListener *listener,
- MemoryRegionSection *section)
-{
- memory_region_ref(section->mr);
- whpx_process_section(section, 1);
-}
-
-static void whpx_region_del(MemoryListener *listener,
- MemoryRegionSection *section)
-{
- whpx_process_section(section, 0);
- memory_region_unref(section->mr);
-}
-
-static void whpx_transaction_begin(MemoryListener *listener)
-{
-}
-
-static void whpx_transaction_commit(MemoryListener *listener)
-{
-}
-
-static void whpx_log_sync(MemoryListener *listener,
- MemoryRegionSection *section)
-{
- MemoryRegion *mr = section->mr;
-
- if (!memory_region_is_ram(mr)) {
- return;
- }
-
- memory_region_set_dirty(mr, 0, int128_get64(section->size));
-}
-
-static MemoryListener whpx_memory_listener = {
- .name = "whpx",
- .begin = whpx_transaction_begin,
- .commit = whpx_transaction_commit,
- .region_add = whpx_region_add,
- .region_del = whpx_region_del,
- .log_sync = whpx_log_sync,
- .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
-};
-
-static void whpx_memory_init(void)
-{
- memory_listener_register(&whpx_memory_listener, &address_space_memory);
-}
-
-/*
- * Load the functions from the given library, using the given handle. If a
- * handle is provided, it is used, otherwise the library is opened. The
- * handle will be updated on return with the opened one.
- */
-static bool load_whp_dispatch_fns(HMODULE *handle,
- WHPFunctionList function_list)
-{
- HMODULE hLib = *handle;
-
- #define WINHV_PLATFORM_DLL "WinHvPlatform.dll"
- #define WINHV_EMULATION_DLL "WinHvEmulation.dll"
- #define WHP_LOAD_FIELD_OPTIONAL(return_type, function_name, signature) \
- whp_dispatch.function_name = \
- (function_name ## _t)GetProcAddress(hLib, #function_name); \
-
- #define WHP_LOAD_FIELD(return_type, function_name, signature) \
- whp_dispatch.function_name = \
- (function_name ## _t)GetProcAddress(hLib, #function_name); \
- if (!whp_dispatch.function_name) { \
- error_report("Could not load function %s", #function_name); \
- goto error; \
- } \
-
- #define WHP_LOAD_LIB(lib_name, handle_lib) \
- if (!handle_lib) { \
- handle_lib = LoadLibrary(lib_name); \
- if (!handle_lib) { \
- error_report("Could not load library %s.", lib_name); \
- goto error; \
- } \
- } \
-
- switch (function_list) {
- case WINHV_PLATFORM_FNS_DEFAULT:
- WHP_LOAD_LIB(WINHV_PLATFORM_DLL, hLib)
- LIST_WINHVPLATFORM_FUNCTIONS(WHP_LOAD_FIELD)
- break;
-
- case WINHV_EMULATION_FNS_DEFAULT:
- WHP_LOAD_LIB(WINHV_EMULATION_DLL, hLib)
- LIST_WINHVEMULATION_FUNCTIONS(WHP_LOAD_FIELD)
- break;
-
- case WINHV_PLATFORM_FNS_SUPPLEMENTAL:
- WHP_LOAD_LIB(WINHV_PLATFORM_DLL, hLib)
- LIST_WINHVPLATFORM_FUNCTIONS_SUPPLEMENTAL(WHP_LOAD_FIELD_OPTIONAL)
- break;
- }
-
- *handle = hLib;
- return true;
-
-error:
- if (hLib) {
- FreeLibrary(hLib);
- }
-
- return false;
-}
-
-static void whpx_set_kernel_irqchip(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- struct whpx_state *whpx = &whpx_global;
- OnOffSplit mode;
-
- if (!visit_type_OnOffSplit(v, name, &mode, errp)) {
- return;
- }
-
- switch (mode) {
- case ON_OFF_SPLIT_ON:
- whpx->kernel_irqchip_allowed = true;
- whpx->kernel_irqchip_required = true;
- break;
-
- case ON_OFF_SPLIT_OFF:
- whpx->kernel_irqchip_allowed = false;
- whpx->kernel_irqchip_required = false;
- break;
-
- case ON_OFF_SPLIT_SPLIT:
- error_setg(errp, "WHPX: split irqchip currently not supported");
- error_append_hint(errp,
- "Try without kernel-irqchip or with kernel-irqchip=on|off");
- break;
-
- default:
- /*
- * The value was checked in visit_type_OnOffSplit() above. If
- * we get here, then something is wrong in QEMU.
- */
- abort();
- }
-}
-
-static void whpx_cpu_instance_init(CPUState *cs)
+void whpx_cpu_instance_init(CPUState *cs)
{
X86CPU *cpu = X86_CPU(cs);
host_cpu_instance_init(cpu);
}
-static void whpx_cpu_accel_class_init(ObjectClass *oc, const void *data)
-{
- AccelCPUClass *acc = ACCEL_CPU_CLASS(oc);
-
- acc->cpu_instance_init = whpx_cpu_instance_init;
-}
-
-static const TypeInfo whpx_cpu_accel_type = {
- .name = ACCEL_CPU_NAME("whpx"),
-
- .parent = TYPE_ACCEL_CPU,
- .class_init = whpx_cpu_accel_class_init,
- .abstract = true,
-};
-
/*
* Partition support
*/
-static int whpx_accel_init(AccelState *as, MachineState *ms)
+int whpx_accel_init(AccelState *as, MachineState *ms)
{
struct whpx_state *whpx;
int ret;
@@ -2712,77 +2274,3 @@ error:
return ret;
}
-
-bool whpx_apic_in_platform(void) {
- return whpx_global.apic_in_platform;
-}
-
-static void whpx_accel_class_init(ObjectClass *oc, const void *data)
-{
- AccelClass *ac = ACCEL_CLASS(oc);
- ac->name = "WHPX";
- ac->init_machine = whpx_accel_init;
- ac->pre_resume_vm = whpx_pre_resume_vm;
- ac->allowed = &whpx_allowed;
-
- object_class_property_add(oc, "kernel-irqchip", "on|off|split",
- NULL, whpx_set_kernel_irqchip,
- NULL, NULL);
- object_class_property_set_description(oc, "kernel-irqchip",
- "Configure WHPX in-kernel irqchip");
-}
-
-static void whpx_accel_instance_init(Object *obj)
-{
- struct whpx_state *whpx = &whpx_global;
-
- memset(whpx, 0, sizeof(struct whpx_state));
- /* Turn on kernel-irqchip, by default */
- whpx->kernel_irqchip_allowed = true;
-}
-
-static const TypeInfo whpx_accel_type = {
- .name = ACCEL_CLASS_NAME("whpx"),
- .parent = TYPE_ACCEL,
- .instance_init = whpx_accel_instance_init,
- .class_init = whpx_accel_class_init,
-};
-
-static void whpx_type_init(void)
-{
- type_register_static(&whpx_accel_type);
- type_register_static(&whpx_cpu_accel_type);
-}
-
-bool init_whp_dispatch(void)
-{
- if (whp_dispatch_initialized) {
- return true;
- }
-
- if (!load_whp_dispatch_fns(&hWinHvPlatform, WINHV_PLATFORM_FNS_DEFAULT)) {
- goto error;
- }
-
- if (!load_whp_dispatch_fns(&hWinHvEmulation, WINHV_EMULATION_FNS_DEFAULT)) {
- goto error;
- }
-
- assert(load_whp_dispatch_fns(&hWinHvPlatform,
- WINHV_PLATFORM_FNS_SUPPLEMENTAL));
- whp_dispatch_initialized = true;
-
- return true;
-error:
- if (hWinHvPlatform) {
- FreeLibrary(hWinHvPlatform);
- }
-
- if (hWinHvEmulation) {
- FreeLibrary(hWinHvEmulation);
- }
-
- return false;
-}
-
-type_init(whpx_type_init);
diff --git a/target/i386/whpx/whpx-apic.c b/target/i386/whpx/whpx-apic.c
index e1ef6d4e6d..badb404b63 100644
--- a/target/i386/whpx/whpx-apic.c
+++ b/target/i386/whpx/whpx-apic.c
@@ -18,7 +18,7 @@
#include "hw/pci/msi.h"
#include "system/hw_accel.h"
#include "system/whpx.h"
-#include "whpx-internal.h"
+#include "system/whpx-internal.h"
struct whpx_lapic_state {
struct {
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 04/14] whpx: ifdef out some x86-only code paths
2025-08-02 8:17 [PATCH v3 00/14] WHPX support for Arm Mohamed Mediouni
` (2 preceding siblings ...)
2025-08-02 8:17 ` [PATCH v3 03/14] whpx: reshuffle common code Mohamed Mediouni
@ 2025-08-02 8:17 ` Mohamed Mediouni
2025-08-03 0:41 ` Richard Henderson
2025-08-03 0:51 ` Richard Henderson
2025-08-02 8:17 ` [PATCH v3 05/14] hw, target, accel: whpx: change apic_in_platform to kernel_irqchip Mohamed Mediouni
` (9 subsequent siblings)
13 siblings, 2 replies; 32+ messages in thread
From: Mohamed Mediouni @ 2025-08-02 8:17 UTC (permalink / raw)
To: qemu-devel
Cc: Richard Henderson, Zhao Liu, Yanan Wang, qemu-arm,
Sunil Muthuswamy, Daniel P. Berrangé, Igor Mammedov,
Peter Maydell, Shannon Zhao, Michael S. Tsirkin,
Marc-André Lureau, Eduardo Habkost, Marcel Apfelbaum,
Mohamed Mediouni, Paolo Bonzini, Philippe Mathieu-Daudé,
Ani Sinha
winhvemulation is x86_64 only.
Exception exit bitmaps are also x86_64 only
Others are just variable definitions not used on arm64.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
accel/whpx/whpx-common.c | 20 ++++++++++++++++++--
include/system/whpx-all.h | 2 ++
include/system/whpx-common.h | 2 ++
include/system/whpx-internal.h | 7 ++++++-
4 files changed, 28 insertions(+), 3 deletions(-)
diff --git a/accel/whpx/whpx-common.c b/accel/whpx/whpx-common.c
index b5e5fda696..eeefaea329 100644
--- a/accel/whpx/whpx-common.c
+++ b/accel/whpx/whpx-common.c
@@ -41,7 +41,9 @@
bool whpx_allowed;
static bool whp_dispatch_initialized;
static HMODULE hWinHvPlatform;
+#ifdef __x86_64__
static HMODULE hWinHvEmulation;
+#endif
struct whpx_state whpx_global;
struct WHPDispatch whp_dispatch;
@@ -106,11 +108,16 @@ int whpx_first_vcpu_starting(CPUState *cpu)
* whpx_translate_cpu_breakpoints(). WHPX breakpoints must
* now be recomputed.
*/
+#ifdef __x86_64__
whpx_translate_cpu_breakpoints(&whpx->breakpoints, cpu, i);
+#endif
}
+#ifdef __x86_64__
/* Actually insert the breakpoints into the memory. */
whpx_apply_breakpoints(whpx->breakpoints.breakpoints, cpu, true);
+#endif
}
+#ifdef __x86_64__
HRESULT hr;
uint64_t exception_mask;
if (whpx->step_pending ||
@@ -132,6 +139,7 @@ int whpx_first_vcpu_starting(CPUState *cpu)
"hr=%08lx.", hr);
return 1;
}
+#endif
return 0;
}
@@ -238,8 +246,10 @@ void whpx_destroy_vcpu(CPUState *cpu)
struct whpx_state *whpx = &whpx_global;
whp_dispatch.WHvDeleteVirtualProcessor(whpx->partition, cpu->cpu_index);
+#ifdef __x86_64__
AccelCPUState *vcpu = cpu->accel;
whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator);
+#endif
g_free(cpu->accel);
}
@@ -414,8 +424,12 @@ static bool load_whp_dispatch_fns(HMODULE *handle,
LIST_WINHVPLATFORM_FUNCTIONS(WHP_LOAD_FIELD)
break;
case WINHV_EMULATION_FNS_DEFAULT:
+#ifdef __x86_64__
WHP_LOAD_LIB(WINHV_EMULATION_DLL, hLib)
LIST_WINHVEMULATION_FUNCTIONS(WHP_LOAD_FIELD)
+#else
+ abort();
+#endif
break;
case WINHV_PLATFORM_FNS_SUPPLEMENTAL:
WHP_LOAD_LIB(WINHV_PLATFORM_DLL, hLib)
@@ -541,11 +555,11 @@ bool init_whp_dispatch(void)
if (!load_whp_dispatch_fns(&hWinHvPlatform, WINHV_PLATFORM_FNS_DEFAULT)) {
goto error;
}
-
+#ifdef __x86_64__
if (!load_whp_dispatch_fns(&hWinHvEmulation, WINHV_EMULATION_FNS_DEFAULT)) {
goto error;
}
-
+#endif
assert(load_whp_dispatch_fns(&hWinHvPlatform,
WINHV_PLATFORM_FNS_SUPPLEMENTAL));
whp_dispatch_initialized = true;
@@ -555,9 +569,11 @@ error:
if (hWinHvPlatform) {
FreeLibrary(hWinHvPlatform);
}
+#ifdef __x86_64__
if (hWinHvEmulation) {
FreeLibrary(hWinHvEmulation);
}
+#endif
return false;
}
diff --git a/include/system/whpx-all.h b/include/system/whpx-all.h
index a82b083284..838a25fa75 100644
--- a/include/system/whpx-all.h
+++ b/include/system/whpx-all.h
@@ -8,5 +8,7 @@ void whpx_get_registers(CPUState *cpu);
void whpx_set_registers(CPUState *cpu, int level);
int whpx_accel_init(AccelState *as, MachineState *ms);
void whpx_cpu_instance_init(CPUState *cs);
+#ifdef __x86_64__
HRESULT whpx_set_exception_exit_bitmap(UINT64 exceptions);
#endif
+#endif
diff --git a/include/system/whpx-common.h b/include/system/whpx-common.h
index e549c7539c..629810b384 100644
--- a/include/system/whpx-common.h
+++ b/include/system/whpx-common.h
@@ -3,6 +3,7 @@
#define SYSTEM_WHPX_COMMON_H
struct AccelCPUState {
+#ifdef __x86_64__
WHV_EMULATOR_HANDLE emulator;
bool window_registered;
bool interruptable;
@@ -10,6 +11,7 @@ struct AccelCPUState {
uint64_t tpr;
uint64_t apic_base;
bool interruption_pending;
+#endif
/* Must be the last field as it may have a tail */
WHV_RUN_VP_EXIT_CONTEXT exit_ctx;
};
diff --git a/include/system/whpx-internal.h b/include/system/whpx-internal.h
index e61375d554..e57d2c8526 100644
--- a/include/system/whpx-internal.h
+++ b/include/system/whpx-internal.h
@@ -4,8 +4,9 @@
#include <windows.h>
#include <winhvplatform.h>
+#ifdef __x86_64__
#include <winhvemulation.h>
-
+#endif
typedef enum WhpxBreakpointState {
WHPX_BP_CLEARED = 0,
WHPX_BP_SET_PENDING,
@@ -98,12 +99,16 @@ void whpx_apic_get(DeviceState *s);
/* Define function typedef */
LIST_WINHVPLATFORM_FUNCTIONS(WHP_DEFINE_TYPE)
+#ifdef __x86_64__
LIST_WINHVEMULATION_FUNCTIONS(WHP_DEFINE_TYPE)
+#endif
LIST_WINHVPLATFORM_FUNCTIONS_SUPPLEMENTAL(WHP_DEFINE_TYPE)
struct WHPDispatch {
LIST_WINHVPLATFORM_FUNCTIONS(WHP_DECLARE_MEMBER)
+#ifdef __x86_64__
LIST_WINHVEMULATION_FUNCTIONS(WHP_DECLARE_MEMBER)
+#endif
LIST_WINHVPLATFORM_FUNCTIONS_SUPPLEMENTAL(WHP_DECLARE_MEMBER)
};
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 05/14] hw, target, accel: whpx: change apic_in_platform to kernel_irqchip
2025-08-02 8:17 [PATCH v3 00/14] WHPX support for Arm Mohamed Mediouni
` (3 preceding siblings ...)
2025-08-02 8:17 ` [PATCH v3 04/14] whpx: ifdef out some x86-only code paths Mohamed Mediouni
@ 2025-08-02 8:17 ` Mohamed Mediouni
2025-08-03 0:42 ` Richard Henderson
2025-08-02 8:17 ` [PATCH v3 06/14] whpx: interrupt controller support Mohamed Mediouni
` (8 subsequent siblings)
13 siblings, 1 reply; 32+ messages in thread
From: Mohamed Mediouni @ 2025-08-02 8:17 UTC (permalink / raw)
To: qemu-devel
Cc: Richard Henderson, Zhao Liu, Yanan Wang, qemu-arm,
Sunil Muthuswamy, Daniel P. Berrangé, Igor Mammedov,
Peter Maydell, Shannon Zhao, Michael S. Tsirkin,
Marc-André Lureau, Eduardo Habkost, Marcel Apfelbaum,
Mohamed Mediouni, Paolo Bonzini, Philippe Mathieu-Daudé,
Ani Sinha
Change terminology to match the KVM one, as APIC is x86-specific.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
accel/whpx/whpx-accel-ops.c | 2 +-
accel/whpx/whpx-common.c | 4 ++--
hw/i386/x86-cpu.c | 4 ++--
include/system/whpx-internal.h | 2 +-
include/system/whpx.h | 4 ++--
target/i386/cpu-apic.c | 2 +-
target/i386/whpx/whpx-all.c | 14 +++++++-------
7 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/accel/whpx/whpx-accel-ops.c b/accel/whpx/whpx-accel-ops.c
index 18488421bc..ef1fe52860 100644
--- a/accel/whpx/whpx-accel-ops.c
+++ b/accel/whpx/whpx-accel-ops.c
@@ -80,7 +80,7 @@ static void whpx_kick_vcpu_thread(CPUState *cpu)
static bool whpx_vcpu_thread_is_idle(CPUState *cpu)
{
- return !whpx_apic_in_platform();
+ return !whpx_irqchip_in_kernel();
}
static void whpx_accel_ops_class_init(ObjectClass *oc, const void *data)
diff --git a/accel/whpx/whpx-common.c b/accel/whpx/whpx-common.c
index eeefaea329..9d702c544b 100644
--- a/accel/whpx/whpx-common.c
+++ b/accel/whpx/whpx-common.c
@@ -504,9 +504,9 @@ static const TypeInfo whpx_cpu_accel_type = {
* Partition support
*/
-bool whpx_apic_in_platform(void)
+bool whpx_irqchip_in_kernel(void)
{
- return whpx_global.apic_in_platform;
+ return whpx_global.kernel_irqchip;
}
static void whpx_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/hw/i386/x86-cpu.c b/hw/i386/x86-cpu.c
index c876e6709e..778607e7ca 100644
--- a/hw/i386/x86-cpu.c
+++ b/hw/i386/x86-cpu.c
@@ -45,7 +45,7 @@ static void pic_irq_request(void *opaque, int irq, int level)
trace_x86_pic_interrupt(irq, level);
if (cpu_is_apic_enabled(cpu->apic_state) && !kvm_irqchip_in_kernel() &&
- !whpx_apic_in_platform()) {
+ !whpx_irqchip_in_kernel()) {
CPU_FOREACH(cs) {
cpu = X86_CPU(cs);
if (apic_accept_pic_intr(cpu->apic_state)) {
@@ -71,7 +71,7 @@ int cpu_get_pic_interrupt(CPUX86State *env)
X86CPU *cpu = env_archcpu(env);
int intno;
- if (!kvm_irqchip_in_kernel() && !whpx_apic_in_platform()) {
+ if (!kvm_irqchip_in_kernel() && !whpx_irqchip_in_kernel()) {
intno = apic_get_interrupt(cpu->apic_state);
if (intno >= 0) {
return intno;
diff --git a/include/system/whpx-internal.h b/include/system/whpx-internal.h
index e57d2c8526..366bc525a3 100644
--- a/include/system/whpx-internal.h
+++ b/include/system/whpx-internal.h
@@ -42,7 +42,7 @@ struct whpx_state {
bool kernel_irqchip_allowed;
bool kernel_irqchip_required;
- bool apic_in_platform;
+ bool kernel_irqchip;
};
extern struct whpx_state whpx_global;
diff --git a/include/system/whpx.h b/include/system/whpx.h
index 00f6a3e523..98fe045ba1 100644
--- a/include/system/whpx.h
+++ b/include/system/whpx.h
@@ -26,10 +26,10 @@
#ifdef CONFIG_WHPX_IS_POSSIBLE
extern bool whpx_allowed;
#define whpx_enabled() (whpx_allowed)
-bool whpx_apic_in_platform(void);
+bool whpx_irqchip_in_kernel(void);
#else /* !CONFIG_WHPX_IS_POSSIBLE */
#define whpx_enabled() 0
-#define whpx_apic_in_platform() (0)
+#define whpx_irqchip_in_kernel() (0)
#endif /* !CONFIG_WHPX_IS_POSSIBLE */
#endif /* QEMU_WHPX_H */
diff --git a/target/i386/cpu-apic.c b/target/i386/cpu-apic.c
index 242a05fdbe..d4d371a616 100644
--- a/target/i386/cpu-apic.c
+++ b/target/i386/cpu-apic.c
@@ -32,7 +32,7 @@ APICCommonClass *apic_get_class(Error **errp)
apic_type = "kvm-apic";
} else if (xen_enabled()) {
apic_type = "xen-apic";
- } else if (whpx_apic_in_platform()) {
+ } else if (whpx_irqchip_in_kernel()) {
apic_type = "whpx-apic";
}
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index 4b4be67773..0ab9aad4cf 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -626,7 +626,7 @@ static void whpx_get_registers(CPUState *cpu)
hr);
}
- if (whpx_apic_in_platform()) {
+ if (whpx_irqchip_in_kernel()) {
/*
* Fetch the TPR value from the emulated APIC. It may get overwritten
* below with the value from CR8 returned by
@@ -768,7 +768,7 @@ static void whpx_get_registers(CPUState *cpu)
assert(idx == RTL_NUMBER_OF(whpx_register_names));
- if (whpx_apic_in_platform()) {
+ if (whpx_irqchip_in_kernel()) {
whpx_apic_get(x86_cpu->apic_state);
}
@@ -1395,7 +1395,7 @@ static void whpx_vcpu_pre_run(CPUState *cpu)
}
/* Get pending hard interruption or replay one that was overwritten */
- if (!whpx_apic_in_platform()) {
+ if (!whpx_irqchip_in_kernel()) {
if (!vcpu->interruption_pending &&
vcpu->interruptable && (env->eflags & IF_MASK)) {
assert(!new_int.InterruptionPending);
@@ -1568,7 +1568,7 @@ static int whpx_vcpu_run(CPUState *cpu)
if (exclusive_step_mode == WHPX_STEP_NONE) {
whpx_vcpu_process_async_events(cpu);
- if (cpu->halted && !whpx_apic_in_platform()) {
+ if (cpu->halted && !whpx_irqchip_in_kernel()) {
cpu->exception_index = EXCP_HLT;
qatomic_set(&cpu->exit_request, false);
return 0;
@@ -1656,7 +1656,7 @@ static int whpx_vcpu_run(CPUState *cpu)
break;
case WHvRunVpExitReasonX64ApicEoi:
- assert(whpx_apic_in_platform());
+ assert(whpx_irqchip_in_kernel());
ioapic_eoi_broadcast(vcpu->exit_ctx.ApicEoi.InterruptVector);
break;
@@ -2203,7 +2203,7 @@ int whpx_accel_init(AccelState *as, MachineState *ms)
goto error;
}
} else {
- whpx->apic_in_platform = true;
+ whpx->kernel_irqchip = true;
}
}
@@ -2212,7 +2212,7 @@ int whpx_accel_init(AccelState *as, MachineState *ms)
prop.ExtendedVmExits.X64MsrExit = 1;
prop.ExtendedVmExits.X64CpuidExit = 1;
prop.ExtendedVmExits.ExceptionExit = 1;
- if (whpx_apic_in_platform()) {
+ if (whpx_irqchip_in_kernel()) {
prop.ExtendedVmExits.X64ApicInitSipiExitTrap = 1;
}
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 06/14] whpx: interrupt controller support
2025-08-02 8:17 [PATCH v3 00/14] WHPX support for Arm Mohamed Mediouni
` (4 preceding siblings ...)
2025-08-02 8:17 ` [PATCH v3 05/14] hw, target, accel: whpx: change apic_in_platform to kernel_irqchip Mohamed Mediouni
@ 2025-08-02 8:17 ` Mohamed Mediouni
2025-08-02 8:17 ` [PATCH v3 07/14] whpx: add arm64 support Mohamed Mediouni
` (7 subsequent siblings)
13 siblings, 0 replies; 32+ messages in thread
From: Mohamed Mediouni @ 2025-08-02 8:17 UTC (permalink / raw)
To: qemu-devel
Cc: Richard Henderson, Zhao Liu, Yanan Wang, qemu-arm,
Sunil Muthuswamy, Daniel P. Berrangé, Igor Mammedov,
Peter Maydell, Shannon Zhao, Michael S. Tsirkin,
Marc-André Lureau, Eduardo Habkost, Marcel Apfelbaum,
Mohamed Mediouni, Paolo Bonzini, Philippe Mathieu-Daudé,
Ani Sinha
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
hw/arm/virt.c | 3 +
hw/intc/arm_gicv3_common.c | 3 +
hw/intc/arm_gicv3_whpx.c | 261 +++++++++++++++++++++++++++++
hw/intc/meson.build | 1 +
include/hw/intc/arm_gicv3_common.h | 3 +
5 files changed, 271 insertions(+)
create mode 100644 hw/intc/arm_gicv3_whpx.c
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 5951b331f3..98a1c74c42 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -49,6 +49,7 @@
#include "system/tcg.h"
#include "system/kvm.h"
#include "system/hvf.h"
+#include "system/whpx.h"
#include "system/qtest.h"
#include "hw/loader.h"
#include "qapi/error.h"
@@ -2060,6 +2061,8 @@ static void finalize_gic_version(VirtMachineState *vms)
/* KVM w/o kernel irqchip can only deal with GICv2 */
gics_supported |= VIRT_GIC_VERSION_2_MASK;
accel_name = "KVM with kernel-irqchip=off";
+ } else if (whpx_enabled()) {
+ gics_supported |= VIRT_GIC_VERSION_3_MASK;
} else if (tcg_enabled() || hvf_enabled() || qtest_enabled()) {
gics_supported |= VIRT_GIC_VERSION_2_MASK;
if (module_object_class_by_name("arm-gicv3")) {
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index e438d8c042..8b85b60c9b 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -32,6 +32,7 @@
#include "gicv3_internal.h"
#include "hw/arm/linux-boot-if.h"
#include "system/kvm.h"
+#include "system/whpx.h"
static void gicv3_gicd_no_migration_shift_bug_post_load(GICv3State *cs)
@@ -662,6 +663,8 @@ const char *gicv3_class_name(void)
{
if (kvm_irqchip_in_kernel()) {
return "kvm-arm-gicv3";
+ } else if (whpx_enabled()) {
+ return TYPE_WHPX_GICV3;
} else {
if (kvm_enabled()) {
error_report("Userspace GICv3 is not supported with KVM");
diff --git a/hw/intc/arm_gicv3_whpx.c b/hw/intc/arm_gicv3_whpx.c
new file mode 100644
index 0000000000..ead4e167c5
--- /dev/null
+++ b/hw/intc/arm_gicv3_whpx.c
@@ -0,0 +1,261 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * ARM Generic Interrupt Controller using HVF platform support
+ *
+ * Copyright (c) 2025 Mohamed Mediouni
+ * Based on vGICv3 KVM code by Pavel Fedin
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/intc/arm_gicv3_common.h"
+#include "qemu/error-report.h"
+#include "qemu/module.h"
+#include "system/runstate.h"
+#include "system/whpx.h"
+#include "system/whpx-internal.h"
+#include "gicv3_internal.h"
+#include "vgic_common.h"
+#include "qom/object.h"
+#include "target/arm/cpregs.h"
+
+#include "hw/arm/bsa.h"
+#include <winhvplatform.h>
+#include <winhvplatformdefs.h>
+#include <winnt.h>
+
+struct WHPXARMGICv3Class {
+ ARMGICv3CommonClass parent_class;
+ DeviceRealize parent_realize;
+ ResettablePhases parent_phases;
+};
+
+typedef struct WHPXARMGICv3Class WHPXARMGICv3Class;
+
+/* This is reusing the GICv3State typedef from ARM_GICV3_ITS_COMMON */
+DECLARE_OBJ_CHECKERS(GICv3State, WHPXARMGICv3Class,
+ WHPX_GICV3, TYPE_WHPX_GICV3);
+
+static void whpx_gicv3_check(GICv3State *s)
+{
+}
+
+static void whpx_gicv3_put_cpu(CPUState *cpu_state, run_on_cpu_data arg)
+{
+}
+
+static void whpx_gicv3_put(GICv3State *s)
+{
+ int ncpu;
+
+ whpx_gicv3_check(s);
+
+ for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
+ run_on_cpu_data data;
+ data.host_ptr = &s->cpu[ncpu];
+ run_on_cpu(s->cpu[ncpu].cpu, whpx_gicv3_put_cpu, data);
+ }
+}
+
+static void whpx_gicv3_get_cpu(CPUState *cpu_state, run_on_cpu_data arg)
+{
+}
+
+static void whpx_gicv3_get(GICv3State *s)
+{
+ int ncpu;
+
+ for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
+ run_on_cpu_data data;
+ data.host_ptr = &s->cpu[ncpu];
+ run_on_cpu(s->cpu[ncpu].cpu, whpx_gicv3_get_cpu, data);
+ }
+}
+
+static void whpx_gicv3_set_irq(void *opaque, int irq, int level)
+{
+ struct whpx_state *whpx = &whpx_global;
+
+ GICv3State *s = (GICv3State *)opaque;
+ if (irq > s->num_irq) {
+ return;
+ }
+ WHV_INTERRUPT_TYPE interrupt_type = WHvArm64InterruptTypeFixed;
+ WHV_INTERRUPT_CONTROL interrupt_control = {
+ interrupt_type = WHvArm64InterruptTypeFixed,
+ .RequestedVector = GIC_INTERNAL + irq, .InterruptControl.Asserted = level};
+
+ whp_dispatch.WHvRequestInterrupt(whpx->partition, &interrupt_control,
+ sizeof(interrupt_control));
+}
+
+static void whpx_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ GICv3State *s;
+ GICv3CPUState *c;
+
+ c = (GICv3CPUState *)env->gicv3state;
+ s = c->gic;
+
+ c->icc_pmr_el1 = 0;
+ /*
+ * Architecturally the reset value of the ICC_BPR registers
+ * is UNKNOWN. We set them all to 0 here; when the kernel
+ * uses these values to program the ICH_VMCR_EL2 fields that
+ * determine the guest-visible ICC_BPR register values, the
+ * hardware's "writing a value less than the minimum sets
+ * the field to the minimum value" behaviour will result in
+ * them effectively resetting to the correct minimum value
+ * for the host GIC.
+ */
+ c->icc_bpr[GICV3_G0] = 0;
+ c->icc_bpr[GICV3_G1] = 0;
+ c->icc_bpr[GICV3_G1NS] = 0;
+
+ c->icc_sre_el1 = 0x7;
+ memset(c->icc_apr, 0, sizeof(c->icc_apr));
+ memset(c->icc_igrpen, 0, sizeof(c->icc_igrpen));
+
+ if (s->migration_blocker) {
+ return;
+ }
+
+ c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS];
+}
+
+static void whpx_gicv3_reset_hold(Object *obj, ResetType type)
+{
+ GICv3State *s = ARM_GICV3_COMMON(obj);
+ WHPXARMGICv3Class *kgc = WHPX_GICV3_GET_CLASS(s);
+
+ if (kgc->parent_phases.hold) {
+ kgc->parent_phases.hold(obj, type);
+ }
+
+ whpx_gicv3_put(s);
+}
+
+
+/*
+ * CPU interface registers of GIC needs to be reset on CPU reset.
+ * For the calling arm_gicv3_icc_reset() on CPU reset, we register
+ * below ARMCPRegInfo. As we reset the whole cpu interface under single
+ * register reset, we define only one register of CPU interface instead
+ * of defining all the registers.
+ */
+static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
+ { .name = "ICC_CTLR_EL1", .state = ARM_CP_STATE_BOTH,
+ .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 4,
+ /*
+ * If ARM_CP_NOP is used, resetfn is not called,
+ * So ARM_CP_NO_RAW is appropriate type.
+ */
+ .type = ARM_CP_NO_RAW,
+ .access = PL1_RW,
+ .readfn = arm_cp_read_zero,
+ .writefn = arm_cp_write_ignore,
+ /*
+ * We hang the whole cpu interface reset routine off here
+ * rather than parcelling it out into one little function
+ * per register
+ */
+ .resetfn = whpx_gicv3_icc_reset,
+ },
+};
+
+static void whpx_set_reg(CPUState *cpu, WHV_REGISTER_NAME reg, WHV_REGISTER_VALUE val)
+{
+ struct whpx_state *whpx = &whpx_global;
+ HRESULT hr;
+ hr = whp_dispatch.WHvSetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index,
+ ®, 1, &val);
+
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to set register %08x, hr=%08lx", reg, hr);
+ }
+}
+
+static void whpx_gicv3_realize(DeviceState *dev, Error **errp)
+{
+ GICv3State *s = WHPX_GICV3(dev);
+ WHPXARMGICv3Class *kgc = WHPX_GICV3_GET_CLASS(s);
+ Error *local_err = NULL;
+ int i;
+
+ kgc->parent_realize(dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ if (s->revision != 3) {
+ error_setg(errp, "unsupported GIC revision %d for platform GIC",
+ s->revision);
+ }
+
+ if (s->security_extn) {
+ error_setg(errp, "the platform vGICv3 does not implement the "
+ "security extensions");
+ return;
+ }
+
+ if (s->nmi_support) {
+ error_setg(errp, "NMI is not supported with the platform GIC");
+ return;
+ }
+
+ if (s->nb_redist_regions > 1) {
+ error_setg(errp, "Multiple VGICv3 redistributor regions are not "
+ "supported by WHPX");
+ error_append_hint(errp, "A maximum of %d VCPUs can be used",
+ s->redist_region_count[0]);
+ return;
+ }
+
+ gicv3_init_irqs_and_mmio(s, whpx_gicv3_set_irq, NULL);
+
+ for (i = 0; i < s->num_cpu; i++) {
+ CPUState *cpu_state = qemu_get_cpu(i);
+ ARMCPU *cpu = ARM_CPU(cpu_state);
+ WHV_REGISTER_VALUE val = {.Reg64 = 0x080A0000 + (GICV3_REDIST_SIZE * i)};
+ whpx_set_reg(cpu_state, WHvArm64RegisterGicrBaseGpa, val);
+ define_arm_cp_regs(cpu, gicv3_cpuif_reginfo);
+ }
+
+ if (s->maint_irq) {
+ error_setg(errp, "Nested virtualisation not currently supported by WHPX.");
+ return;
+ }
+}
+
+static void whpx_gicv3_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+ ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass);
+ WHPXARMGICv3Class *kgc = WHPX_GICV3_CLASS(klass);
+
+ agcc->pre_save = whpx_gicv3_get;
+ agcc->post_load = whpx_gicv3_put;
+
+ device_class_set_parent_realize(dc, whpx_gicv3_realize,
+ &kgc->parent_realize);
+ resettable_class_set_parent_phases(rc, NULL, whpx_gicv3_reset_hold, NULL,
+ &kgc->parent_phases);
+}
+
+static const TypeInfo whpx_arm_gicv3_info = {
+ .name = TYPE_WHPX_GICV3,
+ .parent = TYPE_ARM_GICV3_COMMON,
+ .instance_size = sizeof(GICv3State),
+ .class_init = whpx_gicv3_class_init,
+ .class_size = sizeof(WHPXARMGICv3Class),
+};
+
+static void whpx_gicv3_register_types(void)
+{
+ type_register_static(&whpx_arm_gicv3_info);
+}
+
+type_init(whpx_gicv3_register_types)
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index 3137521a4a..9342ff0e2c 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -41,6 +41,7 @@ specific_ss.add(when: 'CONFIG_APIC', if_true: files('apic.c', 'apic_common.c'))
specific_ss.add(when: 'CONFIG_ARM_GIC', if_true: files('arm_gicv3_cpuif_common.c'))
specific_ss.add(when: 'CONFIG_ARM_GICV3', if_true: files('arm_gicv3_cpuif.c'))
specific_ss.add(when: 'CONFIG_ARM_GIC_KVM', if_true: files('arm_gic_kvm.c'))
+specific_ss.add(when: 'CONFIG_WHPX', if_true: files('arm_gicv3_whpx.c'))
specific_ss.add(when: ['CONFIG_ARM_GIC_KVM', 'TARGET_AARCH64'], if_true: files('arm_gicv3_kvm.c', 'arm_gicv3_its_kvm.c'))
specific_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m_nvic.c'))
specific_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_irqmp.c'))
diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
index c18503869f..7776558a0e 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -306,6 +306,9 @@ typedef struct ARMGICv3CommonClass ARMGICv3CommonClass;
DECLARE_OBJ_CHECKERS(GICv3State, ARMGICv3CommonClass,
ARM_GICV3_COMMON, TYPE_ARM_GICV3_COMMON)
+/* Types for GICv3 kernel-irqchip */
+#define TYPE_WHPX_GICV3 "whpx-arm-gicv3"
+
struct ARMGICv3CommonClass {
/*< private >*/
SysBusDeviceClass parent_class;
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 07/14] whpx: add arm64 support
2025-08-02 8:17 [PATCH v3 00/14] WHPX support for Arm Mohamed Mediouni
` (5 preceding siblings ...)
2025-08-02 8:17 ` [PATCH v3 06/14] whpx: interrupt controller support Mohamed Mediouni
@ 2025-08-02 8:17 ` Mohamed Mediouni
2025-08-03 0:56 ` Richard Henderson
2025-08-02 8:17 ` [PATCH v3 08/14] whpx: copy over memory management logic from hvf Mohamed Mediouni
` (6 subsequent siblings)
13 siblings, 1 reply; 32+ messages in thread
From: Mohamed Mediouni @ 2025-08-02 8:17 UTC (permalink / raw)
To: qemu-devel
Cc: Richard Henderson, Zhao Liu, Yanan Wang, qemu-arm,
Sunil Muthuswamy, Daniel P. Berrangé, Igor Mammedov,
Peter Maydell, Shannon Zhao, Michael S. Tsirkin,
Marc-André Lureau, Eduardo Habkost, Marcel Apfelbaum,
Mohamed Mediouni, Paolo Bonzini, Philippe Mathieu-Daudé,
Ani Sinha
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
accel/whpx/whpx-common.c | 1 +
meson.build | 21 +-
target/arm/meson.build | 1 +
target/arm/whpx/meson.build | 3 +
target/arm/whpx/whpx-all.c | 831 ++++++++++++++++++++++++++++++++++++
5 files changed, 850 insertions(+), 7 deletions(-)
create mode 100644 target/arm/whpx/meson.build
create mode 100644 target/arm/whpx/whpx-all.c
diff --git a/accel/whpx/whpx-common.c b/accel/whpx/whpx-common.c
index 9d702c544b..b974b73082 100644
--- a/accel/whpx/whpx-common.c
+++ b/accel/whpx/whpx-common.c
@@ -16,6 +16,7 @@
#include "gdbstub/helpers.h"
#include "qemu/accel.h"
#include "accel/accel-ops.h"
+#include "system/memory.h"
#include "system/whpx.h"
#include "system/cpus.h"
#include "system/runstate.h"
diff --git a/meson.build b/meson.build
index e53cd5b413..5e6bc965fe 100644
--- a/meson.build
+++ b/meson.build
@@ -327,7 +327,8 @@ accelerator_targets += { 'CONFIG_XEN': xen_targets }
if cpu == 'aarch64'
accelerator_targets += {
- 'CONFIG_HVF': ['aarch64-softmmu']
+ 'CONFIG_HVF': ['aarch64-softmmu'],
+ 'CONFIG_WHPX': ['aarch64-softmmu']
}
elif cpu == 'x86_64'
accelerator_targets += {
@@ -884,14 +885,20 @@ accelerators = []
if get_option('kvm').allowed() and host_os == 'linux'
accelerators += 'CONFIG_KVM'
endif
+
if get_option('whpx').allowed() and host_os == 'windows'
- if get_option('whpx').enabled() and host_machine.cpu() != 'x86_64'
- error('WHPX requires 64-bit host')
- elif cc.has_header('winhvplatform.h', required: get_option('whpx')) and \
- cc.has_header('winhvemulation.h', required: get_option('whpx'))
- accelerators += 'CONFIG_WHPX'
+ if cpu == 'i386'
+ if get_option('whpx').enabled()
+ error('WHPX requires 64-bit host')
+ endif
+ # Leave CONFIG_WHPX disabled
+ else
+ if cc.has_header('winhvplatform.h', required: get_option('whpx')) and \
+ cc.has_header('winhvemulation.h', required: get_option('whpx'))
+ accelerators += 'CONFIG_WHPX'
+ endif
endif
-endif
+ endif
hvf = not_found
if get_option('hvf').allowed()
diff --git a/target/arm/meson.build b/target/arm/meson.build
index 07d9271aa4..e28bd3f8e2 100644
--- a/target/arm/meson.build
+++ b/target/arm/meson.build
@@ -46,6 +46,7 @@ arm_common_system_ss.add(files(
))
subdir('hvf')
+subdir('whpx')
if 'CONFIG_TCG' in config_all_accel
subdir('tcg')
diff --git a/target/arm/whpx/meson.build b/target/arm/whpx/meson.build
new file mode 100644
index 0000000000..1de2ef0283
--- /dev/null
+++ b/target/arm/whpx/meson.build
@@ -0,0 +1,3 @@
+arm_system_ss.add(when: 'CONFIG_WHPX', if_true: files(
+ 'whpx-all.c',
+))
diff --git a/target/arm/whpx/whpx-all.c b/target/arm/whpx/whpx-all.c
new file mode 100644
index 0000000000..127e99cda4
--- /dev/null
+++ b/target/arm/whpx/whpx-all.c
@@ -0,0 +1,831 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU Windows Hypervisor Platform accelerator (WHPX)
+ *
+ * Copyright (c) 2025 Mohamed Mediouni
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "system/address-spaces.h"
+#include "system/ioport.h"
+#include "gdbstub/helpers.h"
+#include "qemu/accel.h"
+#include "accel/accel-ops.h"
+#include "system/whpx.h"
+#include "system/cpus.h"
+#include "system/runstate.h"
+#include "qemu/main-loop.h"
+#include "hw/boards.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "qapi/qapi-types-common.h"
+#include "qapi/qapi-visit-common.h"
+#include "migration/blocker.h"
+#include "accel/accel-cpu-target.h"
+#include <winerror.h>
+
+#include "syndrome.h"
+#include "cpu.h"
+#include "cpregs.h"
+#include "internals.h"
+
+#include "system/whpx-internal.h"
+#include "system/whpx-accel-ops.h"
+#include "system/whpx-all.h"
+#include "system/whpx-common.h"
+#include "hw/arm/bsa.h"
+#include "arm-powerctl.h"
+
+#include <winhvplatform.h>
+#include <winhvplatformdefs.h>
+
+struct whpx_reg_match {
+ WHV_REGISTER_NAME reg;
+ uint64_t offset;
+};
+
+static const struct whpx_reg_match whpx_reg_match[] = {
+ { WHvArm64RegisterX0, offsetof(CPUARMState, xregs[0]) },
+ { WHvArm64RegisterX1, offsetof(CPUARMState, xregs[1]) },
+ { WHvArm64RegisterX2, offsetof(CPUARMState, xregs[2]) },
+ { WHvArm64RegisterX3, offsetof(CPUARMState, xregs[3]) },
+ { WHvArm64RegisterX4, offsetof(CPUARMState, xregs[4]) },
+ { WHvArm64RegisterX5, offsetof(CPUARMState, xregs[5]) },
+ { WHvArm64RegisterX6, offsetof(CPUARMState, xregs[6]) },
+ { WHvArm64RegisterX7, offsetof(CPUARMState, xregs[7]) },
+ { WHvArm64RegisterX8, offsetof(CPUARMState, xregs[8]) },
+ { WHvArm64RegisterX9, offsetof(CPUARMState, xregs[9]) },
+ { WHvArm64RegisterX10, offsetof(CPUARMState, xregs[10]) },
+ { WHvArm64RegisterX11, offsetof(CPUARMState, xregs[11]) },
+ { WHvArm64RegisterX12, offsetof(CPUARMState, xregs[12]) },
+ { WHvArm64RegisterX13, offsetof(CPUARMState, xregs[13]) },
+ { WHvArm64RegisterX14, offsetof(CPUARMState, xregs[14]) },
+ { WHvArm64RegisterX15, offsetof(CPUARMState, xregs[15]) },
+ { WHvArm64RegisterX16, offsetof(CPUARMState, xregs[16]) },
+ { WHvArm64RegisterX17, offsetof(CPUARMState, xregs[17]) },
+ { WHvArm64RegisterX18, offsetof(CPUARMState, xregs[18]) },
+ { WHvArm64RegisterX19, offsetof(CPUARMState, xregs[19]) },
+ { WHvArm64RegisterX20, offsetof(CPUARMState, xregs[20]) },
+ { WHvArm64RegisterX21, offsetof(CPUARMState, xregs[21]) },
+ { WHvArm64RegisterX22, offsetof(CPUARMState, xregs[22]) },
+ { WHvArm64RegisterX23, offsetof(CPUARMState, xregs[23]) },
+ { WHvArm64RegisterX24, offsetof(CPUARMState, xregs[24]) },
+ { WHvArm64RegisterX25, offsetof(CPUARMState, xregs[25]) },
+ { WHvArm64RegisterX26, offsetof(CPUARMState, xregs[26]) },
+ { WHvArm64RegisterX27, offsetof(CPUARMState, xregs[27]) },
+ { WHvArm64RegisterX28, offsetof(CPUARMState, xregs[28]) },
+ { WHvArm64RegisterFp, offsetof(CPUARMState, xregs[29]) },
+ { WHvArm64RegisterLr, offsetof(CPUARMState, xregs[30]) },
+ { WHvArm64RegisterPc, offsetof(CPUARMState, pc) },
+};
+
+static const struct whpx_reg_match whpx_fpreg_match[] = {
+ { WHvArm64RegisterQ0, offsetof(CPUARMState, vfp.zregs[0]) },
+ { WHvArm64RegisterQ1, offsetof(CPUARMState, vfp.zregs[1]) },
+ { WHvArm64RegisterQ2, offsetof(CPUARMState, vfp.zregs[2]) },
+ { WHvArm64RegisterQ3, offsetof(CPUARMState, vfp.zregs[3]) },
+ { WHvArm64RegisterQ4, offsetof(CPUARMState, vfp.zregs[4]) },
+ { WHvArm64RegisterQ5, offsetof(CPUARMState, vfp.zregs[5]) },
+ { WHvArm64RegisterQ6, offsetof(CPUARMState, vfp.zregs[6]) },
+ { WHvArm64RegisterQ7, offsetof(CPUARMState, vfp.zregs[7]) },
+ { WHvArm64RegisterQ8, offsetof(CPUARMState, vfp.zregs[8]) },
+ { WHvArm64RegisterQ9, offsetof(CPUARMState, vfp.zregs[9]) },
+ { WHvArm64RegisterQ10, offsetof(CPUARMState, vfp.zregs[10]) },
+ { WHvArm64RegisterQ11, offsetof(CPUARMState, vfp.zregs[11]) },
+ { WHvArm64RegisterQ12, offsetof(CPUARMState, vfp.zregs[12]) },
+ { WHvArm64RegisterQ13, offsetof(CPUARMState, vfp.zregs[13]) },
+ { WHvArm64RegisterQ14, offsetof(CPUARMState, vfp.zregs[14]) },
+ { WHvArm64RegisterQ15, offsetof(CPUARMState, vfp.zregs[15]) },
+ { WHvArm64RegisterQ16, offsetof(CPUARMState, vfp.zregs[16]) },
+ { WHvArm64RegisterQ17, offsetof(CPUARMState, vfp.zregs[17]) },
+ { WHvArm64RegisterQ18, offsetof(CPUARMState, vfp.zregs[18]) },
+ { WHvArm64RegisterQ19, offsetof(CPUARMState, vfp.zregs[19]) },
+ { WHvArm64RegisterQ20, offsetof(CPUARMState, vfp.zregs[20]) },
+ { WHvArm64RegisterQ21, offsetof(CPUARMState, vfp.zregs[21]) },
+ { WHvArm64RegisterQ22, offsetof(CPUARMState, vfp.zregs[22]) },
+ { WHvArm64RegisterQ23, offsetof(CPUARMState, vfp.zregs[23]) },
+ { WHvArm64RegisterQ24, offsetof(CPUARMState, vfp.zregs[24]) },
+ { WHvArm64RegisterQ25, offsetof(CPUARMState, vfp.zregs[25]) },
+ { WHvArm64RegisterQ26, offsetof(CPUARMState, vfp.zregs[26]) },
+ { WHvArm64RegisterQ27, offsetof(CPUARMState, vfp.zregs[27]) },
+ { WHvArm64RegisterQ28, offsetof(CPUARMState, vfp.zregs[28]) },
+ { WHvArm64RegisterQ29, offsetof(CPUARMState, vfp.zregs[29]) },
+ { WHvArm64RegisterQ30, offsetof(CPUARMState, vfp.zregs[30]) },
+ { WHvArm64RegisterQ31, offsetof(CPUARMState, vfp.zregs[31]) },
+};
+
+#define WHPX_SYSREG(crn, crm, op0, op1, op2) \
+ ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, crn, crm, op0, op1, op2)
+
+struct whpx_sreg_match {
+ WHV_REGISTER_NAME reg;
+ uint32_t key;
+ bool global;
+ uint32_t cp_idx;
+};
+
+static struct whpx_sreg_match whpx_sreg_match[] = {
+/* Do not currently deal with the debug registers: leave them here for experimentation
+ { WHvArm64RegisterDbgbvr0El1, WHPX_SYSREG(0, 0, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr0El1, WHPX_SYSREG(0, 0, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr0El1, WHPX_SYSREG(0, 0, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr0El1, WHPX_SYSREG(0, 0, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr0El1, WHPX_SYSREG(0, 1, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr0El1, WHPX_SYSREG(0, 1, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr0El1, WHPX_SYSREG(0, 1, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr0El1, WHPX_SYSREG(0, 1, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr2El1, WHPX_SYSREG(0, 2, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr2El1, WHPX_SYSREG(0, 2, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr2El1, WHPX_SYSREG(0, 2, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr2El1, WHPX_SYSREG(0, 2, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr3El1, WHPX_SYSREG(0, 3, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr3El1, WHPX_SYSREG(0, 3, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr3El1, WHPX_SYSREG(0, 3, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr3El1, WHPX_SYSREG(0, 3, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr4El1, WHPX_SYSREG(0, 4, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr4El1, WHPX_SYSREG(0, 4, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr4El1, WHPX_SYSREG(0, 4, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr4El1, WHPX_SYSREG(0, 4, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr5El1, WHPX_SYSREG(0, 5, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr5El1, WHPX_SYSREG(0, 5, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr5El1, WHPX_SYSREG(0, 5, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr5El1, WHPX_SYSREG(0, 5, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr6El1, WHPX_SYSREG(0, 6, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr6El1, WHPX_SYSREG(0, 6, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr6El1, WHPX_SYSREG(0, 6, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr6El1, WHPX_SYSREG(0, 6, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr7El1, WHPX_SYSREG(0, 7, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr7El1, WHPX_SYSREG(0, 7, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr7El1, WHPX_SYSREG(0, 7, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr7El1, WHPX_SYSREG(0, 7, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr8El1, WHPX_SYSREG(0, 8, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr8El1, WHPX_SYSREG(0, 8, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr8El1, WHPX_SYSREG(0, 8, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr8El1, WHPX_SYSREG(0, 8, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr9El1, WHPX_SYSREG(0, 9, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr9El1, WHPX_SYSREG(0, 9, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr9El1, WHPX_SYSREG(0, 9, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr9El1, WHPX_SYSREG(0, 9, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr10El1, WHPX_SYSREG(0, 10, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr10El1, WHPX_SYSREG(0, 10, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr10El1, WHPX_SYSREG(0, 10, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr10El1, WHPX_SYSREG(0, 10, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr11El1, WHPX_SYSREG(0, 11, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr11El1, WHPX_SYSREG(0, 11, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr11El1, WHPX_SYSREG(0, 11, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr11El1, WHPX_SYSREG(0, 11, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr12El1, WHPX_SYSREG(0, 12, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr12El1, WHPX_SYSREG(0, 12, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr12El1, WHPX_SYSREG(0, 12, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr12El1, WHPX_SYSREG(0, 12, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr13El1, WHPX_SYSREG(0, 13, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr13El1, WHPX_SYSREG(0, 13, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr13El1, WHPX_SYSREG(0, 13, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr13El1, WHPX_SYSREG(0, 13, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr14El1, WHPX_SYSREG(0, 14, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr14El1, WHPX_SYSREG(0, 14, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr14El1, WHPX_SYSREG(0, 14, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr14El1, WHPX_SYSREG(0, 14, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr15El1, WHPX_SYSREG(0, 15, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr15El1, WHPX_SYSREG(0, 15, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr15El1, WHPX_SYSREG(0, 15, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr15El1, WHPX_SYSREG(0, 15, 2, 0, 7) },
+*/
+#ifdef SYNC_NO_RAW_REGS
+ /*
+ * The registers below are manually synced on init because they are
+ * marked as NO_RAW. We still list them to make number space sync easier.
+ */
+ { WHvArm64RegisterMidrEl1, WHPX_SYSREG(0, 0, 3, 0, 0) },
+ { WHvArm64RegisterMpidrEl1, WHPX_SYSREG(0, 0, 3, 0, 5) },
+ { WHvArm64RegisterIdPfr0El1, WHPX_SYSREG(0, 4, 3, 0, 0) },
+#endif
+ { WHvArm64RegisterIdAa64Pfr1El1, WHPX_SYSREG(0, 4, 3, 0, 1), true },
+ { WHvArm64RegisterIdAa64Dfr0El1, WHPX_SYSREG(0, 5, 3, 0, 0), true },
+ { WHvArm64RegisterIdAa64Dfr1El1, WHPX_SYSREG(0, 5, 3, 0, 1), true },
+ { WHvArm64RegisterIdAa64Isar0El1, WHPX_SYSREG(0, 6, 3, 0, 0), true },
+ { WHvArm64RegisterIdAa64Isar1El1, WHPX_SYSREG(0, 6, 3, 0, 1), true },
+#ifdef SYNC_NO_MMFR0
+ /* We keep the hardware MMFR0 around. HW limits are there anyway */
+ { WHvArm64RegisterIdAa64Mmfr0El1, WHPX_SYSREG(0, 7, 3, 0, 0) },
+#endif
+ { WHvArm64RegisterIdAa64Mmfr1El1, WHPX_SYSREG(0, 7, 3, 0, 1), true },
+ { WHvArm64RegisterIdAa64Mmfr2El1, WHPX_SYSREG(0, 7, 3, 0, 2), true },
+ { WHvArm64RegisterIdAa64Mmfr3El1, WHPX_SYSREG(0, 7, 3, 0, 3), true },
+
+ { WHvArm64RegisterMdscrEl1, WHPX_SYSREG(0, 2, 2, 0, 2) },
+ { WHvArm64RegisterSctlrEl1, WHPX_SYSREG(1, 0, 3, 0, 0) },
+ { WHvArm64RegisterCpacrEl1, WHPX_SYSREG(1, 0, 3, 0, 2) },
+ { WHvArm64RegisterTtbr0El1, WHPX_SYSREG(2, 0, 3, 0, 0) },
+ { WHvArm64RegisterTtbr1El1, WHPX_SYSREG(2, 0, 3, 0, 1) },
+ { WHvArm64RegisterTcrEl1, WHPX_SYSREG(2, 0, 3, 0, 2) },
+
+ { WHvArm64RegisterApiAKeyLoEl1, WHPX_SYSREG(2, 1, 3, 0, 0) },
+ { WHvArm64RegisterApiAKeyHiEl1, WHPX_SYSREG(2, 1, 3, 0, 1) },
+ { WHvArm64RegisterApiBKeyLoEl1, WHPX_SYSREG(2, 1, 3, 0, 2) },
+ { WHvArm64RegisterApiBKeyHiEl1, WHPX_SYSREG(2, 1, 3, 0, 3) },
+ { WHvArm64RegisterApdAKeyLoEl1, WHPX_SYSREG(2, 2, 3, 0, 0) },
+ { WHvArm64RegisterApdAKeyHiEl1, WHPX_SYSREG(2, 2, 3, 0, 1) },
+ { WHvArm64RegisterApdBKeyLoEl1, WHPX_SYSREG(2, 2, 3, 0, 2) },
+ { WHvArm64RegisterApdBKeyHiEl1, WHPX_SYSREG(2, 2, 3, 0, 3) },
+ { WHvArm64RegisterApgAKeyLoEl1, WHPX_SYSREG(2, 3, 3, 0, 0) },
+ { WHvArm64RegisterApgAKeyHiEl1, WHPX_SYSREG(2, 3, 3, 0, 1) },
+
+ { WHvArm64RegisterSpsrEl1, WHPX_SYSREG(4, 0, 3, 0, 0) },
+ { WHvArm64RegisterElrEl1, WHPX_SYSREG(4, 0, 3, 0, 1) },
+ { WHvArm64RegisterSpEl1, WHPX_SYSREG(4, 1, 3, 0, 0) },
+ { WHvArm64RegisterEsrEl1, WHPX_SYSREG(5, 2, 3, 0, 0) },
+ { WHvArm64RegisterFarEl1, WHPX_SYSREG(6, 0, 3, 0, 0) },
+ { WHvArm64RegisterParEl1, WHPX_SYSREG(7, 4, 3, 0, 0) },
+ { WHvArm64RegisterMairEl1, WHPX_SYSREG(10, 2, 3, 0, 0) },
+ { WHvArm64RegisterVbarEl1, WHPX_SYSREG(12, 0, 3, 0, 0) },
+ { WHvArm64RegisterContextidrEl1, WHPX_SYSREG(13, 0, 3, 0, 1) },
+ { WHvArm64RegisterTpidrEl1, WHPX_SYSREG(13, 0, 3, 0, 4) },
+ { WHvArm64RegisterCntkctlEl1, WHPX_SYSREG(14, 1, 3, 0, 0) },
+ { WHvArm64RegisterCsselrEl1, WHPX_SYSREG(0, 0, 3, 2, 0) },
+ { WHvArm64RegisterTpidrEl0, WHPX_SYSREG(13, 0, 3, 3, 2) },
+ { WHvArm64RegisterTpidrroEl0, WHPX_SYSREG(13, 0, 3, 3, 3) },
+ { WHvArm64RegisterCntvCtlEl0, WHPX_SYSREG(14, 3, 3, 3, 1) },
+ { WHvArm64RegisterCntvCvalEl0, WHPX_SYSREG(14, 3, 3, 3, 2) },
+ { WHvArm64RegisterSpEl1, WHPX_SYSREG(4, 1, 3, 4, 0) },
+};
+
+static void flush_cpu_state(CPUState *cpu)
+{
+ if (cpu->vcpu_dirty) {
+ whpx_set_registers(cpu, WHPX_SET_RUNTIME_STATE);
+ cpu->vcpu_dirty = false;
+ }
+}
+
+static void whpx_get_reg(CPUState *cpu, WHV_REGISTER_NAME reg, WHV_REGISTER_VALUE* val)
+{
+ struct whpx_state *whpx = &whpx_global;
+ HRESULT hr;
+
+ flush_cpu_state(cpu);
+
+ hr = whp_dispatch.WHvGetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index,
+ ®, 1, val);
+
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to get register %08x, hr=%08lx", reg, hr);
+ }
+}
+
+static void whpx_set_reg(CPUState *cpu, WHV_REGISTER_NAME reg, WHV_REGISTER_VALUE val)
+{
+ struct whpx_state *whpx = &whpx_global;
+ HRESULT hr;
+ hr = whp_dispatch.WHvSetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index,
+ ®, 1, &val);
+
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to set register %08x, hr=%08lx", reg, hr);
+ }
+}
+
+static void whpx_get_global_reg(WHV_REGISTER_NAME reg, WHV_REGISTER_VALUE *val)
+{
+ struct whpx_state *whpx = &whpx_global;
+ HRESULT hr;
+
+ hr = whp_dispatch.WHvGetVirtualProcessorRegisters(whpx->partition, WHV_ANY_VP,
+ ®, 1, val);
+
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to get register %08x, hr=%08lx", reg, hr);
+ }
+}
+
+static void whpx_set_global_reg(WHV_REGISTER_NAME reg, WHV_REGISTER_VALUE val)
+{
+ struct whpx_state *whpx = &whpx_global;
+ HRESULT hr;
+ hr = whp_dispatch.WHvSetVirtualProcessorRegisters(whpx->partition, WHV_ANY_VP,
+ ®, 1, &val);
+
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to set register %08x, hr=%08lx", reg, hr);
+ }
+}
+
+static uint64_t whpx_get_gp_reg(CPUState *cpu, int rt)
+{
+ if (rt >= 31) {
+ return 0;
+ }
+ WHV_REGISTER_NAME reg = WHvArm64RegisterX0 + rt;
+ WHV_REGISTER_VALUE val;
+ whpx_get_reg(cpu, reg, &val);
+
+ return val.Reg64;
+}
+
+static void whpx_set_gp_reg(CPUState *cpu, int rt, uint64_t val)
+{
+ if (rt >= 31) {
+ abort();
+ }
+ WHV_REGISTER_NAME reg = WHvArm64RegisterX0 + rt;
+ WHV_REGISTER_VALUE reg_val = {.Reg64 = val};
+
+ whpx_set_reg(cpu, reg, reg_val);
+}
+
+static int whpx_handle_mmio(CPUState *cpu, WHV_MEMORY_ACCESS_CONTEXT *ctx)
+{
+ uint64_t syndrome = ctx->Syndrome;
+
+ bool isv = syndrome & ARM_EL_ISV;
+ bool iswrite = (syndrome >> 6) & 1;
+ bool sse = (syndrome >> 21) & 1;
+ uint32_t sas = (syndrome >> 22) & 3;
+ uint32_t len = 1 << sas;
+ uint32_t srt = (syndrome >> 16) & 0x1f;
+ uint32_t cm = (syndrome >> 8) & 0x1;
+ uint64_t val = 0;
+
+ if (cm) {
+ /* We don't cache MMIO regions */
+ abort();
+ return 0;
+ }
+
+ assert(isv);
+
+ if (iswrite) {
+ val = whpx_get_gp_reg(cpu, srt);
+ address_space_write(&address_space_memory,
+ ctx->Gpa,
+ MEMTXATTRS_UNSPECIFIED, &val, len);
+ } else {
+ address_space_read(&address_space_memory,
+ ctx->Gpa,
+ MEMTXATTRS_UNSPECIFIED, &val, len);
+ if (sse) {
+ val = sextract64(val, 0, len * 8);
+ }
+ whpx_set_gp_reg(cpu, srt, val);
+ }
+
+ return 0;
+}
+
+static void whpx_psci_cpu_off(ARMCPU *arm_cpu)
+{
+ int32_t ret = arm_set_cpu_off(arm_cpu_mp_affinity(arm_cpu));
+ assert(ret == QEMU_ARM_POWERCTL_RET_SUCCESS);
+}
+
+int whpx_vcpu_run(CPUState *cpu)
+{
+ HRESULT hr;
+ struct whpx_state *whpx = &whpx_global;
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
+ AccelCPUState *vcpu = cpu->accel;
+ int ret;
+
+
+ g_assert(bql_locked());
+
+ if (whpx->running_cpus++ == 0) {
+ ret = whpx_first_vcpu_starting(cpu);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ bql_unlock();
+
+
+ cpu_exec_start(cpu);
+ do {
+ bool advance_pc = false;
+ if (cpu->vcpu_dirty) {
+ whpx_set_registers(cpu, WHPX_SET_RUNTIME_STATE);
+ cpu->vcpu_dirty = false;
+ }
+
+ if (qatomic_read(&cpu->exit_request)) {
+ whpx_vcpu_kick(cpu);
+ }
+
+ hr = whp_dispatch.WHvRunVirtualProcessor(
+ whpx->partition, cpu->cpu_index,
+ &vcpu->exit_ctx, sizeof(vcpu->exit_ctx));
+
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to exec a virtual processor,"
+ " hr=%08lx", hr);
+ ret = -1;
+ break;
+ }
+
+ switch (vcpu->exit_ctx.ExitReason) {
+ case WHvRunVpExitReasonGpaIntercept:
+ case WHvRunVpExitReasonUnmappedGpa:
+ advance_pc = true;
+
+ if (vcpu->exit_ctx.MemoryAccess.Syndrome >> 8 & 0x1) {
+ error_report("WHPX: cached access to unmapped memory"
+ "Pc = 0x%llx Gva = 0x%llx Gpa = 0x%llx",
+ vcpu->exit_ctx.MemoryAccess.Header.Pc,
+ vcpu->exit_ctx.MemoryAccess.Gpa,
+ vcpu->exit_ctx.MemoryAccess.Gva);
+ break;
+ }
+
+ ret = whpx_handle_mmio(cpu, &vcpu->exit_ctx.MemoryAccess);
+ break;
+ case WHvRunVpExitReasonCanceled:
+ cpu->exception_index = EXCP_INTERRUPT;
+ ret = 1;
+ break;
+ case WHvRunVpExitReasonArm64Reset:
+ if (vcpu->exit_ctx.Arm64Reset.ResetType == WHvArm64ResetTypePowerOff) {
+ qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
+ } else if (vcpu->exit_ctx.Arm64Reset.ResetType == WHvArm64ResetTypeReboot) {
+ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+ } else {
+ abort();
+ }
+ bql_lock();
+ whpx_psci_cpu_off(arm_cpu);
+ bql_unlock();
+ break;
+ case WHvRunVpExitReasonNone:
+ case WHvRunVpExitReasonUnrecoverableException:
+ case WHvRunVpExitReasonInvalidVpRegisterValue:
+ case WHvRunVpExitReasonUnsupportedFeature:
+ default:
+ error_report("WHPX: Unexpected VP exit code 0x%08x",
+ vcpu->exit_ctx.ExitReason);
+ whpx_get_registers(cpu);
+ bql_lock();
+ qemu_system_guest_panicked(cpu_get_crash_info(cpu));
+ bql_unlock();
+ break;
+ }
+ if (advance_pc) {
+ WHV_REGISTER_VALUE pc;
+
+ flush_cpu_state(cpu);
+ pc.Reg64 = vcpu->exit_ctx.MemoryAccess.Header.Pc + 4;
+ whpx_set_reg(cpu, WHvArm64RegisterPc, pc);
+ }
+ } while (!ret);
+
+ cpu_exec_end(cpu);
+
+ bql_lock();
+ current_cpu = cpu;
+
+ if (--whpx->running_cpus == 0) {
+ whpx_last_vcpu_stopping(cpu);
+ }
+
+ qatomic_set(&cpu->exit_request, false);
+
+ return ret < 0;
+}
+
+static void clean_whv_register_value(WHV_REGISTER_VALUE *val)
+{
+ memset(val, 0, sizeof(WHV_REGISTER_VALUE));
+}
+
+void whpx_get_registers(CPUState *cpu)
+{
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
+ CPUARMState *env = &arm_cpu->env;
+ WHV_REGISTER_VALUE val;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(whpx_reg_match); i++) {
+ whpx_get_reg(cpu, whpx_reg_match[i].reg, &val);
+ *(uint64_t *)((void *)env + whpx_reg_match[i].offset) = val.Reg64;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(whpx_fpreg_match); i++) {
+ whpx_get_reg(cpu, whpx_reg_match[i].reg, &val);
+ memcpy((void *)env + whpx_fpreg_match[i].offset, &val, sizeof(val.Reg128));
+ }
+
+ whpx_get_reg(cpu, WHvArm64RegisterPc, &val);
+ env->pc = val.Reg64;
+
+ whpx_get_reg(cpu, WHvArm64RegisterFpcr, &val);
+ vfp_set_fpcr(env, val.Reg32);
+
+ whpx_get_reg(cpu, WHvArm64RegisterFpsr, &val);
+ vfp_set_fpsr(env, val.Reg32);
+
+ whpx_get_reg(cpu, WHvArm64RegisterPstate, &val);
+ pstate_write(env, val.Reg32);
+
+ for (i = 0; i < ARRAY_SIZE(whpx_sreg_match); i++) {
+ if (whpx_sreg_match[i].global == true) {
+ continue;
+ }
+ if (whpx_sreg_match[i].cp_idx == -1) {
+ continue;
+ }
+
+ whpx_get_reg(cpu, whpx_sreg_match[i].reg, &val);
+
+ arm_cpu->cpreg_values[whpx_sreg_match[i].cp_idx] = val.Reg64;
+ }
+
+ /* WHP disallows us from reading global regs as a vCPU */
+ for (i = 0; i < ARRAY_SIZE(whpx_sreg_match); i++) {
+ if (whpx_sreg_match[i].global == false) {
+ continue;
+ }
+ if (whpx_sreg_match[i].cp_idx == -1) {
+ continue;
+ }
+
+ whpx_get_global_reg(whpx_sreg_match[i].reg, &val);
+
+ arm_cpu->cpreg_values[whpx_sreg_match[i].cp_idx] = val.Reg64;
+ }
+ assert(write_list_to_cpustate(arm_cpu));
+
+ aarch64_restore_sp(env, arm_current_el(env));
+}
+
+void whpx_set_registers(CPUState *cpu, int level)
+{
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
+ CPUARMState *env = &arm_cpu->env;
+ WHV_REGISTER_VALUE val;
+ clean_whv_register_value(&val);
+ int i;
+
+ assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
+
+ for (i = 0; i < ARRAY_SIZE(whpx_reg_match); i++) {
+ val.Reg64 = *(uint64_t *)((void *)env + whpx_reg_match[i].offset);
+ whpx_set_reg(cpu, whpx_reg_match[i].reg, val);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(whpx_fpreg_match); i++) {
+ memcpy(&val.Reg128, (void *)env + whpx_fpreg_match[i].offset, sizeof(val.Reg128));
+ whpx_set_reg(cpu, whpx_reg_match[i].reg, val);
+ }
+
+ clean_whv_register_value(&val);
+ val.Reg64 = env->pc;
+ whpx_set_reg(cpu, WHvArm64RegisterPc, val);
+
+ clean_whv_register_value(&val);
+ val.Reg32 = vfp_get_fpcr(env);
+ whpx_set_reg(cpu, WHvArm64RegisterFpcr, val);
+ val.Reg32 = vfp_get_fpsr(env);
+ whpx_set_reg(cpu, WHvArm64RegisterFpsr, val);
+ val.Reg32 = pstate_read(env);
+ whpx_set_reg(cpu, WHvArm64RegisterPstate, val);
+
+ aarch64_save_sp(env, arm_current_el(env));
+
+ assert(write_cpustate_to_list(arm_cpu, false));
+ for (i = 0; i < ARRAY_SIZE(whpx_sreg_match); i++) {
+ if (whpx_sreg_match[i].global == true) {
+ continue;
+ }
+
+ if (whpx_sreg_match[i].cp_idx == -1) {
+ continue;
+ }
+ clean_whv_register_value(&val);
+ val.Reg64 = arm_cpu->cpreg_values[whpx_sreg_match[i].cp_idx];
+ whpx_set_reg(cpu, whpx_sreg_match[i].reg, val);
+ }
+
+ /* Currently set global regs every time. */
+ for (i = 0; i < ARRAY_SIZE(whpx_sreg_match); i++) {
+ if (whpx_sreg_match[i].global == false) {
+ continue;
+ }
+
+ if (whpx_sreg_match[i].cp_idx == -1) {
+ continue;
+ }
+ clean_whv_register_value(&val);
+ val.Reg64 = arm_cpu->cpreg_values[whpx_sreg_match[i].cp_idx];
+ whpx_set_global_reg(whpx_sreg_match[i].reg, val);
+ }
+}
+
+static uint32_t max_vcpu_index;
+
+static void whpx_cpu_update_state(void *opaque, bool running, RunState state)
+{
+}
+
+int whpx_init_vcpu(CPUState *cpu)
+{
+ HRESULT hr;
+ struct whpx_state *whpx = &whpx_global;
+ AccelCPUState *vcpu = NULL;
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
+ CPUARMState *env = &arm_cpu->env;
+ int ret;
+
+ uint32_t sregs_match_len = ARRAY_SIZE(whpx_sreg_match);
+ uint32_t sregs_cnt = 0;
+ WHV_REGISTER_VALUE val;
+ int i;
+
+ vcpu = g_new0(AccelCPUState, 1);
+
+ hr = whp_dispatch.WHvCreateVirtualProcessor(
+ whpx->partition, cpu->cpu_index, 0);
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to create a virtual processor,"
+ " hr=%08lx", hr);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Assumption that CNTFRQ_EL0 is the same between the VMM and the partition. */
+ asm volatile("mrs %0, cntfrq_el0" : "=r"(arm_cpu->gt_cntfrq_hz));
+
+ cpu->vcpu_dirty = true;
+ cpu->accel = vcpu;
+ max_vcpu_index = max(max_vcpu_index, cpu->cpu_index);
+ qemu_add_vm_change_state_handler(whpx_cpu_update_state, env);
+
+ env->aarch64 = true;
+
+ /* Allocate enough space for our sysreg sync */
+ arm_cpu->cpreg_indexes = g_renew(uint64_t, arm_cpu->cpreg_indexes,
+ sregs_match_len);
+ arm_cpu->cpreg_values = g_renew(uint64_t, arm_cpu->cpreg_values,
+ sregs_match_len);
+ arm_cpu->cpreg_vmstate_indexes = g_renew(uint64_t,
+ arm_cpu->cpreg_vmstate_indexes,
+ sregs_match_len);
+ arm_cpu->cpreg_vmstate_values = g_renew(uint64_t,
+ arm_cpu->cpreg_vmstate_values,
+ sregs_match_len);
+
+ memset(arm_cpu->cpreg_values, 0, sregs_match_len * sizeof(uint64_t));
+
+ /* Populate cp list for all known sysregs */
+ for (i = 0; i < sregs_match_len; i++) {
+ const ARMCPRegInfo *ri;
+ uint32_t key = whpx_sreg_match[i].key;
+
+ ri = get_arm_cp_reginfo(arm_cpu->cp_regs, key);
+ if (ri) {
+ assert(!(ri->type & ARM_CP_NO_RAW));
+ whpx_sreg_match[i].cp_idx = sregs_cnt;
+ arm_cpu->cpreg_indexes[sregs_cnt++] = cpreg_to_kvm_id(key);
+ } else {
+ whpx_sreg_match[i].cp_idx = -1;
+ }
+ }
+ arm_cpu->cpreg_array_len = sregs_cnt;
+ arm_cpu->cpreg_vmstate_array_len = sregs_cnt;
+
+ assert(write_cpustate_to_list(arm_cpu, false));
+
+ /* Set CP_NO_RAW system registers on init */
+ val.Reg64 = arm_cpu->midr;
+ whpx_set_reg(cpu, WHvArm64RegisterMidrEl1,
+ val);
+
+ clean_whv_register_value(&val);
+
+ /* bit 31 of MPIDR_EL1 is RES1, and this is enforced by WHPX */
+ val.Reg64 = 0x80000000 + arm_cpu->mp_affinity;
+ whpx_set_reg(cpu, WHvArm64RegisterMpidrEl1,
+ val);
+
+ return 0;
+
+error:
+ g_free(vcpu);
+
+ return ret;
+
+}
+
+void whpx_cpu_instance_init(CPUState *cs)
+{
+}
+
+int whpx_accel_init(AccelState *as, MachineState *ms)
+{
+ struct whpx_state *whpx;
+ int ret;
+ HRESULT hr;
+ WHV_CAPABILITY whpx_cap;
+ UINT32 whpx_cap_size;
+ WHV_PARTITION_PROPERTY prop;
+ WHV_CAPABILITY_FEATURES features = {0};
+
+ whpx = &whpx_global;
+ /* on arm64 Windows Hypervisor Platform, vGICv3 always used */
+ whpx->kernel_irqchip = true;
+
+ if (!init_whp_dispatch()) {
+ ret = -ENOSYS;
+ goto error;
+ }
+
+ whpx->mem_quota = ms->ram_size;
+
+ hr = whp_dispatch.WHvGetCapability(
+ WHvCapabilityCodeHypervisorPresent, &whpx_cap,
+ sizeof(whpx_cap), &whpx_cap_size);
+ if (FAILED(hr) || !whpx_cap.HypervisorPresent) {
+ error_report("WHPX: No accelerator found, hr=%08lx", hr);
+ ret = -ENOSPC;
+ goto error;
+ }
+
+ hr = whp_dispatch.WHvGetCapability(
+ WHvCapabilityCodeFeatures, &features, sizeof(features), NULL);
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to query capabilities, hr=%08lx", hr);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (!features.Arm64Support) {
+ error_report("WHPX: host OS exposing pre-release WHPX implementation. "
+ "Please update your operating system to at least build 26100.3915");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ hr = whp_dispatch.WHvCreatePartition(&whpx->partition);
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to create partition, hr=%08lx", hr);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY));
+ prop.ProcessorCount = ms->smp.cpus;
+ hr = whp_dispatch.WHvSetPartitionProperty(
+ whpx->partition,
+ WHvPartitionPropertyCodeProcessorCount,
+ &prop,
+ sizeof(WHV_PARTITION_PROPERTY));
+
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to set partition processor count to %u,"
+ " hr=%08lx", prop.ProcessorCount, hr);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (!whpx->kernel_irqchip_allowed) {
+ error_report("WHPX: on Arm, only kernel-irqchip=on is currently supported");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY));
+
+ hr = whp_dispatch.WHvSetupPartition(whpx->partition);
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to setup partition, hr=%08lx", hr);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ whpx_memory_init();
+
+ return 0;
+
+error:
+
+ if (NULL != whpx->partition) {
+ whp_dispatch.WHvDeletePartition(whpx->partition);
+ whpx->partition = NULL;
+ }
+
+ return ret;
+}
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 08/14] whpx: copy over memory management logic from hvf
2025-08-02 8:17 [PATCH v3 00/14] WHPX support for Arm Mohamed Mediouni
` (6 preceding siblings ...)
2025-08-02 8:17 ` [PATCH v3 07/14] whpx: add arm64 support Mohamed Mediouni
@ 2025-08-02 8:17 ` Mohamed Mediouni
2025-08-02 8:17 ` [PATCH v3 09/14] target/arm: cpu: mark WHPX as supporting PSCI 1.1 Mohamed Mediouni
` (5 subsequent siblings)
13 siblings, 0 replies; 32+ messages in thread
From: Mohamed Mediouni @ 2025-08-02 8:17 UTC (permalink / raw)
To: qemu-devel
Cc: Richard Henderson, Zhao Liu, Yanan Wang, qemu-arm,
Sunil Muthuswamy, Daniel P. Berrangé, Igor Mammedov,
Peter Maydell, Shannon Zhao, Michael S. Tsirkin,
Marc-André Lureau, Eduardo Habkost, Marcel Apfelbaum,
Mohamed Mediouni, Paolo Bonzini, Philippe Mathieu-Daudé,
Ani Sinha
This allows edk2 to work, although u-boot is still not functional.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
accel/whpx/whpx-common.c | 201 ++++++++++++++++++++++++++++-----------
1 file changed, 147 insertions(+), 54 deletions(-)
diff --git a/accel/whpx/whpx-common.c b/accel/whpx/whpx-common.c
index b974b73082..e2a7961679 100644
--- a/accel/whpx/whpx-common.c
+++ b/accel/whpx/whpx-common.c
@@ -266,89 +266,174 @@ void whpx_vcpu_kick(CPUState *cpu)
* Memory support.
*/
-static void whpx_update_mapping(hwaddr start_pa, ram_addr_t size,
- void *host_va, int add, int rom,
- const char *name)
+ /* whpx_slot flags */
+#define WHPX_SLOT_LOG (1 << 0)
+typedef struct whpx_slot {
+ uint64_t start;
+ uint64_t size;
+ uint8_t *mem;
+ int slot_id;
+ uint32_t flags;
+ MemoryRegion *region;
+} whpx_slot;
+
+typedef struct WHPXState {
+ whpx_slot slots[32];
+ int num_slots;
+} WHPXState;
+
+ WHPXState *whpx_state;
+
+ struct mac_slot {
+ int present;
+ uint64_t size;
+ uint64_t gpa_start;
+ uint64_t gva;
+};
+
+struct mac_slot mac_slots[32];
+
+static int do_whpx_set_memory(whpx_slot *slot, WHV_MAP_GPA_RANGE_FLAGS flags)
{
struct whpx_state *whpx = &whpx_global;
+ struct mac_slot *macslot;
HRESULT hr;
- /*
- if (add) {
- printf("WHPX: ADD PA:%p Size:%p, Host:%p, %s, '%s'\n",
- (void*)start_pa, (void*)size, host_va,
- (rom ? "ROM" : "RAM"), name);
- } else {
- printf("WHPX: DEL PA:%p Size:%p, Host:%p, '%s'\n",
- (void*)start_pa, (void*)size, host_va, name);
+ macslot = &mac_slots[slot->slot_id];
+
+ if (macslot->present) {
+ if (macslot->size != slot->size) {
+ macslot->present = 0;
+ hr = whp_dispatch.WHvUnmapGpaRange(whpx->partition,
+ macslot->gpa_start, macslot->size);
+ if (FAILED(hr)) {
+ abort();
+ }
+ }
}
- */
-
- if (add) {
- hr = whp_dispatch.WHvMapGpaRange(whpx->partition,
- host_va,
- start_pa,
- size,
- (WHvMapGpaRangeFlagRead |
- WHvMapGpaRangeFlagExecute |
- (rom ? 0 : WHvMapGpaRangeFlagWrite)));
- } else {
- hr = whp_dispatch.WHvUnmapGpaRange(whpx->partition,
- start_pa,
- size);
+
+ if (!slot->size) {
+ return 0;
}
- if (FAILED(hr)) {
- error_report("WHPX: Failed to %s GPA range '%s' PA:%p, Size:%p bytes,"
- " Host:%p, hr=%08lx",
- (add ? "MAP" : "UNMAP"), name,
- (void *)(uintptr_t)start_pa, (void *)size, host_va, hr);
+ macslot->present = 1;
+ macslot->gpa_start = slot->start;
+ macslot->size = slot->size;
+ hr = whp_dispatch.WHvMapGpaRange(whpx->partition,
+ slot->mem, slot->start, slot->size, flags);
+ return 0;
+}
+
+static whpx_slot *whpx_find_overlap_slot(uint64_t start, uint64_t size)
+{
+ whpx_slot *slot;
+ int x;
+ for (x = 0; x < whpx_state->num_slots; ++x) {
+ slot = &whpx_state->slots[x];
+ if (slot->size && start < (slot->start + slot->size) &&
+ (start + size) > slot->start) {
+ return slot;
+ }
}
+ return NULL;
}
-static void whpx_process_section(MemoryRegionSection *section, int add)
+static void whpx_set_phys_mem(MemoryRegionSection *section, bool add)
{
- MemoryRegion *mr = section->mr;
- hwaddr start_pa = section->offset_within_address_space;
- ram_addr_t size = int128_get64(section->size);
- unsigned int delta;
- uint64_t host_va;
+ whpx_slot *mem;
+ MemoryRegion *area = section->mr;
+ bool writable = !area->readonly && !area->rom_device;
+ WHV_MAP_GPA_RANGE_FLAGS flags;
+ uint64_t page_size = qemu_real_host_page_size();
+
+ if (!memory_region_is_ram(area)) {
+ if (writable) {
+ return;
+ } else if (!memory_region_is_romd(area)) {
+ /*
+ * If the memory device is not in romd_mode, then we actually want
+ * to remove the whpx memory slot so all accesses will trap.
+ */
+ add = false;
+ }
+ }
- if (!memory_region_is_ram(mr)) {
- return;
+ if (!QEMU_IS_ALIGNED(int128_get64(section->size), page_size) ||
+ !QEMU_IS_ALIGNED(section->offset_within_address_space, page_size)) {
+ /* Not page aligned, so we can not map as RAM */
+ add = false;
}
- delta = qemu_real_host_page_size() - (start_pa & ~qemu_real_host_page_mask());
- delta &= ~qemu_real_host_page_mask();
- if (delta > size) {
- return;
+ mem = whpx_find_overlap_slot(
+ section->offset_within_address_space,
+ int128_get64(section->size));
+
+ if (mem && add) {
+ if (mem->size == int128_get64(section->size) &&
+ mem->start == section->offset_within_address_space &&
+ mem->mem == (memory_region_get_ram_ptr(area) +
+ section->offset_within_region)) {
+ return; /* Same region was attempted to register, go away. */
+ }
+ }
+
+ /* Region needs to be reset. set the size to 0 and remap it. */
+ if (mem) {
+ mem->size = 0;
+ if (do_whpx_set_memory(mem, 0)) {
+ error_report("Failed to reset overlapping slot");
+ abort();
+ }
}
- start_pa += delta;
- size -= delta;
- size &= qemu_real_host_page_mask();
- if (!size || (start_pa & ~qemu_real_host_page_mask())) {
+
+ if (!add) {
return;
}
- host_va = (uintptr_t)memory_region_get_ram_ptr(mr)
- + section->offset_within_region + delta;
+ if (area->readonly ||
+ (!memory_region_is_ram(area) && memory_region_is_romd(area))) {
+ flags = WHvMapGpaRangeFlagRead | WHvMapGpaRangeFlagExecute;
+ } else {
+ flags = WHvMapGpaRangeFlagRead | WHvMapGpaRangeFlagWrite
+ | WHvMapGpaRangeFlagExecute;
+ }
+
+ /* Now make a new slot. */
+ int x;
+
+ for (x = 0; x < whpx_state->num_slots; ++x) {
+ mem = &whpx_state->slots[x];
+ if (!mem->size) {
+ break;
+ }
+ }
+
+ if (x == whpx_state->num_slots) {
+ error_report("No free slots");
+ abort();
+ }
- whpx_update_mapping(start_pa, size, (void *)(uintptr_t)host_va, add,
- memory_region_is_rom(mr), mr->name);
+ mem->size = int128_get64(section->size);
+ mem->mem = memory_region_get_ram_ptr(area) + section->offset_within_region;
+ mem->start = section->offset_within_address_space;
+ mem->region = area;
+
+ if (do_whpx_set_memory(mem, flags)) {
+ error_report("Error registering new memory slot");
+ abort();
+ }
}
static void whpx_region_add(MemoryListener *listener,
MemoryRegionSection *section)
{
- memory_region_ref(section->mr);
- whpx_process_section(section, 1);
+ whpx_set_phys_mem(section, true);
}
static void whpx_region_del(MemoryListener *listener,
MemoryRegionSection *section)
{
- whpx_process_section(section, 0);
- memory_region_unref(section->mr);
+ whpx_set_phys_mem(section, false);
}
static void whpx_transaction_begin(MemoryListener *listener)
@@ -532,6 +617,14 @@ static void whpx_accel_instance_init(Object *obj)
memset(whpx, 0, sizeof(struct whpx_state));
/* Turn on kernel-irqchip, by default */
whpx->kernel_irqchip_allowed = true;
+
+ int x;
+ whpx_state = malloc(sizeof(WHPXState));
+ whpx_state->num_slots = ARRAY_SIZE(whpx_state->slots);
+ for (x = 0; x < whpx_state->num_slots; ++x) {
+ whpx_state->slots[x].size = 0;
+ whpx_state->slots[x].slot_id = x;
+ }
}
static const TypeInfo whpx_accel_type = {
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 09/14] target/arm: cpu: mark WHPX as supporting PSCI 1.1
2025-08-02 8:17 [PATCH v3 00/14] WHPX support for Arm Mohamed Mediouni
` (7 preceding siblings ...)
2025-08-02 8:17 ` [PATCH v3 08/14] whpx: copy over memory management logic from hvf Mohamed Mediouni
@ 2025-08-02 8:17 ` Mohamed Mediouni
2025-08-03 0:56 ` Richard Henderson
2025-08-02 8:17 ` [PATCH v3 10/14] hw/arm: virt: cleanly fail on attempt to use the platform vGIC together with ITS Mohamed Mediouni
` (4 subsequent siblings)
13 siblings, 1 reply; 32+ messages in thread
From: Mohamed Mediouni @ 2025-08-02 8:17 UTC (permalink / raw)
To: qemu-devel
Cc: Richard Henderson, Zhao Liu, Yanan Wang, qemu-arm,
Sunil Muthuswamy, Daniel P. Berrangé, Igor Mammedov,
Peter Maydell, Shannon Zhao, Michael S. Tsirkin,
Marc-André Lureau, Eduardo Habkost, Marcel Apfelbaum,
Mohamed Mediouni, Paolo Bonzini, Philippe Mathieu-Daudé,
Ani Sinha
Hyper-V supports PSCI 1.3, and that implementation is exposed through
WHPX.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
target/arm/cpu.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index e2b2337399..3b69c9786a 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -23,6 +23,7 @@
#include "qemu/timer.h"
#include "qemu/log.h"
#include "exec/page-vary.h"
+#include "system/whpx.h"
#include "target/arm/idau.h"
#include "qemu/module.h"
#include "qapi/error.h"
@@ -1496,7 +1497,7 @@ static void arm_cpu_initfn(Object *obj)
cpu->psci_version = QEMU_PSCI_VERSION_0_1; /* By default assume PSCI v0.1 */
cpu->kvm_target = QEMU_KVM_ARM_TARGET_NONE;
- if (tcg_enabled() || hvf_enabled()) {
+ if (tcg_enabled() || hvf_enabled() || whpx_enabled()) {
/* TCG and HVF implement PSCI 1.1 */
cpu->psci_version = QEMU_PSCI_VERSION_1_1;
}
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 10/14] hw/arm: virt: cleanly fail on attempt to use the platform vGIC together with ITS
2025-08-02 8:17 [PATCH v3 00/14] WHPX support for Arm Mohamed Mediouni
` (8 preceding siblings ...)
2025-08-02 8:17 ` [PATCH v3 09/14] target/arm: cpu: mark WHPX as supporting PSCI 1.1 Mohamed Mediouni
@ 2025-08-02 8:17 ` Mohamed Mediouni
2025-08-03 0:57 ` Richard Henderson
2025-08-02 8:17 ` [PATCH v3 11/14] whpx: arm64: clamp down IPA size Mohamed Mediouni
` (3 subsequent siblings)
13 siblings, 1 reply; 32+ messages in thread
From: Mohamed Mediouni @ 2025-08-02 8:17 UTC (permalink / raw)
To: qemu-devel
Cc: Richard Henderson, Zhao Liu, Yanan Wang, qemu-arm,
Sunil Muthuswamy, Daniel P. Berrangé, Igor Mammedov,
Peter Maydell, Shannon Zhao, Michael S. Tsirkin,
Marc-André Lureau, Eduardo Habkost, Marcel Apfelbaum,
Mohamed Mediouni, Paolo Bonzini, Philippe Mathieu-Daudé,
Ani Sinha
Windows Hypervisor Platform's vGIC doesn't support ITS.
Deal with this by reporting to the user and not creating the ITS device.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
hw/arm/virt.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 98a1c74c42..1c695c0642 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -741,6 +741,16 @@ static void create_its(VirtMachineState *vms)
return;
}
+ if (whpx_enabled() && vms->tcg_its) {
+ /*
+ * In the HVF case, inform the user that they can use the
+ * user-mode GIC if they want to have an ITS.
+ */
+ info_report("ITS not supported without kernel-irqchip=off on WHPX");
+ info_report("Disabling ITS");
+ return;
+ }
+
dev = qdev_new(its_class_name());
object_property_set_link(OBJECT(dev), "parent-gicv3", OBJECT(vms->gic),
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 11/14] whpx: arm64: clamp down IPA size
2025-08-02 8:17 [PATCH v3 00/14] WHPX support for Arm Mohamed Mediouni
` (9 preceding siblings ...)
2025-08-02 8:17 ` [PATCH v3 10/14] hw/arm: virt: cleanly fail on attempt to use the platform vGIC together with ITS Mohamed Mediouni
@ 2025-08-02 8:17 ` Mohamed Mediouni
2025-08-03 1:00 ` Richard Henderson
2025-08-02 8:17 ` [PATCH v3 12/14] whpx: arm64: implement -cpu host Mohamed Mediouni
` (2 subsequent siblings)
13 siblings, 1 reply; 32+ messages in thread
From: Mohamed Mediouni @ 2025-08-02 8:17 UTC (permalink / raw)
To: qemu-devel
Cc: Richard Henderson, Zhao Liu, Yanan Wang, qemu-arm,
Sunil Muthuswamy, Daniel P. Berrangé, Igor Mammedov,
Peter Maydell, Shannon Zhao, Michael S. Tsirkin,
Marc-André Lureau, Eduardo Habkost, Marcel Apfelbaum,
Mohamed Mediouni, Paolo Bonzini, Philippe Mathieu-Daudé,
Ani Sinha
Code taken from HVF and adapted for WHPX use. Note that WHPX doesn't
have a default vs maximum IPA distinction.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
hw/arm/virt.c | 32 ++++++++++++++++++++++++++
include/hw/boards.h | 1 +
target/arm/whpx/meson.build | 2 ++
target/arm/whpx/whpx-all.c | 45 +++++++++++++++++++++++++++++++++++++
target/arm/whpx/whpx-stub.c | 15 +++++++++++++
target/arm/whpx_arm.h | 16 +++++++++++++
6 files changed, 111 insertions(+)
create mode 100644 target/arm/whpx/whpx-stub.c
create mode 100644 target/arm/whpx_arm.h
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 1c695c0642..3682d42482 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -70,6 +70,7 @@
#include "hw/irq.h"
#include "kvm_arm.h"
#include "hvf_arm.h"
+#include "whpx_arm.h"
#include "hw/firmware/smbios.h"
#include "qapi/visitor.h"
#include "qapi/qapi-visit-common.h"
@@ -3162,6 +3163,36 @@ static int virt_kvm_type(MachineState *ms, const char *type_str)
return fixed_ipa ? 0 : requested_pa_size;
}
+static int virt_whpx_get_physical_address_range(MachineState *ms)
+{
+ VirtMachineState *vms = VIRT_MACHINE(ms);
+
+ int max_ipa_size = whpx_arm_get_ipa_bit_size();
+
+ /* We freeze the memory map to compute the highest gpa */
+ virt_set_memmap(vms, max_ipa_size);
+
+ int requested_ipa_size = 64 - clz64(vms->highest_gpa);
+
+ /*
+ * If we're <= the default IPA size just use the default.
+ * If we're above the default but below the maximum, round up to
+ * the maximum. hvf_arm_get_max_ipa_bit_size() conveniently only
+ * returns values that are valid ARM PARange values.
+ */
+ if (requested_ipa_size <= max_ipa_size) {
+ requested_ipa_size = max_ipa_size;
+ } else {
+ error_report("-m and ,maxmem option values "
+ "require an IPA range (%d bits) larger than "
+ "the one supported by the host (%d bits)",
+ requested_ipa_size, max_ipa_size);
+ return -1;
+ }
+
+ return requested_ipa_size;
+}
+
static int virt_hvf_get_physical_address_range(MachineState *ms)
{
VirtMachineState *vms = VIRT_MACHINE(ms);
@@ -3256,6 +3287,7 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
mc->get_default_cpu_node_id = virt_get_default_cpu_node_id;
mc->kvm_type = virt_kvm_type;
mc->hvf_get_physical_address_range = virt_hvf_get_physical_address_range;
+ mc->whpx_get_physical_address_range = virt_whpx_get_physical_address_range;
assert(!mc->get_hotplug_handler);
mc->get_hotplug_handler = virt_machine_get_hotplug_handler;
hc->pre_plug = virt_machine_device_pre_plug_cb;
diff --git a/include/hw/boards.h b/include/hw/boards.h
index f94713e6e2..dde8013bd7 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -276,6 +276,7 @@ struct MachineClass {
void (*wakeup)(MachineState *state);
int (*kvm_type)(MachineState *machine, const char *arg);
int (*hvf_get_physical_address_range)(MachineState *machine);
+ int (*whpx_get_physical_address_range)(MachineState *machine);
BlockInterfaceType block_default_type;
int units_per_default_bus;
diff --git a/target/arm/whpx/meson.build b/target/arm/whpx/meson.build
index 1de2ef0283..3df632c9d3 100644
--- a/target/arm/whpx/meson.build
+++ b/target/arm/whpx/meson.build
@@ -1,3 +1,5 @@
arm_system_ss.add(when: 'CONFIG_WHPX', if_true: files(
'whpx-all.c',
))
+
+arm_common_system_ss.add(when: 'CONFIG_WHPX', if_false: files('whpx-stub.c'))
diff --git a/target/arm/whpx/whpx-all.c b/target/arm/whpx/whpx-all.c
index 127e99cda4..79c200495e 100644
--- a/target/arm/whpx/whpx-all.c
+++ b/target/arm/whpx/whpx-all.c
@@ -35,6 +35,7 @@
#include "system/whpx-accel-ops.h"
#include "system/whpx-all.h"
#include "system/whpx-common.h"
+#include "whpx_arm.h"
#include "hw/arm/bsa.h"
#include "arm-powerctl.h"
@@ -641,6 +642,40 @@ static void whpx_cpu_update_state(void *opaque, bool running, RunState state)
{
}
+uint32_t whpx_arm_get_ipa_bit_size(void)
+{
+ WHV_CAPABILITY whpx_cap;
+ UINT32 whpx_cap_size;
+ HRESULT hr;
+ hr = whp_dispatch.WHvGetCapability(
+ WHvCapabilityCodePhysicalAddressWidth, &whpx_cap,
+ sizeof(whpx_cap), &whpx_cap_size);
+ if (FAILED(hr)) {
+ error_report("WHPX: failed to get supported"
+ "physical address width, hr=%08lx", hr);
+ }
+
+ /*
+ * We clamp any IPA size we want to back the VM with to a valid PARange
+ * value so the guest doesn't try and map memory outside of the valid range.
+ * This logic just clamps the passed in IPA bit size to the first valid
+ * PARange value <= to it.
+ */
+ return round_down_to_parange_bit_size(whpx_cap.PhysicalAddressWidth);
+}
+
+static void clamp_id_aa64mmfr0_parange_to_ipa_size(ARMISARegisters *isar)
+{
+ uint32_t ipa_size = whpx_arm_get_ipa_bit_size();
+ uint64_t id_aa64mmfr0;
+
+ /* Clamp down the PARange to the IPA size the kernel supports. */
+ uint8_t index = round_down_to_parange_index(ipa_size);
+ id_aa64mmfr0 = GET_IDREG(isar, ID_AA64MMFR0);
+ id_aa64mmfr0 = (id_aa64mmfr0 & ~R_ID_AA64MMFR0_PARANGE_MASK) | index;
+ SET_IDREG(isar, ID_AA64MMFR0, id_aa64mmfr0);
+}
+
int whpx_init_vcpu(CPUState *cpu)
{
HRESULT hr;
@@ -721,6 +756,7 @@ int whpx_init_vcpu(CPUState *cpu)
whpx_set_reg(cpu, WHvArm64RegisterMpidrEl1,
val);
+ clamp_id_aa64mmfr0_parange_to_ipa_size(&arm_cpu->isar);
return 0;
error:
@@ -743,6 +779,8 @@ int whpx_accel_init(AccelState *as, MachineState *ms)
UINT32 whpx_cap_size;
WHV_PARTITION_PROPERTY prop;
WHV_CAPABILITY_FEATURES features = {0};
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ int pa_range = 0;
whpx = &whpx_global;
/* on arm64 Windows Hypervisor Platform, vGICv3 always used */
@@ -753,6 +791,13 @@ int whpx_accel_init(AccelState *as, MachineState *ms)
goto error;
}
+ if (mc->whpx_get_physical_address_range) {
+ pa_range = mc->whpx_get_physical_address_range(ms);
+ if (pa_range < 0) {
+ return -EINVAL;
+ }
+ }
+
whpx->mem_quota = ms->ram_size;
hr = whp_dispatch.WHvGetCapability(
diff --git a/target/arm/whpx/whpx-stub.c b/target/arm/whpx/whpx-stub.c
new file mode 100644
index 0000000000..32e434a5f6
--- /dev/null
+++ b/target/arm/whpx/whpx-stub.c
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * WHPX stubs for ARM
+ *
+ * Copyright (c) 2025 Mohamed Mediouni
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "whpx_arm.h"
+
+uint32_t whpx_arm_get_ipa_bit_size(void)
+{
+ g_assert_not_reached();
+}
diff --git a/target/arm/whpx_arm.h b/target/arm/whpx_arm.h
new file mode 100644
index 0000000000..de7406b66f
--- /dev/null
+++ b/target/arm/whpx_arm.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * WHPX support -- ARM specifics
+ *
+ * Copyright (c) 2025 Mohamed Mediouni
+ *
+ */
+
+#ifndef QEMU_WHPX_ARM_H
+#define QEMU_WHPX_ARM_H
+
+#include "target/arm/cpu-qom.h"
+
+uint32_t whpx_arm_get_ipa_bit_size(void);
+
+#endif
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 12/14] whpx: arm64: implement -cpu host
2025-08-02 8:17 [PATCH v3 00/14] WHPX support for Arm Mohamed Mediouni
` (10 preceding siblings ...)
2025-08-02 8:17 ` [PATCH v3 11/14] whpx: arm64: clamp down IPA size Mohamed Mediouni
@ 2025-08-02 8:17 ` Mohamed Mediouni
2025-08-03 1:22 ` Richard Henderson
2025-08-02 8:17 ` [PATCH v3 13/14] target/arm: whpx: instantiate GIC early Mohamed Mediouni
2025-08-02 8:18 ` [PATCH v3 14/14] MAINTAINERS: Add myself as a maintainer for WHPX Mohamed Mediouni
13 siblings, 1 reply; 32+ messages in thread
From: Mohamed Mediouni @ 2025-08-02 8:17 UTC (permalink / raw)
To: qemu-devel
Cc: Richard Henderson, Zhao Liu, Yanan Wang, qemu-arm,
Sunil Muthuswamy, Daniel P. Berrangé, Igor Mammedov,
Peter Maydell, Shannon Zhao, Michael S. Tsirkin,
Marc-André Lureau, Eduardo Habkost, Marcel Apfelbaum,
Mohamed Mediouni, Paolo Bonzini, Philippe Mathieu-Daudé,
Ani Sinha
OpenProcessorKey and ReadRegU64 adapted from:
https://github.com/FEX-Emu/FEX/blob/e6de17e72ef03aa88ba14fa0ec13163061608c74/Source/Windows/Common/CPUFeatures.cpp#L62
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
hw/arm/virt.c | 2 +-
target/arm/cpu64.c | 14 ++--
target/arm/whpx/whpx-all.c | 130 +++++++++++++++++++++++++++++++++++++
target/arm/whpx_arm.h | 1 +
4 files changed, 142 insertions(+), 5 deletions(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 3682d42482..321f6c6612 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -3249,7 +3249,7 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
#ifdef TARGET_AARCH64
ARM_CPU_TYPE_NAME("cortex-a53"),
ARM_CPU_TYPE_NAME("cortex-a57"),
-#if defined(CONFIG_KVM) || defined(CONFIG_HVF)
+#if defined(CONFIG_KVM) || defined(CONFIG_HVF) || defined(CONFIG_WHPX)
ARM_CPU_TYPE_NAME("host"),
#endif /* CONFIG_KVM || CONFIG_HVF */
#endif /* TARGET_AARCH64 */
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 26cf7e6dfa..894b2934fa 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -26,10 +26,12 @@
#include "qemu/units.h"
#include "system/kvm.h"
#include "system/hvf.h"
+#include "system/whpx.h"
#include "system/qtest.h"
#include "system/tcg.h"
#include "kvm_arm.h"
#include "hvf_arm.h"
+#include "whpx_arm.h"
#include "qapi/visitor.h"
#include "hw/qdev-properties.h"
#include "internals.h"
@@ -522,7 +524,7 @@ void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp)
isar2 = FIELD_DP64(isar2, ID_AA64ISAR2, APA3, 0);
isar2 = FIELD_DP64(isar2, ID_AA64ISAR2, GPA3, 0);
- if (kvm_enabled() || hvf_enabled()) {
+ if (kvm_enabled() || hvf_enabled() || whpx_enabled()) {
/*
* Exit early if PAuth is enabled and fall through to disable it.
* The algorithm selection properties are not present.
@@ -599,7 +601,7 @@ void aarch64_add_pauth_properties(Object *obj)
/* Default to PAUTH on, with the architected algorithm on TCG. */
qdev_property_add_static(DEVICE(obj), &arm_cpu_pauth_property);
- if (kvm_enabled() || hvf_enabled()) {
+ if (kvm_enabled() || hvf_enabled() || whpx_enabled()) {
/*
* Mirror PAuth support from the probed sysregs back into the
* property for KVM or hvf. Is it just a bit backward? Yes it is!
@@ -773,6 +775,10 @@ static void aarch64_host_initfn(Object *obj)
ARMCPU *cpu = ARM_CPU(obj);
hvf_arm_set_cpu_features_from_host(cpu);
aarch64_add_pauth_properties(obj);
+#elif defined(CONFIG_WHPX)
+ ARMCPU *cpu = ARM_CPU(obj);
+ whpx_arm_set_cpu_features_from_host(cpu);
+ aarch64_add_pauth_properties(obj);
#else
g_assert_not_reached();
#endif
@@ -780,7 +786,7 @@ static void aarch64_host_initfn(Object *obj)
static void aarch64_max_initfn(Object *obj)
{
- if (kvm_enabled() || hvf_enabled()) {
+ if (kvm_enabled() || hvf_enabled() || whpx_enabled()) {
/* With KVM or HVF, '-cpu max' is identical to '-cpu host' */
aarch64_host_initfn(obj);
return;
@@ -800,7 +806,7 @@ static const ARMCPUInfo aarch64_cpus[] = {
{ .name = "cortex-a57", .initfn = aarch64_a57_initfn },
{ .name = "cortex-a53", .initfn = aarch64_a53_initfn },
{ .name = "max", .initfn = aarch64_max_initfn },
-#if defined(CONFIG_KVM) || defined(CONFIG_HVF)
+#if defined(CONFIG_KVM) || defined(CONFIG_HVF) || defined(CONFIG_WHPX)
{ .name = "host", .initfn = aarch64_host_initfn },
#endif
};
diff --git a/target/arm/whpx/whpx-all.c b/target/arm/whpx/whpx-all.c
index 79c200495e..ba1a4c2e41 100644
--- a/target/arm/whpx/whpx-all.c
+++ b/target/arm/whpx/whpx-all.c
@@ -41,6 +41,17 @@
#include <winhvplatform.h>
#include <winhvplatformdefs.h>
+#include <winreg.h>
+
+typedef struct ARMHostCPUFeatures {
+ ARMISARegisters isar;
+ uint64_t features;
+ uint64_t midr;
+ uint32_t reset_sctlr;
+ const char *dtb_compatible;
+} ARMHostCPUFeatures;
+
+static ARMHostCPUFeatures arm_host_cpu_features;
struct whpx_reg_match {
WHV_REGISTER_NAME reg;
@@ -676,6 +687,125 @@ static void clamp_id_aa64mmfr0_parange_to_ipa_size(ARMISARegisters *isar)
SET_IDREG(isar, ID_AA64MMFR0, id_aa64mmfr0);
}
+static HKEY OpenProcessorKey(void)
+{
+ HKEY Out;
+ const char *path = "Hardware\\Description\\System\\CentralProcessor\\0\\";
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, path, 0, KEY_READ, &Out)) {
+ return NULL;
+ }
+ return Out;
+}
+
+static uint64_t ReadRegU64(HKEY Key, const char *name)
+{
+ uint64_t Value = 0;
+ DWORD Size = sizeof(Value);
+ LONG res = RegGetValueA(Key, NULL, name, RRF_RT_REG_QWORD, NULL, &Value, &Size);
+ if (res != ERROR_SUCCESS) {
+ printf("Failed to get register value: error: 0x%x\n", res);
+ }
+ return Value;
+}
+
+static bool whpx_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
+{
+ ARMISARegisters host_isar = {};
+ const struct isar_regs {
+ WHV_REGISTER_NAME reg;
+ uint64_t *val;
+ } regs[] = {
+ { WHvArm64RegisterIdAa64Pfr0El1, &host_isar.idregs[ID_AA64PFR0_EL1_IDX] },
+ { WHvArm64RegisterIdAa64Pfr1El1, &host_isar.idregs[ID_AA64PFR1_EL1_IDX] },
+ { WHvArm64RegisterIdAa64Dfr0El1, &host_isar.idregs[ID_AA64DFR0_EL1_IDX] },
+ { WHvArm64RegisterIdAa64Dfr1El1 , &host_isar.idregs[ID_AA64DFR1_EL1_IDX] },
+ { WHvArm64RegisterIdAa64Isar0El1, &host_isar.idregs[ID_AA64ISAR0_EL1_IDX] },
+ { WHvArm64RegisterIdAa64Isar1El1, &host_isar.idregs[ID_AA64ISAR1_EL1_IDX] },
+ { WHvArm64RegisterIdAa64Isar2El1, &host_isar.idregs[ID_AA64ISAR2_EL1_IDX] },
+ { WHvArm64RegisterIdAa64Mmfr0El1, &host_isar.idregs[ID_AA64MMFR0_EL1_IDX] },
+ { WHvArm64RegisterIdAa64Mmfr1El1, &host_isar.idregs[ID_AA64MMFR1_EL1_IDX] },
+ { WHvArm64RegisterIdAa64Mmfr2El1, &host_isar.idregs[ID_AA64MMFR2_EL1_IDX] },
+ { WHvArm64RegisterIdAa64Mmfr3El1, &host_isar.idregs[ID_AA64MMFR2_EL1_IDX] }
+ };
+
+ int i;
+ WHV_REGISTER_VALUE val;
+
+ ahcf->dtb_compatible = "arm,armv8";
+ ahcf->features = (1ULL << ARM_FEATURE_V8) |
+ (1ULL << ARM_FEATURE_NEON) |
+ (1ULL << ARM_FEATURE_AARCH64) |
+ (1ULL << ARM_FEATURE_PMU) |
+ (1ULL << ARM_FEATURE_GENERIC_TIMER);
+
+ for (i = 0; i < ARRAY_SIZE(regs); i++) {
+ clean_whv_register_value(&val);
+ whpx_get_global_reg(regs[i].reg, &val);
+ *regs[i].val = val.Reg64;
+ }
+
+ /*
+ * MIDR_EL1 is not a global register on WHPX
+ * As such, read the CPU0 from the registry to get a consistent value.
+ * Otherwise, on heterogenous systems, you'll get variance between CPUs.
+ */
+ HKEY ProcessorKey = OpenProcessorKey();
+ ahcf->midr = ReadRegU64(ProcessorKey, "CP 4000");
+ RegCloseKey(ProcessorKey);
+
+ clamp_id_aa64mmfr0_parange_to_ipa_size(&host_isar);
+
+ /*
+ * Disable SME, which is not properly handled by QEMU hvf yet.
+ * To allow this through we would need to:
+ * - make sure that the SME state is correctly handled in the
+ * get_registers/put_registers functions
+ * - get the SME-specific CPU properties to work with accelerators
+ * other than TCG
+ * - fix any assumptions we made that SME implies SVE (since
+ * on the M4 there is SME but not SVE)
+ */
+ SET_IDREG(&host_isar, ID_AA64PFR1,
+ GET_IDREG(&host_isar, ID_AA64PFR1) & ~R_ID_AA64PFR1_SME_MASK);
+
+ ahcf->isar = host_isar;
+
+ /*
+ * A scratch vCPU returns SCTLR 0, so let's fill our default with the M1
+ * boot SCTLR from https://github.com/AsahiLinux/m1n1/issues/97
+ */
+ ahcf->reset_sctlr = 0x30100180;
+ /*
+ * SPAN is disabled by default when SCTLR.SPAN=1. To improve compatibility,
+ * let's disable it on boot and then allow guest software to turn it on by
+ * setting it to 0.
+ */
+ ahcf->reset_sctlr |= 0x00800000;
+
+ return true;
+}
+
+void whpx_arm_set_cpu_features_from_host(ARMCPU *cpu)
+{
+ if (!arm_host_cpu_features.dtb_compatible) {
+ if (!whpx_enabled() ||
+ !whpx_arm_get_host_cpu_features(&arm_host_cpu_features)) {
+ /*
+ * We can't report this error yet, so flag that we need to
+ * in arm_cpu_realizefn().
+ */
+ cpu->host_cpu_probe_failed = true;
+ return;
+ }
+ }
+
+ cpu->dtb_compatible = arm_host_cpu_features.dtb_compatible;
+ cpu->isar = arm_host_cpu_features.isar;
+ cpu->env.features = arm_host_cpu_features.features;
+ cpu->midr = arm_host_cpu_features.midr;
+ cpu->reset_sctlr = arm_host_cpu_features.reset_sctlr;
+}
+
int whpx_init_vcpu(CPUState *cpu)
{
HRESULT hr;
diff --git a/target/arm/whpx_arm.h b/target/arm/whpx_arm.h
index de7406b66f..df65fd753c 100644
--- a/target/arm/whpx_arm.h
+++ b/target/arm/whpx_arm.h
@@ -12,5 +12,6 @@
#include "target/arm/cpu-qom.h"
uint32_t whpx_arm_get_ipa_bit_size(void);
+void whpx_arm_set_cpu_features_from_host(ARMCPU *cpu);
#endif
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 13/14] target/arm: whpx: instantiate GIC early
2025-08-02 8:17 [PATCH v3 00/14] WHPX support for Arm Mohamed Mediouni
` (11 preceding siblings ...)
2025-08-02 8:17 ` [PATCH v3 12/14] whpx: arm64: implement -cpu host Mohamed Mediouni
@ 2025-08-02 8:17 ` Mohamed Mediouni
2025-08-02 8:18 ` [PATCH v3 14/14] MAINTAINERS: Add myself as a maintainer for WHPX Mohamed Mediouni
13 siblings, 0 replies; 32+ messages in thread
From: Mohamed Mediouni @ 2025-08-02 8:17 UTC (permalink / raw)
To: qemu-devel
Cc: Richard Henderson, Zhao Liu, Yanan Wang, qemu-arm,
Sunil Muthuswamy, Daniel P. Berrangé, Igor Mammedov,
Peter Maydell, Shannon Zhao, Michael S. Tsirkin,
Marc-André Lureau, Eduardo Habkost, Marcel Apfelbaum,
Mohamed Mediouni, Paolo Bonzini, Philippe Mathieu-Daudé,
Ani Sinha
While figuring out a better spot for it, put it in whpx_accel_init.
Needs to be done before WHvSetupPartition.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
target/arm/whpx/whpx-all.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/target/arm/whpx/whpx-all.c b/target/arm/whpx/whpx-all.c
index ba1a4c2e41..149ec7b709 100644
--- a/target/arm/whpx/whpx-all.c
+++ b/target/arm/whpx/whpx-all.c
@@ -984,6 +984,29 @@ int whpx_accel_init(AccelState *as, MachineState *ms)
memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY));
+ WHV_ARM64_IC_PARAMETERS ic_params = {
+ .EmulationMode = WHvArm64IcEmulationModeGicV3,
+ .GicV3Parameters = {
+ .GicdBaseAddress = 0x08000000,
+ .GitsTranslaterBaseAddress = 0x08080000,
+ .GicLpiIntIdBits = 0,
+ .GicPpiPerformanceMonitorsInterrupt = VIRTUAL_PMU_IRQ,
+ .GicPpiOverflowInterruptFromCntv = ARCH_TIMER_VIRT_IRQ
+ }
+ };
+ prop.Arm64IcParameters = ic_params;
+
+ hr = whp_dispatch.WHvSetPartitionProperty(
+ whpx->partition,
+ WHvPartitionPropertyCodeArm64IcParameters,
+ &prop,
+ sizeof(WHV_PARTITION_PROPERTY));
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to enable GICv3 interrupt controller, hr=%08lx", hr);
+ ret = -EINVAL;
+ goto error;
+ }
+
hr = whp_dispatch.WHvSetupPartition(whpx->partition);
if (FAILED(hr)) {
error_report("WHPX: Failed to setup partition, hr=%08lx", hr);
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 14/14] MAINTAINERS: Add myself as a maintainer for WHPX
2025-08-02 8:17 [PATCH v3 00/14] WHPX support for Arm Mohamed Mediouni
` (12 preceding siblings ...)
2025-08-02 8:17 ` [PATCH v3 13/14] target/arm: whpx: instantiate GIC early Mohamed Mediouni
@ 2025-08-02 8:18 ` Mohamed Mediouni
2025-08-03 1:23 ` Richard Henderson
13 siblings, 1 reply; 32+ messages in thread
From: Mohamed Mediouni @ 2025-08-02 8:18 UTC (permalink / raw)
To: qemu-devel
Cc: Richard Henderson, Zhao Liu, Yanan Wang, qemu-arm,
Sunil Muthuswamy, Daniel P. Berrangé, Igor Mammedov,
Peter Maydell, Shannon Zhao, Michael S. Tsirkin,
Marc-André Lureau, Eduardo Habkost, Marcel Apfelbaum,
Mohamed Mediouni, Paolo Bonzini, Philippe Mathieu-Daudé,
Ani Sinha
And add arm64 files.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
MAINTAINERS | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 259b010f55..9397e55c4a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -539,11 +539,14 @@ F: accel/stubs/hvf-stub.c
F: include/system/hvf.h
F: include/system/hvf_int.h
-WHPX CPUs
+WHPX
M: Sunil Muthuswamy <sunilmut@microsoft.com>
+M: Mohamed Mediouni <mohamed@unpredictable.fr>
S: Supported
F: accel/whpx/
F: target/i386/whpx/
+F: target/arm/whpx_arm.h
+F: target/arm/whpx/
F: accel/stubs/whpx-stub.c
F: include/system/whpx.h
F: include/system/whpx-accel-ops.h
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [PATCH v3 02/14] whpx: Move around files before introducing AArch64 support
2025-08-02 8:17 ` [PATCH v3 02/14] whpx: Move around files before introducing AArch64 support Mohamed Mediouni
@ 2025-08-02 8:53 ` Mohamed Mediouni
2025-08-03 0:03 ` Richard Henderson
1 sibling, 0 replies; 32+ messages in thread
From: Mohamed Mediouni @ 2025-08-02 8:53 UTC (permalink / raw)
To: qemu-devel
Cc: Richard Henderson, Zhao Liu, Yanan Wang, qemu-arm,
Sunil Muthuswamy, "Daniel P. Berrangé",
Igor Mammedov, Peter Maydell, Shannon Zhao, Michael S. Tsirkin,
Marc-André Lureau, Eduardo Habkost, Marcel Apfelbaum,
Paolo Bonzini, Philippe Mathieu-Daudé, Ani Sinha
[-- Attachment #1: Type: text/plain, Size: 4481 bytes --]
Note: I _also_ screwed up this rebase a bit unfortunately but this one should be clean: https://github.com/mediouni-m/qemu/commit/66f052d80b6b51a60374074cec876f9bfc8a756c
To not cause too much spam on the ML will most likely batch this when I have more changes...
> On 2. Aug 2025, at 10:17, Mohamed Mediouni <mohamed@unpredictable.fr> wrote:
>
> Switch to a design where we can share whpx code between x86 and AArch64 when it makes sense to do so.
>
> Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
> ---
> MAINTAINERS | 2 ++
> accel/meson.build | 1 +
> accel/whpx/meson.build | 6 ++++++
> {target/i386 => accel}/whpx/whpx-accel-ops.c | 4 ++--
> {target/i386/whpx => include/system}/whpx-accel-ops.h | 0
> target/i386/whpx/meson.build | 1 -
> target/i386/whpx/whpx-all.c | 4 ++--
> target/i386/whpx/whpx-internal.h | 1 +
> 8 files changed, 14 insertions(+), 5 deletions(-)
> create mode 100644 accel/whpx/meson.build
> rename {target/i386 => accel}/whpx/whpx-accel-ops.c (97%)
> rename {target/i386/whpx => include/system}/whpx-accel-ops.h (100%)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 28cea34271..238065e1c9 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -542,9 +542,11 @@ F: include/system/hvf_int.h
> WHPX CPUs
> M: Sunil Muthuswamy <sunilmut@microsoft.com>
> S: Supported
> +F: accel/whpx/
> F: target/i386/whpx/
> F: accel/stubs/whpx-stub.c
> F: include/system/whpx.h
> +F: include/system/whpx-accel-ops.h
>
> X86 Instruction Emulator
> M: Cameron Esfahani <dirty@apple.com>
> diff --git a/accel/meson.build b/accel/meson.build
> index 25b0f100b5..de927a3b37 100644
> --- a/accel/meson.build
> +++ b/accel/meson.build
> @@ -6,6 +6,7 @@ user_ss.add(files('accel-user.c'))
> subdir('tcg')
> if have_system
> subdir('hvf')
> + subdir('whpx')
> subdir('qtest')
> subdir('kvm')
> subdir('xen')
> diff --git a/accel/whpx/meson.build b/accel/whpx/meson.build
> new file mode 100644
> index 0000000000..7b3d6f1c1c
> --- /dev/null
> +++ b/accel/whpx/meson.build
> @@ -0,0 +1,6 @@
> +whpx_ss = ss.source_set()
> +whpx_ss.add(files(
> + 'whpx-accel-ops.c',
> +))
> +
> +specific_ss.add_all(when: 'CONFIG_WHPX', if_true: whpx_ss)
> diff --git a/target/i386/whpx/whpx-accel-ops.c b/accel/whpx/whpx-accel-ops.c
> similarity index 97%
> rename from target/i386/whpx/whpx-accel-ops.c
> rename to accel/whpx/whpx-accel-ops.c
> index da58805b1a..18488421bc 100644
> --- a/target/i386/whpx/whpx-accel-ops.c
> +++ b/accel/whpx/whpx-accel-ops.c
> @@ -16,8 +16,8 @@
> #include "qemu/guest-random.h"
>
> #include "system/whpx.h"
> -#include "whpx-internal.h"
> -#include "whpx-accel-ops.h"
> +#include "system/whpx-internal.h"
> +#include "system/whpx-accel-ops.h"
>
> static void *whpx_cpu_thread_fn(void *arg)
> {
> diff --git a/target/i386/whpx/whpx-accel-ops.h b/include/system/whpx-accel-ops.h
> similarity index 100%
> rename from target/i386/whpx/whpx-accel-ops.h
> rename to include/system/whpx-accel-ops.h
> diff --git a/target/i386/whpx/meson.build b/target/i386/whpx/meson.build
> index 9c54aaad39..c3aaaff9fd 100644
> --- a/target/i386/whpx/meson.build
> +++ b/target/i386/whpx/meson.build
> @@ -1,5 +1,4 @@
> i386_system_ss.add(when: 'CONFIG_WHPX', if_true: files(
> 'whpx-all.c',
> 'whpx-apic.c',
> - 'whpx-accel-ops.c',
> ))
> diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
> index b72dcff3c8..5a431fc3c7 100644
> --- a/target/i386/whpx/whpx-all.c
> +++ b/target/i386/whpx/whpx-all.c
> @@ -31,8 +31,8 @@
> #include "accel/accel-cpu-target.h"
> #include <winerror.h>
>
> -#include "whpx-internal.h"
> -#include "whpx-accel-ops.h"
> +#include "system/whpx-internal.h"
> +#include "system/whpx-accel-ops.h"
>
> #include <winhvplatform.h>
> #include <winhvemulation.h>
> diff --git a/target/i386/whpx/whpx-internal.h b/target/i386/whpx/whpx-internal.h
> index 6633e9c4ca..435e0c5046 100644
> --- a/target/i386/whpx/whpx-internal.h
> +++ b/target/i386/whpx/whpx-internal.h
> @@ -117,3 +117,4 @@ typedef enum WHPFunctionList {
> } WHPFunctionList;
>
> #endif /* TARGET_I386_WHPX_INTERNAL_H */
> +
> --
> 2.39.5 (Apple Git-154)
>
[-- Attachment #2: Type: text/html, Size: 6094 bytes --]
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 02/14] whpx: Move around files before introducing AArch64 support
2025-08-02 8:17 ` [PATCH v3 02/14] whpx: Move around files before introducing AArch64 support Mohamed Mediouni
2025-08-02 8:53 ` Mohamed Mediouni
@ 2025-08-03 0:03 ` Richard Henderson
1 sibling, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2025-08-03 0:03 UTC (permalink / raw)
To: Mohamed Mediouni, qemu-devel; +Cc: open list:ARM
On 8/2/25 18:17, Mohamed Mediouni wrote:
> Switch to a design where we can share whpx code between x86 and AArch64 when it makes sense to do so.
>
> Signed-off-by: Mohamed Mediouni<mohamed@unpredictable.fr>
>
> Reviewed-by: Philippe Mathieu-Daudé<philmd@linaro.org>
> ---
> MAINTAINERS | 2 ++
> accel/meson.build | 1 +
> accel/whpx/meson.build | 6 ++++++
> {target/i386 => accel}/whpx/whpx-accel-ops.c | 4 ++--
> {target/i386/whpx => include/system}/whpx-accel-ops.h | 0
> target/i386/whpx/meson.build | 1 -
> target/i386/whpx/whpx-all.c | 4 ++--
> target/i386/whpx/whpx-internal.h | 1 +
> 8 files changed, 14 insertions(+), 5 deletions(-)
> create mode 100644 accel/whpx/meson.build
> rename {target/i386 => accel}/whpx/whpx-accel-ops.c (97%)
> rename {target/i386/whpx => include/system}/whpx-accel-ops.h (100%)
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 03/14] whpx: reshuffle common code
2025-08-02 8:17 ` [PATCH v3 03/14] whpx: reshuffle common code Mohamed Mediouni
@ 2025-08-03 0:15 ` Richard Henderson
0 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2025-08-03 0:15 UTC (permalink / raw)
To: Mohamed Mediouni, qemu-devel
On 8/2/25 18:17, Mohamed Mediouni wrote:
> --- /dev/null
> +++ b/accel/whpx/whpx-common.c
...
> +bool whpx_allowed;
> +static bool whp_dispatch_initialized;
> +static HMODULE hWinHvPlatform;
> +static HMODULE hWinHvEmulation;
> +
> +struct whpx_state whpx_global;
> +struct WHPDispatch whp_dispatch;
You failed to remove these from target/i386/whpx/whpx-all.c.
I'm surprised you didn't receive a link error for at least whpx_allowed. I guess the
windows compiler doesn't support -fno-common? Or a compile-time error for the unused
static variables?
You need to make sure x86 still builds at every step.
r~
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 04/14] whpx: ifdef out some x86-only code paths
2025-08-02 8:17 ` [PATCH v3 04/14] whpx: ifdef out some x86-only code paths Mohamed Mediouni
@ 2025-08-03 0:41 ` Richard Henderson
2025-08-03 0:55 ` Mohamed Mediouni
2025-08-03 0:51 ` Richard Henderson
1 sibling, 1 reply; 32+ messages in thread
From: Richard Henderson @ 2025-08-03 0:41 UTC (permalink / raw)
To: Mohamed Mediouni, qemu-devel
On 8/2/25 18:17, Mohamed Mediouni wrote:
> winhvemulation is x86_64 only.
> Exception exit bitmaps are also x86_64 only
> Others are just variable definitions not used on arm64.
>
> Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
> ---
> accel/whpx/whpx-common.c | 20 ++++++++++++++++++--
> include/system/whpx-all.h | 2 ++
> include/system/whpx-common.h | 2 ++
> include/system/whpx-internal.h | 7 ++++++-
> 4 files changed, 28 insertions(+), 3 deletions(-)
>
> diff --git a/accel/whpx/whpx-common.c b/accel/whpx/whpx-common.c
> index b5e5fda696..eeefaea329 100644
> --- a/accel/whpx/whpx-common.c
> +++ b/accel/whpx/whpx-common.c
> @@ -41,7 +41,9 @@
> bool whpx_allowed;
> static bool whp_dispatch_initialized;
> static HMODULE hWinHvPlatform;
> +#ifdef __x86_64__
> static HMODULE hWinHvEmulation;
> +#endif
>
> struct whpx_state whpx_global;
> struct WHPDispatch whp_dispatch;
> @@ -106,11 +108,16 @@ int whpx_first_vcpu_starting(CPUState *cpu)
> * whpx_translate_cpu_breakpoints(). WHPX breakpoints must
> * now be recomputed.
> */
> +#ifdef __x86_64__
> whpx_translate_cpu_breakpoints(&whpx->breakpoints, cpu, i);
> +#endif
> }
> +#ifdef __x86_64__
> /* Actually insert the breakpoints into the memory. */
> whpx_apply_breakpoints(whpx->breakpoints.breakpoints, cpu, true);
> +#endif
> }
These are still static in target/i386/whpx/whpx-all.c, so the split in the previous patch
didn't work. You probably want arm to *have* these functions, even if they're empty.
> +#ifdef __x86_64__
> HRESULT hr;
> uint64_t exception_mask;
> if (whpx->step_pending ||
> @@ -132,6 +139,7 @@ int whpx_first_vcpu_starting(CPUState *cpu)
> "hr=%08lx.", hr);
> return 1;
> }
> +#endif
I'm not quite sure what this is doing, but it probably needs to be split out to a new
function which can be specialized between architectures.
> @@ -238,8 +246,10 @@ void whpx_destroy_vcpu(CPUState *cpu)
> struct whpx_state *whpx = &whpx_global;
>
> whp_dispatch.WHvDeleteVirtualProcessor(whpx->partition, cpu->cpu_index);
> +#ifdef __x86_64__
> AccelCPUState *vcpu = cpu->accel;
> whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator);
> +#endif
Does the os function exist on arm? The answer to that determines whether we must split
this out to an architecture function or if we can do
if (vcpu->emulator) {
destroy
}
> @@ -414,8 +424,12 @@ static bool load_whp_dispatch_fns(HMODULE *handle,
> LIST_WINHVPLATFORM_FUNCTIONS(WHP_LOAD_FIELD)
> break;
> case WINHV_EMULATION_FNS_DEFAULT:
> +#ifdef __x86_64__
> WHP_LOAD_LIB(WINHV_EMULATION_DLL, hLib)
> LIST_WINHVEMULATION_FUNCTIONS(WHP_LOAD_FIELD)
> +#else
> + abort();
> +#endif
Use g_assert_not_reached not abort.
That said, it might be cleaner to split this into two functions, rather than select pieces
of the function via an enumerator. At which point I could see the entire set of emulation
code staying in target/i386/.
r~
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 05/14] hw, target, accel: whpx: change apic_in_platform to kernel_irqchip
2025-08-02 8:17 ` [PATCH v3 05/14] hw, target, accel: whpx: change apic_in_platform to kernel_irqchip Mohamed Mediouni
@ 2025-08-03 0:42 ` Richard Henderson
0 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2025-08-03 0:42 UTC (permalink / raw)
To: Mohamed Mediouni, qemu-devel
On 8/2/25 18:17, Mohamed Mediouni wrote:
> Change terminology to match the KVM one, as APIC is x86-specific.
>
> Signed-off-by: Mohamed Mediouni<mohamed@unpredictable.fr>
> ---
> accel/whpx/whpx-accel-ops.c | 2 +-
> accel/whpx/whpx-common.c | 4 ++--
> hw/i386/x86-cpu.c | 4 ++--
> include/system/whpx-internal.h | 2 +-
> include/system/whpx.h | 4 ++--
> target/i386/cpu-apic.c | 2 +-
> target/i386/whpx/whpx-all.c | 14 +++++++-------
> 7 files changed, 16 insertions(+), 16 deletions(-)
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 04/14] whpx: ifdef out some x86-only code paths
2025-08-02 8:17 ` [PATCH v3 04/14] whpx: ifdef out some x86-only code paths Mohamed Mediouni
2025-08-03 0:41 ` Richard Henderson
@ 2025-08-03 0:51 ` Richard Henderson
1 sibling, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2025-08-03 0:51 UTC (permalink / raw)
To: Mohamed Mediouni, qemu-devel
On 8/2/25 18:17, Mohamed Mediouni wrote:
> @@ -414,8 +424,12 @@ static bool load_whp_dispatch_fns(HMODULE *handle,
> LIST_WINHVPLATFORM_FUNCTIONS(WHP_LOAD_FIELD)
> break;
> case WINHV_EMULATION_FNS_DEFAULT:
> +#ifdef __x86_64__
> WHP_LOAD_LIB(WINHV_EMULATION_DLL, hLib)
> LIST_WINHVEMULATION_FUNCTIONS(WHP_LOAD_FIELD)
> +#else
> + abort();
> +#endif
> break;
BTW, are there import libraries for these?
If not, could we use dlltool or something to create one at build time?
Since they are required for whpx to function, I just thought it might be easier to have
them auto-loaded with the executable, and functions dispatched by the linker, rather than
go through whp_dispatch.
r~
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 04/14] whpx: ifdef out some x86-only code paths
2025-08-03 0:41 ` Richard Henderson
@ 2025-08-03 0:55 ` Mohamed Mediouni
2025-08-03 1:03 ` Richard Henderson
0 siblings, 1 reply; 32+ messages in thread
From: Mohamed Mediouni @ 2025-08-03 0:55 UTC (permalink / raw)
To: Richard Henderson; +Cc: qemu-devel
> On 3. Aug 2025, at 02:41, Richard Henderson <richard.henderson@linaro.org> wrote:
>
> On 8/2/25 18:17, Mohamed Mediouni wrote:
>> winhvemulation is x86_64 only.
>> Exception exit bitmaps are also x86_64 only
>> Others are just variable definitions not used on arm64.
>> Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
>> ---
>> accel/whpx/whpx-common.c | 20 ++++++++++++++++++--
>> include/system/whpx-all.h | 2 ++
>> include/system/whpx-common.h | 2 ++
>> include/system/whpx-internal.h | 7 ++++++-
>> 4 files changed, 28 insertions(+), 3 deletions(-)
>> diff --git a/accel/whpx/whpx-common.c b/accel/whpx/whpx-common.c
>> index b5e5fda696..eeefaea329 100644
>> --- a/accel/whpx/whpx-common.c
>> +++ b/accel/whpx/whpx-common.c
>> @@ -41,7 +41,9 @@
>> bool whpx_allowed;
>> static bool whp_dispatch_initialized;
>> static HMODULE hWinHvPlatform;
>> +#ifdef __x86_64__
>> static HMODULE hWinHvEmulation;
>> +#endif
>> struct whpx_state whpx_global;
>> struct WHPDispatch whp_dispatch;
>> @@ -106,11 +108,16 @@ int whpx_first_vcpu_starting(CPUState *cpu)
>> * whpx_translate_cpu_breakpoints(). WHPX breakpoints must
>> * now be recomputed.
>> */
>> +#ifdef __x86_64__
>> whpx_translate_cpu_breakpoints(&whpx->breakpoints, cpu, i);
>> +#endif
>> }
>> +#ifdef __x86_64__
>> /* Actually insert the breakpoints into the memory. */
>> whpx_apply_breakpoints(whpx->breakpoints.breakpoints, cpu, true);
>> +#endif
>> }
>
> These are still static in target/i386/whpx/whpx-all.c, so the split in the previous patch didn't work. You probably want arm to *have* these functions, even if they're empty.
>
>> +#ifdef __x86_64__
>> HRESULT hr;
>> uint64_t exception_mask;
>> if (whpx->step_pending ||
>> @@ -132,6 +139,7 @@ int whpx_first_vcpu_starting(CPUState *cpu)
>> "hr=%08lx.", hr);
>> return 1;
>> }
>> +#endif
>
> I'm not quite sure what this is doing, but it probably needs to be split out to a new function which can be specialized between architectures.
Hello,
Arm WHPX has no specific functionality for debugging today, but we could support kernel mode breakpoints via replacing them by an unhandled hvc #2, stubbing might be the right route to go...
>
>> @@ -238,8 +246,10 @@ void whpx_destroy_vcpu(CPUState *cpu)
>> struct whpx_state *whpx = &whpx_global;
>> whp_dispatch.WHvDeleteVirtualProcessor(whpx->partition, cpu->cpu_index);
>> +#ifdef __x86_64__
>> AccelCPUState *vcpu = cpu->accel;
>> whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator);
>> +#endif
>
> Does the os function exist on arm? The answer to that determines whether we must split this out to an architecture function or if we can do
>
> if (vcpu->emulator) {
> destroy
> }
The winhvemulation header has x86-isms and isn’t parsable on arm unfortunately.
The whole winhvemulation library is x86_64 specific.
That said, I don’t think we need winhvemulation on x86 in the first place and it could be a good idea to get rid of the dependency there too.
>> @@ -414,8 +424,12 @@ static bool load_whp_dispatch_fns(HMODULE *handle,
>> LIST_WINHVPLATFORM_FUNCTIONS(WHP_LOAD_FIELD)
>> break;
>> case WINHV_EMULATION_FNS_DEFAULT:
>> +#ifdef __x86_64__
>> WHP_LOAD_LIB(WINHV_EMULATION_DLL, hLib)
>> LIST_WINHVEMULATION_FUNCTIONS(WHP_LOAD_FIELD)
>> +#else
>> + abort();
>> +#endif
>
> Use g_assert_not_reached not abort.
>
> That said, it might be cleaner to split this into two functions, rather than select pieces of the function via an enumerator. At which point I could see the entire set of emulation code staying in target/i386/.
There’s still significant shared code that might be worth keeping I think… will test a bit on x86 and see what makes sense to do…
Thank you,
>
> r~
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 07/14] whpx: add arm64 support
2025-08-02 8:17 ` [PATCH v3 07/14] whpx: add arm64 support Mohamed Mediouni
@ 2025-08-03 0:56 ` Richard Henderson
2025-08-03 1:03 ` Mohamed Mediouni
0 siblings, 1 reply; 32+ messages in thread
From: Richard Henderson @ 2025-08-03 0:56 UTC (permalink / raw)
To: Mohamed Mediouni, qemu-devel
On 8/2/25 18:17, Mohamed Mediouni wrote:
> +struct whpx_sreg_match {
> + WHV_REGISTER_NAME reg;
> + uint32_t key;
> + bool global;
> + uint32_t cp_idx;
> +};
> +
> +static struct whpx_sreg_match whpx_sreg_match[] = {
const.
> +#ifdef SYNC_NO_RAW_REGS
> + /*
> + * The registers below are manually synced on init because they are
> + * marked as NO_RAW. We still list them to make number space sync easier.
> + */
> + { WHvArm64RegisterMidrEl1, WHPX_SYSREG(0, 0, 3, 0, 0) },
> + { WHvArm64RegisterMpidrEl1, WHPX_SYSREG(0, 0, 3, 0, 5) },
> + { WHvArm64RegisterIdPfr0El1, WHPX_SYSREG(0, 4, 3, 0, 0) },
> +#endif
> + { WHvArm64RegisterIdAa64Pfr1El1, WHPX_SYSREG(0, 4, 3, 0, 1), true },
> + { WHvArm64RegisterIdAa64Dfr0El1, WHPX_SYSREG(0, 5, 3, 0, 0), true },
> + { WHvArm64RegisterIdAa64Dfr1El1, WHPX_SYSREG(0, 5, 3, 0, 1), true },
> + { WHvArm64RegisterIdAa64Isar0El1, WHPX_SYSREG(0, 6, 3, 0, 0), true },
> + { WHvArm64RegisterIdAa64Isar1El1, WHPX_SYSREG(0, 6, 3, 0, 1), true },
> +#ifdef SYNC_NO_MMFR0
> + /* We keep the hardware MMFR0 around. HW limits are there anyway */
> + { WHvArm64RegisterIdAa64Mmfr0El1, WHPX_SYSREG(0, 7, 3, 0, 0) },
> +#endif
> + { WHvArm64RegisterIdAa64Mmfr1El1, WHPX_SYSREG(0, 7, 3, 0, 1), true },
> + { WHvArm64RegisterIdAa64Mmfr2El1, WHPX_SYSREG(0, 7, 3, 0, 2), true },
> + { WHvArm64RegisterIdAa64Mmfr3El1, WHPX_SYSREG(0, 7, 3, 0, 3), true },
All of these are id registers. I can understand reading them once at startup, to populate
-cpu host, but they need not be synced otherwise.
> +static uint64_t whpx_get_gp_reg(CPUState *cpu, int rt)
> +{
> + if (rt >= 31) {
> + return 0;
> + }
assert? Or return 0 for 31 and assert <= 32?
> + WHV_REGISTER_NAME reg = WHvArm64RegisterX0 + rt;
> + WHV_REGISTER_VALUE val;
> + whpx_get_reg(cpu, reg, &val);
> +
> + return val.Reg64;
> +}
> +
> +static void whpx_set_gp_reg(CPUState *cpu, int rt, uint64_t val)
> +{
> + if (rt >= 31) {
> + abort();
> + }
assert. Or ignore write to 31 and assert <= 32?
> + if (cm) {
> + /* We don't cache MMIO regions */
> + abort();
> + return 0;
> + }
assert.
r~
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 09/14] target/arm: cpu: mark WHPX as supporting PSCI 1.1
2025-08-02 8:17 ` [PATCH v3 09/14] target/arm: cpu: mark WHPX as supporting PSCI 1.1 Mohamed Mediouni
@ 2025-08-03 0:56 ` Richard Henderson
0 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2025-08-03 0:56 UTC (permalink / raw)
To: Mohamed Mediouni, qemu-devel
On 8/2/25 18:17, Mohamed Mediouni wrote:
> Hyper-V supports PSCI 1.3, and that implementation is exposed through
> WHPX.
>
> Signed-off-by: Mohamed Mediouni<mohamed@unpredictable.fr>
> ---
> target/arm/cpu.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 10/14] hw/arm: virt: cleanly fail on attempt to use the platform vGIC together with ITS
2025-08-02 8:17 ` [PATCH v3 10/14] hw/arm: virt: cleanly fail on attempt to use the platform vGIC together with ITS Mohamed Mediouni
@ 2025-08-03 0:57 ` Richard Henderson
0 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2025-08-03 0:57 UTC (permalink / raw)
To: Mohamed Mediouni, qemu-devel
On 8/2/25 18:17, Mohamed Mediouni wrote:
> Windows Hypervisor Platform's vGIC doesn't support ITS.
> Deal with this by reporting to the user and not creating the ITS device.
>
> Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
> ---
> hw/arm/virt.c | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
> index 98a1c74c42..1c695c0642 100644
> --- a/hw/arm/virt.c
> +++ b/hw/arm/virt.c
> @@ -741,6 +741,16 @@ static void create_its(VirtMachineState *vms)
> return;
> }
>
> + if (whpx_enabled() && vms->tcg_its) {
> + /*
> + * In the HVF case, inform the user that they can use the
Watch out for the cut-and-paste of HVF.
r~
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 11/14] whpx: arm64: clamp down IPA size
2025-08-02 8:17 ` [PATCH v3 11/14] whpx: arm64: clamp down IPA size Mohamed Mediouni
@ 2025-08-03 1:00 ` Richard Henderson
0 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2025-08-03 1:00 UTC (permalink / raw)
To: Mohamed Mediouni, qemu-devel
On 8/2/25 18:17, Mohamed Mediouni wrote:
> +++ b/include/hw/boards.h
> @@ -276,6 +276,7 @@ struct MachineClass {
> void (*wakeup)(MachineState *state);
> int (*kvm_type)(MachineState *machine, const char *arg);
> int (*hvf_get_physical_address_range)(MachineState *machine);
> + int (*whpx_get_physical_address_range)(MachineState *machine);
We need to generalize this to an accelerator hook, so that there's one code path for both
hvf and whpx. And kvm, for that matter, though it's less obvious how that's handled.
r~
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 04/14] whpx: ifdef out some x86-only code paths
2025-08-03 0:55 ` Mohamed Mediouni
@ 2025-08-03 1:03 ` Richard Henderson
2025-08-03 1:08 ` Mohamed Mediouni
0 siblings, 1 reply; 32+ messages in thread
From: Richard Henderson @ 2025-08-03 1:03 UTC (permalink / raw)
To: Mohamed Mediouni; +Cc: qemu-devel
On 8/3/25 10:55, Mohamed Mediouni wrote:
> Arm WHPX has no specific functionality for debugging today, but we could support kernel mode breakpoints via replacing them by an unhandled hvc #2, stubbing might be the right route to go...
Surely the debug registers are usable? In the meantime, stub functions which do nothing
are better than ifdefs wherever possible.
r~
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 07/14] whpx: add arm64 support
2025-08-03 0:56 ` Richard Henderson
@ 2025-08-03 1:03 ` Mohamed Mediouni
0 siblings, 0 replies; 32+ messages in thread
From: Mohamed Mediouni @ 2025-08-03 1:03 UTC (permalink / raw)
To: Richard Henderson; +Cc: qemu-devel
> On 3. Aug 2025, at 02:56, Richard Henderson <richard.henderson@linaro.org> wrote:
>
> On 8/2/25 18:17, Mohamed Mediouni wrote:
>> +struct whpx_sreg_match {
>> + WHV_REGISTER_NAME reg;
>> + uint32_t key;
>> + bool global;
>> + uint32_t cp_idx;
>> +};
>> +
>> +static struct whpx_sreg_match whpx_sreg_match[] = {
>
> const.
cp_idx is constructed at runtime (in whpx_init_vcpu) , so this is not constant.
>
>> +#ifdef SYNC_NO_RAW_REGS
>> + /*
>> + * The registers below are manually synced on init because they are
>> + * marked as NO_RAW. We still list them to make number space sync easier.
>> + */
>> + { WHvArm64RegisterMidrEl1, WHPX_SYSREG(0, 0, 3, 0, 0) },
>> + { WHvArm64RegisterMpidrEl1, WHPX_SYSREG(0, 0, 3, 0, 5) },
>> + { WHvArm64RegisterIdPfr0El1, WHPX_SYSREG(0, 4, 3, 0, 0) },
>> +#endif
>> + { WHvArm64RegisterIdAa64Pfr1El1, WHPX_SYSREG(0, 4, 3, 0, 1), true },
>> + { WHvArm64RegisterIdAa64Dfr0El1, WHPX_SYSREG(0, 5, 3, 0, 0), true },
>> + { WHvArm64RegisterIdAa64Dfr1El1, WHPX_SYSREG(0, 5, 3, 0, 1), true },
>> + { WHvArm64RegisterIdAa64Isar0El1, WHPX_SYSREG(0, 6, 3, 0, 0), true },
>> + { WHvArm64RegisterIdAa64Isar1El1, WHPX_SYSREG(0, 6, 3, 0, 1), true },
>> +#ifdef SYNC_NO_MMFR0
>> + /* We keep the hardware MMFR0 around. HW limits are there anyway */
>> + { WHvArm64RegisterIdAa64Mmfr0El1, WHPX_SYSREG(0, 7, 3, 0, 0) },
>> +#endif
>> + { WHvArm64RegisterIdAa64Mmfr1El1, WHPX_SYSREG(0, 7, 3, 0, 1), true },
>> + { WHvArm64RegisterIdAa64Mmfr2El1, WHPX_SYSREG(0, 7, 3, 0, 2), true },
>> + { WHvArm64RegisterIdAa64Mmfr3El1, WHPX_SYSREG(0, 7, 3, 0, 3), true },
>
> All of these are id registers. I can understand reading them once at startup, to populate -cpu host, but they need not be synced otherwise.
Will need to sync them once somewhere for targets other than -cpu host, but no need to do so for every vCPU (as they’re global values)
>> +static uint64_t whpx_get_gp_reg(CPUState *cpu, int rt)
>> +{
>> + if (rt >= 31) {
>> + return 0;
>> + }
>
> assert? Or return 0 for 31 and assert <= 32?
>
>> + WHV_REGISTER_NAME reg = WHvArm64RegisterX0 + rt;
>> + WHV_REGISTER_VALUE val;
>> + whpx_get_reg(cpu, reg, &val);
>> +
>> + return val.Reg64;
>> +}
>> +
>> +static void whpx_set_gp_reg(CPUState *cpu, int rt, uint64_t val)
>> +{
>> + if (rt >= 31) {
>> + abort();
>> + }
>
> assert. Or ignore write to 31 and assert <= 32?
>
>> + if (cm) {
>> + /* We don't cache MMIO regions */
>> + abort();
>> + return 0;
>> + }
>
> assert.
>
>
> r~
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 04/14] whpx: ifdef out some x86-only code paths
2025-08-03 1:03 ` Richard Henderson
@ 2025-08-03 1:08 ` Mohamed Mediouni
2025-08-03 1:14 ` Richard Henderson
0 siblings, 1 reply; 32+ messages in thread
From: Mohamed Mediouni @ 2025-08-03 1:08 UTC (permalink / raw)
To: Richard Henderson; +Cc: qemu-devel
> On 3. Aug 2025, at 03:03, Richard Henderson <richard.henderson@linaro.org> wrote:
>
> On 8/3/25 10:55, Mohamed Mediouni wrote:
>> Arm WHPX has no specific functionality for debugging today, but we could support kernel mode breakpoints via replacing them by an unhandled hvc #2, stubbing might be the right route to go...
>
> Surely the debug registers are usable? In the meantime, stub functions which do nothing are better than ifdefs wherever possible.
The debug exception goes to EL1 if we do so instead of the hypervisor because there aren't exit bitmaps/a debug trap API on arm64 WHP to make the HV vmexit in that case
> r~
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 04/14] whpx: ifdef out some x86-only code paths
2025-08-03 1:08 ` Mohamed Mediouni
@ 2025-08-03 1:14 ` Richard Henderson
0 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2025-08-03 1:14 UTC (permalink / raw)
To: Mohamed Mediouni; +Cc: qemu-devel
On 8/3/25 11:08, Mohamed Mediouni wrote:
>
>
>> On 3. Aug 2025, at 03:03, Richard Henderson <richard.henderson@linaro.org> wrote:
>>
>> On 8/3/25 10:55, Mohamed Mediouni wrote:
>>> Arm WHPX has no specific functionality for debugging today, but we could support kernel mode breakpoints via replacing them by an unhandled hvc #2, stubbing might be the right route to go...
>>
>> Surely the debug registers are usable? In the meantime, stub functions which do nothing are better than ifdefs wherever possible.
> The debug exception goes to EL1 if we do so instead of the hypervisor because there aren't exit bitmaps/a debug trap API on arm64 WHP to make the HV vmexit in that case
Huh. I thought I remembered some el2 debugging. Oh well.
Leaving it support as stub functions is good enough for now.
r~
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 12/14] whpx: arm64: implement -cpu host
2025-08-02 8:17 ` [PATCH v3 12/14] whpx: arm64: implement -cpu host Mohamed Mediouni
@ 2025-08-03 1:22 ` Richard Henderson
0 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2025-08-03 1:22 UTC (permalink / raw)
To: Mohamed Mediouni, qemu-devel
On 8/2/25 18:17, Mohamed Mediouni wrote:
> @@ -522,7 +524,7 @@ void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp)
> isar2 = FIELD_DP64(isar2, ID_AA64ISAR2, APA3, 0);
> isar2 = FIELD_DP64(isar2, ID_AA64ISAR2, GPA3, 0);
>
> - if (kvm_enabled() || hvf_enabled()) {
> + if (kvm_enabled() || hvf_enabled() || whpx_enabled()) {
Just a heads up, Phil has a patch which adds hwaccel_enabled().
https://lore.kernel.org/qemu-devel/20250703105540.67664-47-philmd@linaro.org/
and I believe cleans up both here...
> /*
> * Exit early if PAuth is enabled and fall through to disable it.
> * The algorithm selection properties are not present.
> @@ -599,7 +601,7 @@ void aarch64_add_pauth_properties(Object *obj)
>
> /* Default to PAUTH on, with the architected algorithm on TCG. */
> qdev_property_add_static(DEVICE(obj), &arm_cpu_pauth_property);
> - if (kvm_enabled() || hvf_enabled()) {
> + if (kvm_enabled() || hvf_enabled() || whpx_enabled()) {
here...
> @@ -780,7 +786,7 @@ static void aarch64_host_initfn(Object *obj)
>
> static void aarch64_max_initfn(Object *obj)
> {
> - if (kvm_enabled() || hvf_enabled()) {
> + if (kvm_enabled() || hvf_enabled() || whpx_enabled()) {
> /* With KVM or HVF, '-cpu max' is identical to '-cpu host' */
and here.
> +static HKEY OpenProcessorKey(void)
> +{
> + HKEY Out;
> + const char *path = "Hardware\\Description\\System\\CentralProcessor\\0\\";
> + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, path, 0, KEY_READ, &Out)) {
> + return NULL;
> + }
> + return Out;
> +}
> +
> +static uint64_t ReadRegU64(HKEY Key, const char *name)
> +{
> + uint64_t Value = 0;
> + DWORD Size = sizeof(Value);
> + LONG res = RegGetValueA(Key, NULL, name, RRF_RT_REG_QWORD, NULL, &Value, &Size);
> + if (res != ERROR_SUCCESS) {
> + printf("Failed to get register value: error: 0x%x\n", res);
> + }
> + return Value;
> +}
4 space indentation.
assert, not printf. :-)
> +
> +static bool whpx_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
> +{
> + ARMISARegisters host_isar = {};
> + const struct isar_regs {
> + WHV_REGISTER_NAME reg;
> + uint64_t *val;
> + } regs[] = {
> + { WHvArm64RegisterIdAa64Pfr0El1, &host_isar.idregs[ID_AA64PFR0_EL1_IDX] },
> + { WHvArm64RegisterIdAa64Pfr1El1, &host_isar.idregs[ID_AA64PFR1_EL1_IDX] },
> + { WHvArm64RegisterIdAa64Dfr0El1, &host_isar.idregs[ID_AA64DFR0_EL1_IDX] },
> + { WHvArm64RegisterIdAa64Dfr1El1 , &host_isar.idregs[ID_AA64DFR1_EL1_IDX] },
> + { WHvArm64RegisterIdAa64Isar0El1, &host_isar.idregs[ID_AA64ISAR0_EL1_IDX] },
> + { WHvArm64RegisterIdAa64Isar1El1, &host_isar.idregs[ID_AA64ISAR1_EL1_IDX] },
> + { WHvArm64RegisterIdAa64Isar2El1, &host_isar.idregs[ID_AA64ISAR2_EL1_IDX] },
> + { WHvArm64RegisterIdAa64Mmfr0El1, &host_isar.idregs[ID_AA64MMFR0_EL1_IDX] },
> + { WHvArm64RegisterIdAa64Mmfr1El1, &host_isar.idregs[ID_AA64MMFR1_EL1_IDX] },
> + { WHvArm64RegisterIdAa64Mmfr2El1, &host_isar.idregs[ID_AA64MMFR2_EL1_IDX] },
> + { WHvArm64RegisterIdAa64Mmfr3El1, &host_isar.idregs[ID_AA64MMFR2_EL1_IDX] }
> + };
I'm sure this arrangement was easiest before the id regs reorg, but now we can store the
ID_* not the pointer in the table, and the table can be static const.
Why do we need the host_isar local variable?
We could be writing to ahcf->isar to begin.
> + /*
> + * Disable SME, which is not properly handled by QEMU hvf yet.
hvf. :-)
> + /*
> + * A scratch vCPU returns SCTLR 0, so let's fill our default with the M1
> + * boot SCTLR from https://github.com/AsahiLinux/m1n1/issues/97
> + */
> + ahcf->reset_sctlr = 0x30100180;
> + /*
> + * SPAN is disabled by default when SCTLR.SPAN=1. To improve compatibility,
> + * let's disable it on boot and then allow guest software to turn it on by
> + * setting it to 0.
> + */
> + ahcf->reset_sctlr |= 0x00800000;
Is this really required, or just copied from hvf?
r~
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 14/14] MAINTAINERS: Add myself as a maintainer for WHPX
2025-08-02 8:18 ` [PATCH v3 14/14] MAINTAINERS: Add myself as a maintainer for WHPX Mohamed Mediouni
@ 2025-08-03 1:23 ` Richard Henderson
0 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2025-08-03 1:23 UTC (permalink / raw)
To: Mohamed Mediouni, qemu-devel
On 8/2/25 18:18, Mohamed Mediouni wrote:
> And add arm64 files.
>
> Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 32+ messages in thread
end of thread, other threads:[~2025-08-03 1:23 UTC | newest]
Thread overview: 32+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-02 8:17 [PATCH v3 00/14] WHPX support for Arm Mohamed Mediouni
2025-08-02 8:17 ` [PATCH v3 01/14] hw/arm: virt: add GICv2m for the case when ITS is not available Mohamed Mediouni
2025-08-02 8:17 ` [PATCH v3 02/14] whpx: Move around files before introducing AArch64 support Mohamed Mediouni
2025-08-02 8:53 ` Mohamed Mediouni
2025-08-03 0:03 ` Richard Henderson
2025-08-02 8:17 ` [PATCH v3 03/14] whpx: reshuffle common code Mohamed Mediouni
2025-08-03 0:15 ` Richard Henderson
2025-08-02 8:17 ` [PATCH v3 04/14] whpx: ifdef out some x86-only code paths Mohamed Mediouni
2025-08-03 0:41 ` Richard Henderson
2025-08-03 0:55 ` Mohamed Mediouni
2025-08-03 1:03 ` Richard Henderson
2025-08-03 1:08 ` Mohamed Mediouni
2025-08-03 1:14 ` Richard Henderson
2025-08-03 0:51 ` Richard Henderson
2025-08-02 8:17 ` [PATCH v3 05/14] hw, target, accel: whpx: change apic_in_platform to kernel_irqchip Mohamed Mediouni
2025-08-03 0:42 ` Richard Henderson
2025-08-02 8:17 ` [PATCH v3 06/14] whpx: interrupt controller support Mohamed Mediouni
2025-08-02 8:17 ` [PATCH v3 07/14] whpx: add arm64 support Mohamed Mediouni
2025-08-03 0:56 ` Richard Henderson
2025-08-03 1:03 ` Mohamed Mediouni
2025-08-02 8:17 ` [PATCH v3 08/14] whpx: copy over memory management logic from hvf Mohamed Mediouni
2025-08-02 8:17 ` [PATCH v3 09/14] target/arm: cpu: mark WHPX as supporting PSCI 1.1 Mohamed Mediouni
2025-08-03 0:56 ` Richard Henderson
2025-08-02 8:17 ` [PATCH v3 10/14] hw/arm: virt: cleanly fail on attempt to use the platform vGIC together with ITS Mohamed Mediouni
2025-08-03 0:57 ` Richard Henderson
2025-08-02 8:17 ` [PATCH v3 11/14] whpx: arm64: clamp down IPA size Mohamed Mediouni
2025-08-03 1:00 ` Richard Henderson
2025-08-02 8:17 ` [PATCH v3 12/14] whpx: arm64: implement -cpu host Mohamed Mediouni
2025-08-03 1:22 ` Richard Henderson
2025-08-02 8:17 ` [PATCH v3 13/14] target/arm: whpx: instantiate GIC early Mohamed Mediouni
2025-08-02 8:18 ` [PATCH v3 14/14] MAINTAINERS: Add myself as a maintainer for WHPX Mohamed Mediouni
2025-08-03 1:23 ` Richard Henderson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).