* [PATCH v10 01/28] target/arm/kvm: add constants for new PSCI versions
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
@ 2025-10-29 16:54 ` Mohamed Mediouni
2025-10-29 16:54 ` [PATCH v10 02/28] accel/system: Introduce hwaccel_enabled() helper Mohamed Mediouni
` (27 subsequent siblings)
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:54 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé, Sebastian Ott, Pierrick Bouvier
From: Sebastian Ott <sebott@redhat.com>
Add constants for PSCI version 1_2 and 1_3.
Signed-off-by: Sebastian Ott <sebott@redhat.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
---
target/arm/kvm-consts.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/target/arm/kvm-consts.h b/target/arm/kvm-consts.h
index 54ae5da7ce..9fba3e886d 100644
--- a/target/arm/kvm-consts.h
+++ b/target/arm/kvm-consts.h
@@ -97,6 +97,8 @@ MISMATCH_CHECK(QEMU_PSCI_1_0_FN_PSCI_FEATURES, PSCI_1_0_FN_PSCI_FEATURES);
#define QEMU_PSCI_VERSION_0_2 0x00002
#define QEMU_PSCI_VERSION_1_0 0x10000
#define QEMU_PSCI_VERSION_1_1 0x10001
+#define QEMU_PSCI_VERSION_1_2 0x10002
+#define QEMU_PSCI_VERSION_1_3 0x10003
MISMATCH_CHECK(QEMU_PSCI_0_2_RET_TOS_MIGRATION_NOT_REQUIRED, PSCI_0_2_TOS_MP);
/* We don't bother to check every possible version value */
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v10 02/28] accel/system: Introduce hwaccel_enabled() helper
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
2025-10-29 16:54 ` [PATCH v10 01/28] target/arm/kvm: add constants for new PSCI versions Mohamed Mediouni
@ 2025-10-29 16:54 ` Mohamed Mediouni
2025-10-29 16:54 ` [PATCH v10 03/28] qtest: hw/arm: virt: skip ACPI test for ITS off Mohamed Mediouni
` (26 subsequent siblings)
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:54 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé
From: Philippe Mathieu-Daudé <philmd@linaro.org>
hwaccel_enabled() return whether any hardware accelerator
is enabled.
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
include/system/hw_accel.h | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/include/system/hw_accel.h b/include/system/hw_accel.h
index 55497edc29..628a50e066 100644
--- a/include/system/hw_accel.h
+++ b/include/system/hw_accel.h
@@ -40,4 +40,17 @@ void cpu_synchronize_pre_loadvm(CPUState *cpu);
void cpu_synchronize_post_reset(CPUState *cpu);
void cpu_synchronize_post_init(CPUState *cpu);
+/**
+ * hwaccel_enabled:
+ *
+ * Returns: %true if a hardware accelerator is enabled, %false otherwise.
+ */
+static inline bool hwaccel_enabled(void)
+{
+ return hvf_enabled()
+ || kvm_enabled()
+ || nvmm_enabled()
+ || whpx_enabled();
+}
+
#endif /* QEMU_HW_ACCEL_H */
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v10 03/28] qtest: hw/arm: virt: skip ACPI test for ITS off
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
2025-10-29 16:54 ` [PATCH v10 01/28] target/arm/kvm: add constants for new PSCI versions Mohamed Mediouni
2025-10-29 16:54 ` [PATCH v10 02/28] accel/system: Introduce hwaccel_enabled() helper Mohamed Mediouni
@ 2025-10-29 16:54 ` Mohamed Mediouni
2025-10-29 16:54 ` [PATCH v10 04/28] hw/arm: virt: add GICv2m for the case when ITS is not available Mohamed Mediouni
` (25 subsequent siblings)
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:54 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé, Pierrick Bouvier
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
---
tests/qtest/bios-tables-test-allowed-diff.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h
index dfb8523c8b..bfc4d60124 100644
--- a/tests/qtest/bios-tables-test-allowed-diff.h
+++ b/tests/qtest/bios-tables-test-allowed-diff.h
@@ -1 +1,2 @@
/* List of comma-separated changed AML files to ignore */
+"tests/data/acpi/aarch64/virt/APIC.its_off",
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v10 04/28] hw/arm: virt: add GICv2m for the case when ITS is not available
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (2 preceding siblings ...)
2025-10-29 16:54 ` [PATCH v10 03/28] qtest: hw/arm: virt: skip ACPI test for ITS off Mohamed Mediouni
@ 2025-10-29 16:54 ` Mohamed Mediouni
2025-10-29 16:54 ` [PATCH v10 05/28] tests: data: update AArch64 ACPI tables Mohamed Mediouni
` (24 subsequent siblings)
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:54 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé, Pierrick Bouvier
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>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
---
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 8bb6b60515..0a6ec74aa0 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -959,7 +959,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->gic_version != VIRT_GIC_VERSION_2 && 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 175023897a..61d7bab803 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -956,6 +956,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);
}
@@ -2447,6 +2449,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);
@@ -3484,6 +3488,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;
@@ -3536,9 +3541,12 @@ DEFINE_VIRT_MACHINE_AS_LATEST(10, 2)
static void virt_machine_10_1_options(MachineClass *mc)
{
+ VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
+
virt_machine_10_2_options(mc);
mc->smbios_memory_device_size = 2047 * TiB;
compat_props_add(mc->compat_props, hw_compat_10_1, hw_compat_10_1_len);
+ vmc->no_gicv3_with_gicv2m = true;
}
DEFINE_VIRT_MACHINE(10, 1)
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 04a09af354..d31348dd61 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -132,6 +132,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;
};
@@ -180,6 +181,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;
bool legacy_smmuv3_present;
};
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v10 05/28] tests: data: update AArch64 ACPI tables
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (3 preceding siblings ...)
2025-10-29 16:54 ` [PATCH v10 04/28] hw/arm: virt: add GICv2m for the case when ITS is not available Mohamed Mediouni
@ 2025-10-29 16:54 ` Mohamed Mediouni
2025-10-29 16:54 ` [PATCH v10 06/28] whpx: Move around files before introducing AArch64 support Mohamed Mediouni
` (23 subsequent siblings)
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:54 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé
After the previous commit introducing GICv3 + GICv2m configurations,
update the AArch64 ACPI table for the its=off case.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
tests/data/acpi/aarch64/virt/APIC.its_off | Bin 164 -> 188 bytes
tests/qtest/bios-tables-test-allowed-diff.h | 1 -
2 files changed, 1 deletion(-)
diff --git a/tests/data/acpi/aarch64/virt/APIC.its_off b/tests/data/acpi/aarch64/virt/APIC.its_off
index 6130cb7d07103b326feb4dcd7034f85808bebadf..16a01a17c0af605daf64f3cd2de3572be9e60cab 100644
GIT binary patch
delta 43
qcmZ3&xQCI;F~HM#4+8@Oi@`*$SrWVwKqeS4aeydBAa-B~U;qHCpaq8j
delta 18
ZcmdnPxP+0*F~HM#2?GNI3&%vRSpY3v1aANU
diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h
index bfc4d60124..dfb8523c8b 100644
--- a/tests/qtest/bios-tables-test-allowed-diff.h
+++ b/tests/qtest/bios-tables-test-allowed-diff.h
@@ -1,2 +1 @@
/* List of comma-separated changed AML files to ignore */
-"tests/data/acpi/aarch64/virt/APIC.its_off",
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v10 06/28] whpx: Move around files before introducing AArch64 support
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (4 preceding siblings ...)
2025-10-29 16:54 ` [PATCH v10 05/28] tests: data: update AArch64 ACPI tables Mohamed Mediouni
@ 2025-10-29 16:54 ` Mohamed Mediouni
2025-10-29 16:54 ` [PATCH v10 07/28] whpx: reshuffle common code Mohamed Mediouni
` (22 subsequent siblings)
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:54 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé, Pierrick Bouvier
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>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@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 | 4 ++--
{target/i386/whpx => include/system}/whpx-internal.h | 5 +++--
target/i386/whpx/meson.build | 1 -
target/i386/whpx/whpx-all.c | 4 ++--
target/i386/whpx/whpx-apic.c | 2 +-
9 files changed, 19 insertions(+), 10 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 (92%)
rename {target/i386/whpx => include/system}/whpx-internal.h (98%)
diff --git a/MAINTAINERS b/MAINTAINERS
index 64491c800c..4ea4c48a2a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -549,9 +549,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
MSHV
M: Magnus Kulke <magnus.kulke@linux.microsoft.com>
diff --git a/accel/meson.build b/accel/meson.build
index 983dfd0bd5..289b7420ff 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 f75886128d..c84a25c273 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 92%
rename from target/i386/whpx/whpx-accel-ops.h
rename to include/system/whpx-accel-ops.h
index 54cfc25a14..ed9d4c49f4 100644
--- a/target/i386/whpx/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/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 2dcad1f565..c59f9de091 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>
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 6bf8d5f4bb..c0bd429d19 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-apic.c b/target/i386/whpx/whpx-apic.c
index afcb25843b..b934fdcbe1 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.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v10 07/28] whpx: reshuffle common code
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (5 preceding siblings ...)
2025-10-29 16:54 ` [PATCH v10 06/28] whpx: Move around files before introducing AArch64 support Mohamed Mediouni
@ 2025-10-29 16:54 ` Mohamed Mediouni
2025-10-29 16:54 ` [PATCH v10 08/28] whpx: ifdef out winhvemulation on non-x86_64 Mohamed Mediouni
` (21 subsequent siblings)
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:54 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé, Pierrick Bouvier
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>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
---
MAINTAINERS | 2 +
accel/whpx/meson.build | 1 +
accel/whpx/whpx-common.c | 562 +++++++++++++++++++++++++++++++++++
include/system/whpx-all.h | 20 ++
include/system/whpx-common.h | 21 ++
target/i386/whpx/whpx-all.c | 551 +---------------------------------
6 files changed, 616 insertions(+), 541 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
diff --git a/MAINTAINERS b/MAINTAINERS
index 4ea4c48a2a..c6b7f45459 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -554,6 +554,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
MSHV
M: Magnus Kulke <magnus.kulke@linux.microsoft.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..66c9238586
--- /dev/null
+++ b/accel/whpx/whpx-common.c
@@ -0,0 +1,562 @@
+/* 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)
+{
+ whpx_apply_breakpoints(whpx_global.breakpoints.breakpoints, cpu, false);
+ 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-all.h b/include/system/whpx-all.h
new file mode 100644
index 0000000000..f13cdf7f66
--- /dev/null
+++ b/include/system/whpx-all.h
@@ -0,0 +1,20 @@
+/* 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);
+void whpx_apply_breakpoints(
+struct whpx_breakpoint_collection *breakpoints,
+ CPUState *cpu,
+ bool resuming);
+void whpx_translate_cpu_breakpoints(
+ struct whpx_breakpoints *breakpoints,
+ CPUState *cpu,
+ int cpu_breakpoint_count);
+#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-all.c b/target/i386/whpx/whpx-all.c
index c0bd429d19..c63bb28b20 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>
@@ -232,28 +234,9 @@ typedef enum WhpxStepMode {
WHPX_STEP_EXCLUSIVE,
} WhpxStepMode;
-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;
-};
-
-bool whpx_allowed;
-static bool whp_dispatch_initialized;
-static HMODULE hWinHvPlatform, hWinHvEmulation;
static uint32_t max_vcpu_index;
static WHV_PROCESSOR_XSAVE_FEATURES whpx_xsave_cap;
-struct whpx_state whpx_global;
-struct WHPDispatch whp_dispatch;
-
static bool whpx_has_xsave(void)
{
return whpx_xsave_cap.XsaveSupport;
@@ -379,7 +362,7 @@ static uint64_t whpx_cr8_to_apic_tpr(uint64_t cr8)
return cr8 << 4;
}
-static void whpx_set_registers(CPUState *cpu, int level)
+void whpx_set_registers(CPUState *cpu, int level)
{
struct whpx_state *whpx = &whpx_global;
AccelCPUState *vcpu = cpu->accel;
@@ -594,7 +577,7 @@ static void whpx_get_xcrs(CPUState *cpu)
cpu_env(cpu)->xcr0 = xcr0.Reg64;
}
-static void whpx_get_registers(CPUState *cpu)
+void whpx_get_registers(CPUState *cpu)
{
struct whpx_state *whpx = &whpx_global;
AccelCPUState *vcpu = cpu->accel;
@@ -934,7 +917,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, };
@@ -1084,23 +1067,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
@@ -1136,7 +1102,7 @@ static const uint8_t whpx_breakpoint_instruction = 0xF1;
* memory, but doesn't actually do it. The memory accessing is done in
* whpx_apply_breakpoints().
*/
-static void whpx_translate_cpu_breakpoints(
+void whpx_translate_cpu_breakpoints(
struct whpx_breakpoints *breakpoints,
CPUState *cpu,
int cpu_breakpoint_count)
@@ -1230,7 +1196,7 @@ static void whpx_translate_cpu_breakpoints(
* Passing resuming=true will try to set all previously unset breakpoints.
* Passing resuming=false will remove all inserted ones.
*/
-static void whpx_apply_breakpoints(
+void whpx_apply_breakpoints(
struct whpx_breakpoint_collection *breakpoints,
CPUState *cpu,
bool resuming)
@@ -1306,93 +1272,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)
{
@@ -1634,7 +1513,7 @@ static void whpx_vcpu_process_async_events(CPUState *cpu)
}
}
-static int whpx_vcpu_run(CPUState *cpu)
+int whpx_vcpu_run(CPUState *cpu)
{
HRESULT hr;
struct whpx_state *whpx = &whpx_global;
@@ -2057,65 +1936,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.
*/
@@ -2244,295 +2064,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;
@@ -2715,77 +2258,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);
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v10 08/28] whpx: ifdef out winhvemulation on non-x86_64
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (6 preceding siblings ...)
2025-10-29 16:54 ` [PATCH v10 07/28] whpx: reshuffle common code Mohamed Mediouni
@ 2025-10-29 16:54 ` Mohamed Mediouni
2025-10-29 16:54 ` [PATCH v10 09/28] whpx: common: add WHPX_INTERCEPT_DEBUG_TRAPS define Mohamed Mediouni
` (20 subsequent siblings)
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:54 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé, Pierrick Bouvier
winhvemulation is x86_64 only.
In the future, we might want to get rid of winhvemulation usage
entirely.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
---
accel/whpx/whpx-common.c | 14 ++++++++++++--
include/system/whpx-common.h | 2 ++
include/system/whpx-internal.h | 7 ++++++-
3 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/accel/whpx/whpx-common.c b/accel/whpx/whpx-common.c
index 66c9238586..95664a1df7 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;
@@ -236,8 +238,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);
}
@@ -412,8 +416,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
+ g_assert_not_reached();
+#endif
break;
case WINHV_PLATFORM_FNS_SUPPLEMENTAL:
WHP_LOAD_LIB(WINHV_PLATFORM_DLL, hLib)
@@ -539,11 +547,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;
@@ -553,9 +561,11 @@ error:
if (hWinHvPlatform) {
FreeLibrary(hWinHvPlatform);
}
+#ifdef __x86_64__
if (hWinHvEmulation) {
FreeLibrary(hWinHvEmulation);
}
+#endif
return false;
}
diff --git a/include/system/whpx-common.h b/include/system/whpx-common.h
index e549c7539c..7a7c607e0a 100644
--- a/include/system/whpx-common.h
+++ b/include/system/whpx-common.h
@@ -3,7 +3,9 @@
#define SYSTEM_WHPX_COMMON_H
struct AccelCPUState {
+#ifdef __x86_64__
WHV_EMULATOR_HANDLE emulator;
+#endif
bool window_registered;
bool interruptable;
bool ready_for_pic_interrupt;
diff --git a/include/system/whpx-internal.h b/include/system/whpx-internal.h
index c59f9de091..4565436682 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
#include "hw/i386/apic.h"
typedef enum WhpxBreakpointState {
@@ -100,12 +101,16 @@ void whpx_apic_get(APICCommonState *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.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v10 09/28] whpx: common: add WHPX_INTERCEPT_DEBUG_TRAPS define
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (7 preceding siblings ...)
2025-10-29 16:54 ` [PATCH v10 08/28] whpx: ifdef out winhvemulation on non-x86_64 Mohamed Mediouni
@ 2025-10-29 16:54 ` Mohamed Mediouni
2025-10-29 16:54 ` [PATCH v10 10/28] hw, target, accel: whpx: change apic_in_platform to kernel_irqchip Mohamed Mediouni
` (19 subsequent siblings)
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:54 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé, Pierrick Bouvier
As of why: WHPX on arm64 doesn't have debug trap support as of today.
Keep the exception bitmap interface for now - despite that being entirely unavailable on arm64 too.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
---
accel/whpx/whpx-common.c | 2 +-
include/system/whpx-common.h | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/accel/whpx/whpx-common.c b/accel/whpx/whpx-common.c
index 95664a1df7..c0ff6cacb8 100644
--- a/accel/whpx/whpx-common.c
+++ b/accel/whpx/whpx-common.c
@@ -123,7 +123,7 @@ int whpx_first_vcpu_starting(CPUState *cpu)
* have one or more breakpoints enabled. Both require intercepting
* the WHvX64ExceptionTypeBreakpointTrap exception.
*/
- exception_mask = 1UL << WHvX64ExceptionTypeDebugTrapOrFault;
+ exception_mask = 1UL << WHPX_INTERCEPT_DEBUG_TRAPS;
} else {
/* Let the guest handle all exceptions. */
exception_mask = 0;
diff --git a/include/system/whpx-common.h b/include/system/whpx-common.h
index 7a7c607e0a..73b9f7c119 100644
--- a/include/system/whpx-common.h
+++ b/include/system/whpx-common.h
@@ -20,4 +20,7 @@ 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);
+
+/* On x64: same as WHvX64ExceptionTypeDebugTrapOrFault */
+#define WHPX_INTERCEPT_DEBUG_TRAPS 1
#endif
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v10 10/28] hw, target, accel: whpx: change apic_in_platform to kernel_irqchip
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (8 preceding siblings ...)
2025-10-29 16:54 ` [PATCH v10 09/28] whpx: common: add WHPX_INTERCEPT_DEBUG_TRAPS define Mohamed Mediouni
@ 2025-10-29 16:54 ` Mohamed Mediouni
2025-10-29 16:54 ` [PATCH v10 11/28] whpx: interrupt controller support Mohamed Mediouni
` (18 subsequent siblings)
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:54 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé, Pierrick Bouvier
Change terminology to match the KVM one, as APIC is x86-specific.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
---
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 c84a25c273..50fadea0fd 100644
--- a/accel/whpx/whpx-accel-ops.c
+++ b/accel/whpx/whpx-accel-ops.c
@@ -78,7 +78,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 c0ff6cacb8..18d93225c1 100644
--- a/accel/whpx/whpx-common.c
+++ b/accel/whpx/whpx-common.c
@@ -496,9 +496,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 1a86a853d5..aee7fc76f5 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 4565436682..81c0c1819f 100644
--- a/include/system/whpx-internal.h
+++ b/include/system/whpx-internal.h
@@ -44,7 +44,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 564c1288e4..c0492035b8 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 c63bb28b20..d778e358f6 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -607,7 +607,7 @@ 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
@@ -749,7 +749,7 @@ 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);
}
@@ -1379,7 +1379,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);
@@ -1553,7 +1553,7 @@ 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;
@@ -1642,7 +1642,7 @@ 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;
@@ -2187,7 +2187,7 @@ int whpx_accel_init(AccelState *as, MachineState *ms)
goto error;
}
} else {
- whpx->apic_in_platform = true;
+ whpx->kernel_irqchip = true;
}
}
@@ -2196,7 +2196,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.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v10 11/28] whpx: interrupt controller support
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (9 preceding siblings ...)
2025-10-29 16:54 ` [PATCH v10 10/28] hw, target, accel: whpx: change apic_in_platform to kernel_irqchip Mohamed Mediouni
@ 2025-10-29 16:54 ` Mohamed Mediouni
2025-10-29 16:54 ` [PATCH v10 12/28] whpx: add arm64 support Mohamed Mediouni
` (17 subsequent siblings)
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:54 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé, Pierrick Bouvier
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
---
hw/arm/virt.c | 3 +
hw/intc/arm_gicv3_common.c | 3 +
hw/intc/arm_gicv3_whpx.c | 239 +++++++++++++++++++++++++++++
hw/intc/meson.build | 1 +
include/hw/intc/arm_gicv3_common.h | 3 +
5 files changed, 249 insertions(+)
create mode 100644 hw/intc/arm_gicv3_whpx.c
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 61d7bab803..9121eb37eb 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -47,6 +47,7 @@
#include "system/tcg.h"
#include "system/kvm.h"
#include "system/hvf.h"
+#include "system/whpx.h"
#include "system/qtest.h"
#include "system/system.h"
#include "hw/loader.h"
@@ -2105,6 +2106,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 2d0df6da86..1fd1e329e8 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)
@@ -663,6 +664,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..88a05e5901
--- /dev/null
+++ b/hw/intc/arm_gicv3_whpx.c
@@ -0,0 +1,239 @@
+/* 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);
+
+/* TODO: Implement GIC state save-restore */
+static void whpx_gicv3_check(GICv3State *s)
+{
+}
+
+static void whpx_gicv3_put(GICv3State *s)
+{
+ whpx_gicv3_check(s);
+}
+
+static void whpx_gicv3_get(GICv3State *s)
+{
+}
+
+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 faae20b93d..96742df090 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'))
arm_common_ss.add(when: 'CONFIG_ARM_GIC', if_true: files('arm_gicv3_cpuif_common.c'))
arm_common_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', 'TARGET_AARCH64'], 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'))
arm_common_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 61d51915e0..9fd8b9b858 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -313,6 +313,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.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v10 12/28] whpx: add arm64 support
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (10 preceding siblings ...)
2025-10-29 16:54 ` [PATCH v10 11/28] whpx: interrupt controller support Mohamed Mediouni
@ 2025-10-29 16:54 ` Mohamed Mediouni
2025-10-29 16:54 ` [PATCH v10 13/28] whpx: change memory management logic Mohamed Mediouni
` (16 subsequent siblings)
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:54 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé, Pierrick Bouvier
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
---
accel/whpx/whpx-common.c | 1 +
target/arm/meson.build | 1 +
target/arm/whpx/meson.build | 3 +
target/arm/whpx/whpx-all.c | 845 ++++++++++++++++++++++++++++++++++++
4 files changed, 850 insertions(+)
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 18d93225c1..c69792e638 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/target/arm/meson.build b/target/arm/meson.build
index 3df7e03654..61277a627c 100644
--- a/target/arm/meson.build
+++ b/target/arm/meson.build
@@ -59,6 +59,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..8c34650765
--- /dev/null
+++ b/target/arm/whpx/whpx-all.c
@@ -0,0 +1,845 @@
+/* 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 "target/arm/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]) },
+};
+
+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[] = {
+ { WHvArm64RegisterDbgbvr0El1, ENCODE_AA64_CP_REG(0, 0, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr0El1, ENCODE_AA64_CP_REG(0, 0, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr0El1, ENCODE_AA64_CP_REG(0, 0, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr0El1, ENCODE_AA64_CP_REG(0, 0, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr0El1, ENCODE_AA64_CP_REG(0, 1, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr0El1, ENCODE_AA64_CP_REG(0, 1, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr0El1, ENCODE_AA64_CP_REG(0, 1, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr0El1, ENCODE_AA64_CP_REG(0, 1, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr2El1, ENCODE_AA64_CP_REG(0, 2, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr2El1, ENCODE_AA64_CP_REG(0, 2, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr2El1, ENCODE_AA64_CP_REG(0, 2, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr2El1, ENCODE_AA64_CP_REG(0, 2, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr3El1, ENCODE_AA64_CP_REG(0, 3, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr3El1, ENCODE_AA64_CP_REG(0, 3, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr3El1, ENCODE_AA64_CP_REG(0, 3, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr3El1, ENCODE_AA64_CP_REG(0, 3, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr4El1, ENCODE_AA64_CP_REG(0, 4, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr4El1, ENCODE_AA64_CP_REG(0, 4, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr4El1, ENCODE_AA64_CP_REG(0, 4, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr4El1, ENCODE_AA64_CP_REG(0, 4, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr5El1, ENCODE_AA64_CP_REG(0, 5, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr5El1, ENCODE_AA64_CP_REG(0, 5, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr5El1, ENCODE_AA64_CP_REG(0, 5, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr5El1, ENCODE_AA64_CP_REG(0, 5, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr6El1, ENCODE_AA64_CP_REG(0, 6, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr6El1, ENCODE_AA64_CP_REG(0, 6, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr6El1, ENCODE_AA64_CP_REG(0, 6, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr6El1, ENCODE_AA64_CP_REG(0, 6, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr7El1, ENCODE_AA64_CP_REG(0, 7, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr7El1, ENCODE_AA64_CP_REG(0, 7, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr7El1, ENCODE_AA64_CP_REG(0, 7, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr7El1, ENCODE_AA64_CP_REG(0, 7, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr8El1, ENCODE_AA64_CP_REG(0, 8, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr8El1, ENCODE_AA64_CP_REG(0, 8, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr8El1, ENCODE_AA64_CP_REG(0, 8, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr8El1, ENCODE_AA64_CP_REG(0, 8, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr9El1, ENCODE_AA64_CP_REG(0, 9, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr9El1, ENCODE_AA64_CP_REG(0, 9, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr9El1, ENCODE_AA64_CP_REG(0, 9, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr9El1, ENCODE_AA64_CP_REG(0, 9, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr10El1, ENCODE_AA64_CP_REG(0, 10, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr10El1, ENCODE_AA64_CP_REG(0, 10, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr10El1, ENCODE_AA64_CP_REG(0, 10, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr10El1, ENCODE_AA64_CP_REG(0, 10, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr11El1, ENCODE_AA64_CP_REG(0, 11, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr11El1, ENCODE_AA64_CP_REG(0, 11, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr11El1, ENCODE_AA64_CP_REG(0, 11, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr11El1, ENCODE_AA64_CP_REG(0, 11, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr12El1, ENCODE_AA64_CP_REG(0, 12, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr12El1, ENCODE_AA64_CP_REG(0, 12, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr12El1, ENCODE_AA64_CP_REG(0, 12, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr12El1, ENCODE_AA64_CP_REG(0, 12, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr13El1, ENCODE_AA64_CP_REG(0, 13, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr13El1, ENCODE_AA64_CP_REG(0, 13, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr13El1, ENCODE_AA64_CP_REG(0, 13, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr13El1, ENCODE_AA64_CP_REG(0, 13, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr14El1, ENCODE_AA64_CP_REG(0, 14, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr14El1, ENCODE_AA64_CP_REG(0, 14, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr14El1, ENCODE_AA64_CP_REG(0, 14, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr14El1, ENCODE_AA64_CP_REG(0, 14, 2, 0, 7) },
+
+ { WHvArm64RegisterDbgbvr15El1, ENCODE_AA64_CP_REG(0, 15, 2, 0, 4) },
+ { WHvArm64RegisterDbgbcr15El1, ENCODE_AA64_CP_REG(0, 15, 2, 0, 5) },
+ { WHvArm64RegisterDbgwvr15El1, ENCODE_AA64_CP_REG(0, 15, 2, 0, 6) },
+ { WHvArm64RegisterDbgwcr15El1, ENCODE_AA64_CP_REG(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, ENCODE_AA64_CP_REG(0, 0, 3, 0, 0) },
+ { WHvArm64RegisterMpidrEl1, ENCODE_AA64_CP_REG(0, 0, 3, 0, 5) },
+ { WHvArm64RegisterIdPfr0El1, ENCODE_AA64_CP_REG(0, 4, 3, 0, 0) },
+#endif
+ { WHvArm64RegisterIdAa64Pfr1El1, ENCODE_AA64_CP_REG(0, 4, 3, 0, 1), true },
+ { WHvArm64RegisterIdAa64Dfr0El1, ENCODE_AA64_CP_REG(0, 5, 3, 0, 0), true },
+ { WHvArm64RegisterIdAa64Dfr1El1, ENCODE_AA64_CP_REG(0, 5, 3, 0, 1), true },
+ { WHvArm64RegisterIdAa64Isar0El1, ENCODE_AA64_CP_REG(0, 6, 3, 0, 0), true },
+ { WHvArm64RegisterIdAa64Isar1El1, ENCODE_AA64_CP_REG(0, 6, 3, 0, 1), true },
+#ifdef SYNC_NO_MMFR0
+ /* We keep the hardware MMFR0 around. HW limits are there anyway */
+ { WHvArm64RegisterIdAa64Mmfr0El1, ENCODE_AA64_CP_REG(0, 7, 3, 0, 0) },
+#endif
+ { WHvArm64RegisterIdAa64Mmfr1El1, ENCODE_AA64_CP_REG(0, 7, 3, 0, 1), true },
+ { WHvArm64RegisterIdAa64Mmfr2El1, ENCODE_AA64_CP_REG(0, 7, 3, 0, 2), true },
+ { WHvArm64RegisterIdAa64Mmfr3El1, ENCODE_AA64_CP_REG(0, 7, 3, 0, 3), true },
+
+ { WHvArm64RegisterMdscrEl1, ENCODE_AA64_CP_REG(0, 2, 2, 0, 2) },
+ { WHvArm64RegisterSctlrEl1, ENCODE_AA64_CP_REG(1, 0, 3, 0, 0) },
+ { WHvArm64RegisterCpacrEl1, ENCODE_AA64_CP_REG(1, 0, 3, 0, 2) },
+ { WHvArm64RegisterTtbr0El1, ENCODE_AA64_CP_REG(2, 0, 3, 0, 0) },
+ { WHvArm64RegisterTtbr1El1, ENCODE_AA64_CP_REG(2, 0, 3, 0, 1) },
+ { WHvArm64RegisterTcrEl1, ENCODE_AA64_CP_REG(2, 0, 3, 0, 2) },
+
+ { WHvArm64RegisterApiAKeyLoEl1, ENCODE_AA64_CP_REG(2, 1, 3, 0, 0) },
+ { WHvArm64RegisterApiAKeyHiEl1, ENCODE_AA64_CP_REG(2, 1, 3, 0, 1) },
+ { WHvArm64RegisterApiBKeyLoEl1, ENCODE_AA64_CP_REG(2, 1, 3, 0, 2) },
+ { WHvArm64RegisterApiBKeyHiEl1, ENCODE_AA64_CP_REG(2, 1, 3, 0, 3) },
+ { WHvArm64RegisterApdAKeyLoEl1, ENCODE_AA64_CP_REG(2, 2, 3, 0, 0) },
+ { WHvArm64RegisterApdAKeyHiEl1, ENCODE_AA64_CP_REG(2, 2, 3, 0, 1) },
+ { WHvArm64RegisterApdBKeyLoEl1, ENCODE_AA64_CP_REG(2, 2, 3, 0, 2) },
+ { WHvArm64RegisterApdBKeyHiEl1, ENCODE_AA64_CP_REG(2, 2, 3, 0, 3) },
+ { WHvArm64RegisterApgAKeyLoEl1, ENCODE_AA64_CP_REG(2, 3, 3, 0, 0) },
+ { WHvArm64RegisterApgAKeyHiEl1, ENCODE_AA64_CP_REG(2, 3, 3, 0, 1) },
+
+ { WHvArm64RegisterSpsrEl1, ENCODE_AA64_CP_REG(4, 0, 3, 0, 0) },
+ { WHvArm64RegisterElrEl1, ENCODE_AA64_CP_REG(4, 0, 3, 0, 1) },
+ { WHvArm64RegisterSpEl1, ENCODE_AA64_CP_REG(4, 1, 3, 0, 0) },
+ { WHvArm64RegisterEsrEl1, ENCODE_AA64_CP_REG(5, 2, 3, 0, 0) },
+ { WHvArm64RegisterFarEl1, ENCODE_AA64_CP_REG(6, 0, 3, 0, 0) },
+ { WHvArm64RegisterParEl1, ENCODE_AA64_CP_REG(7, 4, 3, 0, 0) },
+ { WHvArm64RegisterMairEl1, ENCODE_AA64_CP_REG(10, 2, 3, 0, 0) },
+ { WHvArm64RegisterVbarEl1, ENCODE_AA64_CP_REG(12, 0, 3, 0, 0) },
+ { WHvArm64RegisterContextidrEl1, ENCODE_AA64_CP_REG(13, 0, 3, 0, 1) },
+ { WHvArm64RegisterTpidrEl1, ENCODE_AA64_CP_REG(13, 0, 3, 0, 4) },
+ { WHvArm64RegisterCntkctlEl1, ENCODE_AA64_CP_REG(14, 1, 3, 0, 0) },
+ { WHvArm64RegisterCsselrEl1, ENCODE_AA64_CP_REG(0, 0, 3, 2, 0) },
+ { WHvArm64RegisterTpidrEl0, ENCODE_AA64_CP_REG(13, 0, 3, 3, 2) },
+ { WHvArm64RegisterTpidrroEl0, ENCODE_AA64_CP_REG(13, 0, 3, 3, 3) },
+ { WHvArm64RegisterCntvCtlEl0, ENCODE_AA64_CP_REG(14, 3, 3, 3, 1) },
+ { WHvArm64RegisterCntvCvalEl0, ENCODE_AA64_CP_REG(14, 3, 3, 3, 2) },
+ { WHvArm64RegisterSpEl1, ENCODE_AA64_CP_REG(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;
+ }
+}
+
+HRESULT whpx_set_exception_exit_bitmap(UINT64 exceptions)
+{
+ if (exceptions != 0) {
+ return E_NOTIMPL;
+ }
+ return ERROR_SUCCESS;
+}
+void whpx_apply_breakpoints(
+struct whpx_breakpoint_collection *breakpoints,
+ CPUState *cpu,
+ bool resuming)
+{
+
+}
+void whpx_translate_cpu_breakpoints(
+ struct whpx_breakpoints *breakpoints,
+ CPUState *cpu,
+ int cpu_breakpoint_count)
+{
+
+}
+
+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)
+{
+ assert(rt <= 31);
+ 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)
+{
+ assert(rt < 31);
+ 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;
+
+ assert(!cm);
+ 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:
+ switch (vcpu->exit_ctx.Arm64Reset.ResetType) {
+ case WHvArm64ResetTypePowerOff:
+ qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
+ break;
+ case WHvArm64ResetTypeReboot:
+ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ bql_lock();
+ if (arm_cpu->power_state != PSCI_OFF) {
+ 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);
+
+ val.Reg64 = deposit64(arm_cpu->mp_affinity, 31, 1, 1 /* RES1 */);
+ 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.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v10 13/28] whpx: change memory management logic
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (11 preceding siblings ...)
2025-10-29 16:54 ` [PATCH v10 12/28] whpx: add arm64 support Mohamed Mediouni
@ 2025-10-29 16:54 ` Mohamed Mediouni
2025-11-10 22:59 ` Bernhard Beschow
2025-10-29 16:54 ` [PATCH v10 14/28] target/arm: cpu: mark WHPX as supporting PSCI 1.3 Mohamed Mediouni
` (15 subsequent siblings)
28 siblings, 1 reply; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:54 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé
This allows edk2 to work on Arm, although u-boot is still not functional.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
accel/whpx/whpx-common.c | 101 +++++++++++++++------------------------
1 file changed, 38 insertions(+), 63 deletions(-)
diff --git a/accel/whpx/whpx-common.c b/accel/whpx/whpx-common.c
index c69792e638..aefec4bc8f 100644
--- a/accel/whpx/whpx-common.c
+++ b/accel/whpx/whpx-common.c
@@ -258,89 +258,64 @@ 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)
+static void whpx_set_phys_mem(MemoryRegionSection *section, bool add)
{
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);
+ 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();
+ uint64_t gva = section->offset_within_address_space;
+ uint64_t size = int128_get64(section->size);
+ HRESULT res;
+ void *mem;
+
+ if (!memory_region_is_ram(area)) {
+ if (writable) {
+ return;
+ } else if (!memory_region_is_romd(area)) {
+ add = false;
+ }
}
-}
-
-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;
+ if (!QEMU_IS_ALIGNED(size, page_size) ||
+ !QEMU_IS_ALIGNED(gva, 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;
- }
- start_pa += delta;
- size -= delta;
- size &= qemu_real_host_page_mask();
- if (!size || (start_pa & ~qemu_real_host_page_mask())) {
+ if (!add) {
+ res = whp_dispatch.WHvUnmapGpaRange(whpx->partition,
+ gva, size);
+ if (!SUCCEEDED(res)) {
+ error_report("WHPX: failed to unmap GPA range");
+ abort();
+ }
return;
}
- host_va = (uintptr_t)memory_region_get_ram_ptr(mr)
- + section->offset_within_region + delta;
+ flags = WHvMapGpaRangeFlagRead | WHvMapGpaRangeFlagExecute
+ | (writable ? WHvMapGpaRangeFlagWrite : 0);
+ mem = memory_region_get_ram_ptr(area) + section->offset_within_region;
- whpx_update_mapping(start_pa, size, (void *)(uintptr_t)host_va, add,
- memory_region_is_rom(mr), mr->name);
+ res = whp_dispatch.WHvMapGpaRange(whpx->partition,
+ mem, gva, size, flags);
+ if (!SUCCEEDED(res)) {
+ error_report("WHPX: failed to map GPA range");
+ 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)
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* Re: [PATCH v10 13/28] whpx: change memory management logic
2025-10-29 16:54 ` [PATCH v10 13/28] whpx: change memory management logic Mohamed Mediouni
@ 2025-11-10 22:59 ` Bernhard Beschow
0 siblings, 0 replies; 36+ messages in thread
From: Bernhard Beschow @ 2025-11-10 22:59 UTC (permalink / raw)
To: qemu-devel, Mohamed Mediouni, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé
Am 29. Oktober 2025 16:54:55 UTC schrieb Mohamed Mediouni <mohamed@unpredictable.fr>:
>This allows edk2 to work on Arm, although u-boot is still not functional.
This seems to fix https://gitlab.com/qemu-project/qemu/-/issues/513, at least it works for me with x86 SeaBIOS via pflash. Also, https://gitlab.com/qemu-project/qemu/-/issues/934 looks like a duplicate.
I wonder if this patch could be 10.2 material such that OVMF can finally work with WHPX.
Best regards,
Bernhard
>
>Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
>---
> accel/whpx/whpx-common.c | 101 +++++++++++++++------------------------
> 1 file changed, 38 insertions(+), 63 deletions(-)
>
>diff --git a/accel/whpx/whpx-common.c b/accel/whpx/whpx-common.c
>index c69792e638..aefec4bc8f 100644
>--- a/accel/whpx/whpx-common.c
>+++ b/accel/whpx/whpx-common.c
>@@ -258,89 +258,64 @@ 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)
>+static void whpx_set_phys_mem(MemoryRegionSection *section, bool add)
> {
> 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);
>+ 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();
>+ uint64_t gva = section->offset_within_address_space;
>+ uint64_t size = int128_get64(section->size);
>+ HRESULT res;
>+ void *mem;
>+
>+ if (!memory_region_is_ram(area)) {
>+ if (writable) {
>+ return;
>+ } else if (!memory_region_is_romd(area)) {
>+ add = false;
>+ }
> }
>-}
>-
>-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;
>+ if (!QEMU_IS_ALIGNED(size, page_size) ||
>+ !QEMU_IS_ALIGNED(gva, 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;
>- }
>- start_pa += delta;
>- size -= delta;
>- size &= qemu_real_host_page_mask();
>- if (!size || (start_pa & ~qemu_real_host_page_mask())) {
>+ if (!add) {
>+ res = whp_dispatch.WHvUnmapGpaRange(whpx->partition,
>+ gva, size);
>+ if (!SUCCEEDED(res)) {
>+ error_report("WHPX: failed to unmap GPA range");
>+ abort();
>+ }
> return;
> }
>
>- host_va = (uintptr_t)memory_region_get_ram_ptr(mr)
>- + section->offset_within_region + delta;
>+ flags = WHvMapGpaRangeFlagRead | WHvMapGpaRangeFlagExecute
>+ | (writable ? WHvMapGpaRangeFlagWrite : 0);
>+ mem = memory_region_get_ram_ptr(area) + section->offset_within_region;
>
>- whpx_update_mapping(start_pa, size, (void *)(uintptr_t)host_va, add,
>- memory_region_is_rom(mr), mr->name);
>+ res = whp_dispatch.WHvMapGpaRange(whpx->partition,
>+ mem, gva, size, flags);
>+ if (!SUCCEEDED(res)) {
>+ error_report("WHPX: failed to map GPA range");
>+ 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)
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH v10 14/28] target/arm: cpu: mark WHPX as supporting PSCI 1.3
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (12 preceding siblings ...)
2025-10-29 16:54 ` [PATCH v10 13/28] whpx: change memory management logic Mohamed Mediouni
@ 2025-10-29 16:54 ` Mohamed Mediouni
2025-10-29 16:54 ` [PATCH v10 15/28] hw/arm: virt: cleanly fail on attempt to use the platform vGIC together with ITS Mohamed Mediouni
` (14 subsequent siblings)
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:54 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé, Pierrick Bouvier
Hyper-V supports PSCI 1.3, and that implementation is exposed through
WHPX.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
---
target/arm/cpu.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index d2fc17eab6..854b46f40a 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"
@@ -1143,6 +1144,8 @@ static void arm_cpu_initfn(Object *obj)
if (tcg_enabled() || hvf_enabled()) {
/* TCG and HVF implement PSCI 1.1 */
cpu->psci_version = QEMU_PSCI_VERSION_1_1;
+ } else if (whpx_enabled()) {
+ cpu->psci_version = QEMU_PSCI_VERSION_1_3;
}
}
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v10 15/28] hw/arm: virt: cleanly fail on attempt to use the platform vGIC together with ITS
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (13 preceding siblings ...)
2025-10-29 16:54 ` [PATCH v10 14/28] target/arm: cpu: mark WHPX as supporting PSCI 1.3 Mohamed Mediouni
@ 2025-10-29 16:54 ` Mohamed Mediouni
2025-10-29 16:54 ` [PATCH v10 16/28] hw: arm: virt: rework MSI-X configuration Mohamed Mediouni
` (13 subsequent siblings)
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:54 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé
Switch its to a tristate.
Windows Hypervisor Platform's vGIC doesn't support ITS.
Deal with this by reporting to the user and exiting.
Regular configuration: GICv3 + ITS
New default configuration with WHPX: GICv3 with GICv2m
And its=off explicitly for the newest machine version: GICv3 + GICv2m
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
hw/arm/virt-acpi-build.c | 15 +++++++------
hw/arm/virt.c | 46 +++++++++++++++++++++++++++++++---------
include/hw/arm/virt.h | 4 +++-
3 files changed, 47 insertions(+), 18 deletions(-)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 0a6ec74aa0..8e730731ca 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -472,7 +472,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
nb_nodes = num_smmus + 1; /* RC and SMMUv3 */
rc_mapping_count = rc_smmu_idmaps_len;
- if (vms->its) {
+ if (virt_is_its_enabled(vms)) {
/*
* Knowing the ID ranges from the RC to the SMMU, it's possible to
* determine the ID ranges from RC that go directly to ITS.
@@ -483,7 +483,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
rc_mapping_count += rc_its_idmaps->len;
}
} else {
- if (vms->its) {
+ if (virt_is_its_enabled(vms)) {
nb_nodes = 2; /* RC and ITS */
rc_mapping_count = 1; /* Direct map to ITS */
} else {
@@ -498,7 +498,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
build_append_int_noprefix(table_data, IORT_NODE_OFFSET, 4);
build_append_int_noprefix(table_data, 0, 4); /* Reserved */
- if (vms->its) {
+ if (virt_is_its_enabled(vms)) {
/* Table 12 ITS Group Format */
build_append_int_noprefix(table_data, 0 /* ITS Group */, 1); /* Type */
node_size = 20 /* fixed header size */ + 4 /* 1 GIC ITS Identifier */;
@@ -517,7 +517,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
int smmu_mapping_count, offset_to_id_array;
int irq = sdev->irq;
- if (vms->its) {
+ if (virt_is_its_enabled(vms)) {
smmu_mapping_count = 1; /* ITS Group node */
offset_to_id_array = SMMU_V3_ENTRY_SIZE; /* Just after the header */
} else {
@@ -610,7 +610,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
}
}
- if (vms->its) {
+ if (virt_is_its_enabled(vms)) {
/*
* Map bypassed (don't go through the SMMU) RIDs (input) to
* ITS Group node directly: RC -> ITS.
@@ -945,7 +945,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
memmap[VIRT_HIGH_GIC_REDIST2].size);
}
- if (vms->its) {
+ if (virt_is_its_enabled(vms)) {
/*
* ACPI spec, Revision 6.0 Errata A
* (original 6.0 definition has invalid Length)
@@ -961,7 +961,8 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
}
}
- if (!(vms->gic_version != VIRT_GIC_VERSION_2 && vms->its) && !vms->no_gicv3_with_gicv2m) {
+ if (!(vms->gic_version != VIRT_GIC_VERSION_2 && virt_is_its_enabled(vms))
+ && !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 9121eb37eb..dbf9a28b8d 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -735,7 +735,7 @@ static void create_its(VirtMachineState *vms)
{
DeviceState *dev;
- assert(vms->its);
+ assert(virt_is_its_enabled(vms));
if (!kvm_irqchip_in_kernel() && !vms->tcg_its) {
/*
* Do nothing if ITS is neither supported by the host nor emulated by
@@ -744,6 +744,15 @@ static void create_its(VirtMachineState *vms)
return;
}
+ if (whpx_enabled() && vms->tcg_its) {
+ /*
+ * Signal to the user when ITS is neither supported by the host
+ * nor emulated by the machine.
+ */
+ info_report("ITS not supported on WHPX.");
+ exit(1);
+ }
+
dev = qdev_new(its_class_name());
object_property_set_link(OBJECT(dev), "parent-gicv3", OBJECT(vms->gic),
@@ -955,7 +964,7 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
fdt_add_gic_node(vms);
- if (vms->gic_version != VIRT_GIC_VERSION_2 && vms->its) {
+ if (vms->gic_version != VIRT_GIC_VERSION_2 && virt_is_its_enabled(vms)) {
create_its(vms);
} else if (vms->gic_version != VIRT_GIC_VERSION_2 && !vms->no_gicv3_with_gicv2m) {
create_v2m(vms);
@@ -2705,18 +2714,34 @@ static void virt_set_highmem_mmio_size(Object *obj, Visitor *v,
extended_memmap[VIRT_HIGH_PCIE_MMIO].size = size;
}
-static bool virt_get_its(Object *obj, Error **errp)
+bool virt_is_its_enabled(VirtMachineState *vms)
+{
+ if (vms->its == ON_OFF_AUTO_OFF) {
+ return false;
+ }
+ if (vms->its == ON_OFF_AUTO_AUTO) {
+ if (whpx_enabled()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static void virt_get_its(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
{
VirtMachineState *vms = VIRT_MACHINE(obj);
+ OnOffAuto its = vms->its;
- return vms->its;
+ visit_type_OnOffAuto(v, name, &its, errp);
}
-static void virt_set_its(Object *obj, bool value, Error **errp)
+static void virt_set_its(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
{
VirtMachineState *vms = VIRT_MACHINE(obj);
- vms->its = value;
+ visit_type_OnOffAuto(v, name, &vms->its, errp);
}
static bool virt_get_dtb_randomness(Object *obj, Error **errp)
@@ -3426,8 +3451,9 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
"guest CPU which implements the ARM "
"Memory Tagging Extension");
- object_class_property_add_bool(oc, "its", virt_get_its,
- virt_set_its);
+ object_class_property_add(oc, "its", "OnOffAuto",
+ virt_get_its, virt_set_its,
+ NULL, NULL);
object_class_property_set_description(oc, "its",
"Set on/off to enable/disable "
"ITS instantiation");
@@ -3487,8 +3513,8 @@ static void virt_instance_init(Object *obj)
vms->highmem_mmio = true;
vms->highmem_redists = true;
- /* Default allows ITS instantiation */
- vms->its = true;
+ /* Default allows ITS instantiation if available */
+ vms->its = ON_OFF_AUTO_AUTO;
/* Allow ITS emulation if the machine version supports it */
vms->tcg_its = !vmc->no_tcg_its;
vms->no_gicv3_with_gicv2m = false;
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index d31348dd61..997dd51678 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -149,7 +149,7 @@ struct VirtMachineState {
bool highmem_ecam;
bool highmem_mmio;
bool highmem_redists;
- bool its;
+ OnOffAuto its;
bool tcg_its;
bool virt;
bool ras;
@@ -218,4 +218,6 @@ static inline int virt_gicv3_redist_region_count(VirtMachineState *vms)
vms->highmem_redists) ? 2 : 1;
}
+bool virt_is_its_enabled(VirtMachineState *vms);
+
#endif /* QEMU_ARM_VIRT_H */
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v10 16/28] hw: arm: virt: rework MSI-X configuration
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (14 preceding siblings ...)
2025-10-29 16:54 ` [PATCH v10 15/28] hw/arm: virt: cleanly fail on attempt to use the platform vGIC together with ITS Mohamed Mediouni
@ 2025-10-29 16:54 ` Mohamed Mediouni
2025-10-30 11:28 ` Bernhard Beschow
2025-11-01 16:45 ` Bernhard Beschow
2025-10-29 16:54 ` [PATCH v10 17/28] hw: arm: virt-acpi-build: add hack Mohamed Mediouni
` (12 subsequent siblings)
28 siblings, 2 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:54 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé
Introduce a -M msi= argument to be able to control MSI-X support independently
from ITS, as part of supporting GICv3 + GICv2m platforms.
Remove vms->its as it's no longer needed after that change.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
hw/arm/virt-acpi-build.c | 3 +-
hw/arm/virt.c | 110 +++++++++++++++++++++++++++++++--------
include/hw/arm/virt.h | 4 +-
3 files changed, 93 insertions(+), 24 deletions(-)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 8e730731ca..a6a56455a9 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -961,8 +961,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
}
}
- if (!(vms->gic_version != VIRT_GIC_VERSION_2 && virt_is_its_enabled(vms))
- && !vms->no_gicv3_with_gicv2m) {
+ if (virt_is_gicv2m_enabled(vms)) {
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 dbf9a28b8d..6978d4e867 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -964,12 +964,12 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
fdt_add_gic_node(vms);
- if (vms->gic_version != VIRT_GIC_VERSION_2 && virt_is_its_enabled(vms)) {
+ if (virt_is_its_enabled(vms)) {
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) {
+ } else if (virt_is_gicv2m_enabled(vms)) {
create_v2m(vms);
+ } else {
+ vms->msi_controller = VIRT_MSI_CTRL_NONE;
}
}
@@ -2716,32 +2716,93 @@ static void virt_set_highmem_mmio_size(Object *obj, Visitor *v,
bool virt_is_its_enabled(VirtMachineState *vms)
{
- if (vms->its == ON_OFF_AUTO_OFF) {
- return false;
+ switch (vms->msi_controller) {
+ case VIRT_MSI_CTRL_NONE:
+ return false;
+ case VIRT_MSI_CTRL_ITS:
+ return true;
+ case VIRT_MSI_CTRL_GICV2M:
+ return false;
+ case VIRT_MSI_CTRL_AUTO:
+ if (whpx_enabled() && whpx_irqchip_in_kernel()) {
+ return false;
+ }
+ if (vms->gic_version == VIRT_GIC_VERSION_2) {
+ return false;
+ }
+ return true;
+ default:
+ return false;
}
- if (vms->its == ON_OFF_AUTO_AUTO) {
- if (whpx_enabled()) {
+}
+
+bool virt_is_gicv2m_enabled(VirtMachineState *vms)
+{
+ switch (vms->msi_controller) {
+ case VIRT_MSI_CTRL_NONE:
return false;
- }
+ default:
+ return !virt_is_its_enabled(vms);
}
- return true;
}
-static void virt_get_its(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
+static char *virt_get_msi(Object *obj, Error **errp)
+{
+ VirtMachineState *vms = VIRT_MACHINE(obj);
+ const char *val;
+
+ switch (vms->msi_controller) {
+ case VIRT_MSI_CTRL_NONE:
+ val = "off";
+ break;
+ case VIRT_MSI_CTRL_ITS:
+ val = "its";
+ break;
+ case VIRT_MSI_CTRL_GICV2M:
+ val = "gicv2m";
+ default:
+ val = "auto";
+ break;
+ }
+ return g_strdup(val);
+}
+
+static void virt_set_msi(Object *obj, const char *value, Error **errp)
{
VirtMachineState *vms = VIRT_MACHINE(obj);
- OnOffAuto its = vms->its;
- visit_type_OnOffAuto(v, name, &its, errp);
+ if (!strcmp(value, "auto")) {
+ vms->msi_controller = VIRT_MSI_CTRL_AUTO; /* Will be overriden later */
+ } else if (!strcmp(value, "its")) {
+ vms->msi_controller = VIRT_MSI_CTRL_ITS;
+ } else if (!strcmp(value, "gicv2m")) {
+ vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
+ } else if (!strcmp(value, "none")) {
+ vms->msi_controller = VIRT_MSI_CTRL_NONE;
+ } else {
+ error_setg(errp, "Invalid msi value");
+ error_append_hint(errp, "Valid values are auto, gicv2m, its, off\n");
+ }
}
-static void virt_set_its(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
+static bool virt_get_its(Object *obj, Error **errp)
{
VirtMachineState *vms = VIRT_MACHINE(obj);
- visit_type_OnOffAuto(v, name, &vms->its, errp);
+ return virt_is_its_enabled(vms);
+}
+
+static void virt_set_its(Object *obj, bool value, Error **errp)
+{
+ VirtMachineState *vms = VIRT_MACHINE(obj);
+
+ if (value) {
+ vms->msi_controller = VIRT_MSI_CTRL_ITS;
+ } else if (vms->no_gicv3_with_gicv2m) {
+ vms->msi_controller = VIRT_MSI_CTRL_NONE;
+ } else {
+ vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
+ }
}
static bool virt_get_dtb_randomness(Object *obj, Error **errp)
@@ -3068,6 +3129,8 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
db_start = base_memmap[VIRT_GIC_V2M].base;
db_end = db_start + base_memmap[VIRT_GIC_V2M].size - 1;
break;
+ case VIRT_MSI_CTRL_AUTO:
+ g_assert_not_reached();
}
resv_prop_str = g_strdup_printf("0x%"PRIx64":0x%"PRIx64":%u",
db_start, db_end,
@@ -3451,13 +3514,18 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
"guest CPU which implements the ARM "
"Memory Tagging Extension");
- object_class_property_add(oc, "its", "OnOffAuto",
- virt_get_its, virt_set_its,
- NULL, NULL);
+ object_class_property_add_bool(oc, "its", virt_get_its,
+ virt_set_its);
object_class_property_set_description(oc, "its",
"Set on/off to enable/disable "
"ITS instantiation");
+ object_class_property_add_str(oc, "msi", virt_get_msi,
+ virt_set_msi);
+ object_class_property_set_description(oc, "msi",
+ "Set MSI settings. "
+ "Valid values are auto/gicv2m/its/off");
+
object_class_property_add_bool(oc, "dtb-randomness",
virt_get_dtb_randomness,
virt_set_dtb_randomness);
@@ -3514,7 +3582,7 @@ static void virt_instance_init(Object *obj)
vms->highmem_redists = true;
/* Default allows ITS instantiation if available */
- vms->its = ON_OFF_AUTO_AUTO;
+ vms->msi_controller = VIRT_MSI_CTRL_AUTO;
/* Allow ITS emulation if the machine version supports it */
vms->tcg_its = !vmc->no_tcg_its;
vms->no_gicv3_with_gicv2m = false;
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 997dd51678..99db8607e7 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -101,6 +101,8 @@ typedef enum VirtIOMMUType {
typedef enum VirtMSIControllerType {
VIRT_MSI_CTRL_NONE,
+ /* This value is overriden at runtime.*/
+ VIRT_MSI_CTRL_AUTO,
VIRT_MSI_CTRL_GICV2M,
VIRT_MSI_CTRL_ITS,
} VirtMSIControllerType;
@@ -149,7 +151,6 @@ struct VirtMachineState {
bool highmem_ecam;
bool highmem_mmio;
bool highmem_redists;
- OnOffAuto its;
bool tcg_its;
bool virt;
bool ras;
@@ -219,5 +220,6 @@ static inline int virt_gicv3_redist_region_count(VirtMachineState *vms)
}
bool virt_is_its_enabled(VirtMachineState *vms);
+bool virt_is_gicv2m_enabled(VirtMachineState *vms);
#endif /* QEMU_ARM_VIRT_H */
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* Re: [PATCH v10 16/28] hw: arm: virt: rework MSI-X configuration
2025-10-29 16:54 ` [PATCH v10 16/28] hw: arm: virt: rework MSI-X configuration Mohamed Mediouni
@ 2025-10-30 11:28 ` Bernhard Beschow
2025-11-01 16:45 ` Bernhard Beschow
1 sibling, 0 replies; 36+ messages in thread
From: Bernhard Beschow @ 2025-10-30 11:28 UTC (permalink / raw)
To: qemu-devel, Mohamed Mediouni, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé
Am 29. Oktober 2025 16:54:58 UTC schrieb Mohamed Mediouni <mohamed@unpredictable.fr>:
>Introduce a -M msi= argument to be able to control MSI-X support independently
>from ITS, as part of supporting GICv3 + GICv2m platforms.
>
>Remove vms->its as it's no longer needed after that change.
>
>Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
>---
> hw/arm/virt-acpi-build.c | 3 +-
> hw/arm/virt.c | 110 +++++++++++++++++++++++++++++++--------
> include/hw/arm/virt.h | 4 +-
> 3 files changed, 93 insertions(+), 24 deletions(-)
>
>diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
>index 8e730731ca..a6a56455a9 100644
>--- a/hw/arm/virt-acpi-build.c
>+++ b/hw/arm/virt-acpi-build.c
>@@ -961,8 +961,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
> }
> }
>
>- if (!(vms->gic_version != VIRT_GIC_VERSION_2 && virt_is_its_enabled(vms))
>- && !vms->no_gicv3_with_gicv2m) {
>+ if (virt_is_gicv2m_enabled(vms)) {
> 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 dbf9a28b8d..6978d4e867 100644
>--- a/hw/arm/virt.c
>+++ b/hw/arm/virt.c
>@@ -964,12 +964,12 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
>
> fdt_add_gic_node(vms);
>
>- if (vms->gic_version != VIRT_GIC_VERSION_2 && virt_is_its_enabled(vms)) {
>+ if (virt_is_its_enabled(vms)) {
> 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) {
>+ } else if (virt_is_gicv2m_enabled(vms)) {
> create_v2m(vms);
>+ } else {
>+ vms->msi_controller = VIRT_MSI_CTRL_NONE;
> }
> }
>
>@@ -2716,32 +2716,93 @@ static void virt_set_highmem_mmio_size(Object *obj, Visitor *v,
>
> bool virt_is_its_enabled(VirtMachineState *vms)
> {
>- if (vms->its == ON_OFF_AUTO_OFF) {
>- return false;
>+ switch (vms->msi_controller) {
>+ case VIRT_MSI_CTRL_NONE:
>+ return false;
>+ case VIRT_MSI_CTRL_ITS:
>+ return true;
>+ case VIRT_MSI_CTRL_GICV2M:
>+ return false;
>+ case VIRT_MSI_CTRL_AUTO:
>+ if (whpx_enabled() && whpx_irqchip_in_kernel()) {
>+ return false;
>+ }
>+ if (vms->gic_version == VIRT_GIC_VERSION_2) {
>+ return false;
>+ }
>+ return true;
>+ default:
>+ return false;
> }
>- if (vms->its == ON_OFF_AUTO_AUTO) {
>- if (whpx_enabled()) {
>+}
>+
>+bool virt_is_gicv2m_enabled(VirtMachineState *vms)
>+{
>+ switch (vms->msi_controller) {
>+ case VIRT_MSI_CTRL_NONE:
> return false;
>- }
>+ default:
>+ return !virt_is_its_enabled(vms);
> }
>- return true;
> }
>
>-static void virt_get_its(Object *obj, Visitor *v, const char *name,
>- void *opaque, Error **errp)
>+static char *virt_get_msi(Object *obj, Error **errp)
>+{
>+ VirtMachineState *vms = VIRT_MACHINE(obj);
>+ const char *val;
>+
>+ switch (vms->msi_controller) {
>+ case VIRT_MSI_CTRL_NONE:
>+ val = "off";
>+ break;
>+ case VIRT_MSI_CTRL_ITS:
>+ val = "its";
>+ break;
>+ case VIRT_MSI_CTRL_GICV2M:
>+ val = "gicv2m";
Missing break.
Best regards,
Bernhard
>+ default:
>+ val = "auto";
>+ break;
>+ }
>+ return g_strdup(val);
>+}
>+
>+static void virt_set_msi(Object *obj, const char *value, Error **errp)
> {
> VirtMachineState *vms = VIRT_MACHINE(obj);
>- OnOffAuto its = vms->its;
>
>- visit_type_OnOffAuto(v, name, &its, errp);
>+ if (!strcmp(value, "auto")) {
>+ vms->msi_controller = VIRT_MSI_CTRL_AUTO; /* Will be overriden later */
>+ } else if (!strcmp(value, "its")) {
>+ vms->msi_controller = VIRT_MSI_CTRL_ITS;
>+ } else if (!strcmp(value, "gicv2m")) {
>+ vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
>+ } else if (!strcmp(value, "none")) {
>+ vms->msi_controller = VIRT_MSI_CTRL_NONE;
>+ } else {
>+ error_setg(errp, "Invalid msi value");
>+ error_append_hint(errp, "Valid values are auto, gicv2m, its, off\n");
>+ }
> }
>
>-static void virt_set_its(Object *obj, Visitor *v, const char *name,
>- void *opaque, Error **errp)
>+static bool virt_get_its(Object *obj, Error **errp)
> {
> VirtMachineState *vms = VIRT_MACHINE(obj);
>
>- visit_type_OnOffAuto(v, name, &vms->its, errp);
>+ return virt_is_its_enabled(vms);
>+}
>+
>+static void virt_set_its(Object *obj, bool value, Error **errp)
>+{
>+ VirtMachineState *vms = VIRT_MACHINE(obj);
>+
>+ if (value) {
>+ vms->msi_controller = VIRT_MSI_CTRL_ITS;
>+ } else if (vms->no_gicv3_with_gicv2m) {
>+ vms->msi_controller = VIRT_MSI_CTRL_NONE;
>+ } else {
>+ vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
>+ }
> }
>
> static bool virt_get_dtb_randomness(Object *obj, Error **errp)
>@@ -3068,6 +3129,8 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
> db_start = base_memmap[VIRT_GIC_V2M].base;
> db_end = db_start + base_memmap[VIRT_GIC_V2M].size - 1;
> break;
>+ case VIRT_MSI_CTRL_AUTO:
>+ g_assert_not_reached();
> }
> resv_prop_str = g_strdup_printf("0x%"PRIx64":0x%"PRIx64":%u",
> db_start, db_end,
>@@ -3451,13 +3514,18 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
> "guest CPU which implements the ARM "
> "Memory Tagging Extension");
>
>- object_class_property_add(oc, "its", "OnOffAuto",
>- virt_get_its, virt_set_its,
>- NULL, NULL);
>+ object_class_property_add_bool(oc, "its", virt_get_its,
>+ virt_set_its);
> object_class_property_set_description(oc, "its",
> "Set on/off to enable/disable "
> "ITS instantiation");
>
>+ object_class_property_add_str(oc, "msi", virt_get_msi,
>+ virt_set_msi);
>+ object_class_property_set_description(oc, "msi",
>+ "Set MSI settings. "
>+ "Valid values are auto/gicv2m/its/off");
>+
> object_class_property_add_bool(oc, "dtb-randomness",
> virt_get_dtb_randomness,
> virt_set_dtb_randomness);
>@@ -3514,7 +3582,7 @@ static void virt_instance_init(Object *obj)
> vms->highmem_redists = true;
>
> /* Default allows ITS instantiation if available */
>- vms->its = ON_OFF_AUTO_AUTO;
>+ vms->msi_controller = VIRT_MSI_CTRL_AUTO;
> /* Allow ITS emulation if the machine version supports it */
> vms->tcg_its = !vmc->no_tcg_its;
> vms->no_gicv3_with_gicv2m = false;
>diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
>index 997dd51678..99db8607e7 100644
>--- a/include/hw/arm/virt.h
>+++ b/include/hw/arm/virt.h
>@@ -101,6 +101,8 @@ typedef enum VirtIOMMUType {
>
> typedef enum VirtMSIControllerType {
> VIRT_MSI_CTRL_NONE,
>+ /* This value is overriden at runtime.*/
>+ VIRT_MSI_CTRL_AUTO,
> VIRT_MSI_CTRL_GICV2M,
> VIRT_MSI_CTRL_ITS,
> } VirtMSIControllerType;
>@@ -149,7 +151,6 @@ struct VirtMachineState {
> bool highmem_ecam;
> bool highmem_mmio;
> bool highmem_redists;
>- OnOffAuto its;
> bool tcg_its;
> bool virt;
> bool ras;
>@@ -219,5 +220,6 @@ static inline int virt_gicv3_redist_region_count(VirtMachineState *vms)
> }
>
> bool virt_is_its_enabled(VirtMachineState *vms);
>+bool virt_is_gicv2m_enabled(VirtMachineState *vms);
>
> #endif /* QEMU_ARM_VIRT_H */
^ permalink raw reply [flat|nested] 36+ messages in thread* Re: [PATCH v10 16/28] hw: arm: virt: rework MSI-X configuration
2025-10-29 16:54 ` [PATCH v10 16/28] hw: arm: virt: rework MSI-X configuration Mohamed Mediouni
2025-10-30 11:28 ` Bernhard Beschow
@ 2025-11-01 16:45 ` Bernhard Beschow
1 sibling, 0 replies; 36+ messages in thread
From: Bernhard Beschow @ 2025-11-01 16:45 UTC (permalink / raw)
To: qemu-devel, Mohamed Mediouni, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé
Am 29. Oktober 2025 16:54:58 UTC schrieb Mohamed Mediouni <mohamed@unpredictable.fr>:
>Introduce a -M msi= argument to be able to control MSI-X support independently
>from ITS, as part of supporting GICv3 + GICv2m platforms.
>
>Remove vms->its as it's no longer needed after that change.
>
>Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
>---
> hw/arm/virt-acpi-build.c | 3 +-
> hw/arm/virt.c | 110 +++++++++++++++++++++++++++++++--------
> include/hw/arm/virt.h | 4 +-
> 3 files changed, 93 insertions(+), 24 deletions(-)
>
>diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
>index 8e730731ca..a6a56455a9 100644
>--- a/hw/arm/virt-acpi-build.c
>+++ b/hw/arm/virt-acpi-build.c
>@@ -961,8 +961,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
> }
> }
>
>- if (!(vms->gic_version != VIRT_GIC_VERSION_2 && virt_is_its_enabled(vms))
>- && !vms->no_gicv3_with_gicv2m) {
>+ if (virt_is_gicv2m_enabled(vms)) {
> 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 dbf9a28b8d..6978d4e867 100644
>--- a/hw/arm/virt.c
>+++ b/hw/arm/virt.c
>@@ -964,12 +964,12 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
>
> fdt_add_gic_node(vms);
>
>- if (vms->gic_version != VIRT_GIC_VERSION_2 && virt_is_its_enabled(vms)) {
>+ if (virt_is_its_enabled(vms)) {
> 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) {
>+ } else if (virt_is_gicv2m_enabled(vms)) {
> create_v2m(vms);
>+ } else {
>+ vms->msi_controller = VIRT_MSI_CTRL_NONE;
> }
> }
>
>@@ -2716,32 +2716,93 @@ static void virt_set_highmem_mmio_size(Object *obj, Visitor *v,
>
> bool virt_is_its_enabled(VirtMachineState *vms)
> {
>- if (vms->its == ON_OFF_AUTO_OFF) {
>- return false;
>+ switch (vms->msi_controller) {
>+ case VIRT_MSI_CTRL_NONE:
>+ return false;
>+ case VIRT_MSI_CTRL_ITS:
>+ return true;
>+ case VIRT_MSI_CTRL_GICV2M:
>+ return false;
>+ case VIRT_MSI_CTRL_AUTO:
>+ if (whpx_enabled() && whpx_irqchip_in_kernel()) {
Under x86_64 Linux whpx_irqchip_in_kernel() isn't found during linking.
Best regards,
Bernhard
>+ return false;
>+ }
>+ if (vms->gic_version == VIRT_GIC_VERSION_2) {
>+ return false;
>+ }
>+ return true;
>+ default:
>+ return false;
> }
>- if (vms->its == ON_OFF_AUTO_AUTO) {
>- if (whpx_enabled()) {
>+}
>+
>+bool virt_is_gicv2m_enabled(VirtMachineState *vms)
>+{
>+ switch (vms->msi_controller) {
>+ case VIRT_MSI_CTRL_NONE:
> return false;
>- }
>+ default:
>+ return !virt_is_its_enabled(vms);
> }
>- return true;
> }
>
>-static void virt_get_its(Object *obj, Visitor *v, const char *name,
>- void *opaque, Error **errp)
>+static char *virt_get_msi(Object *obj, Error **errp)
>+{
>+ VirtMachineState *vms = VIRT_MACHINE(obj);
>+ const char *val;
>+
>+ switch (vms->msi_controller) {
>+ case VIRT_MSI_CTRL_NONE:
>+ val = "off";
>+ break;
>+ case VIRT_MSI_CTRL_ITS:
>+ val = "its";
>+ break;
>+ case VIRT_MSI_CTRL_GICV2M:
>+ val = "gicv2m";
>+ default:
>+ val = "auto";
>+ break;
>+ }
>+ return g_strdup(val);
>+}
>+
>+static void virt_set_msi(Object *obj, const char *value, Error **errp)
> {
> VirtMachineState *vms = VIRT_MACHINE(obj);
>- OnOffAuto its = vms->its;
>
>- visit_type_OnOffAuto(v, name, &its, errp);
>+ if (!strcmp(value, "auto")) {
>+ vms->msi_controller = VIRT_MSI_CTRL_AUTO; /* Will be overriden later */
>+ } else if (!strcmp(value, "its")) {
>+ vms->msi_controller = VIRT_MSI_CTRL_ITS;
>+ } else if (!strcmp(value, "gicv2m")) {
>+ vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
>+ } else if (!strcmp(value, "none")) {
>+ vms->msi_controller = VIRT_MSI_CTRL_NONE;
>+ } else {
>+ error_setg(errp, "Invalid msi value");
>+ error_append_hint(errp, "Valid values are auto, gicv2m, its, off\n");
>+ }
> }
>
>-static void virt_set_its(Object *obj, Visitor *v, const char *name,
>- void *opaque, Error **errp)
>+static bool virt_get_its(Object *obj, Error **errp)
> {
> VirtMachineState *vms = VIRT_MACHINE(obj);
>
>- visit_type_OnOffAuto(v, name, &vms->its, errp);
>+ return virt_is_its_enabled(vms);
>+}
>+
>+static void virt_set_its(Object *obj, bool value, Error **errp)
>+{
>+ VirtMachineState *vms = VIRT_MACHINE(obj);
>+
>+ if (value) {
>+ vms->msi_controller = VIRT_MSI_CTRL_ITS;
>+ } else if (vms->no_gicv3_with_gicv2m) {
>+ vms->msi_controller = VIRT_MSI_CTRL_NONE;
>+ } else {
>+ vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
>+ }
> }
>
> static bool virt_get_dtb_randomness(Object *obj, Error **errp)
>@@ -3068,6 +3129,8 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
> db_start = base_memmap[VIRT_GIC_V2M].base;
> db_end = db_start + base_memmap[VIRT_GIC_V2M].size - 1;
> break;
>+ case VIRT_MSI_CTRL_AUTO:
>+ g_assert_not_reached();
> }
> resv_prop_str = g_strdup_printf("0x%"PRIx64":0x%"PRIx64":%u",
> db_start, db_end,
>@@ -3451,13 +3514,18 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
> "guest CPU which implements the ARM "
> "Memory Tagging Extension");
>
>- object_class_property_add(oc, "its", "OnOffAuto",
>- virt_get_its, virt_set_its,
>- NULL, NULL);
>+ object_class_property_add_bool(oc, "its", virt_get_its,
>+ virt_set_its);
> object_class_property_set_description(oc, "its",
> "Set on/off to enable/disable "
> "ITS instantiation");
>
>+ object_class_property_add_str(oc, "msi", virt_get_msi,
>+ virt_set_msi);
>+ object_class_property_set_description(oc, "msi",
>+ "Set MSI settings. "
>+ "Valid values are auto/gicv2m/its/off");
>+
> object_class_property_add_bool(oc, "dtb-randomness",
> virt_get_dtb_randomness,
> virt_set_dtb_randomness);
>@@ -3514,7 +3582,7 @@ static void virt_instance_init(Object *obj)
> vms->highmem_redists = true;
>
> /* Default allows ITS instantiation if available */
>- vms->its = ON_OFF_AUTO_AUTO;
>+ vms->msi_controller = VIRT_MSI_CTRL_AUTO;
> /* Allow ITS emulation if the machine version supports it */
> vms->tcg_its = !vmc->no_tcg_its;
> vms->no_gicv3_with_gicv2m = false;
>diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
>index 997dd51678..99db8607e7 100644
>--- a/include/hw/arm/virt.h
>+++ b/include/hw/arm/virt.h
>@@ -101,6 +101,8 @@ typedef enum VirtIOMMUType {
>
> typedef enum VirtMSIControllerType {
> VIRT_MSI_CTRL_NONE,
>+ /* This value is overriden at runtime.*/
>+ VIRT_MSI_CTRL_AUTO,
> VIRT_MSI_CTRL_GICV2M,
> VIRT_MSI_CTRL_ITS,
> } VirtMSIControllerType;
>@@ -149,7 +151,6 @@ struct VirtMachineState {
> bool highmem_ecam;
> bool highmem_mmio;
> bool highmem_redists;
>- OnOffAuto its;
> bool tcg_its;
> bool virt;
> bool ras;
>@@ -219,5 +220,6 @@ static inline int virt_gicv3_redist_region_count(VirtMachineState *vms)
> }
>
> bool virt_is_its_enabled(VirtMachineState *vms);
>+bool virt_is_gicv2m_enabled(VirtMachineState *vms);
>
> #endif /* QEMU_ARM_VIRT_H */
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH v10 17/28] hw: arm: virt-acpi-build: add hack
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (15 preceding siblings ...)
2025-10-29 16:54 ` [PATCH v10 16/28] hw: arm: virt: rework MSI-X configuration Mohamed Mediouni
@ 2025-10-29 16:54 ` Mohamed Mediouni
2025-11-06 9:40 ` Gustavo Romero
2025-10-29 16:55 ` [PATCH v10 18/28] docs: arm: update virt machine model description Mohamed Mediouni
` (11 subsequent siblings)
28 siblings, 1 reply; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:54 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé
Looks like in the prior Qemu ACPI table handling, GICv2 configurations
had vms->its=1...
Match that assumption to not make the test suite fail. Probably not merge-worthy...
And then maybe see what to do for older releases too?
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
hw/arm/virt-acpi-build.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index a6a56455a9..39dd3d1020 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -472,7 +472,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
nb_nodes = num_smmus + 1; /* RC and SMMUv3 */
rc_mapping_count = rc_smmu_idmaps_len;
- if (virt_is_its_enabled(vms)) {
+ if (virt_is_its_enabled(vms) || vms->gic_version == 2) {
/*
* Knowing the ID ranges from the RC to the SMMU, it's possible to
* determine the ID ranges from RC that go directly to ITS.
@@ -483,7 +483,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
rc_mapping_count += rc_its_idmaps->len;
}
} else {
- if (virt_is_its_enabled(vms)) {
+ if (virt_is_its_enabled(vms) || vms->gic_version == 2) {
nb_nodes = 2; /* RC and ITS */
rc_mapping_count = 1; /* Direct map to ITS */
} else {
@@ -498,7 +498,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
build_append_int_noprefix(table_data, IORT_NODE_OFFSET, 4);
build_append_int_noprefix(table_data, 0, 4); /* Reserved */
- if (virt_is_its_enabled(vms)) {
+ if (virt_is_its_enabled(vms) || vms->gic_version == 2) {
/* Table 12 ITS Group Format */
build_append_int_noprefix(table_data, 0 /* ITS Group */, 1); /* Type */
node_size = 20 /* fixed header size */ + 4 /* 1 GIC ITS Identifier */;
@@ -517,7 +517,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
int smmu_mapping_count, offset_to_id_array;
int irq = sdev->irq;
- if (virt_is_its_enabled(vms)) {
+ if (virt_is_its_enabled(vms) || vms->gic_version == 2) {
smmu_mapping_count = 1; /* ITS Group node */
offset_to_id_array = SMMU_V3_ENTRY_SIZE; /* Just after the header */
} else {
@@ -610,7 +610,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
}
}
- if (virt_is_its_enabled(vms)) {
+ if (virt_is_its_enabled(vms) || vms->gic_version == 2) {
/*
* Map bypassed (don't go through the SMMU) RIDs (input) to
* ITS Group node directly: RC -> ITS.
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* Re: [PATCH v10 17/28] hw: arm: virt-acpi-build: add hack
2025-10-29 16:54 ` [PATCH v10 17/28] hw: arm: virt-acpi-build: add hack Mohamed Mediouni
@ 2025-11-06 9:40 ` Gustavo Romero
2025-11-06 12:09 ` Mohamed Mediouni
0 siblings, 1 reply; 36+ messages in thread
From: Gustavo Romero @ 2025-11-06 9:40 UTC (permalink / raw)
To: Mohamed Mediouni, qemu-devel, Philippe Mathieu-Daudé
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson
Hi Mohamed and Phil,
On 10/29/25 17:54, Mohamed Mediouni wrote:
> Looks like in the prior Qemu ACPI table handling, GICv2 configurations
> had vms->its=1...
To me, ITS should not be present on machines that have GICv2, so we should not generate
any ACPI table advertising ITS when GICv2 is used.
Cheers,
Gustavo
> Match that assumption to not make the test suite fail. Probably not merge-worthy...
>
> And then maybe see what to do for older releases too?
>
> Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
> ---
> hw/arm/virt-acpi-build.c | 10 +++++-----
> 1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
> index a6a56455a9..39dd3d1020 100644
> --- a/hw/arm/virt-acpi-build.c
> +++ b/hw/arm/virt-acpi-build.c
> @@ -472,7 +472,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
> nb_nodes = num_smmus + 1; /* RC and SMMUv3 */
> rc_mapping_count = rc_smmu_idmaps_len;
>
> - if (virt_is_its_enabled(vms)) {
> + if (virt_is_its_enabled(vms) || vms->gic_version == 2) {
> /*
> * Knowing the ID ranges from the RC to the SMMU, it's possible to
> * determine the ID ranges from RC that go directly to ITS.
> @@ -483,7 +483,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
> rc_mapping_count += rc_its_idmaps->len;
> }
> } else {
> - if (virt_is_its_enabled(vms)) {
> + if (virt_is_its_enabled(vms) || vms->gic_version == 2) {
> nb_nodes = 2; /* RC and ITS */
> rc_mapping_count = 1; /* Direct map to ITS */
> } else {
> @@ -498,7 +498,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
> build_append_int_noprefix(table_data, IORT_NODE_OFFSET, 4);
> build_append_int_noprefix(table_data, 0, 4); /* Reserved */
>
> - if (virt_is_its_enabled(vms)) {
> + if (virt_is_its_enabled(vms) || vms->gic_version == 2) {
> /* Table 12 ITS Group Format */
> build_append_int_noprefix(table_data, 0 /* ITS Group */, 1); /* Type */
> node_size = 20 /* fixed header size */ + 4 /* 1 GIC ITS Identifier */;
> @@ -517,7 +517,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
> int smmu_mapping_count, offset_to_id_array;
> int irq = sdev->irq;
>
> - if (virt_is_its_enabled(vms)) {
> + if (virt_is_its_enabled(vms) || vms->gic_version == 2) {
> smmu_mapping_count = 1; /* ITS Group node */
> offset_to_id_array = SMMU_V3_ENTRY_SIZE; /* Just after the header */
> } else {
> @@ -610,7 +610,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
> }
> }
>
> - if (virt_is_its_enabled(vms)) {
> + if (virt_is_its_enabled(vms) || vms->gic_version == 2) {
> /*
> * Map bypassed (don't go through the SMMU) RIDs (input) to
> * ITS Group node directly: RC -> ITS.
^ permalink raw reply [flat|nested] 36+ messages in thread* Re: [PATCH v10 17/28] hw: arm: virt-acpi-build: add hack
2025-11-06 9:40 ` Gustavo Romero
@ 2025-11-06 12:09 ` Mohamed Mediouni
0 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-11-06 12:09 UTC (permalink / raw)
To: Gustavo Romero
Cc: qemu-devel, Philippe Mathieu-Daudé, Pedro Barbuda,
Paolo Bonzini, qemu-arm, Alexander Graf, Peter Maydell,
Phil Dennis-Jordan, Richard Henderson
> On 6. Nov 2025, at 10:40, Gustavo Romero <gustavo.romero@linaro.org> wrote:
>
> Hi Mohamed and Phil,
>
> On 10/29/25 17:54, Mohamed Mediouni wrote:
>> Looks like in the prior Qemu ACPI table handling, GICv2 configurations
>> had vms->its=1...
>
> To me, ITS should not be present on machines that have GICv2, so we should not generate
> any ACPI table advertising ITS when GICv2 is used.
>
The problem is breaking migration/backwards compatibility… is it an ignorable concern or
should be the new behaviour be quirked to apply to only Qemu 11.0 onwards?
Thank you,
-Mohamed
> Cheers,
> Gustavo
>
>> Match that assumption to not make the test suite fail. Probably not merge-worthy...
>> And then maybe see what to do for older releases too?
>> Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
>> ---
>> hw/arm/virt-acpi-build.c | 10 +++++-----
>> 1 file changed, 5 insertions(+), 5 deletions(-)
>> diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
>> index a6a56455a9..39dd3d1020 100644
>> --- a/hw/arm/virt-acpi-build.c
>> +++ b/hw/arm/virt-acpi-build.c
>> @@ -472,7 +472,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
>> nb_nodes = num_smmus + 1; /* RC and SMMUv3 */
>> rc_mapping_count = rc_smmu_idmaps_len;
>> - if (virt_is_its_enabled(vms)) {
>> + if (virt_is_its_enabled(vms) || vms->gic_version == 2) {
>> /*
>> * Knowing the ID ranges from the RC to the SMMU, it's possible to
>> * determine the ID ranges from RC that go directly to ITS.
>> @@ -483,7 +483,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
>> rc_mapping_count += rc_its_idmaps->len;
>> }
>> } else {
>> - if (virt_is_its_enabled(vms)) {
>> + if (virt_is_its_enabled(vms) || vms->gic_version == 2) {
>> nb_nodes = 2; /* RC and ITS */
>> rc_mapping_count = 1; /* Direct map to ITS */
>> } else {
>> @@ -498,7 +498,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
>> build_append_int_noprefix(table_data, IORT_NODE_OFFSET, 4);
>> build_append_int_noprefix(table_data, 0, 4); /* Reserved */
>> - if (virt_is_its_enabled(vms)) {
>> + if (virt_is_its_enabled(vms) || vms->gic_version == 2) {
>> /* Table 12 ITS Group Format */
>> build_append_int_noprefix(table_data, 0 /* ITS Group */, 1); /* Type */
>> node_size = 20 /* fixed header size */ + 4 /* 1 GIC ITS Identifier */;
>> @@ -517,7 +517,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
>> int smmu_mapping_count, offset_to_id_array;
>> int irq = sdev->irq;
>> - if (virt_is_its_enabled(vms)) {
>> + if (virt_is_its_enabled(vms) || vms->gic_version == 2) {
>> smmu_mapping_count = 1; /* ITS Group node */
>> offset_to_id_array = SMMU_V3_ENTRY_SIZE; /* Just after the header */
>> } else {
>> @@ -610,7 +610,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
>> }
>> }
>> - if (virt_is_its_enabled(vms)) {
>> + if (virt_is_its_enabled(vms) || vms->gic_version == 2) {
>> /*
>> * Map bypassed (don't go through the SMMU) RIDs (input) to
>> * ITS Group node directly: RC -> ITS.
>
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH v10 18/28] docs: arm: update virt machine model description
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (16 preceding siblings ...)
2025-10-29 16:54 ` [PATCH v10 17/28] hw: arm: virt-acpi-build: add hack Mohamed Mediouni
@ 2025-10-29 16:55 ` Mohamed Mediouni
2025-10-29 16:55 ` [PATCH v10 19/28] whpx: arm64: clamp down IPA size Mohamed Mediouni
` (10 subsequent siblings)
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:55 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé
Update the documentation to match current QEMU.
Remove the mention of pre-2.7 machine models as those aren't provided
anymore.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
docs/system/arm/virt.rst | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst
index 10cbffc8a7..fe95be991e 100644
--- a/docs/system/arm/virt.rst
+++ b/docs/system/arm/virt.rst
@@ -40,9 +40,10 @@ The virt board supports:
- An optional SMMUv3 IOMMU
- hotpluggable DIMMs
- hotpluggable NVDIMMs
-- An MSI controller (GICv2M or ITS). GICv2M is selected by default along
- with GICv2. ITS is selected by default with GICv3 (>= virt-2.7). Note
- that ITS is not modeled in TCG mode.
+- An MSI controller (GICv2m or ITS).
+ - When using a GICv3, ITS is selected by default when available on the platform.
+ - If using a GICv2 or when ITS is not available, a GICv2m is provided by default instead.
+ - Before virt-10.2, a GICv2m is not provided when the ITS is disabled.
- 32 virtio-mmio transport devices
- running guests using the KVM accelerator on aarch64 hardware
- large amounts of RAM (at least 255GB, and more if using highmem)
@@ -167,8 +168,7 @@ gic-version
``4`` if ``virtualization`` is ``on``, but this may change in future)
its
- Set ``on``/``off`` to enable/disable ITS instantiation. The default is ``on``
- for machine types later than ``virt-2.7``.
+ Set ``on``/``off``/``auto`` to control ITS instantiation. The default is ``auto``.
iommu
Set the IOMMU type to create for the guest. Valid values are:
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v10 19/28] whpx: arm64: clamp down IPA size
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (17 preceding siblings ...)
2025-10-29 16:55 ` [PATCH v10 18/28] docs: arm: update virt machine model description Mohamed Mediouni
@ 2025-10-29 16:55 ` Mohamed Mediouni
2025-10-29 16:55 ` [PATCH v10 20/28] hw/arm, accel/hvf, whpx: unify get_physical_address_range between WHPX and HVF Mohamed Mediouni
` (9 subsequent siblings)
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:55 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé, Pierrick Bouvier
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>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
---
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 6978d4e867..480d165ebc 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"
@@ -3316,6 +3317,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);
@@ -3408,6 +3439,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 a48ed4f86a..fb2c531018 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -278,6 +278,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 8c34650765..e6bafb0601 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"
@@ -657,6 +658,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;
@@ -735,6 +770,7 @@ int whpx_init_vcpu(CPUState *cpu)
val.Reg64 = deposit64(arm_cpu->mp_affinity, 31, 1, 1 /* RES1 */);
whpx_set_reg(cpu, WHvArm64RegisterMpidrEl1, val);
+ clamp_id_aa64mmfr0_parange_to_ipa_size(&arm_cpu->isar);
return 0;
error:
@@ -757,6 +793,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 */
@@ -767,6 +805,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.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v10 20/28] hw/arm, accel/hvf, whpx: unify get_physical_address_range between WHPX and HVF
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (18 preceding siblings ...)
2025-10-29 16:55 ` [PATCH v10 19/28] whpx: arm64: clamp down IPA size Mohamed Mediouni
@ 2025-10-29 16:55 ` Mohamed Mediouni
2025-10-29 16:55 ` [PATCH v10 21/28] whpx: arm64: implement -cpu host Mohamed Mediouni
` (8 subsequent siblings)
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:55 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé, Pierrick Bouvier
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
---
accel/hvf/hvf-all.c | 7 +++++--
hw/arm/virt.c | 41 ++++----------------------------------
include/hw/boards.h | 4 ++--
include/system/hvf_int.h | 2 ++
target/arm/hvf-stub.c | 20 -------------------
target/arm/hvf/hvf.c | 6 +++---
target/arm/hvf_arm.h | 3 ---
target/arm/meson.build | 1 -
target/arm/whpx/whpx-all.c | 5 +++--
target/i386/hvf/hvf.c | 11 ++++++++++
10 files changed, 30 insertions(+), 70 deletions(-)
delete mode 100644 target/arm/hvf-stub.c
diff --git a/accel/hvf/hvf-all.c b/accel/hvf/hvf-all.c
index 0a4b498e83..8229ad8640 100644
--- a/accel/hvf/hvf-all.c
+++ b/accel/hvf/hvf-all.c
@@ -17,6 +17,7 @@
#include "system/hvf_int.h"
#include "hw/core/cpu.h"
#include "hw/boards.h"
+#include "target/arm/hvf_arm.h"
#include "trace.h"
bool hvf_allowed;
@@ -256,8 +257,10 @@ static int hvf_accel_init(AccelState *as, MachineState *ms)
int pa_range = 36;
MachineClass *mc = MACHINE_GET_CLASS(ms);
- if (mc->hvf_get_physical_address_range) {
- pa_range = mc->hvf_get_physical_address_range(ms);
+
+ if (mc->get_physical_address_range) {
+ pa_range = mc->get_physical_address_range(ms,
+ hvf_arch_get_default_ipa_bit_size(), hvf_arch_get_max_ipa_bit_size());
if (pa_range < 0) {
return -EINVAL;
}
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 480d165ebc..58fa657cae 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -3317,43 +3317,11 @@ 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)
+static int virt_get_physical_address_range(MachineState *ms,
+ int default_ipa_size, int max_ipa_size)
{
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);
-
- int default_ipa_size = hvf_arm_get_default_ipa_bit_size();
- int max_ipa_size = hvf_arm_get_max_ipa_bit_size();
-
/* We freeze the memory map to compute the highest gpa */
virt_set_memmap(vms, max_ipa_size);
@@ -3362,7 +3330,7 @@ static int virt_hvf_get_physical_address_range(MachineState *ms)
/*
* 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
+ * the maximum. hvf_arch_get_max_ipa_bit_size() conveniently only
* returns values that are valid ARM PARange values.
*/
if (requested_ipa_size <= default_ipa_size) {
@@ -3438,8 +3406,7 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
mc->valid_cpu_types = valid_cpu_types;
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;
+ mc->get_physical_address_range = virt_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 fb2c531018..fa5f71471d 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -277,8 +277,8 @@ struct MachineClass {
void (*reset)(MachineState *state, ResetType type);
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);
+ int (*get_physical_address_range)(MachineState *machine,
+ int default_ipa_size, int max_ipa_size);
BlockInterfaceType block_default_type;
int units_per_default_bus;
diff --git a/include/system/hvf_int.h b/include/system/hvf_int.h
index a3b06a3e75..8b6447c238 100644
--- a/include/system/hvf_int.h
+++ b/include/system/hvf_int.h
@@ -71,6 +71,8 @@ void assert_hvf_ok_impl(hv_return_t ret, const char *file, unsigned int line,
const char *hvf_return_string(hv_return_t ret);
int hvf_arch_init(void);
hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range);
+uint32_t hvf_arch_get_default_ipa_bit_size(void);
+uint32_t hvf_arch_get_max_ipa_bit_size(void);
int hvf_arch_init_vcpu(CPUState *cpu);
void hvf_arch_vcpu_destroy(CPUState *cpu);
int hvf_vcpu_exec(CPUState *);
diff --git a/target/arm/hvf-stub.c b/target/arm/hvf-stub.c
deleted file mode 100644
index ff137267a0..0000000000
--- a/target/arm/hvf-stub.c
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * QEMU Hypervisor.framework (HVF) stubs for ARM
- *
- * Copyright (c) Linaro
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#include "qemu/osdep.h"
-#include "hvf_arm.h"
-
-uint32_t hvf_arm_get_default_ipa_bit_size(void)
-{
- g_assert_not_reached();
-}
-
-uint32_t hvf_arm_get_max_ipa_bit_size(void)
-{
- g_assert_not_reached();
-}
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 0658a99a2d..ecca1a63ec 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -725,7 +725,7 @@ static uint64_t hvf_get_reg(CPUState *cpu, int rt)
static void clamp_id_aa64mmfr0_parange_to_ipa_size(ARMISARegisters *isar)
{
uint32_t ipa_size = chosen_ipa_bit_size ?
- chosen_ipa_bit_size : hvf_arm_get_max_ipa_bit_size();
+ chosen_ipa_bit_size : hvf_arch_get_max_ipa_bit_size();
uint64_t id_aa64mmfr0;
/* Clamp down the PARange to the IPA size the kernel supports. */
@@ -816,7 +816,7 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
return r == HV_SUCCESS;
}
-uint32_t hvf_arm_get_default_ipa_bit_size(void)
+uint32_t hvf_arch_get_default_ipa_bit_size(void)
{
uint32_t default_ipa_size;
hv_return_t ret = hv_vm_config_get_default_ipa_size(&default_ipa_size);
@@ -825,7 +825,7 @@ uint32_t hvf_arm_get_default_ipa_bit_size(void)
return default_ipa_size;
}
-uint32_t hvf_arm_get_max_ipa_bit_size(void)
+uint32_t hvf_arch_get_max_ipa_bit_size(void)
{
uint32_t max_ipa_size;
hv_return_t ret = hv_vm_config_get_max_ipa_size(&max_ipa_size);
diff --git a/target/arm/hvf_arm.h b/target/arm/hvf_arm.h
index ea82f2691d..5d19d82e5d 100644
--- a/target/arm/hvf_arm.h
+++ b/target/arm/hvf_arm.h
@@ -22,7 +22,4 @@ void hvf_arm_init_debug(void);
void hvf_arm_set_cpu_features_from_host(ARMCPU *cpu);
-uint32_t hvf_arm_get_default_ipa_bit_size(void);
-uint32_t hvf_arm_get_max_ipa_bit_size(void);
-
#endif
diff --git a/target/arm/meson.build b/target/arm/meson.build
index 61277a627c..9f2eb91635 100644
--- a/target/arm/meson.build
+++ b/target/arm/meson.build
@@ -41,7 +41,6 @@ arm_common_system_ss.add(files('cpu.c'))
arm_common_system_ss.add(when: 'TARGET_AARCH64', if_false: files(
'cpu32-stubs.c'))
arm_common_system_ss.add(when: 'CONFIG_KVM', if_false: files('kvm-stub.c'))
-arm_common_system_ss.add(when: 'CONFIG_HVF', if_false: files('hvf-stub.c'))
arm_common_system_ss.add(when: 'CONFIG_ARM_COMPATIBLE_SEMIHOSTING',
if_true: files('common-semi-target.c'))
arm_common_system_ss.add(files(
diff --git a/target/arm/whpx/whpx-all.c b/target/arm/whpx/whpx-all.c
index e6bafb0601..23c7beefaf 100644
--- a/target/arm/whpx/whpx-all.c
+++ b/target/arm/whpx/whpx-all.c
@@ -805,8 +805,9 @@ 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 (mc->get_physical_address_range) {
+ pa_range = mc->get_physical_address_range(ms,
+ whpx_arm_get_ipa_bit_size(), whpx_arm_get_ipa_bit_size());
if (pa_range < 0) {
return -EINVAL;
}
diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c
index 33f723a76a..1d7ec47f59 100644
--- a/target/i386/hvf/hvf.c
+++ b/target/i386/hvf/hvf.c
@@ -225,6 +225,17 @@ int hvf_arch_init(void)
return 0;
}
+/* 48-bit on all Intel Macs. Function currently unused. */
+uint32_t hvf_arch_get_default_ipa_bit_size(void)
+{
+ g_assert_not_reached();
+}
+
+uint32_t hvf_arch_get_max_ipa_bit_size(void)
+{
+ g_assert_not_reached();
+}
+
hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range)
{
return hv_vm_create(HV_VM_DEFAULT);
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v10 21/28] whpx: arm64: implement -cpu host
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (19 preceding siblings ...)
2025-10-29 16:55 ` [PATCH v10 20/28] hw/arm, accel/hvf, whpx: unify get_physical_address_range between WHPX and HVF Mohamed Mediouni
@ 2025-10-29 16:55 ` Mohamed Mediouni
2025-10-29 16:55 ` [PATCH v10 22/28] target/arm: whpx: instantiate GIC early Mohamed Mediouni
` (7 subsequent siblings)
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:55 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé, Pierrick Bouvier
Logic to fetch MIDR_EL1 for cpu 0 adapted from:
https://github.com/FEX-Emu/FEX/blob/e6de17e72ef03aa88ba14fa0ec13163061608c74/Source/Windows/Common/CPUFeatures.cpp#L62
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
---
hw/arm/virt.c | 2 +-
target/arm/cpu64.c | 19 ++++---
target/arm/whpx/whpx-all.c | 104 +++++++++++++++++++++++++++++++++++++
target/arm/whpx_arm.h | 1 +
4 files changed, 119 insertions(+), 7 deletions(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 58fa657cae..9ec3cf00f5 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -3371,7 +3371,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..3f00071081 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -26,10 +26,13 @@
#include "qemu/units.h"
#include "system/kvm.h"
#include "system/hvf.h"
+#include "system/whpx.h"
+#include "system/hw_accel.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 +525,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 (hwaccel_enabled()) {
/*
* Exit early if PAuth is enabled and fall through to disable it.
* The algorithm selection properties are not present.
@@ -599,10 +602,10 @@ 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 (hwaccel_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!
+ * property for HW accel. Is it just a bit backward? Yes it is!
* Note that prop_pauth is true whether the host CPU supports the
* architected QARMA5 algorithm or the IMPDEF one. We don't
* provide the separate pauth-impdef property for KVM or hvf,
@@ -773,6 +776,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,8 +787,8 @@ static void aarch64_host_initfn(Object *obj)
static void aarch64_max_initfn(Object *obj)
{
- if (kvm_enabled() || hvf_enabled()) {
- /* With KVM or HVF, '-cpu max' is identical to '-cpu host' */
+ if (hwaccel_enabled()) {
+ /* When hardware acceleration enabled, '-cpu max' is identical to '-cpu host' */
aarch64_host_initfn(obj);
return;
}
@@ -800,7 +807,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 23c7beefaf..8f0a54f080 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;
@@ -692,6 +703,99 @@ static void clamp_id_aa64mmfr0_parange_to_ipa_size(ARMISARegisters *isar)
SET_IDREG(isar, ID_AA64MMFR0, id_aa64mmfr0);
}
+static uint64_t whpx_read_midr(void)
+{
+ HKEY key;
+ uint64_t midr_el1;
+ DWORD size = sizeof(midr_el1);
+ const char *path = "Hardware\\Description\\System\\CentralProcessor\\0\\";
+ assert(!RegOpenKeyExA(HKEY_LOCAL_MACHINE, path, 0, KEY_READ, &key));
+ assert(!RegGetValueA(key, NULL, "CP 4000", RRF_RT_REG_QWORD, NULL, &midr_el1, &size));
+ RegCloseKey(key);
+ return midr_el1;
+}
+
+static bool whpx_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
+{
+ const struct isar_regs {
+ WHV_REGISTER_NAME reg;
+ uint64_t *val;
+ } regs[] = {
+ { WHvArm64RegisterIdAa64Pfr0El1, &ahcf->isar.idregs[ID_AA64PFR0_EL1_IDX] },
+ { WHvArm64RegisterIdAa64Pfr1El1, &ahcf->isar.idregs[ID_AA64PFR1_EL1_IDX] },
+ { WHvArm64RegisterIdAa64Dfr0El1, &ahcf->isar.idregs[ID_AA64DFR0_EL1_IDX] },
+ { WHvArm64RegisterIdAa64Dfr1El1 , &ahcf->isar.idregs[ID_AA64DFR1_EL1_IDX] },
+ { WHvArm64RegisterIdAa64Isar0El1, &ahcf->isar.idregs[ID_AA64ISAR0_EL1_IDX] },
+ { WHvArm64RegisterIdAa64Isar1El1, &ahcf->isar.idregs[ID_AA64ISAR1_EL1_IDX] },
+ { WHvArm64RegisterIdAa64Isar2El1, &ahcf->isar.idregs[ID_AA64ISAR2_EL1_IDX] },
+ { WHvArm64RegisterIdAa64Mmfr0El1, &ahcf->isar.idregs[ID_AA64MMFR0_EL1_IDX] },
+ { WHvArm64RegisterIdAa64Mmfr1El1, &ahcf->isar.idregs[ID_AA64MMFR1_EL1_IDX] },
+ { WHvArm64RegisterIdAa64Mmfr2El1, &ahcf->isar.idregs[ID_AA64MMFR2_EL1_IDX] },
+ { WHvArm64RegisterIdAa64Mmfr3El1, &ahcf->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.
+ */
+ ahcf->midr = whpx_read_midr();
+
+ clamp_id_aa64mmfr0_parange_to_ipa_size(&ahcf->isar);
+
+ /*
+ * Disable SVE, which is not supported by QEMU whpx yet.
+ * Work needed for SVE support:
+ * - SVE state save/restore
+ * - any potentially needed VL management
+ * Also disable SME at the same time. (not currently supported by Hyper-V)
+ */
+ SET_IDREG(&ahcf->isar, ID_AA64PFR0,
+ GET_IDREG(&ahcf->isar, ID_AA64PFR0) & ~R_ID_AA64PFR0_SVE_MASK);
+
+ SET_IDREG(&ahcf->isar, ID_AA64PFR1,
+ GET_IDREG(&ahcf->isar, ID_AA64PFR1) & ~R_ID_AA64PFR1_SME_MASK);
+
+ 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.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v10 22/28] target/arm: whpx: instantiate GIC early
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (20 preceding siblings ...)
2025-10-29 16:55 ` [PATCH v10 21/28] whpx: arm64: implement -cpu host Mohamed Mediouni
@ 2025-10-29 16:55 ` Mohamed Mediouni
2025-10-29 16:55 ` [PATCH v10 23/28] whpx: arm64: gicv3: add migration blocker Mohamed Mediouni
` (6 subsequent siblings)
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:55 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé, Pierrick Bouvier
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>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
---
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 8f0a54f080..4d58e5e939 100644
--- a/target/arm/whpx/whpx-all.c
+++ b/target/arm/whpx/whpx-all.c
@@ -973,6 +973,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.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v10 23/28] whpx: arm64: gicv3: add migration blocker
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (21 preceding siblings ...)
2025-10-29 16:55 ` [PATCH v10 22/28] target/arm: whpx: instantiate GIC early Mohamed Mediouni
@ 2025-10-29 16:55 ` Mohamed Mediouni
2025-10-29 16:55 ` [PATCH v10 24/28] whpx: enable arm64 builds Mohamed Mediouni
` (5 subsequent siblings)
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:55 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé, Pierrick Bouvier
GICv3 state save-restore is currently not implemented yet.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
---
hw/intc/arm_gicv3_whpx.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/hw/intc/arm_gicv3_whpx.c b/hw/intc/arm_gicv3_whpx.c
index 88a05e5901..6ceae78483 100644
--- a/hw/intc/arm_gicv3_whpx.c
+++ b/hw/intc/arm_gicv3_whpx.c
@@ -17,6 +17,7 @@
#include "system/whpx-internal.h"
#include "gicv3_internal.h"
#include "vgic_common.h"
+#include "migration/blocker.h"
#include "qom/object.h"
#include "target/arm/cpregs.h"
@@ -205,6 +206,15 @@ static void whpx_gicv3_realize(DeviceState *dev, Error **errp)
error_setg(errp, "Nested virtualisation not currently supported by WHPX.");
return;
}
+
+ Error *whpx_migration_blocker = NULL;
+
+ error_setg(&whpx_migration_blocker,
+ "Live migration disabled because GIC state save/restore not supported on WHPX");
+ if (migrate_add_blocker(&whpx_migration_blocker, errp)) {
+ error_free(whpx_migration_blocker);
+ return;
+ }
}
static void whpx_gicv3_class_init(ObjectClass *klass, const void *data)
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v10 24/28] whpx: enable arm64 builds
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (22 preceding siblings ...)
2025-10-29 16:55 ` [PATCH v10 23/28] whpx: arm64: gicv3: add migration blocker Mohamed Mediouni
@ 2025-10-29 16:55 ` Mohamed Mediouni
2025-10-29 16:55 ` [PATCH v10 25/28] MAINTAINERS: update maintainers for WHPX Mohamed Mediouni
` (4 subsequent siblings)
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:55 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé, Pierrick Bouvier
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
---
meson.build | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/meson.build b/meson.build
index 8ad37c992b..065cb1c493 100644
--- a/meson.build
+++ b/meson.build
@@ -325,7 +325,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 += {
@@ -891,13 +892,18 @@ if get_option('mshv').allowed() and host_os == 'linux'
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()
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v10 25/28] MAINTAINERS: update maintainers for WHPX
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (23 preceding siblings ...)
2025-10-29 16:55 ` [PATCH v10 24/28] whpx: enable arm64 builds Mohamed Mediouni
@ 2025-10-29 16:55 ` Mohamed Mediouni
2025-10-29 16:55 ` [PATCH v10 26/28] whpx: apic: use non-deprecated APIs to control interrupt controller state Mohamed Mediouni
` (3 subsequent siblings)
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:55 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé
And add arm64 files.
From Pedro Barbuda (on Teams):
> we meant to have that switched a while back. you can add me as the maintainer. Pedro Barbuda (pbarbuda@microsoft.com)
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
MAINTAINERS | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index c6b7f45459..0e7288116f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -546,11 +546,14 @@ F: accel/stubs/hvf-stub.c
F: include/system/hvf.h
F: include/system/hvf_int.h
-WHPX CPUs
-M: Sunil Muthuswamy <sunilmut@microsoft.com>
+WHPX
+M: Pedro Barbuda <pbarbuda@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.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v10 26/28] whpx: apic: use non-deprecated APIs to control interrupt controller state
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (24 preceding siblings ...)
2025-10-29 16:55 ` [PATCH v10 25/28] MAINTAINERS: update maintainers for WHPX Mohamed Mediouni
@ 2025-10-29 16:55 ` Mohamed Mediouni
2025-10-30 11:54 ` Bernhard Beschow
2025-10-29 16:55 ` [PATCH v10 27/28] whpx: arm64: check for physical address width after WHPX availability Mohamed Mediouni
` (2 subsequent siblings)
28 siblings, 1 reply; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:55 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé, Pierrick Bouvier
WHvGetVirtualProcessorInterruptControllerState2 and
WHvSetVirtualProcessorInterruptControllerState2 are
deprecated since Windows 10 version 2004.
Use the non-deprecated WHvGetVirtualProcessorState and
WHvSetVirtualProcessorState when available.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
---
include/system/whpx-internal.h | 9 +++++++
target/i386/whpx/whpx-apic.c | 46 +++++++++++++++++++++++++---------
2 files changed, 43 insertions(+), 12 deletions(-)
diff --git a/include/system/whpx-internal.h b/include/system/whpx-internal.h
index 81c0c1819f..90b4077b76 100644
--- a/include/system/whpx-internal.h
+++ b/include/system/whpx-internal.h
@@ -86,6 +86,15 @@ void whpx_apic_get(APICCommonState *s);
X(HRESULT, WHvSetVirtualProcessorInterruptControllerState2, \
(WHV_PARTITION_HANDLE Partition, UINT32 VpIndex, PVOID State, \
UINT32 StateSize)) \
+ X(HRESULT, WHvGetVirtualProcessorState, \
+ (WHV_PARTITION_HANDLE Partition, UINT32 VpIndex, \
+ WHV_VIRTUAL_PROCESSOR_STATE_TYPE StateType, PVOID Buffer, \
+ UINT32 BufferSizeInBytes, UINT32 *BytesWritten)) \
+ X(HRESULT, WHvSetVirtualProcessorState, \
+ (WHV_PARTITION_HANDLE Partition, UINT32 VpIndex, \
+ WHV_VIRTUAL_PROCESSOR_STATE_TYPE StateType, PVOID Buffer, \
+ UINT32 BufferSizeInBytes)) \
+
#define LIST_WINHVEMULATION_FUNCTIONS(X) \
X(HRESULT, WHvEmulatorCreateEmulator, (const WHV_EMULATOR_CALLBACKS* Callbacks, WHV_EMULATOR_HANDLE* Emulator)) \
diff --git a/target/i386/whpx/whpx-apic.c b/target/i386/whpx/whpx-apic.c
index b934fdcbe1..fa45a64b21 100644
--- a/target/i386/whpx/whpx-apic.c
+++ b/target/i386/whpx/whpx-apic.c
@@ -137,11 +137,21 @@ static void whpx_apic_put(CPUState *cs, run_on_cpu_data data)
whpx_put_apic_base(CPU(s->cpu), s->apicbase);
whpx_put_apic_state(s, &kapic);
- hr = whp_dispatch.WHvSetVirtualProcessorInterruptControllerState2(
- whpx_global.partition,
- cs->cpu_index,
- &kapic,
- sizeof(kapic));
+ if (whp_dispatch.WHvSetVirtualProcessorState) {
+ hr = whp_dispatch.WHvSetVirtualProcessorState(
+ whpx_global.partition,
+ cs->cpu_index,
+ WHvVirtualProcessorStateTypeInterruptControllerState2,
+ &kapic,
+ sizeof(kapic));
+ } else {
+ hr = whp_dispatch.WHvSetVirtualProcessorInterruptControllerState2(
+ whpx_global.partition,
+ cs->cpu_index,
+ &kapic,
+ sizeof(kapic));
+ }
+
if (FAILED(hr)) {
fprintf(stderr,
"WHvSetVirtualProcessorInterruptControllerState failed: %08lx\n",
@@ -155,16 +165,28 @@ void whpx_apic_get(APICCommonState *s)
{
CPUState *cpu = CPU(s->cpu);
struct whpx_lapic_state kapic;
+ HRESULT hr;
+
+ if (whp_dispatch.WHvGetVirtualProcessorState) {
+ hr = whp_dispatch.WHvGetVirtualProcessorState(
+ whpx_global.partition,
+ cpu->cpu_index,
+ WHvVirtualProcessorStateTypeInterruptControllerState2,
+ &kapic,
+ sizeof(kapic),
+ NULL);
+ } else {
+ hr = whp_dispatch.WHvGetVirtualProcessorInterruptControllerState2(
+ whpx_global.partition,
+ cpu->cpu_index,
+ &kapic,
+ sizeof(kapic),
+ NULL);
+ }
- HRESULT hr = whp_dispatch.WHvGetVirtualProcessorInterruptControllerState2(
- whpx_global.partition,
- cpu->cpu_index,
- &kapic,
- sizeof(kapic),
- NULL);
if (FAILED(hr)) {
fprintf(stderr,
- "WHvSetVirtualProcessorInterruptControllerState failed: %08lx\n",
+ "WHvGetVirtualProcessorInterruptControllerState failed: %08lx\n",
hr);
abort();
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* Re: [PATCH v10 26/28] whpx: apic: use non-deprecated APIs to control interrupt controller state
2025-10-29 16:55 ` [PATCH v10 26/28] whpx: apic: use non-deprecated APIs to control interrupt controller state Mohamed Mediouni
@ 2025-10-30 11:54 ` Bernhard Beschow
0 siblings, 0 replies; 36+ messages in thread
From: Bernhard Beschow @ 2025-10-30 11:54 UTC (permalink / raw)
To: qemu-devel, Mohamed Mediouni, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé, Pierrick Bouvier
Am 29. Oktober 2025 16:55:08 UTC schrieb Mohamed Mediouni <mohamed@unpredictable.fr>:
>WHvGetVirtualProcessorInterruptControllerState2 and
>WHvSetVirtualProcessorInterruptControllerState2 are
>deprecated since Windows 10 version 2004.
>
>Use the non-deprecated WHvGetVirtualProcessorState and
>WHvSetVirtualProcessorState when available.
I still have to revert this patch to avoid termination of the VM.
Best regards,
Bernhard
>
>Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
>
>Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
>---
> include/system/whpx-internal.h | 9 +++++++
> target/i386/whpx/whpx-apic.c | 46 +++++++++++++++++++++++++---------
> 2 files changed, 43 insertions(+), 12 deletions(-)
>
>diff --git a/include/system/whpx-internal.h b/include/system/whpx-internal.h
>index 81c0c1819f..90b4077b76 100644
>--- a/include/system/whpx-internal.h
>+++ b/include/system/whpx-internal.h
>@@ -86,6 +86,15 @@ void whpx_apic_get(APICCommonState *s);
> X(HRESULT, WHvSetVirtualProcessorInterruptControllerState2, \
> (WHV_PARTITION_HANDLE Partition, UINT32 VpIndex, PVOID State, \
> UINT32 StateSize)) \
>+ X(HRESULT, WHvGetVirtualProcessorState, \
>+ (WHV_PARTITION_HANDLE Partition, UINT32 VpIndex, \
>+ WHV_VIRTUAL_PROCESSOR_STATE_TYPE StateType, PVOID Buffer, \
>+ UINT32 BufferSizeInBytes, UINT32 *BytesWritten)) \
>+ X(HRESULT, WHvSetVirtualProcessorState, \
>+ (WHV_PARTITION_HANDLE Partition, UINT32 VpIndex, \
>+ WHV_VIRTUAL_PROCESSOR_STATE_TYPE StateType, PVOID Buffer, \
>+ UINT32 BufferSizeInBytes)) \
>+
>
> #define LIST_WINHVEMULATION_FUNCTIONS(X) \
> X(HRESULT, WHvEmulatorCreateEmulator, (const WHV_EMULATOR_CALLBACKS* Callbacks, WHV_EMULATOR_HANDLE* Emulator)) \
>diff --git a/target/i386/whpx/whpx-apic.c b/target/i386/whpx/whpx-apic.c
>index b934fdcbe1..fa45a64b21 100644
>--- a/target/i386/whpx/whpx-apic.c
>+++ b/target/i386/whpx/whpx-apic.c
>@@ -137,11 +137,21 @@ static void whpx_apic_put(CPUState *cs, run_on_cpu_data data)
> whpx_put_apic_base(CPU(s->cpu), s->apicbase);
> whpx_put_apic_state(s, &kapic);
>
>- hr = whp_dispatch.WHvSetVirtualProcessorInterruptControllerState2(
>- whpx_global.partition,
>- cs->cpu_index,
>- &kapic,
>- sizeof(kapic));
>+ if (whp_dispatch.WHvSetVirtualProcessorState) {
>+ hr = whp_dispatch.WHvSetVirtualProcessorState(
>+ whpx_global.partition,
>+ cs->cpu_index,
>+ WHvVirtualProcessorStateTypeInterruptControllerState2,
>+ &kapic,
>+ sizeof(kapic));
>+ } else {
>+ hr = whp_dispatch.WHvSetVirtualProcessorInterruptControllerState2(
>+ whpx_global.partition,
>+ cs->cpu_index,
>+ &kapic,
>+ sizeof(kapic));
>+ }
>+
> if (FAILED(hr)) {
> fprintf(stderr,
> "WHvSetVirtualProcessorInterruptControllerState failed: %08lx\n",
>@@ -155,16 +165,28 @@ void whpx_apic_get(APICCommonState *s)
> {
> CPUState *cpu = CPU(s->cpu);
> struct whpx_lapic_state kapic;
>+ HRESULT hr;
>+
>+ if (whp_dispatch.WHvGetVirtualProcessorState) {
>+ hr = whp_dispatch.WHvGetVirtualProcessorState(
>+ whpx_global.partition,
>+ cpu->cpu_index,
>+ WHvVirtualProcessorStateTypeInterruptControllerState2,
>+ &kapic,
>+ sizeof(kapic),
>+ NULL);
>+ } else {
>+ hr = whp_dispatch.WHvGetVirtualProcessorInterruptControllerState2(
>+ whpx_global.partition,
>+ cpu->cpu_index,
>+ &kapic,
>+ sizeof(kapic),
>+ NULL);
>+ }
>
>- HRESULT hr = whp_dispatch.WHvGetVirtualProcessorInterruptControllerState2(
>- whpx_global.partition,
>- cpu->cpu_index,
>- &kapic,
>- sizeof(kapic),
>- NULL);
> if (FAILED(hr)) {
> fprintf(stderr,
>- "WHvSetVirtualProcessorInterruptControllerState failed: %08lx\n",
>+ "WHvGetVirtualProcessorInterruptControllerState failed: %08lx\n",
> hr);
>
> abort();
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH v10 27/28] whpx: arm64: check for physical address width after WHPX availability
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (25 preceding siblings ...)
2025-10-29 16:55 ` [PATCH v10 26/28] whpx: apic: use non-deprecated APIs to control interrupt controller state Mohamed Mediouni
@ 2025-10-29 16:55 ` Mohamed Mediouni
2025-10-29 16:55 ` [PATCH v10 28/28] whpx: arm64: add partition-wide reset on the reboot path Mohamed Mediouni
2025-10-29 20:22 ` [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:55 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé
In the case where WHPX isn't supported on the platform, makes the
intended error appear instead of failing at getting the IPA width.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
target/arm/whpx/whpx-all.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/target/arm/whpx/whpx-all.c b/target/arm/whpx/whpx-all.c
index 4d58e5e939..ce1794952c 100644
--- a/target/arm/whpx/whpx-all.c
+++ b/target/arm/whpx/whpx-all.c
@@ -678,7 +678,7 @@ uint32_t whpx_arm_get_ipa_bit_size(void)
WHvCapabilityCodePhysicalAddressWidth, &whpx_cap,
sizeof(whpx_cap), &whpx_cap_size);
if (FAILED(hr)) {
- error_report("WHPX: failed to get supported"
+ error_report("WHPX: failed to get supported "
"physical address width, hr=%08lx", hr);
}
@@ -909,14 +909,6 @@ int whpx_accel_init(AccelState *as, MachineState *ms)
goto error;
}
- if (mc->get_physical_address_range) {
- pa_range = mc->get_physical_address_range(ms,
- whpx_arm_get_ipa_bit_size(), whpx_arm_get_ipa_bit_size());
- if (pa_range < 0) {
- return -EINVAL;
- }
- }
-
whpx->mem_quota = ms->ram_size;
hr = whp_dispatch.WHvGetCapability(
@@ -943,6 +935,14 @@ int whpx_accel_init(AccelState *as, MachineState *ms)
goto error;
}
+ if (mc->get_physical_address_range) {
+ pa_range = mc->get_physical_address_range(ms,
+ whpx_arm_get_ipa_bit_size(), whpx_arm_get_ipa_bit_size());
+ if (pa_range < 0) {
+ return -EINVAL;
+ }
+ }
+
hr = whp_dispatch.WHvCreatePartition(&whpx->partition);
if (FAILED(hr)) {
error_report("WHPX: Failed to create partition, hr=%08lx", hr);
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v10 28/28] whpx: arm64: add partition-wide reset on the reboot path
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (26 preceding siblings ...)
2025-10-29 16:55 ` [PATCH v10 27/28] whpx: arm64: check for physical address width after WHPX availability Mohamed Mediouni
@ 2025-10-29 16:55 ` Mohamed Mediouni
2025-10-29 20:22 ` [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 16:55 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé
This resets non-architectural state to allow for reboots to succeed.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
include/system/whpx-internal.h | 2 ++
target/arm/whpx/whpx-all.c | 2 ++
2 files changed, 4 insertions(+)
diff --git a/include/system/whpx-internal.h b/include/system/whpx-internal.h
index 90b4077b76..40918c025f 100644
--- a/include/system/whpx-internal.h
+++ b/include/system/whpx-internal.h
@@ -94,6 +94,8 @@ void whpx_apic_get(APICCommonState *s);
(WHV_PARTITION_HANDLE Partition, UINT32 VpIndex, \
WHV_VIRTUAL_PROCESSOR_STATE_TYPE StateType, PVOID Buffer, \
UINT32 BufferSizeInBytes)) \
+ X(HRESULT, WHvResetPartition, \
+ (WHV_PARTITION_HANDLE Partition)) \
#define LIST_WINHVEMULATION_FUNCTIONS(X) \
diff --git a/target/arm/whpx/whpx-all.c b/target/arm/whpx/whpx-all.c
index ce1794952c..c558ab8613 100644
--- a/target/arm/whpx/whpx-all.c
+++ b/target/arm/whpx/whpx-all.c
@@ -497,6 +497,8 @@ int whpx_vcpu_run(CPUState *cpu)
if (arm_cpu->power_state != PSCI_OFF) {
whpx_psci_cpu_off(arm_cpu);
}
+ /* Partition-wide reset, to reset state for reboots to succeed. */
+ whp_dispatch.WHvResetPartition(whpx->partition);
bql_unlock();
break;
case WHvRunVpExitReasonNone:
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 36+ messages in thread* Re: [PATCH v10 00/28] WHPX support for Arm
2025-10-29 16:54 [PATCH v10 00/28] WHPX support for Arm Mohamed Mediouni
` (27 preceding siblings ...)
2025-10-29 16:55 ` [PATCH v10 28/28] whpx: arm64: add partition-wide reset on the reboot path Mohamed Mediouni
@ 2025-10-29 20:22 ` Mohamed Mediouni
28 siblings, 0 replies; 36+ messages in thread
From: Mohamed Mediouni @ 2025-10-29 20:22 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Pedro Barbuda, Paolo Bonzini, qemu-arm, Alexander Graf,
Peter Maydell, Phil Dennis-Jordan, Richard Henderson,
Philippe Mathieu-Daudé
> On 29. Oct 2025, at 17:54, Mohamed Mediouni <mohamed@unpredictable.fr> wrote:
>
> Link to branch: https://github.com/mediouni-m/qemu whpx (tag for this submission: whpx-v10)
>
> And yet another note:
> On build 26200 on Snapdragon X, I often observe CLOCK_WATCHDOG_TIMEOUT BSoDs _on the host_ when using WHPX qemu. This is currently
> being looked at. This also affects prior revisions of this patch series.
More details on that:
When specifying both -cpu to a valid value _and_ -bios to firmware (or the pflash arguments), Qemu will work.
When not doing that, the host OS will crash with a BSoD.
Currently taking further a look into that...
Thank you,
^ permalink raw reply [flat|nested] 36+ messages in thread