* [PATCH v18 01/22] target/arm/kvm: add constants for new PSCI versions
2026-01-27 18:27 [PATCH v18 00/22] WHPX support for Arm Mohamed Mediouni
@ 2026-01-27 18:27 ` Mohamed Mediouni
2026-01-28 8:14 ` Philippe Mathieu-Daudé
2026-01-27 18:27 ` [PATCH v18 02/22] accel/system: Introduce hwaccel_enabled() helper Mohamed Mediouni
` (20 subsequent siblings)
21 siblings, 1 reply; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-27 18:27 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Zhao Liu, Michael S. Tsirkin, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Philippe Mathieu-Daudé,
Yanan Wang, Akihiko Odaki, Marcel Apfelbaum, Pedro Barbuda,
Richard Henderson, Paolo Bonzini, Marc-André Lureau,
Shannon Zhao, Igor Mammedov, Cameron Esfahani, Alexander Graf,
Peter Maydell, Eduardo Habkost, Phil Dennis-Jordan, 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>
Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
---
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] 35+ messages in thread* Re: [PATCH v18 01/22] target/arm/kvm: add constants for new PSCI versions
2026-01-27 18:27 ` [PATCH v18 01/22] target/arm/kvm: add constants for new PSCI versions Mohamed Mediouni
@ 2026-01-28 8:14 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 35+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-01-28 8:14 UTC (permalink / raw)
To: Mohamed Mediouni, qemu-devel
Cc: Zhao Liu, Michael S. Tsirkin, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Yanan Wang, Akihiko Odaki,
Marcel Apfelbaum, Pedro Barbuda, Richard Henderson, Paolo Bonzini,
Marc-André Lureau, Shannon Zhao, Igor Mammedov,
Cameron Esfahani, Alexander Graf, Peter Maydell, Eduardo Habkost,
Phil Dennis-Jordan, Sebastian Ott, Pierrick Bouvier
On 27/1/26 19:27, Mohamed Mediouni wrote:
> 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>
> Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
> ---
> target/arm/kvm-consts.h | 2 ++
> 1 file changed, 2 insertions(+)
As in v17
(https://lore.kernel.org/qemu-devel/fe7038e9-5675-43da-b75c-d7c316b14ea7@linaro.org/):
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH v18 02/22] accel/system: Introduce hwaccel_enabled() helper
2026-01-27 18:27 [PATCH v18 00/22] WHPX support for Arm Mohamed Mediouni
2026-01-27 18:27 ` [PATCH v18 01/22] target/arm/kvm: add constants for new PSCI versions Mohamed Mediouni
@ 2026-01-27 18:27 ` Mohamed Mediouni
2026-01-27 18:27 ` [PATCH v18 03/22] qtest: hw/arm: virt: skip ACPI test for IORT with GICv2 Mohamed Mediouni
` (19 subsequent siblings)
21 siblings, 0 replies; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-27 18:27 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Zhao Liu, Michael S. Tsirkin, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Philippe Mathieu-Daudé,
Yanan Wang, Akihiko Odaki, Marcel Apfelbaum, Pedro Barbuda,
Richard Henderson, Paolo Bonzini, Marc-André Lureau,
Shannon Zhao, Igor Mammedov, Cameron Esfahani, Alexander Graf,
Peter Maydell, Eduardo Habkost, Phil Dennis-Jordan,
Pierrick Bouvier
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>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
---
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] 35+ messages in thread* [PATCH v18 03/22] qtest: hw/arm: virt: skip ACPI test for IORT with GICv2
2026-01-27 18:27 [PATCH v18 00/22] WHPX support for Arm Mohamed Mediouni
2026-01-27 18:27 ` [PATCH v18 01/22] target/arm/kvm: add constants for new PSCI versions Mohamed Mediouni
2026-01-27 18:27 ` [PATCH v18 02/22] accel/system: Introduce hwaccel_enabled() helper Mohamed Mediouni
@ 2026-01-27 18:27 ` Mohamed Mediouni
2026-01-27 18:27 ` [PATCH v18 04/22] hw: arm: virt: rework MSI-X configuration Mohamed Mediouni
` (18 subsequent siblings)
21 siblings, 0 replies; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-27 18:27 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Zhao Liu, Michael S. Tsirkin, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Philippe Mathieu-Daudé,
Yanan Wang, Akihiko Odaki, Marcel Apfelbaum, Pedro Barbuda,
Richard Henderson, Paolo Bonzini, Marc-André Lureau,
Shannon Zhao, Igor Mammedov, Cameron Esfahani, Alexander Graf,
Peter Maydell, Eduardo Habkost, Phil Dennis-Jordan
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
tests/qtest/bios-tables-test-allowed-diff.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h
index dfb8523c8b..7acaf464dd 100644
--- a/tests/qtest/bios-tables-test-allowed-diff.h
+++ b/tests/qtest/bios-tables-test-allowed-diff.h
@@ -1 +1,4 @@
/* List of comma-separated changed AML files to ignore */
+"tests/data/acpi/aarch64/virt/IORT",
+"tests/data/acpi/aarch64/virt/IORT.smmuv3-dev",
+"tests/data/acpi/aarch64/virt/IORT.smmuv3-legacy",
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PATCH v18 04/22] hw: arm: virt: rework MSI-X configuration
2026-01-27 18:27 [PATCH v18 00/22] WHPX support for Arm Mohamed Mediouni
` (2 preceding siblings ...)
2026-01-27 18:27 ` [PATCH v18 03/22] qtest: hw/arm: virt: skip ACPI test for IORT with GICv2 Mohamed Mediouni
@ 2026-01-27 18:27 ` Mohamed Mediouni
2026-01-29 15:21 ` Peter Maydell
2026-01-27 18:27 ` [PATCH v18 05/22] tests: data: update AArch64 ACPI tables Mohamed Mediouni
` (17 subsequent siblings)
21 siblings, 1 reply; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-27 18:27 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Zhao Liu, Michael S. Tsirkin, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Philippe Mathieu-Daudé,
Yanan Wang, Akihiko Odaki, Marcel Apfelbaum, Pedro Barbuda,
Richard Henderson, Paolo Bonzini, Marc-André Lureau,
Shannon Zhao, Igor Mammedov, Cameron Esfahani, Alexander Graf,
Peter Maydell, Eduardo Habkost, Phil Dennis-Jordan
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 | 20 ++++---
hw/arm/virt.c | 112 ++++++++++++++++++++++++++++++++++++---
include/hw/arm/virt.h | 5 +-
3 files changed, 121 insertions(+), 16 deletions(-)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 03b4342574..f87bf1bf2f 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -473,7 +473,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 (vms->msi_controller == VIRT_MSI_CTRL_ITS) {
/*
* 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.
@@ -484,7 +484,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
rc_mapping_count += rc_its_idmaps->len;
}
} else {
- if (vms->its) {
+ if (vms->msi_controller == VIRT_MSI_CTRL_ITS) {
nb_nodes = 2; /* RC and ITS */
rc_mapping_count = 1; /* Direct map to ITS */
} else {
@@ -499,7 +499,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 (vms->msi_controller == VIRT_MSI_CTRL_ITS) {
/* 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 */;
@@ -518,7 +518,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 (vms->msi_controller == VIRT_MSI_CTRL_ITS) {
smmu_mapping_count = 1; /* ITS Group node */
offset_to_id_array = SMMU_V3_ENTRY_SIZE; /* Just after the header */
} else {
@@ -611,7 +611,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
}
}
- if (vms->its) {
+ if (vms->msi_controller == VIRT_MSI_CTRL_ITS) {
/*
* Map bypassed (don't go through the SMMU) RIDs (input) to
* ITS Group node directly: RC -> ITS.
@@ -629,7 +629,9 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
* SMMU: RC -> ITS.
* Output IORT node is the ITS Group node (the first node).
*/
- build_iort_id_mapping(table_data, 0, 0x10000, IORT_NODE_OFFSET);
+ if (vms->msi_controller == VIRT_MSI_CTRL_ITS) {
+ build_iort_id_mapping(table_data, 0, 0x10000, IORT_NODE_OFFSET);
+ }
}
acpi_table_end(linker, &table);
@@ -946,7 +948,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
memmap[VIRT_HIGH_GIC_REDIST2].size);
}
- if (vms->its) {
+ if (vms->msi_controller == VIRT_MSI_CTRL_ITS) {
/*
* ACPI spec, Revision 6.0 Errata A
* (original 6.0 definition has invalid Length)
@@ -960,7 +962,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->msi_controller == VIRT_MSI_CTRL_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 4badc1a734..3d7f02ce0e 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -737,7 +737,7 @@ static void create_its(VirtMachineState *vms)
{
DeviceState *dev;
- assert(vms->its);
+ assert(vms->msi_controller == VIRT_MSI_CTRL_ITS);
if (!kvm_irqchip_in_kernel() && !vms->tcg_its) {
/*
* Do nothing if ITS is neither supported by the host nor emulated by
@@ -957,9 +957,9 @@ 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->msi_controller == VIRT_MSI_CTRL_ITS) {
create_its(vms);
- } else if (vms->gic_version == VIRT_GIC_VERSION_2) {
+ } else if (vms->msi_controller == VIRT_MSI_CTRL_GICV2M) {
create_v2m(vms);
}
}
@@ -2132,6 +2132,36 @@ static void finalize_gic_version(VirtMachineState *vms)
gics_supported, max_cpus);
}
+static void finalize_msi_controller(VirtMachineState *vms)
+{
+ if (vms->msi_controller == VIRT_MSI_LEGACY_OPT_ITS_OFF) {
+ if (vms->gic_version == 2) {
+ vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
+ }
+ else {
+ vms->msi_controller = VIRT_MSI_CTRL_NONE;
+ }
+ }
+ if (vms->msi_controller == VIRT_MSI_CTRL_AUTO) {
+ if (vms->gic_version == VIRT_GIC_VERSION_2) {
+ vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
+ }
+ else {
+ vms->msi_controller = VIRT_MSI_CTRL_ITS;
+ }
+ }
+
+ if (vms->msi_controller == VIRT_MSI_CTRL_ITS) {
+ if (vms->gic_version == VIRT_GIC_VERSION_2) {
+ /* Older Qemu releases accepted this, but better to error. */
+ error_report("GICv2 + ITS is an invalid configuration.");
+ exit(1);
+ }
+ }
+
+ assert(vms->msi_controller != VIRT_MSI_CTRL_AUTO);
+}
+
/*
* virt_post_cpus_gic_realized() must be called after the CPUs and
* the GIC have both been realized.
@@ -2251,6 +2281,7 @@ static void machvirt_init(MachineState *machine)
* KVM is not available yet
*/
finalize_gic_version(vms);
+ finalize_msi_controller(vms);
if (vms->secure) {
/*
@@ -2700,18 +2731,76 @@ static void virt_set_highmem_mmio_size(Object *obj, Visitor *v,
extended_memmap[VIRT_HIGH_PCIE_MMIO].size = size;
}
+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:
+ case VIRT_MSI_LEGACY_OPT_ITS_OFF:
+ val = "off";
+ break;
+ case VIRT_MSI_CTRL_ITS:
+ val = "its";
+ break;
+ case VIRT_MSI_CTRL_GICV2M:
+ val = "gicv2m";
+ break;
+ case VIRT_MSI_CTRL_AUTO:
+ val = "auto";
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ return g_strdup(val);
+}
+
+static void virt_set_msi(Object *obj, const char *value, Error **errp)
+{
+ ERRP_GUARD();
+ VirtMachineState *vms = VIRT_MACHINE(obj);
+
+ 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 bool virt_get_its(Object *obj, Error **errp)
{
VirtMachineState *vms = VIRT_MACHINE(obj);
- return vms->its;
+ switch (vms->msi_controller) {
+ case VIRT_MSI_CTRL_AUTO:
+ case VIRT_MSI_CTRL_ITS:
+ return true;
+ case VIRT_MSI_CTRL_NONE:
+ case VIRT_MSI_CTRL_GICV2M:
+ case VIRT_MSI_LEGACY_OPT_ITS_OFF:
+ return false;
+ default:
+ g_assert_not_reached();
+ }
}
static void virt_set_its(Object *obj, bool value, Error **errp)
{
VirtMachineState *vms = VIRT_MACHINE(obj);
- vms->its = value;
+ if (value) {
+ vms->msi_controller = VIRT_MSI_CTRL_ITS;
+ } else {
+ vms->msi_controller = VIRT_MSI_LEGACY_OPT_ITS_OFF;
+ }
}
static bool virt_get_dtb_randomness(Object *obj, Error **errp)
@@ -3038,6 +3127,9 @@ 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:
+ case VIRT_MSI_LEGACY_OPT_ITS_OFF:
+ g_assert_not_reached();
}
resv_prop_str = g_strdup_printf("0x%"PRIx64":0x%"PRIx64":%u",
db_start, db_end,
@@ -3438,6 +3530,12 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
"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);
@@ -3493,8 +3591,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->msi_controller = VIRT_MSI_CTRL_AUTO;
/* Allow ITS emulation if the machine version supports it */
vms->tcg_its = !vmc->no_tcg_its;
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 5907d41dbb..d384355c4a 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -101,6 +101,10 @@ typedef enum VirtIOMMUType {
typedef enum VirtMSIControllerType {
VIRT_MSI_CTRL_NONE,
+ /* This value is overriden at runtime.*/
+ VIRT_MSI_CTRL_AUTO,
+ /* Legacy option: its=off provides a GICv2m when using GICv2 */
+ VIRT_MSI_LEGACY_OPT_ITS_OFF,
VIRT_MSI_CTRL_GICV2M,
VIRT_MSI_CTRL_ITS,
} VirtMSIControllerType;
@@ -146,7 +150,6 @@ struct VirtMachineState {
bool highmem_ecam;
bool highmem_mmio;
bool highmem_redists;
- bool its;
bool tcg_its;
bool virt;
bool ras;
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 35+ messages in thread* Re: [PATCH v18 04/22] hw: arm: virt: rework MSI-X configuration
2026-01-27 18:27 ` [PATCH v18 04/22] hw: arm: virt: rework MSI-X configuration Mohamed Mediouni
@ 2026-01-29 15:21 ` Peter Maydell
0 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-01-29 15:21 UTC (permalink / raw)
To: Mohamed Mediouni
Cc: qemu-devel, Zhao Liu, Michael S. Tsirkin, Roman Bolshakov,
qemu-arm, Ani Sinha, Daniel P. Berrangé,
Philippe Mathieu-Daudé, Yanan Wang, Akihiko Odaki,
Marcel Apfelbaum, Pedro Barbuda, Richard Henderson, Paolo Bonzini,
Marc-André Lureau, Shannon Zhao, Igor Mammedov,
Cameron Esfahani, Alexander Graf, Eduardo Habkost,
Phil Dennis-Jordan
On Tue, 27 Jan 2026 at 18:28, Mohamed Mediouni <mohamed@unpredictable.fr> wrote:
>
> 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 | 20 ++++---
> hw/arm/virt.c | 112 ++++++++++++++++++++++++++++++++++++---
> include/hw/arm/virt.h | 5 +-
> 3 files changed, 121 insertions(+), 16 deletions(-)
>
> diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
> index 03b4342574..f87bf1bf2f 100644
> --- a/hw/arm/virt-acpi-build.c
> +++ b/hw/arm/virt-acpi-build.c
You'll find the SMMUv3 acceleration changes produce some minor
conflicts in this file that you'll need to sort out.
The rest below here is minor stuff.
> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
> index 4badc1a734..3d7f02ce0e 100644
> --- a/hw/arm/virt.c
> +++ b/hw/arm/virt.c
> @@ -737,7 +737,7 @@ static void create_its(VirtMachineState *vms)
> {
> DeviceState *dev;
>
> - assert(vms->its);
> + assert(vms->msi_controller == VIRT_MSI_CTRL_ITS);
I think we colud now simply drop this assert, given the simplicity
of the calling logic.
> if (!kvm_irqchip_in_kernel() && !vms->tcg_its) {
> /*
> * Do nothing if ITS is neither supported by the host nor emulated by
> @@ -957,9 +957,9 @@ 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->msi_controller == VIRT_MSI_CTRL_ITS) {
> create_its(vms);
> - } else if (vms->gic_version == VIRT_GIC_VERSION_2) {
> + } else if (vms->msi_controller == VIRT_MSI_CTRL_GICV2M) {
> create_v2m(vms);
> }
> }
> @@ -2132,6 +2132,36 @@ static void finalize_gic_version(VirtMachineState *vms)
> gics_supported, max_cpus);
> }
>
> +static void finalize_msi_controller(VirtMachineState *vms)
> +{
> + if (vms->msi_controller == VIRT_MSI_LEGACY_OPT_ITS_OFF) {
> + if (vms->gic_version == 2) {
> + vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
> + }
> + else {
> + vms->msi_controller = VIRT_MSI_CTRL_NONE;
> + }
This needs commentary to explain why it is doing what it's
doing.
> + }
> + if (vms->msi_controller == VIRT_MSI_CTRL_AUTO) {
> + if (vms->gic_version == VIRT_GIC_VERSION_2) {
> + vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
> + }
> + else {
> + vms->msi_controller = VIRT_MSI_CTRL_ITS;
> + }
> + }
> +
> + if (vms->msi_controller == VIRT_MSI_CTRL_ITS) {
> + if (vms->gic_version == VIRT_GIC_VERSION_2) {
> + /* Older Qemu releases accepted this, but better to error. */
"QEMU" is all-caps.
Also, do you mean "older QEMU releases accepted the command line,
and we now error"? Generally we shouldn't do that. If you mean
"the old legacy its= option permits this, but the new msi= one
diagnoses it as an error", the comment could be clearer.
> + error_report("GICv2 + ITS is an invalid configuration.");
> + exit(1);
> + }
> + }
> +
> + assert(vms->msi_controller != VIRT_MSI_CTRL_AUTO);
> +}
> +
> +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:
> + case VIRT_MSI_LEGACY_OPT_ITS_OFF:
> + val = "off";
> + break;
> + case VIRT_MSI_CTRL_ITS:
> + val = "its";
> + break;
> + case VIRT_MSI_CTRL_GICV2M:
> + val = "gicv2m";
> + break;
> + case VIRT_MSI_CTRL_AUTO:
> + val = "auto";
> + break;
> + default:
> + g_assert_not_reached();
> + }
> + return g_strdup(val);
> +}
> +
> +static void virt_set_msi(Object *obj, const char *value, Error **errp)
> +{
> + ERRP_GUARD();
> + VirtMachineState *vms = VIRT_MACHINE(obj);
> +
> + 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")) {
Everywhere else seems to use "off" for the fourth value of
this option (so auto, its, gicv2m, off), but here we have "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");
> + }
> +}
> + 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");
We use '/' for 'on/off' but list all the values like
"Valid values are 2, 3, 4, host and max" for a set of strings.
thanks
-- PMM
^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH v18 05/22] tests: data: update AArch64 ACPI tables
2026-01-27 18:27 [PATCH v18 00/22] WHPX support for Arm Mohamed Mediouni
` (3 preceding siblings ...)
2026-01-27 18:27 ` [PATCH v18 04/22] hw: arm: virt: rework MSI-X configuration Mohamed Mediouni
@ 2026-01-27 18:27 ` Mohamed Mediouni
2026-01-29 13:36 ` Peter Maydell
2026-01-27 18:27 ` [PATCH v18 06/22] qtest: hw/arm: virt: add new test case for GICv3 + GICv2m Mohamed Mediouni
` (16 subsequent siblings)
21 siblings, 1 reply; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-27 18:27 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Zhao Liu, Michael S. Tsirkin, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Philippe Mathieu-Daudé,
Yanan Wang, Akihiko Odaki, Marcel Apfelbaum, Pedro Barbuda,
Richard Henderson, Paolo Bonzini, Marc-André Lureau,
Shannon Zhao, Igor Mammedov, Cameron Esfahani, Alexander Graf,
Peter Maydell, Eduardo Habkost, Phil Dennis-Jordan
After the previous commit introducing GICv3 + GICv2m configurations,
update the AArch64 ACPI tables for the GICv2 case.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
tests/data/acpi/aarch64/virt/IORT | Bin 128 -> 84 bytes
tests/data/acpi/aarch64/virt/IORT.smmuv3-dev | Bin 364 -> 260 bytes
tests/data/acpi/aarch64/virt/IORT.smmuv3-legacy | Bin 276 -> 192 bytes
tests/qtest/bios-tables-test-allowed-diff.h | 3 ---
4 files changed, 3 deletions(-)
diff --git a/tests/data/acpi/aarch64/virt/IORT b/tests/data/acpi/aarch64/virt/IORT
index 7efd0ce8a6b3928efa7e1373f688ab4c5f50543b..9cce77cacdda976f64eabcc7213646af25cb93eb 100644
GIT binary patch
delta 42
ocmZo*4B_(h4+;rkU|?Xjo5&?4$_Qi`05J$KsW32u850Ag0fA@))Bpeg
literal 128
zcmebD4+?2uU|?Y0?Bwt45v<@85#X!<1dKp25F11@0kHuPgMkDCNC*yK93~3}W)K^M
VRiHGGVg_O`aDdYP|3ers^8jQz3IPBB
diff --git a/tests/data/acpi/aarch64/virt/IORT.smmuv3-dev b/tests/data/acpi/aarch64/virt/IORT.smmuv3-dev
index 67be268f62afbf2d9459540984da5e9340afdaaa..604121e2b25532351b5bd454b832a9f3f923ddb9 100644
GIT binary patch
delta 107
zcmaFE)WXE&=^qrr!pOkD>^+f7N|Kp@fx!TXL4d`Dfd#?>k`qJCc|ig|l@Ks-tvM%?
f4+Aq3kjpfgkx^X+rjJ2@f#E+$5s)r{C}scvit`FW
literal 364
zcmebD4+_a)WME)E<>c?|5v<@85#X!<1VAAM5F13Z0I>lOgMkDCNC*yK9F_<M77!bR
zT_CbNAPOcA5rU8tfYd}Fo(#m3AVP5R|9=P*W*^90CZG_)Tqd06P64W$3dGZacp4BR
z19WqlN*I`#feJu=QvqVAJ3&HV-~grnLnS<*d<Fpq2Cx%>^a7X|(1HJXfgB(Wb2oz^
MQ0yI03`oPo01?F*0RR91
diff --git a/tests/data/acpi/aarch64/virt/IORT.smmuv3-legacy b/tests/data/acpi/aarch64/virt/IORT.smmuv3-legacy
index 41981a449fc306b80cccd87ddec3c593a8d72c07..a0df7fcc4e084a97a6ce7ffd305bd38b4fee984b 100644
GIT binary patch
delta 74
zcmbQjbbyh|(?2NW00RR9v)n{3DM=<E%K(T$fW?J@1;PT76GP28nS2<S8G&r3i7V9^
M4JKX`=71>$0E<}(h5!Hn
literal 276
zcmX|*K@NgI3`M`puy8?wi3^u3IDkhWzycE!jI!Vis5{Ti6^7s1@{>QmeVugXHa@5G
z0SNbY?1op>&X2C5h#<9Ops%#*0ztdHi8G?q;$EluQNrhn>{ys@`b&R|d8G8O{Jrdl
mkP$_?rfr{mN!3^;8w}Q?1auX1XIzvDUSRruoXA!(rn3!nx)K2Z
diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h
index 7acaf464dd..dfb8523c8b 100644
--- a/tests/qtest/bios-tables-test-allowed-diff.h
+++ b/tests/qtest/bios-tables-test-allowed-diff.h
@@ -1,4 +1 @@
/* List of comma-separated changed AML files to ignore */
-"tests/data/acpi/aarch64/virt/IORT",
-"tests/data/acpi/aarch64/virt/IORT.smmuv3-dev",
-"tests/data/acpi/aarch64/virt/IORT.smmuv3-legacy",
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 35+ messages in thread* Re: [PATCH v18 05/22] tests: data: update AArch64 ACPI tables
2026-01-27 18:27 ` [PATCH v18 05/22] tests: data: update AArch64 ACPI tables Mohamed Mediouni
@ 2026-01-29 13:36 ` Peter Maydell
2026-01-29 13:41 ` Peter Maydell
` (2 more replies)
0 siblings, 3 replies; 35+ messages in thread
From: Peter Maydell @ 2026-01-29 13:36 UTC (permalink / raw)
To: Mohamed Mediouni
Cc: qemu-devel, Zhao Liu, Michael S. Tsirkin, Roman Bolshakov,
qemu-arm, Ani Sinha, Daniel P. Berrangé,
Philippe Mathieu-Daudé, Yanan Wang, Akihiko Odaki,
Marcel Apfelbaum, Pedro Barbuda, Richard Henderson, Paolo Bonzini,
Marc-André Lureau, Shannon Zhao, Igor Mammedov,
Cameron Esfahani, Alexander Graf, Eduardo Habkost,
Phil Dennis-Jordan
On Tue, 27 Jan 2026 at 18:28, Mohamed Mediouni <mohamed@unpredictable.fr> wrote:
>
> After the previous commit introducing GICv3 + GICv2m configurations,
> update the AArch64 ACPI tables for the GICv2 case.
>
> Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
> ---
> tests/data/acpi/aarch64/virt/IORT | Bin 128 -> 84 bytes
> tests/data/acpi/aarch64/virt/IORT.smmuv3-dev | Bin 364 -> 260 bytes
> tests/data/acpi/aarch64/virt/IORT.smmuv3-legacy | Bin 276 -> 192 bytes
> tests/qtest/bios-tables-test-allowed-diff.h | 3 ---
> 4 files changed, 3 deletions(-)
The process documented in tests/qtest/bios-tables-test.c says
that this commit is supposed to have the diff of the disassembled
table data in the commit message, so that human reviewers can
confirm that the changes are as expected. (If you git log
tests/data/acpi you can see how this looks.)
Can you provide the ASL diff, please? (If this is going to be the
only fix needed to this version of the series, which I hope it
will be, then I can update the commit message as I apply the
series, so you don't need to respin, just reply with the updated
commit message with the diff in it.)
thanks
-- PMM
^ permalink raw reply [flat|nested] 35+ messages in thread* Re: [PATCH v18 05/22] tests: data: update AArch64 ACPI tables
2026-01-29 13:36 ` Peter Maydell
@ 2026-01-29 13:41 ` Peter Maydell
2026-01-29 13:58 ` Michael S. Tsirkin
2026-01-29 14:34 ` Mohamed Mediouni
2 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-01-29 13:41 UTC (permalink / raw)
To: Mohamed Mediouni
Cc: qemu-devel, Zhao Liu, Michael S. Tsirkin, Roman Bolshakov,
qemu-arm, Ani Sinha, Daniel P. Berrangé,
Philippe Mathieu-Daudé, Yanan Wang, Akihiko Odaki,
Marcel Apfelbaum, Pedro Barbuda, Richard Henderson, Paolo Bonzini,
Marc-André Lureau, Shannon Zhao, Igor Mammedov,
Cameron Esfahani, Alexander Graf, Eduardo Habkost,
Phil Dennis-Jordan
On Thu, 29 Jan 2026 at 13:36, Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On Tue, 27 Jan 2026 at 18:28, Mohamed Mediouni <mohamed@unpredictable.fr> wrote:
> >
> > After the previous commit introducing GICv3 + GICv2m configurations,
> > update the AArch64 ACPI tables for the GICv2 case.
> >
> > Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
> > ---
> > tests/data/acpi/aarch64/virt/IORT | Bin 128 -> 84 bytes
> > tests/data/acpi/aarch64/virt/IORT.smmuv3-dev | Bin 364 -> 260 bytes
> > tests/data/acpi/aarch64/virt/IORT.smmuv3-legacy | Bin 276 -> 192 bytes
> > tests/qtest/bios-tables-test-allowed-diff.h | 3 ---
> > 4 files changed, 3 deletions(-)
>
> The process documented in tests/qtest/bios-tables-test.c says
> that this commit is supposed to have the diff of the disassembled
> table data in the commit message, so that human reviewers can
> confirm that the changes are as expected. (If you git log
> tests/data/acpi you can see how this looks.)
>
> Can you provide the ASL diff, please? (If this is going to be the
> only fix needed to this version of the series, which I hope it
> will be, then I can update the commit message as I apply the
> series, so you don't need to respin, just reply with the updated
> commit message with the diff in it.)
...ah, it looks like unfortunately this is going to conflict
with the smmuv3 acceleration series I already have queued,
because that series also updates these ACPI blobs. So I think
the best thing is if I get that out in a target-arm pullreq
and then you can rebase on top of that.
thanks
-- PMM
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v18 05/22] tests: data: update AArch64 ACPI tables
2026-01-29 13:36 ` Peter Maydell
2026-01-29 13:41 ` Peter Maydell
@ 2026-01-29 13:58 ` Michael S. Tsirkin
2026-01-29 14:34 ` Mohamed Mediouni
2 siblings, 0 replies; 35+ messages in thread
From: Michael S. Tsirkin @ 2026-01-29 13:58 UTC (permalink / raw)
To: Peter Maydell
Cc: Mohamed Mediouni, qemu-devel, Zhao Liu, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Philippe Mathieu-Daudé,
Yanan Wang, Akihiko Odaki, Marcel Apfelbaum, Pedro Barbuda,
Richard Henderson, Paolo Bonzini, Marc-André Lureau,
Shannon Zhao, Igor Mammedov, Cameron Esfahani, Alexander Graf,
Eduardo Habkost, Phil Dennis-Jordan
On Thu, Jan 29, 2026 at 01:36:49PM +0000, Peter Maydell wrote:
> On Tue, 27 Jan 2026 at 18:28, Mohamed Mediouni <mohamed@unpredictable.fr> wrote:
> >
> > After the previous commit introducing GICv3 + GICv2m configurations,
> > update the AArch64 ACPI tables for the GICv2 case.
> >
> > Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
> > ---
> > tests/data/acpi/aarch64/virt/IORT | Bin 128 -> 84 bytes
> > tests/data/acpi/aarch64/virt/IORT.smmuv3-dev | Bin 364 -> 260 bytes
> > tests/data/acpi/aarch64/virt/IORT.smmuv3-legacy | Bin 276 -> 192 bytes
> > tests/qtest/bios-tables-test-allowed-diff.h | 3 ---
> > 4 files changed, 3 deletions(-)
>
> The process documented in tests/qtest/bios-tables-test.c says
> that this commit is supposed to have the diff of the disassembled
> table data in the commit message, so that human reviewers can
> confirm that the changes are as expected. (If you git log
> tests/data/acpi you can see how this looks.)
not just that, also so the patch can be rebased.
> Can you provide the ASL diff, please? (If this is going to be the
> only fix needed to this version of the series, which I hope it
> will be, then I can update the commit message as I apply the
> series, so you don't need to respin, just reply with the updated
> commit message with the diff in it.)
>
> thanks
> -- PMM
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v18 05/22] tests: data: update AArch64 ACPI tables
2026-01-29 13:36 ` Peter Maydell
2026-01-29 13:41 ` Peter Maydell
2026-01-29 13:58 ` Michael S. Tsirkin
@ 2026-01-29 14:34 ` Mohamed Mediouni
2026-01-29 15:05 ` Peter Maydell
2 siblings, 1 reply; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-29 14:34 UTC (permalink / raw)
To: Peter Maydell
Cc: qemu-devel, Zhao Liu, Michael S. Tsirkin, Roman Bolshakov,
qemu-arm, Ani Sinha, "Daniel P. Berrangé",
Philippe Mathieu-Daudé, Yanan Wang, Akihiko Odaki,
Marcel Apfelbaum, Pedro Barbuda, Richard Henderson, Paolo Bonzini,
Marc-André Lureau, Shannon Zhao, Igor Mammedov,
Cameron Esfahani, Alexander Graf, Eduardo Habkost,
Phil Dennis-Jordan
> On 29. Jan 2026, at 14:36, Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On Tue, 27 Jan 2026 at 18:28, Mohamed Mediouni <mohamed@unpredictable.fr> wrote:
>>
>> After the previous commit introducing GICv3 + GICv2m configurations,
>> update the AArch64 ACPI tables for the GICv2 case.
>>
>> Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
>> ---
>> tests/data/acpi/aarch64/virt/IORT | Bin 128 -> 84 bytes
>> tests/data/acpi/aarch64/virt/IORT.smmuv3-dev | Bin 364 -> 260 bytes
>> tests/data/acpi/aarch64/virt/IORT.smmuv3-legacy | Bin 276 -> 192 bytes
>> tests/qtest/bios-tables-test-allowed-diff.h | 3 ---
>> 4 files changed, 3 deletions(-)
>
> The process documented in tests/qtest/bios-tables-test.c says
> that this commit is supposed to have the diff of the disassembled
> table data in the commit message, so that human reviewers can
> confirm that the changes are as expected. (If you git log
> tests/data/acpi you can see how this looks.)
>
> Can you provide the ASL diff, please? (If this is going to be the
> only fix needed to this version of the series, which I hope it
> will be, then I can update the commit message as I apply the
> series, so you don't need to respin, just reply with the updated
> commit message with the diff in it.)
>
> thanks
> — PMM
Hi,
Here’s the expected asl diff:
diff otp/tests/data/acpi/aarch64/virt/IORT.dsl otp2/tests/data/acpi/aarch64/virt/IORT.dsl
14c14
< [004h 0004 004h] Table Length : 00000080
---
> [004h 0004 004h] Table Length : 00000054
16c16
< [009h 0009 001h] Checksum : B3
---
> [009h 0009 001h] Checksum : 3E
23c23
< [024h 0036 004h] Node Count : 00000002
---
> [024h 0036 004h] Node Count : 00000001
27,29c27,29
< [030h 0048 001h] Type : 00
< [031h 0049 002h] Length : 0018
< [033h 0051 001h] Revision : 01
---
> [030h 0048 001h] Type : 02
> [031h 0049 002h] Length : 0024
> [033h 0051 001h] Revision : 03
32c32
< [03Ch 0060 004h] Mapping Offset : 00000000
---
> [03Ch 0060 004h] Mapping Offset : 00000024
34,46c34,36
< [040h 0064 004h] ItsCount : 00000001
< [044h 0068 004h] Identifiers : 00000000
<
< [048h 0072 001h] Type : 02
< [049h 0073 002h] Length : 0038
< [04Bh 0075 001h] Revision : 03
< [04Ch 0076 004h] Identifier : 00000001
< [050h 0080 004h] Mapping Count : 00000001
< [054h 0084 004h] Mapping Offset : 00000024
<
< [058h 0088 008h] Memory Properties : [IORT Memory Access Properties]
< [058h 0088 004h] Cache Coherency : 00000001
< [05Ch 0092 001h] Hints (decoded below) : 00
---
> [040h 0064 008h] Memory Properties : [IORT Memory Access Properties]
> [040h 0064 004h] Cache Coherency : 00000001
> [044h 0068 001h] Hints (decoded below) : 00
51,52c41,42
< [05Dh 0093 002h] Reserved : 0000
< [05Fh 0095 001h] Memory Flags (decoded below) : 03
---
> [045h 0069 002h] Reserved : 0000
> [047h 0071 001h] Memory Flags (decoded below) : 03
56,60c46,50
< [060h 0096 004h] ATS Attribute : 00000000
< [064h 0100 004h] PCI Segment Number : 00000000
< [068h 0104 001h] Memory Size Limit : 40
< [069h 0105 002h] PASID Capabilities : 0000
< [06Bh 0107 001h] Reserved : 00
---
> [048h 0072 004h] ATS Attribute : 00000000
> [04Ch 0076 004h] PCI Segment Number : 00000000
> [050h 0080 001h] Memory Size Limit : 40
> [051h 0081 002h] PASID Capabilities : 0000
> [053h 0083 001h] Reserved : 00
62,67c52
< [06Ch 0108 004h] Input base : 00000000
< [070h 0112 004h] ID Count : 0000FFFF
< [074h 0116 004h] Output Base : 00000000
< [078h 0120 004h] Output Reference : 00000030
< [07Ch 0124 004h] Flags (decoded below) : 00000000
< Single Mapping : 0
---
> Raw Table Data: Length 84 (0x54)
69,71c54
< Raw Table Data: Length 128 (0x80)
<
< 0000: 49 4F 52 54 80 00 00 00 03 B3 42 4F 43 48 53 20 // IORT......BOCHS
---
> 0000: 49 4F 52 54 54 00 00 00 03 3E 42 4F 43 48 53 20 // IORTT....>BOCHS
73,78c56,59
< 0020: 01 00 00 00 02 00 00 00 30 00 00 00 00 00 00 00 // ........0.......
< 0030: 00 18 00 01 00 00 00 00 00 00 00 00 00 00 00 00 // ................
< 0040: 01 00 00 00 00 00 00 00 02 38 00 03 01 00 00 00 // .........8......
< 0050: 01 00 00 00 24 00 00 00 01 00 00 00 00 00 00 03 // ....$...........
< 0060: 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 // ........@.......
< 0070: FF FF 00 00 00 00 00 00 30 00 00 00 00 00 00 00 // ........0.......
---
> 0020: 01 00 00 00 01 00 00 00 30 00 00 00 00 00 00 00 // ........0.......
> 0030: 02 24 00 03 00 00 00 00 00 00 00 00 24 00 00 00 // .$..........$...
> 0040: 01 00 00 00 00 00 00 03 00 00 00 00 00 00 00 00 // ................
> 0050: 40 00 00 00 // @...
diff otp/tests/data/acpi/aarch64/virt/IORT.smmuv3-dev.dsl otp2/tests/data/acpi/aarch64/virt/IORT.smmuv3-dev.dsl
14c14
< [004h 0004 004h] Table Length : 0000016C
---
> [004h 0004 004h] Table Length : 00000104
16c16
< [009h 0009 001h] Checksum : CA
---
> [009h 0009 001h] Checksum : 4B
23c23
< [024h 0036 004h] Node Count : 00000004
---
> [024h 0036 004h] Node Count : 00000003
27,29c27,29
< [030h 0048 001h] Type : 00
< [031h 0049 002h] Length : 0018
< [033h 0051 001h] Revision : 01
---
> [030h 0048 001h] Type : 04
> [031h 0049 002h] Length : 0044
> [033h 0051 001h] Revision : 04
34,45c34,35
< [040h 0064 004h] ItsCount : 00000001
< [044h 0068 004h] Identifiers : 00000000
<
< [048h 0072 001h] Type : 04
< [049h 0073 002h] Length : 0058
< [04Bh 0075 001h] Revision : 04
< [04Ch 0076 004h] Identifier : 00000001
< [050h 0080 004h] Mapping Count : 00000001
< [054h 0084 004h] Mapping Offset : 00000044
<
< [058h 0088 008h] Base Address : 000000000C000000
< [060h 0096 004h] Flags (decoded below) : 00000001
---
> [040h 0064 008h] Base Address : 000000000C000000
> [048h 0072 004h] Flags (decoded below) : 00000001
50,58c40,48
< [064h 0100 004h] Reserved : 00000000
< [068h 0104 008h] VATOS Address : 0000000000000000
< [070h 0112 004h] Model : 00000000
< [074h 0116 004h] Event GSIV : 00000090
< [078h 0120 004h] PRI GSIV : 00000091
< [07Ch 0124 004h] GERR GSIV : 00000093
< [080h 0128 004h] Sync GSIV : 00000092
< [084h 0132 004h] Proximity Domain : 00000000
< [088h 0136 004h] Device ID Mapping Index : 00000000
---
> [04Ch 0076 004h] Reserved : 00000000
> [050h 0080 008h] VATOS Address : 0000000000000000
> [058h 0088 004h] Model : 00000000
> [05Ch 0092 004h] Event GSIV : 00000090
> [060h 0096 004h] PRI GSIV : 00000091
> [064h 0100 004h] GERR GSIV : 00000093
> [068h 0104 004h] Sync GSIV : 00000092
> [06Ch 0108 004h] Proximity Domain : 00000000
> [070h 0112 004h] Device ID Mapping Index : 00000000
60,65c50,55
< [08Ch 0140 004h] Input base : 00000000
< [090h 0144 004h] ID Count : 0000FFFF
< [094h 0148 004h] Output Base : 00000000
< [098h 0152 004h] Output Reference : 00000030
< [09Ch 0156 004h] Flags (decoded below) : 00000000
< Single Mapping : 0
---
> [074h 0116 001h] Type : 04
> [075h 0117 002h] Length : 0044
> [077h 0119 001h] Revision : 04
> [078h 0120 004h] Identifier : 00000001
> [07Ch 0124 004h] Mapping Count : 00000000
> [080h 0128 004h] Mapping Offset : 00000000
67,75c57,58
< [0A0h 0160 001h] Type : 04
< [0A1h 0161 002h] Length : 0058
< [0A3h 0163 001h] Revision : 04
< [0A4h 0164 004h] Identifier : 00000002
< [0A8h 0168 004h] Mapping Count : 00000001
< [0ACh 0172 004h] Mapping Offset : 00000044
<
< [0B0h 0176 008h] Base Address : 000000000C020000
< [0B8h 0184 004h] Flags (decoded below) : 00000001
---
> [084h 0132 008h] Base Address : 000000000C020000
> [08Ch 0140 004h] Flags (decoded below) : 00000001
80,88c63,71
< [0BCh 0188 004h] Reserved : 00000000
< [0C0h 0192 008h] VATOS Address : 0000000000000000
< [0C8h 0200 004h] Model : 00000000
< [0CCh 0204 004h] Event GSIV : 00000094
< [0D0h 0208 004h] PRI GSIV : 00000095
< [0D4h 0212 004h] GERR GSIV : 00000097
< [0D8h 0216 004h] Sync GSIV : 00000096
< [0DCh 0220 004h] Proximity Domain : 00000000
< [0E0h 0224 004h] Device ID Mapping Index : 00000000
---
> [090h 0144 004h] Reserved : 00000000
> [094h 0148 008h] VATOS Address : 0000000000000000
> [09Ch 0156 004h] Model : 00000000
> [0A0h 0160 004h] Event GSIV : 00000094
> [0A4h 0164 004h] PRI GSIV : 00000095
> [0A8h 0168 004h] GERR GSIV : 00000097
> [0ACh 0172 004h] Sync GSIV : 00000096
> [0B0h 0176 004h] Proximity Domain : 00000000
> [0B4h 0180 004h] Device ID Mapping Index : 00000000
90,95c73,78
< [0E4h 0228 004h] Input base : 00000000
< [0E8h 0232 004h] ID Count : 0000FFFF
< [0ECh 0236 004h] Output Base : 00000000
< [0F0h 0240 004h] Output Reference : 00000030
< [0F4h 0244 004h] Flags (decoded below) : 00000000
< Single Mapping : 0
---
> [0B8h 0184 001h] Type : 02
> [0B9h 0185 002h] Length : 004C
> [0BBh 0187 001h] Revision : 03
> [0BCh 0188 004h] Identifier : 00000002
> [0C0h 0192 004h] Mapping Count : 00000002
> [0C4h 0196 004h] Mapping Offset : 00000024
97,106c80,82
< [0F8h 0248 001h] Type : 02
< [0F9h 0249 002h] Length : 0074
< [0FBh 0251 001h] Revision : 03
< [0FCh 0252 004h] Identifier : 00000003
< [100h 0256 004h] Mapping Count : 00000004
< [104h 0260 004h] Mapping Offset : 00000024
<
< [108h 0264 008h] Memory Properties : [IORT Memory Access Properties]
< [108h 0264 004h] Cache Coherency : 00000001
< [10Ch 0268 001h] Hints (decoded below) : 00
---
> [0C8h 0200 008h] Memory Properties : [IORT Memory Access Properties]
> [0C8h 0200 004h] Cache Coherency : 00000001
> [0CCh 0204 001h] Hints (decoded below) : 00
111,112c87,88
< [10Dh 0269 002h] Reserved : 0000
< [10Fh 0271 001h] Memory Flags (decoded below) : 03
---
> [0CDh 0205 002h] Reserved : 0000
> [0CFh 0207 001h] Memory Flags (decoded below) : 03
116,120c92,96
< [110h 0272 004h] ATS Attribute : 00000000
< [114h 0276 004h] PCI Segment Number : 00000000
< [118h 0280 001h] Memory Size Limit : 40
< [119h 0281 002h] PASID Capabilities : 0000
< [11Bh 0283 001h] Reserved : 00
---
> [0D0h 0208 004h] ATS Attribute : 00000000
> [0D4h 0212 004h] PCI Segment Number : 00000000
> [0D8h 0216 001h] Memory Size Limit : 40
> [0D9h 0217 002h] PASID Capabilities : 0000
> [0DBh 0219 001h] Reserved : 00
122,126c98,102
< [11Ch 0284 004h] Input base : 00000000
< [120h 0288 004h] ID Count : 000001FF
< [124h 0292 004h] Output Base : 00000000
< [128h 0296 004h] Output Reference : 00000048
< [12Ch 0300 004h] Flags (decoded below) : 00000000
---
> [0DCh 0220 004h] Input base : 00000000
> [0E0h 0224 004h] ID Count : 000001FF
> [0E4h 0228 004h] Output Base : 00000000
> [0E8h 0232 004h] Output Reference : 00000030
> [0ECh 0236 004h] Flags (decoded below) : 00000000
129,133c105,109
< [130h 0304 004h] Input base : 00001000
< [134h 0308 004h] ID Count : 000000FF
< [138h 0312 004h] Output Base : 00001000
< [13Ch 0316 004h] Output Reference : 000000A0
< [140h 0320 004h] Flags (decoded below) : 00000000
---
> [0F0h 0240 004h] Input base : 00001000
> [0F4h 0244 004h] ID Count : 000000FF
> [0F8h 0248 004h] Output Base : 00001000
> [0FCh 0252 004h] Output Reference : 00000074
> [100h 0256 004h] Flags (decoded below) : 00000000
136,141c112
< [144h 0324 004h] Input base : 00000200
< [148h 0328 004h] ID Count : 00000DFF
< [14Ch 0332 004h] Output Base : 00000200
< [150h 0336 004h] Output Reference : 00000030
< [154h 0340 004h] Flags (decoded below) : 00000000
< Single Mapping : 0
---
> Raw Table Data: Length 260 (0x104)
143,152c114
< [158h 0344 004h] Input base : 00001100
< [15Ch 0348 004h] ID Count : 0000EEFF
< [160h 0352 004h] Output Base : 00001100
< [164h 0356 004h] Output Reference : 00000030
< [168h 0360 004h] Flags (decoded below) : 00000000
< Single Mapping : 0
<
< Raw Table Data: Length 364 (0x16C)
<
< 0000: 49 4F 52 54 6C 01 00 00 03 CA 42 4F 43 48 53 20 // IORTl.....BOCHS
---
> 0000: 49 4F 52 54 04 01 00 00 03 4B 42 4F 43 48 53 20 // IORT.....KBOCHS
154,174c116,130
< 0020: 01 00 00 00 04 00 00 00 30 00 00 00 00 00 00 00 // ........0.......
< 0030: 00 18 00 01 00 00 00 00 00 00 00 00 00 00 00 00 // ................
< 0040: 01 00 00 00 00 00 00 00 04 58 00 04 01 00 00 00 // .........X......
< 0050: 01 00 00 00 44 00 00 00 00 00 00 0C 00 00 00 00 // ....D...........
< 0060: 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // ................
< 0070: 00 00 00 00 90 00 00 00 91 00 00 00 93 00 00 00 // ................
< 0080: 92 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // ................
< 0090: FF FF 00 00 00 00 00 00 30 00 00 00 00 00 00 00 // ........0.......
< 00A0: 04 58 00 04 02 00 00 00 01 00 00 00 44 00 00 00 // .X..........D...
< 00B0: 00 00 02 0C 00 00 00 00 01 00 00 00 00 00 00 00 // ................
< 00C0: 00 00 00 00 00 00 00 00 00 00 00 00 94 00 00 00 // ................
< 00D0: 95 00 00 00 97 00 00 00 96 00 00 00 00 00 00 00 // ................
< 00E0: 00 00 00 00 00 00 00 00 FF FF 00 00 00 00 00 00 // ................
< 00F0: 30 00 00 00 00 00 00 00 02 74 00 03 03 00 00 00 // 0........t......
< 0100: 04 00 00 00 24 00 00 00 01 00 00 00 00 00 00 03 // ....$...........
< 0110: 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 // ........@.......
< 0120: FF 01 00 00 00 00 00 00 48 00 00 00 00 00 00 00 // ........H.......
< 0130: 00 10 00 00 FF 00 00 00 00 10 00 00 A0 00 00 00 // ................
< 0140: 00 00 00 00 00 02 00 00 FF 0D 00 00 00 02 00 00 // ................
< 0150: 30 00 00 00 00 00 00 00 00 11 00 00 FF EE 00 00 // 0...............
< 0160: 00 11 00 00 30 00 00 00 00 00 00 00 // ....0.......
---
> 0020: 01 00 00 00 03 00 00 00 30 00 00 00 00 00 00 00 // ........0.......
> 0030: 04 44 00 04 00 00 00 00 00 00 00 00 00 00 00 00 // .D..............
> 0040: 00 00 00 0C 00 00 00 00 01 00 00 00 00 00 00 00 // ................
> 0050: 00 00 00 00 00 00 00 00 00 00 00 00 90 00 00 00 // ................
> 0060: 91 00 00 00 93 00 00 00 92 00 00 00 00 00 00 00 // ................
> 0070: 00 00 00 00 04 44 00 04 01 00 00 00 00 00 00 00 // .....D..........
> 0080: 00 00 00 00 00 00 02 0C 00 00 00 00 01 00 00 00 // ................
> 0090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // ................
> 00A0: 94 00 00 00 95 00 00 00 97 00 00 00 96 00 00 00 // ................
> 00B0: 00 00 00 00 00 00 00 00 02 4C 00 03 02 00 00 00 // .........L......
> 00C0: 02 00 00 00 24 00 00 00 01 00 00 00 00 00 00 03 // ....$...........
> 00D0: 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 // ........@.......
> 00E0: FF 01 00 00 00 00 00 00 30 00 00 00 00 00 00 00 // ........0.......
> 00F0: 00 10 00 00 FF 00 00 00 00 10 00 00 74 00 00 00 // ............t...
> 0100: 00 00 00 00 // ....
diff otp/tests/data/acpi/aarch64/virt/IORT.smmuv3-legacy.dsl otp2/tests/data/acpi/aarch64/virt/IORT.smmuv3-legacy.dsl
14c14
< [004h 0004 004h] Table Length : 00000114
---
> [004h 0004 004h] Table Length : 000000C0
16c16
< [009h 0009 001h] Checksum : 4C
---
> [009h 0009 001h] Checksum : 1E
23c23
< [024h 0036 004h] Node Count : 00000003
---
> [024h 0036 004h] Node Count : 00000002
27,29c27,29
< [030h 0048 001h] Type : 00
< [031h 0049 002h] Length : 0018
< [033h 0051 001h] Revision : 01
---
> [030h 0048 001h] Type : 04
> [031h 0049 002h] Length : 0044
> [033h 0051 001h] Revision : 04
34,45c34,35
< [040h 0064 004h] ItsCount : 00000001
< [044h 0068 004h] Identifiers : 00000000
<
< [048h 0072 001h] Type : 04
< [049h 0073 002h] Length : 0058
< [04Bh 0075 001h] Revision : 04
< [04Ch 0076 004h] Identifier : 00000001
< [050h 0080 004h] Mapping Count : 00000001
< [054h 0084 004h] Mapping Offset : 00000044
<
< [058h 0088 008h] Base Address : 0000000009050000
< [060h 0096 004h] Flags (decoded below) : 00000001
---
> [040h 0064 008h] Base Address : 0000000009050000
> [048h 0072 004h] Flags (decoded below) : 00000001
50,58c40,48
< [064h 0100 004h] Reserved : 00000000
< [068h 0104 008h] VATOS Address : 0000000000000000
< [070h 0112 004h] Model : 00000000
< [074h 0116 004h] Event GSIV : 0000006A
< [078h 0120 004h] PRI GSIV : 0000006B
< [07Ch 0124 004h] GERR GSIV : 0000006D
< [080h 0128 004h] Sync GSIV : 0000006C
< [084h 0132 004h] Proximity Domain : 00000000
< [088h 0136 004h] Device ID Mapping Index : 00000000
---
> [04Ch 0076 004h] Reserved : 00000000
> [050h 0080 008h] VATOS Address : 0000000000000000
> [058h 0088 004h] Model : 00000000
> [05Ch 0092 004h] Event GSIV : 0000006A
> [060h 0096 004h] PRI GSIV : 0000006B
> [064h 0100 004h] GERR GSIV : 0000006D
> [068h 0104 004h] Sync GSIV : 0000006C
> [06Ch 0108 004h] Proximity Domain : 00000000
> [070h 0112 004h] Device ID Mapping Index : 00000000
60,65c50,55
< [08Ch 0140 004h] Input base : 00000000
< [090h 0144 004h] ID Count : 0000FFFF
< [094h 0148 004h] Output Base : 00000000
< [098h 0152 004h] Output Reference : 00000030
< [09Ch 0156 004h] Flags (decoded below) : 00000000
< Single Mapping : 0
---
> [074h 0116 001h] Type : 02
> [075h 0117 002h] Length : 004C
> [077h 0119 001h] Revision : 03
> [078h 0120 004h] Identifier : 00000001
> [07Ch 0124 004h] Mapping Count : 00000002
> [080h 0128 004h] Mapping Offset : 00000024
67,76c57,59
< [0A0h 0160 001h] Type : 02
< [0A1h 0161 002h] Length : 0074
< [0A3h 0163 001h] Revision : 03
< [0A4h 0164 004h] Identifier : 00000002
< [0A8h 0168 004h] Mapping Count : 00000004
< [0ACh 0172 004h] Mapping Offset : 00000024
<
< [0B0h 0176 008h] Memory Properties : [IORT Memory Access Properties]
< [0B0h 0176 004h] Cache Coherency : 00000001
< [0B4h 0180 001h] Hints (decoded below) : 00
---
> [084h 0132 008h] Memory Properties : [IORT Memory Access Properties]
> [084h 0132 004h] Cache Coherency : 00000001
> [088h 0136 001h] Hints (decoded below) : 00
81,82c64,65
< [0B5h 0181 002h] Reserved : 0000
< [0B7h 0183 001h] Memory Flags (decoded below) : 03
---
> [089h 0137 002h] Reserved : 0000
> [08Bh 0139 001h] Memory Flags (decoded below) : 03
86,90c69,73
< [0B8h 0184 004h] ATS Attribute : 00000000
< [0BCh 0188 004h] PCI Segment Number : 00000000
< [0C0h 0192 001h] Memory Size Limit : 40
< [0C1h 0193 002h] PASID Capabilities : 0000
< [0C3h 0195 001h] Reserved : 00
---
> [08Ch 0140 004h] ATS Attribute : 00000000
> [090h 0144 004h] PCI Segment Number : 00000000
> [094h 0148 001h] Memory Size Limit : 40
> [095h 0149 002h] PASID Capabilities : 0000
> [097h 0151 001h] Reserved : 00
92,96c75,79
< [0C4h 0196 004h] Input base : 00000000
< [0C8h 0200 004h] ID Count : 000001FF
< [0CCh 0204 004h] Output Base : 00000000
< [0D0h 0208 004h] Output Reference : 00000048
< [0D4h 0212 004h] Flags (decoded below) : 00000000
---
> [098h 0152 004h] Input base : 00000000
> [09Ch 0156 004h] ID Count : 000001FF
> [0A0h 0160 004h] Output Base : 00000000
> [0A4h 0164 004h] Output Reference : 00000030
> [0A8h 0168 004h] Flags (decoded below) : 00000000
99,103c82,86
< [0D8h 0216 004h] Input base : 00001000
< [0DCh 0220 004h] ID Count : 000000FF
< [0E0h 0224 004h] Output Base : 00001000
< [0E4h 0228 004h] Output Reference : 00000048
< [0E8h 0232 004h] Flags (decoded below) : 00000000
---
> [0ACh 0172 004h] Input base : 00001000
> [0B0h 0176 004h] ID Count : 000000FF
> [0B4h 0180 004h] Output Base : 00001000
> [0B8h 0184 004h] Output Reference : 00000030
> [0BCh 0188 004h] Flags (decoded below) : 00000000
106,111c89
< [0ECh 0236 004h] Input base : 00000200
< [0F0h 0240 004h] ID Count : 00000DFF
< [0F4h 0244 004h] Output Base : 00000200
< [0F8h 0248 004h] Output Reference : 00000030
< [0FCh 0252 004h] Flags (decoded below) : 00000000
< Single Mapping : 0
---
> Raw Table Data: Length 192 (0xC0)
113,122c91
< [100h 0256 004h] Input base : 00001100
< [104h 0260 004h] ID Count : 0000EEFF
< [108h 0264 004h] Output Base : 00001100
< [10Ch 0268 004h] Output Reference : 00000030
< [110h 0272 004h] Flags (decoded below) : 00000000
< Single Mapping : 0
<
< Raw Table Data: Length 276 (0x114)
<
< 0000: 49 4F 52 54 14 01 00 00 03 4C 42 4F 43 48 53 20 // IORT.....LBOCHS
---
> 0000: 49 4F 52 54 C0 00 00 00 03 1E 42 4F 43 48 53 20 // IORT......BOCHS
124,139c93,102
< 0020: 01 00 00 00 03 00 00 00 30 00 00 00 00 00 00 00 // ........0.......
< 0030: 00 18 00 01 00 00 00 00 00 00 00 00 00 00 00 00 // ................
< 0040: 01 00 00 00 00 00 00 00 04 58 00 04 01 00 00 00 // .........X......
< 0050: 01 00 00 00 44 00 00 00 00 00 05 09 00 00 00 00 // ....D...........
< 0060: 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // ................
< 0070: 00 00 00 00 6A 00 00 00 6B 00 00 00 6D 00 00 00 // ....j...k...m...
< 0080: 6C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // l...............
< 0090: FF FF 00 00 00 00 00 00 30 00 00 00 00 00 00 00 // ........0.......
< 00A0: 02 74 00 03 02 00 00 00 04 00 00 00 24 00 00 00 // .t..........$...
< 00B0: 01 00 00 00 00 00 00 03 00 00 00 00 00 00 00 00 // ................
< 00C0: 40 00 00 00 00 00 00 00 FF 01 00 00 00 00 00 00 // @...............
< 00D0: 48 00 00 00 00 00 00 00 00 10 00 00 FF 00 00 00 // H...............
< 00E0: 00 10 00 00 48 00 00 00 00 00 00 00 00 02 00 00 // ....H...........
< 00F0: FF 0D 00 00 00 02 00 00 30 00 00 00 00 00 00 00 // ........0.......
< 0100: 00 11 00 00 FF EE 00 00 00 11 00 00 30 00 00 00 // ............0...
< 0110: 00 00 00 00 // ....
---
> 0020: 01 00 00 00 02 00 00 00 30 00 00 00 00 00 00 00 // ........0.......
> 0030: 04 44 00 04 00 00 00 00 00 00 00 00 00 00 00 00 // .D..............
> 0040: 00 00 05 09 00 00 00 00 01 00 00 00 00 00 00 00 // ................
> 0050: 00 00 00 00 00 00 00 00 00 00 00 00 6A 00 00 00 // ............j...
> 0060: 6B 00 00 00 6D 00 00 00 6C 00 00 00 00 00 00 00 // k...m...l.......
> 0070: 00 00 00 00 02 4C 00 03 01 00 00 00 02 00 00 00 // .....L..........
> 0080: 24 00 00 00 01 00 00 00 00 00 00 03 00 00 00 00 // $...............
> 0090: 00 00 00 00 40 00 00 00 00 00 00 00 FF 01 00 00 // ....@...........
> 00A0: 00 00 00 00 30 00 00 00 00 00 00 00 00 10 00 00 // ....0...........
> 00B0: FF 00 00 00 00 10 00 00 30 00 00 00 00 00 00 00 // ........0.......
As you noted in the follow up email, the blob is probably expected to be re-generated in this case after the SMMUv3 patches (if you’re going to take it without a further revision)
Thank you,
-Mohamed
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v18 05/22] tests: data: update AArch64 ACPI tables
2026-01-29 14:34 ` Mohamed Mediouni
@ 2026-01-29 15:05 ` Peter Maydell
0 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-01-29 15:05 UTC (permalink / raw)
To: Mohamed Mediouni
Cc: qemu-devel, Zhao Liu, Michael S. Tsirkin, Roman Bolshakov,
qemu-arm, Ani Sinha, Daniel P. Berrangé,
Philippe Mathieu-Daudé, Yanan Wang, Akihiko Odaki,
Marcel Apfelbaum, Pedro Barbuda, Richard Henderson, Paolo Bonzini,
Marc-André Lureau, Shannon Zhao, Igor Mammedov,
Cameron Esfahani, Alexander Graf, Eduardo Habkost,
Phil Dennis-Jordan
On Thu, 29 Jan 2026 at 14:34, Mohamed Mediouni <mohamed@unpredictable.fr> wrote:
>
>
>
> > On 29. Jan 2026, at 14:36, Peter Maydell <peter.maydell@linaro.org> wrote:
> >
> > On Tue, 27 Jan 2026 at 18:28, Mohamed Mediouni <mohamed@unpredictable.fr> wrote:
> >>
> >> After the previous commit introducing GICv3 + GICv2m configurations,
> >> update the AArch64 ACPI tables for the GICv2 case.
> >>
> >> Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
> >> ---
> >> tests/data/acpi/aarch64/virt/IORT | Bin 128 -> 84 bytes
> >> tests/data/acpi/aarch64/virt/IORT.smmuv3-dev | Bin 364 -> 260 bytes
> >> tests/data/acpi/aarch64/virt/IORT.smmuv3-legacy | Bin 276 -> 192 bytes
> >> tests/qtest/bios-tables-test-allowed-diff.h | 3 ---
> >> 4 files changed, 3 deletions(-)
> >
> > The process documented in tests/qtest/bios-tables-test.c says
> > that this commit is supposed to have the diff of the disassembled
> > table data in the commit message, so that human reviewers can
> > confirm that the changes are as expected. (If you git log
> > tests/data/acpi you can see how this looks.)
> >
> > Can you provide the ASL diff, please? (If this is going to be the
> > only fix needed to this version of the series, which I hope it
> > will be, then I can update the commit message as I apply the
> > series, so you don't need to respin, just reply with the updated
> > commit message with the diff in it.)
> >
> > thanks
> > — PMM
> Hi,
>
> Here’s the expected asl diff:
>
> diff otp/tests/data/acpi/aarch64/virt/IORT.dsl otp2/tests/data/acpi/aarch64/virt/IORT.dsl
diff -u, please. But you're going to need to rebase this so
I'll let you redo the commit message at that point.
-- PMM
^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH v18 06/22] qtest: hw/arm: virt: add new test case for GICv3 + GICv2m
2026-01-27 18:27 [PATCH v18 00/22] WHPX support for Arm Mohamed Mediouni
` (4 preceding siblings ...)
2026-01-27 18:27 ` [PATCH v18 05/22] tests: data: update AArch64 ACPI tables Mohamed Mediouni
@ 2026-01-27 18:27 ` Mohamed Mediouni
2026-01-27 18:27 ` [PATCH v18 07/22] docs: arm: update virt machine model description Mohamed Mediouni
` (15 subsequent siblings)
21 siblings, 0 replies; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-27 18:27 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Zhao Liu, Michael S. Tsirkin, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Philippe Mathieu-Daudé,
Yanan Wang, Akihiko Odaki, Marcel Apfelbaum, Pedro Barbuda,
Richard Henderson, Paolo Bonzini, Marc-André Lureau,
Shannon Zhao, Igor Mammedov, Cameron Esfahani, Alexander Graf,
Peter Maydell, Eduardo Habkost, Phil Dennis-Jordan
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
tests/data/acpi/aarch64/virt/APIC.msi_gicv2m | Bin 0 -> 188 bytes
tests/data/acpi/aarch64/virt/IORT.msi_gicv2m | Bin 0 -> 172 bytes
tests/qtest/bios-tables-test.c | 21 +++++++++++++++++++
3 files changed, 21 insertions(+)
create mode 100644 tests/data/acpi/aarch64/virt/APIC.msi_gicv2m
create mode 100644 tests/data/acpi/aarch64/virt/IORT.msi_gicv2m
diff --git a/tests/data/acpi/aarch64/virt/APIC.msi_gicv2m b/tests/data/acpi/aarch64/virt/APIC.msi_gicv2m
new file mode 100644
index 0000000000000000000000000000000000000000..16a01a17c0af605daf64f3cd2de3572be9e60cab
GIT binary patch
literal 188
zcmZ<^@O0k8z`(#_;N<V@5v<@85#X!<1dKp25F13p0FMNW#lQh$F#{Rg0Wcl|15CX*
dLWpD*p8!Y;7u1e#47_lAnZRNoI~*7S7y#H%2>}2A
literal 0
HcmV?d00001
diff --git a/tests/data/acpi/aarch64/virt/IORT.msi_gicv2m b/tests/data/acpi/aarch64/virt/IORT.msi_gicv2m
new file mode 100644
index 0000000000000000000000000000000000000000..c10da4e61dd00e7eb062558a2735d49ca0b20620
GIT binary patch
literal 172
zcmebD4+>esz`(#f-O1nCBUr&HBEVSz2pEB4AU23*0%8Lo1_2fq1{MelMzV5(SRi%i
nAPXpv4aB)XoP#9EWWm4;QV+r^P#Q=v12GslK<WQb8fG^DHhBvH
literal 0
HcmV?d00001
diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
index e489d94331..a5a5b8807b 100644
--- a/tests/qtest/bios-tables-test.c
+++ b/tests/qtest/bios-tables-test.c
@@ -2252,6 +2252,25 @@ static void test_acpi_aarch64_virt_tcg_its_off(void)
free_test_data(&data);
}
+static void test_acpi_aarch64_virt_tcg_msi_gicv2m(void)
+{
+ test_data data = {
+ .machine = "virt",
+ .arch = "aarch64",
+ .variant = ".msi_gicv2m",
+ .tcg_only = true,
+ .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
+ .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
+ .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2",
+ .ram_start = 0x40000000ULL,
+ .scan_len = 128ULL * 1024 * 1024,
+ };
+
+ test_acpi_one("-cpu cortex-a57 "
+ "-M gic-version=3,iommu=smmuv3,msi=gicv2m", &data);
+ free_test_data(&data);
+}
+
static void test_acpi_q35_viot(void)
{
test_data data = {
@@ -2834,6 +2853,8 @@ int main(int argc, char *argv[])
test_acpi_aarch64_virt_tcg_topology);
qtest_add_func("acpi/virt/its_off",
test_acpi_aarch64_virt_tcg_its_off);
+ qtest_add_func("acpi/virt/msi_gicv2m",
+ test_acpi_aarch64_virt_tcg_msi_gicv2m);
qtest_add_func("acpi/virt/numamem",
test_acpi_aarch64_virt_tcg_numamem);
qtest_add_func("acpi/virt/memhp", test_acpi_aarch64_virt_tcg_memhp);
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PATCH v18 07/22] docs: arm: update virt machine model description
2026-01-27 18:27 [PATCH v18 00/22] WHPX support for Arm Mohamed Mediouni
` (5 preceding siblings ...)
2026-01-27 18:27 ` [PATCH v18 06/22] qtest: hw/arm: virt: add new test case for GICv3 + GICv2m Mohamed Mediouni
@ 2026-01-27 18:27 ` Mohamed Mediouni
2026-01-29 15:23 ` Peter Maydell
2026-01-27 18:27 ` [PATCH v18 08/22] whpx: Move around files before introducing AArch64 support Mohamed Mediouni
` (14 subsequent siblings)
21 siblings, 1 reply; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-27 18:27 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Zhao Liu, Michael S. Tsirkin, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Philippe Mathieu-Daudé,
Yanan Wang, Akihiko Odaki, Marcel Apfelbaum, Pedro Barbuda,
Richard Henderson, Paolo Bonzini, Marc-André Lureau,
Shannon Zhao, Igor Mammedov, Cameron Esfahani, Alexander Graf,
Peter Maydell, Eduardo Habkost, Phil Dennis-Jordan
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 | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst
index e5570773ba..3799d2237e 100644
--- a/docs/system/arm/virt.rst
+++ b/docs/system/arm/virt.rst
@@ -41,9 +41,10 @@ The virt board supports:
- User-creatable SMMUv3 devices (see below for example)
- 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 GICv3, ITS is selected by default when available on the platform.
+ - If using GICv2, a GICv2m is provided by default instead.
+ - When ITS is not available on a GICv3 platform, a GICv2m is provided by default.
- 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,9 +168,11 @@ gic-version
with TCG this is currently ``3`` if ``virtualization`` is ``off`` and
``4`` if ``virtualization`` is ``on``, but this may change in future)
+msi
+ Set ``auto``/``gicv2m``/``its``/``none`` to control MSI controller configuration. The default is ``auto``.
+
its
- Set ``on``/``off`` to enable/disable ITS instantiation. The default is ``on``
- for machine types later than ``virt-2.7``.
+ Set ``on``/``off`` to control ITS instantiation. This is a deprecated option, use ``msi`` instead.
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] 35+ messages in thread* Re: [PATCH v18 07/22] docs: arm: update virt machine model description
2026-01-27 18:27 ` [PATCH v18 07/22] docs: arm: update virt machine model description Mohamed Mediouni
@ 2026-01-29 15:23 ` Peter Maydell
0 siblings, 0 replies; 35+ messages in thread
From: Peter Maydell @ 2026-01-29 15:23 UTC (permalink / raw)
To: Mohamed Mediouni
Cc: qemu-devel, Zhao Liu, Michael S. Tsirkin, Roman Bolshakov,
qemu-arm, Ani Sinha, Daniel P. Berrangé,
Philippe Mathieu-Daudé, Yanan Wang, Akihiko Odaki,
Marcel Apfelbaum, Pedro Barbuda, Richard Henderson, Paolo Bonzini,
Marc-André Lureau, Shannon Zhao, Igor Mammedov,
Cameron Esfahani, Alexander Graf, Eduardo Habkost,
Phil Dennis-Jordan
On Tue, 27 Jan 2026 at 18:28, Mohamed Mediouni <mohamed@unpredictable.fr> wrote:
>
> 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 | 13 ++++++++-----
> 1 file changed, 8 insertions(+), 5 deletions(-)
>
> diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst
> index e5570773ba..3799d2237e 100644
> --- a/docs/system/arm/virt.rst
> +++ b/docs/system/arm/virt.rst
> @@ -41,9 +41,10 @@ The virt board supports:
> - User-creatable SMMUv3 devices (see below for example)
> - 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 GICv3, ITS is selected by default when available on the platform.
> + - If using GICv2, a GICv2m is provided by default instead.
> + - When ITS is not available on a GICv3 platform, a GICv2m is provided by default.
> - 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,9 +168,11 @@ gic-version
> with TCG this is currently ``3`` if ``virtualization`` is ``off`` and
> ``4`` if ``virtualization`` is ``on``, but this may change in future)
>
> +msi
> + Set ``auto``/``gicv2m``/``its``/``none`` to control MSI controller configuration. The default is ``auto``.
We can be a bit more verbose than this. Compare
https://patchew.org/QEMU/20260120180339.1416328-1-peter.maydell@linaro.org/20260120180339.1416328-5-peter.maydell@linaro.org/
thanks
-- PMM
^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH v18 08/22] whpx: Move around files before introducing AArch64 support
2026-01-27 18:27 [PATCH v18 00/22] WHPX support for Arm Mohamed Mediouni
` (6 preceding siblings ...)
2026-01-27 18:27 ` [PATCH v18 07/22] docs: arm: update virt machine model description Mohamed Mediouni
@ 2026-01-27 18:27 ` Mohamed Mediouni
2026-01-27 18:27 ` [PATCH v18 09/22] whpx: reshuffle common code Mohamed Mediouni
` (13 subsequent siblings)
21 siblings, 0 replies; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-27 18:27 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Zhao Liu, Michael S. Tsirkin, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Philippe Mathieu-Daudé,
Yanan Wang, Akihiko Odaki, Marcel Apfelbaum, Pedro Barbuda,
Richard Henderson, Paolo Bonzini, Marc-André Lureau,
Shannon Zhao, Igor Mammedov, Cameron Esfahani, Alexander Graf,
Peter Maydell, Eduardo Habkost, Phil Dennis-Jordan,
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>
Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
---
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 | 6 ++++--
target/i386/whpx/meson.build | 1 -
target/i386/whpx/whpx-all.c | 4 ++--
target/i386/whpx/whpx-apic.c | 2 +-
9 files changed, 20 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 (97%)
diff --git a/MAINTAINERS b/MAINTAINERS
index e23354235d..ba565ca5fb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -565,9 +565,11 @@ WHPX CPUs
M: Pedro Barbuda <pbarbuda@microsoft.com>
M: Mohamed Mediouni <mohamed@unpredictable.fr>
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 97%
rename from target/i386/whpx/whpx-internal.h
rename to include/system/whpx-internal.h
index 2dcad1f565..041fa958b4 100644
--- a/target/i386/whpx/whpx-internal.h
+++ b/include/system/whpx-internal.h
@@ -1,11 +1,13 @@
-#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>
#include <winhvemulation.h>
#include "hw/i386/apic.h"
+#include "exec/vaddr.h"
typedef enum WhpxBreakpointState {
WHPX_BP_CLEARED = 0,
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 db184e1b0d..cef31fc1a8 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] 35+ messages in thread* [PATCH v18 09/22] whpx: reshuffle common code
2026-01-27 18:27 [PATCH v18 00/22] WHPX support for Arm Mohamed Mediouni
` (7 preceding siblings ...)
2026-01-27 18:27 ` [PATCH v18 08/22] whpx: Move around files before introducing AArch64 support Mohamed Mediouni
@ 2026-01-27 18:27 ` Mohamed Mediouni
2026-01-27 18:27 ` [PATCH v18 10/22] whpx: ifdef out winhvemulation on non-x86_64 Mohamed Mediouni
` (12 subsequent siblings)
21 siblings, 0 replies; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-27 18:27 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Zhao Liu, Michael S. Tsirkin, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Philippe Mathieu-Daudé,
Yanan Wang, Akihiko Odaki, Marcel Apfelbaum, Pedro Barbuda,
Richard Henderson, Paolo Bonzini, Marc-André Lureau,
Shannon Zhao, Igor Mammedov, Cameron Esfahani, Alexander Graf,
Peter Maydell, Eduardo Habkost, Phil Dennis-Jordan,
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>
Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
---
MAINTAINERS | 2 +
accel/whpx/meson.build | 1 +
accel/whpx/whpx-common.c | 558 +++++++++++++++++++++++++++++++++++
include/system/whpx-all.h | 20 ++
include/system/whpx-common.h | 21 ++
target/i386/whpx/whpx-all.c | 551 +---------------------------------
6 files changed, 612 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 ba565ca5fb..5a7b955111 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -570,6 +570,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..0a6068fdde
--- /dev/null
+++ b/accel/whpx/whpx-common.c
@@ -0,0 +1,558 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU Windows Hypervisor Platform accelerator (WHPX)
+ *
+ * Copyright Microsoft Corp. 2017
+ */
+
+#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/core/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 cef31fc1a8..052cda42bf 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] 35+ messages in thread* [PATCH v18 10/22] whpx: ifdef out winhvemulation on non-x86_64
2026-01-27 18:27 [PATCH v18 00/22] WHPX support for Arm Mohamed Mediouni
` (8 preceding siblings ...)
2026-01-27 18:27 ` [PATCH v18 09/22] whpx: reshuffle common code Mohamed Mediouni
@ 2026-01-27 18:27 ` Mohamed Mediouni
2026-01-27 18:27 ` [PATCH v18 11/22] whpx: common: add WHPX_INTERCEPT_DEBUG_TRAPS define Mohamed Mediouni
` (11 subsequent siblings)
21 siblings, 0 replies; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-27 18:27 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Zhao Liu, Michael S. Tsirkin, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Philippe Mathieu-Daudé,
Yanan Wang, Akihiko Odaki, Marcel Apfelbaum, Pedro Barbuda,
Richard Henderson, Paolo Bonzini, Marc-André Lureau,
Shannon Zhao, Igor Mammedov, Cameron Esfahani, Alexander Graf,
Peter Maydell, Eduardo Habkost, Phil Dennis-Jordan,
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>
Reviewed-by: Philippe Mathieu-Daudé <philmd@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 0a6068fdde..c58344cb61 100644
--- a/accel/whpx/whpx-common.c
+++ b/accel/whpx/whpx-common.c
@@ -37,7 +37,9 @@
bool whpx_allowed;
static bool whp_dispatch_initialized;
static HMODULE hWinHvPlatform;
+#ifdef HOST_X86_64
static HMODULE hWinHvEmulation;
+#endif
struct whpx_state whpx_global;
struct WHPDispatch whp_dispatch;
@@ -232,8 +234,10 @@ void whpx_destroy_vcpu(CPUState *cpu)
struct whpx_state *whpx = &whpx_global;
whp_dispatch.WHvDeleteVirtualProcessor(whpx->partition, cpu->cpu_index);
+#ifdef HOST_X86_64
AccelCPUState *vcpu = cpu->accel;
whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator);
+#endif
g_free(cpu->accel);
}
@@ -408,8 +412,12 @@ static bool load_whp_dispatch_fns(HMODULE *handle,
LIST_WINHVPLATFORM_FUNCTIONS(WHP_LOAD_FIELD)
break;
case WINHV_EMULATION_FNS_DEFAULT:
+#ifdef HOST_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)
@@ -535,11 +543,11 @@ bool init_whp_dispatch(void)
if (!load_whp_dispatch_fns(&hWinHvPlatform, WINHV_PLATFORM_FNS_DEFAULT)) {
goto error;
}
-
+#ifdef HOST_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;
@@ -549,9 +557,11 @@ error:
if (hWinHvPlatform) {
FreeLibrary(hWinHvPlatform);
}
+#ifdef HOST_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..8f171d1397 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 HOST_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 041fa958b4..609d0e1c08 100644
--- a/include/system/whpx-internal.h
+++ b/include/system/whpx-internal.h
@@ -4,8 +4,9 @@
#include <windows.h>
#include <winhvplatform.h>
+#ifdef HOST_X86_64
#include <winhvemulation.h>
-
+#endif
#include "hw/i386/apic.h"
#include "exec/vaddr.h"
@@ -101,12 +102,16 @@ void whpx_apic_get(APICCommonState *s);
/* Define function typedef */
LIST_WINHVPLATFORM_FUNCTIONS(WHP_DEFINE_TYPE)
+#ifdef HOST_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 HOST_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] 35+ messages in thread* [PATCH v18 11/22] whpx: common: add WHPX_INTERCEPT_DEBUG_TRAPS define
2026-01-27 18:27 [PATCH v18 00/22] WHPX support for Arm Mohamed Mediouni
` (9 preceding siblings ...)
2026-01-27 18:27 ` [PATCH v18 10/22] whpx: ifdef out winhvemulation on non-x86_64 Mohamed Mediouni
@ 2026-01-27 18:27 ` Mohamed Mediouni
2026-01-27 18:27 ` [PATCH v18 12/22] hw, target, accel: whpx: change apic_in_platform to kernel_irqchip Mohamed Mediouni
` (10 subsequent siblings)
21 siblings, 0 replies; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-27 18:27 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Zhao Liu, Michael S. Tsirkin, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Philippe Mathieu-Daudé,
Yanan Wang, Akihiko Odaki, Marcel Apfelbaum, Pedro Barbuda,
Richard Henderson, Paolo Bonzini, Marc-André Lureau,
Shannon Zhao, Igor Mammedov, Cameron Esfahani, Alexander Graf,
Peter Maydell, Eduardo Habkost, Phil Dennis-Jordan,
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>
Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
---
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 c58344cb61..c0610815d9 100644
--- a/accel/whpx/whpx-common.c
+++ b/accel/whpx/whpx-common.c
@@ -119,7 +119,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 8f171d1397..b86fe9db6e 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] 35+ messages in thread* [PATCH v18 12/22] hw, target, accel: whpx: change apic_in_platform to kernel_irqchip
2026-01-27 18:27 [PATCH v18 00/22] WHPX support for Arm Mohamed Mediouni
` (10 preceding siblings ...)
2026-01-27 18:27 ` [PATCH v18 11/22] whpx: common: add WHPX_INTERCEPT_DEBUG_TRAPS define Mohamed Mediouni
@ 2026-01-27 18:27 ` Mohamed Mediouni
2026-01-27 18:27 ` [PATCH v18 13/22] whpx: interrupt controller support Mohamed Mediouni
` (9 subsequent siblings)
21 siblings, 0 replies; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-27 18:27 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Zhao Liu, Michael S. Tsirkin, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Philippe Mathieu-Daudé,
Yanan Wang, Akihiko Odaki, Marcel Apfelbaum, Pedro Barbuda,
Richard Henderson, Paolo Bonzini, Marc-André Lureau,
Shannon Zhao, Igor Mammedov, Cameron Esfahani, Alexander Graf,
Peter Maydell, Eduardo Habkost, Phil Dennis-Jordan,
Pierrick Bouvier
Change terminology to match the KVM one, as APIC is x86-specific.
And move out whpx_irqchip_in_kernel() to make it usable from common
code even when not compiling with WHPX support.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
---
accel/stubs/whpx-stub.c | 1 +
accel/whpx/whpx-accel-ops.c | 2 +-
accel/whpx/whpx-common.c | 10 +---------
hw/i386/x86-cpu.c | 4 ++--
include/system/whpx-internal.h | 1 -
include/system/whpx.h | 5 +++--
target/i386/cpu-apic.c | 2 +-
target/i386/whpx/whpx-all.c | 14 +++++++-------
8 files changed, 16 insertions(+), 23 deletions(-)
diff --git a/accel/stubs/whpx-stub.c b/accel/stubs/whpx-stub.c
index c564c89fd0..4529dc4f78 100644
--- a/accel/stubs/whpx-stub.c
+++ b/accel/stubs/whpx-stub.c
@@ -10,3 +10,4 @@
#include "system/whpx.h"
bool whpx_allowed;
+bool whpx_irqchip_in_kernel;
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 c0610815d9..05f9e520b7 100644
--- a/accel/whpx/whpx-common.c
+++ b/accel/whpx/whpx-common.c
@@ -35,6 +35,7 @@
#include <winhvplatformdefs.h>
bool whpx_allowed;
+bool whpx_irqchip_in_kernel;
static bool whp_dispatch_initialized;
static HMODULE hWinHvPlatform;
#ifdef HOST_X86_64
@@ -488,15 +489,6 @@ static const TypeInfo whpx_cpu_accel_type = {
.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);
diff --git a/hw/i386/x86-cpu.c b/hw/i386/x86-cpu.c
index 276f2b0cdf..95e08e3c2a 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 609d0e1c08..8ded54a39b 100644
--- a/include/system/whpx-internal.h
+++ b/include/system/whpx-internal.h
@@ -45,7 +45,6 @@ struct whpx_state {
bool kernel_irqchip_allowed;
bool kernel_irqchip_required;
- bool apic_in_platform;
};
extern struct whpx_state whpx_global;
diff --git a/include/system/whpx.h b/include/system/whpx.h
index 00f6a3e523..4217a27e91 100644
--- a/include/system/whpx.h
+++ b/include/system/whpx.h
@@ -25,11 +25,12 @@
#ifdef CONFIG_WHPX_IS_POSSIBLE
extern bool whpx_allowed;
+extern bool whpx_irqchip_in_kernel;
#define whpx_enabled() (whpx_allowed)
-bool whpx_apic_in_platform(void);
+#define whpx_irqchip_in_kernel() (whpx_irqchip_in_kernel)
#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 eeee62b52a..50a2b8ae86 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 052cda42bf..8210250dc3 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_irqchip_in_kernel = 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] 35+ messages in thread* [PATCH v18 13/22] whpx: interrupt controller support
2026-01-27 18:27 [PATCH v18 00/22] WHPX support for Arm Mohamed Mediouni
` (11 preceding siblings ...)
2026-01-27 18:27 ` [PATCH v18 12/22] hw, target, accel: whpx: change apic_in_platform to kernel_irqchip Mohamed Mediouni
@ 2026-01-27 18:27 ` Mohamed Mediouni
2026-01-29 15:28 ` Peter Maydell
2026-01-27 18:27 ` [PATCH v18 14/22] whpx: add arm64 support Mohamed Mediouni
` (8 subsequent siblings)
21 siblings, 1 reply; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-27 18:27 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Zhao Liu, Michael S. Tsirkin, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Philippe Mathieu-Daudé,
Yanan Wang, Akihiko Odaki, Marcel Apfelbaum, Pedro Barbuda,
Richard Henderson, Paolo Bonzini, Marc-André Lureau,
Shannon Zhao, Igor Mammedov, Cameron Esfahani, Alexander Graf,
Peter Maydell, Eduardo Habkost, Phil Dennis-Jordan
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
MAINTAINERS | 1 +
hw/arm/virt.c | 10 ++
hw/intc/arm_gicv3_common.c | 3 +
hw/intc/arm_gicv3_whpx.c | 237 +++++++++++++++++++++++++++++
hw/intc/meson.build | 1 +
include/hw/intc/arm_gicv3_common.h | 3 +
6 files changed, 255 insertions(+)
create mode 100644 hw/intc/arm_gicv3_whpx.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 5a7b955111..d18978a36b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -567,6 +567,7 @@ M: Mohamed Mediouni <mohamed@unpredictable.fr>
S: Supported
F: accel/whpx/
F: target/i386/whpx/
+F: hw/intc/arm_gicv3_whpx.c
F: accel/stubs/whpx-stub.c
F: include/system/whpx.h
F: include/system/whpx-accel-ops.h
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 3d7f02ce0e..9e989b721b 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -49,6 +49,7 @@
#include "system/tcg.h"
#include "system/kvm.h"
#include "system/hvf.h"
+#include "system/whpx.h"
#include "system/qtest.h"
#include "system/system.h"
#include "hw/core/loader.h"
@@ -2110,6 +2111,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")) {
@@ -2143,6 +2146,9 @@ static void finalize_msi_controller(VirtMachineState *vms)
}
}
if (vms->msi_controller == VIRT_MSI_CTRL_AUTO) {
+ if (whpx_enabled() && whpx_irqchip_in_kernel()) {
+ vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
+ }
if (vms->gic_version == VIRT_GIC_VERSION_2) {
vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
}
@@ -2157,6 +2163,10 @@ static void finalize_msi_controller(VirtMachineState *vms)
error_report("GICv2 + ITS is an invalid configuration.");
exit(1);
}
+ if (whpx_enabled()) {
+ error_report("ITS not supported on WHPX.");
+ exit(1);
+ }
}
assert(vms->msi_controller != VIRT_MSI_CTRL_AUTO);
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index 0a2e5a3e2f..9054143ea7 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..849a005242
--- /dev/null
+++ b/hw/intc/arm_gicv3_whpx.c
@@ -0,0 +1,237 @@
+/* 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 "migration/blocker.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;
+};
+
+OBJECT_DECLARE_TYPE(GICv3State, WHPXARMGICv3Class, 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 = opaque;
+ WHV_INTERRUPT_CONTROL interrupt_control = {
+ .InterruptControl.InterruptType = WHvArm64InterruptTypeFixed,
+ .RequestedVector = GIC_INTERNAL + irq,
+ .InterruptControl.Asserted = level
+ };
+
+ if (irq > s->num_irq) {
+ return;
+ }
+
+
+ whp_dispatch.WHvRequestInterrupt(whpx->partition, &interrupt_control,
+ sizeof(interrupt_control));
+}
+
+static void whpx_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ GICv3CPUState *c;
+
+ c = env->gicv3state;
+
+ 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));
+}
+
+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)
+{
+ ERRP_GUARD();
+ GICv3State *s = WHPX_GICV3(dev);
+ WHPXARMGICv3Class *kgc = WHPX_GICV3_GET_CLASS(s);
+ int i;
+
+ kgc->parent_realize(dev, errp);
+ if (*errp) {
+ return;
+ }
+
+ if (s->revision != 3) {
+ error_setg(errp, "unsupported GIC revision %d for platform GIC",
+ s->revision);
+ return;
+ }
+
+ 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;
+ }
+
+ error_setg(&s->migration_blocker,
+ "Live migration disabled because GIC state save/restore not supported on WHPX");
+ if (migrate_add_blocker(&s->migration_blocker, errp) < 0) {
+ error_report_err(*errp);
+ }
+}
+
+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 3d24ad22d2..c55cf18120 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] 35+ messages in thread* Re: [PATCH v18 13/22] whpx: interrupt controller support
2026-01-27 18:27 ` [PATCH v18 13/22] whpx: interrupt controller support Mohamed Mediouni
@ 2026-01-29 15:28 ` Peter Maydell
2026-01-29 16:51 ` Mohamed Mediouni
0 siblings, 1 reply; 35+ messages in thread
From: Peter Maydell @ 2026-01-29 15:28 UTC (permalink / raw)
To: Mohamed Mediouni
Cc: qemu-devel, Zhao Liu, Michael S. Tsirkin, Roman Bolshakov,
qemu-arm, Ani Sinha, Daniel P. Berrangé,
Philippe Mathieu-Daudé, Yanan Wang, Akihiko Odaki,
Marcel Apfelbaum, Pedro Barbuda, Richard Henderson, Paolo Bonzini,
Marc-André Lureau, Shannon Zhao, Igor Mammedov,
Cameron Esfahani, Alexander Graf, Eduardo Habkost,
Phil Dennis-Jordan
On Tue, 27 Jan 2026 at 18:29, Mohamed Mediouni <mohamed@unpredictable.fr> wrote:
>
> Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
> @@ -2143,6 +2146,9 @@ static void finalize_msi_controller(VirtMachineState *vms)
> }
> }
> if (vms->msi_controller == VIRT_MSI_CTRL_AUTO) {
> + if (whpx_enabled() && whpx_irqchip_in_kernel()) {
> + vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
> + }
This looks like it ought to be an "else if" or some other
construct so we don't fall through into the logic below --
if we've decided we definitely want a GICV2M we can stop
making decisions about how to set vms->msi_controller.
> if (vms->gic_version == VIRT_GIC_VERSION_2) {
> vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
> }
Otherwise
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
thanks
-- PMM
^ permalink raw reply [flat|nested] 35+ messages in thread* Re: [PATCH v18 13/22] whpx: interrupt controller support
2026-01-29 15:28 ` Peter Maydell
@ 2026-01-29 16:51 ` Mohamed Mediouni
0 siblings, 0 replies; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-29 16:51 UTC (permalink / raw)
To: Peter Maydell
Cc: qemu-devel, Zhao Liu, Michael S. Tsirkin, Roman Bolshakov,
qemu-arm, Ani Sinha, "Daniel P. Berrangé",
Philippe Mathieu-Daudé, Yanan Wang, Akihiko Odaki,
Marcel Apfelbaum, Pedro Barbuda, Richard Henderson, Paolo Bonzini,
Marc-André Lureau, Shannon Zhao, Igor Mammedov,
Cameron Esfahani, Alexander Graf, Eduardo Habkost,
Phil Dennis-Jordan
> On 29. Jan 2026, at 16:28, Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On Tue, 27 Jan 2026 at 18:29, Mohamed Mediouni <mohamed@unpredictable.fr> wrote:
>>
>> Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
>
>
>
>> @@ -2143,6 +2146,9 @@ static void finalize_msi_controller(VirtMachineState *vms)
>> }
>> }
>> if (vms->msi_controller == VIRT_MSI_CTRL_AUTO) {
>> + if (whpx_enabled() && whpx_irqchip_in_kernel()) {
>> + vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
>> + }
>
> This looks like it ought to be an "else if" or some other
> construct so we don't fall through into the logic below --
> if we've decided we definitely want a GICV2M we can stop
> making decisions about how to set vms->msi_controller.
Would just doing a return; be a right way to deal with this, or converting to case?
Thank you,
-Mohamed
>> if (vms->gic_version == VIRT_GIC_VERSION_2) {
>> vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
>> }
>
> Otherwise
> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
>
> thanks
> -- PMM
^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH v18 14/22] whpx: add arm64 support
2026-01-27 18:27 [PATCH v18 00/22] WHPX support for Arm Mohamed Mediouni
` (12 preceding siblings ...)
2026-01-27 18:27 ` [PATCH v18 13/22] whpx: interrupt controller support Mohamed Mediouni
@ 2026-01-27 18:27 ` Mohamed Mediouni
2026-01-27 18:27 ` [PATCH v18 15/22] whpx: change memory management logic Mohamed Mediouni
` (7 subsequent siblings)
21 siblings, 0 replies; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-27 18:27 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Zhao Liu, Michael S. Tsirkin, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Philippe Mathieu-Daudé,
Yanan Wang, Akihiko Odaki, Marcel Apfelbaum, Pedro Barbuda,
Richard Henderson, Paolo Bonzini, Marc-André Lureau,
Shannon Zhao, Igor Mammedov, Cameron Esfahani, Alexander Graf,
Peter Maydell, Eduardo Habkost, Phil Dennis-Jordan,
Pierrick Bouvier
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
---
MAINTAINERS | 1 +
accel/whpx/whpx-common.c | 1 +
target/arm/meson.build | 1 +
target/arm/whpx/meson.build | 3 +
target/arm/whpx/whpx-all.c | 810 ++++++++++++++++++++++++++++++++++++
5 files changed, 816 insertions(+)
create mode 100644 target/arm/whpx/meson.build
create mode 100644 target/arm/whpx/whpx-all.c
diff --git a/MAINTAINERS b/MAINTAINERS
index d18978a36b..669a97a9b9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -567,6 +567,7 @@ M: Mohamed Mediouni <mohamed@unpredictable.fr>
S: Supported
F: accel/whpx/
F: target/i386/whpx/
+F: target/arm/whpx/
F: hw/intc/arm_gicv3_whpx.c
F: accel/stubs/whpx-stub.c
F: include/system/whpx.h
diff --git a/accel/whpx/whpx-common.c b/accel/whpx/whpx-common.c
index 05f9e520b7..827f50f3e0 100644
--- a/accel/whpx/whpx-common.c
+++ b/accel/whpx/whpx-common.c
@@ -12,6 +12,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 462c71148d..ce155ba9b4 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..192d7ec7a8
--- /dev/null
+++ b/target/arm/whpx/whpx-all.c
@@ -0,0 +1,810 @@
+/* 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/core/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>
+
+typedef struct WHPXRegMatch {
+ WHV_REGISTER_NAME reg;
+ uint64_t offset;
+} WHPXRegMatch;
+
+static const WHPXRegMatch 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 WHPXRegMatch 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)
+{
+ /* Breakpoints aren’t supported on this platform */
+}
+void whpx_translate_cpu_breakpoints(
+ struct whpx_breakpoints *breakpoints,
+ CPUState *cpu,
+ int cpu_breakpoint_count)
+{
+ /* Breakpoints aren’t supported on this platform */
+}
+
+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 & BIT(8)) {
+ 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 *)((char *)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((char *)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].cp_idx == -1) {
+ continue;
+ }
+
+ if (whpx_sreg_match[i].global) {
+ /* WHP disallows us from accessing global regs as a vCPU */
+ whpx_get_global_reg(whpx_sreg_match[i].reg, &val);
+ } else {
+ whpx_get_reg(cpu, 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 *)((char *)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, (char *)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));
+
+ /* Currently set global regs every time. */
+ for (i = 0; i < ARRAY_SIZE(whpx_sreg_match); i++) {
+ if (whpx_sreg_match[i].cp_idx == -1) {
+ continue;
+ }
+
+ val.Reg64 = arm_cpu->cpreg_values[whpx_sreg_match[i].cp_idx];
+ if (whpx_sreg_match[i].global) {
+ /* WHP disallows us from accessing global regs as a vCPU */
+ whpx_set_global_reg(whpx_sreg_match[i].reg, val);
+ } else {
+ whpx_set_reg(cpu, 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;
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
+ CPUARMState *env = &arm_cpu->env;
+
+ uint32_t sregs_match_len = ARRAY_SIZE(whpx_sreg_match);
+ uint32_t sregs_cnt = 0;
+ WHV_REGISTER_VALUE val;
+ int i;
+
+ 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);
+ return -EINVAL;
+ }
+
+ /* 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 = g_new0(AccelCPUState, 1);
+ 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;
+}
+
+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;
+
+ whpx = &whpx_global;
+ /* on arm64 Windows Hypervisor Platform, vGICv3 always used */
+ whpx_irqchip_in_kernel = 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;
+ }
+
+ memset(&features, 0, sizeof(features));
+ 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(prop));
+ prop.ProcessorCount = ms->smp.cpus;
+ hr = whp_dispatch.WHvSetPartitionProperty(
+ whpx->partition,
+ WHvPartitionPropertyCodeProcessorCount,
+ &prop,
+ sizeof(prop));
+
+ 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(prop));
+
+ 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 (whpx->partition != NULL) {
+ whp_dispatch.WHvDeletePartition(whpx->partition);
+ whpx->partition = NULL;
+ }
+
+ return ret;
+}
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 35+ messages in thread* [PATCH v18 15/22] whpx: change memory management logic
2026-01-27 18:27 [PATCH v18 00/22] WHPX support for Arm Mohamed Mediouni
` (13 preceding siblings ...)
2026-01-27 18:27 ` [PATCH v18 14/22] whpx: add arm64 support Mohamed Mediouni
@ 2026-01-27 18:27 ` Mohamed Mediouni
2026-01-27 18:27 ` [PATCH v18 16/22] target/arm: cpu: mark WHPX as supporting PSCI 1.3 Mohamed Mediouni
` (6 subsequent siblings)
21 siblings, 0 replies; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-27 18:27 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Zhao Liu, Michael S. Tsirkin, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Philippe Mathieu-Daudé,
Yanan Wang, Akihiko Odaki, Marcel Apfelbaum, Pedro Barbuda,
Richard Henderson, Paolo Bonzini, Marc-André Lureau,
Shannon Zhao, Igor Mammedov, Cameron Esfahani, Alexander Graf,
Peter Maydell, Eduardo Habkost, Phil Dennis-Jordan,
Pierrick Bouvier
This allows edk2 to work on Arm, although u-boot is still not functional.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
---
accel/whpx/whpx-common.c | 97 +++++++++++++++-------------------------
1 file changed, 36 insertions(+), 61 deletions(-)
diff --git a/accel/whpx/whpx-common.c b/accel/whpx/whpx-common.c
index 827f50f3e0..f018a8f5c7 100644
--- a/accel/whpx/whpx-common.c
+++ b/accel/whpx/whpx-common.c
@@ -255,89 +255,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;
+ 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 hr;
+ void *mem;
- /*
- 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);
+ 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) {
+ hr = whp_dispatch.WHvUnmapGpaRange(whpx->partition,
+ gva, size);
+ if (FAILED(hr)) {
+ 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);
+ hr = whp_dispatch.WHvMapGpaRange(whpx->partition,
+ mem, gva, size, flags);
+ if (FAILED(hr)) {
+ 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] 35+ messages in thread* [PATCH v18 16/22] target/arm: cpu: mark WHPX as supporting PSCI 1.3
2026-01-27 18:27 [PATCH v18 00/22] WHPX support for Arm Mohamed Mediouni
` (14 preceding siblings ...)
2026-01-27 18:27 ` [PATCH v18 15/22] whpx: change memory management logic Mohamed Mediouni
@ 2026-01-27 18:27 ` Mohamed Mediouni
2026-01-27 18:27 ` [PATCH v18 17/22] whpx: arm64: clamp down IPA size Mohamed Mediouni
` (5 subsequent siblings)
21 siblings, 0 replies; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-27 18:27 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Zhao Liu, Michael S. Tsirkin, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Philippe Mathieu-Daudé,
Yanan Wang, Akihiko Odaki, Marcel Apfelbaum, Pedro Barbuda,
Richard Henderson, Paolo Bonzini, Marc-André Lureau,
Shannon Zhao, Igor Mammedov, Cameron Esfahani, Alexander Graf,
Peter Maydell, Eduardo Habkost, Phil Dennis-Jordan,
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>
Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
---
target/arm/cpu.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 6e1cbf3d61..7bfc3ecd2e 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] 35+ messages in thread* [PATCH v18 17/22] whpx: arm64: clamp down IPA size
2026-01-27 18:27 [PATCH v18 00/22] WHPX support for Arm Mohamed Mediouni
` (15 preceding siblings ...)
2026-01-27 18:27 ` [PATCH v18 16/22] target/arm: cpu: mark WHPX as supporting PSCI 1.3 Mohamed Mediouni
@ 2026-01-27 18:27 ` Mohamed Mediouni
2026-01-27 18:27 ` [PATCH v18 18/22] hw/arm, accel/hvf, whpx: unify get_physical_address_range between WHPX and HVF Mohamed Mediouni
` (4 subsequent siblings)
21 siblings, 0 replies; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-27 18:27 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Zhao Liu, Michael S. Tsirkin, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Philippe Mathieu-Daudé,
Yanan Wang, Akihiko Odaki, Marcel Apfelbaum, Pedro Barbuda,
Richard Henderson, Paolo Bonzini, Marc-André Lureau,
Shannon Zhao, Igor Mammedov, Cameron Esfahani, Alexander Graf,
Peter Maydell, Eduardo Habkost, Phil Dennis-Jordan,
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/core/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 9e989b721b..7a9bcd15fd 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -72,6 +72,7 @@
#include "hw/core/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"
@@ -3329,6 +3330,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. whpx_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);
@@ -3428,6 +3459,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/core/boards.h b/include/hw/core/boards.h
index 07f8938752..0b2aefb126 100644
--- a/include/hw/core/boards.h
+++ b/include/hw/core/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 192d7ec7a8..850f6ec81f 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"
@@ -633,6 +634,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;
@@ -706,6 +741,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;
}
@@ -722,6 +758,8 @@ int whpx_accel_init(AccelState *as, MachineState *ms)
UINT32 whpx_cap_size;
WHV_PARTITION_PROPERTY prop;
WHV_CAPABILITY_FEATURES features;
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ int pa_range = 0;
whpx = &whpx_global;
/* on arm64 Windows Hypervisor Platform, vGICv3 always used */
@@ -732,6 +770,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] 35+ messages in thread* [PATCH v18 18/22] hw/arm, accel/hvf, whpx: unify get_physical_address_range between WHPX and HVF
2026-01-27 18:27 [PATCH v18 00/22] WHPX support for Arm Mohamed Mediouni
` (16 preceding siblings ...)
2026-01-27 18:27 ` [PATCH v18 17/22] whpx: arm64: clamp down IPA size Mohamed Mediouni
@ 2026-01-27 18:27 ` Mohamed Mediouni
2026-01-27 18:27 ` [PATCH v18 19/22] whpx: arm64: implement -cpu host Mohamed Mediouni
` (3 subsequent siblings)
21 siblings, 0 replies; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-27 18:27 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Zhao Liu, Michael S. Tsirkin, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Philippe Mathieu-Daudé,
Yanan Wang, Akihiko Odaki, Marcel Apfelbaum, Pedro Barbuda,
Richard Henderson, Paolo Bonzini, Marc-André Lureau,
Shannon Zhao, Igor Mammedov, Cameron Esfahani, Alexander Graf,
Peter Maydell, Eduardo Habkost, Phil Dennis-Jordan,
Pierrick Bouvier
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
accel/hvf/hvf-all.c | 7 +++++--
hw/arm/virt.c | 43 +++++---------------------------------
include/hw/core/boards.h | 4 ++--
include/system/hvf_int.h | 4 ++++
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, 33 insertions(+), 71 deletions(-)
delete mode 100644 target/arm/hvf-stub.c
diff --git a/accel/hvf/hvf-all.c b/accel/hvf/hvf-all.c
index 0fbe27dfa2..033c677b6f 100644
--- a/accel/hvf/hvf-all.c
+++ b/accel/hvf/hvf-all.c
@@ -18,6 +18,7 @@
#include "system/hvf_int.h"
#include "hw/core/cpu.h"
#include "hw/core/boards.h"
+#include "target/arm/hvf_arm.h"
#include "trace.h"
bool hvf_allowed;
@@ -186,8 +187,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 7a9bcd15fd..fd9a3ed480 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -3330,43 +3330,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. whpx_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);
@@ -3375,8 +3343,8 @@ 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
- * returns values that are valid ARM PARange values.
+ * the maximum. hvf/whpx_arch_get_max_ipa_bit_size() conveniently only
+ * return values that are valid ARM PARange values.
*/
if (requested_ipa_size <= default_ipa_size) {
requested_ipa_size = default_ipa_size;
@@ -3458,8 +3426,7 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
mc->get_valid_cpu_types = virt_get_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/core/boards.h b/include/hw/core/boards.h
index 0b2aefb126..26e0879e1a 100644
--- a/include/hw/core/boards.h
+++ b/include/hw/core/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 96790b4938..2621164cb2 100644
--- a/include/system/hvf_int.h
+++ b/include/system/hvf_int.h
@@ -57,6 +57,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);
void hvf_kick_vcpu_thread(CPUState *cpu);
/* Must be called by the owning thread */
@@ -107,5 +109,7 @@ int hvf_update_guest_debug(CPUState *cpu);
bool hvf_arch_supports_guest_debug(void);
bool hvf_arch_cpu_realize(CPUState *cpu, Error **errp);
+uint32_t hvf_arch_get_default_ipa_bit_size(void);
+uint32_t hvf_arch_get_max_ipa_bit_size(void);
#endif
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 e4c0d936f1..74b6f5e7db 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -729,7 +729,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. */
@@ -825,7 +825,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);
@@ -834,7 +834,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 ce155ba9b4..1ddc4b2a54 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 850f6ec81f..6067918b27 100644
--- a/target/arm/whpx/whpx-all.c
+++ b/target/arm/whpx/whpx-all.c
@@ -770,8 +770,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 7cfaee389e..ce54020f00 100644
--- a/target/i386/hvf/hvf.c
+++ b/target/i386/hvf/hvf.c
@@ -228,6 +228,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] 35+ messages in thread* [PATCH v18 19/22] whpx: arm64: implement -cpu host
2026-01-27 18:27 [PATCH v18 00/22] WHPX support for Arm Mohamed Mediouni
` (17 preceding siblings ...)
2026-01-27 18:27 ` [PATCH v18 18/22] hw/arm, accel/hvf, whpx: unify get_physical_address_range between WHPX and HVF Mohamed Mediouni
@ 2026-01-27 18:27 ` Mohamed Mediouni
2026-01-27 18:28 ` [PATCH v18 20/22] target/arm: whpx: instantiate GIC early Mohamed Mediouni
` (2 subsequent siblings)
21 siblings, 0 replies; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-27 18:27 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Zhao Liu, Michael S. Tsirkin, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Philippe Mathieu-Daudé,
Yanan Wang, Akihiko Odaki, Marcel Apfelbaum, Pedro Barbuda,
Richard Henderson, Paolo Bonzini, Marc-André Lureau,
Shannon Zhao, Igor Mammedov, Cameron Esfahani, Alexander Graf,
Peter Maydell, Eduardo Habkost, Phil Dennis-Jordan,
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>
Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
---
target/arm/cpu64.c | 17 +++---
target/arm/whpx/whpx-all.c | 104 +++++++++++++++++++++++++++++++++++++
target/arm/whpx_arm.h | 1 +
3 files changed, 116 insertions(+), 6 deletions(-)
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index bf30381370..689babe822 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/core/qdev-properties.h"
#include "internals.h"
@@ -521,7 +524,7 @@ void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp)
isar2 = FIELD_DP64(isar2, ID_AA64ISAR2, APA3, 0);
isar2 = FIELD_DP64(isar2, ID_AA64ISAR2, GPA3, 0);
- if (kvm_enabled() || hvf_enabled()) {
+ if (hwaccel_enabled()) {
/*
* Exit early if PAuth is enabled and fall through to disable it.
* The algorithm selection properties are not present.
@@ -598,10 +601,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,
@@ -769,6 +772,8 @@ static void aarch64_host_initfn(Object *obj)
}
#elif defined(CONFIG_HVF)
hvf_arm_set_cpu_features_from_host(cpu);
+#elif defined(CONFIG_WHPX)
+ whpx_arm_set_cpu_features_from_host(cpu);
#else
g_assert_not_reached();
#endif
@@ -779,8 +784,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;
}
@@ -799,7 +804,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 6067918b27..c88c67a9e2 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;
typedef struct WHPXRegMatch {
WHV_REGISTER_NAME reg;
@@ -668,6 +679,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] 35+ messages in thread* [PATCH v18 20/22] target/arm: whpx: instantiate GIC early
2026-01-27 18:27 [PATCH v18 00/22] WHPX support for Arm Mohamed Mediouni
` (18 preceding siblings ...)
2026-01-27 18:27 ` [PATCH v18 19/22] whpx: arm64: implement -cpu host Mohamed Mediouni
@ 2026-01-27 18:28 ` Mohamed Mediouni
2026-01-29 15:31 ` Peter Maydell
2026-01-27 18:28 ` [PATCH v18 21/22] whpx: enable arm64 builds Mohamed Mediouni
2026-01-27 18:28 ` [PATCH v18 22/22] whpx: arm64: add partition-wide reset on the reboot path Mohamed Mediouni
21 siblings, 1 reply; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-27 18:28 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Zhao Liu, Michael S. Tsirkin, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Philippe Mathieu-Daudé,
Yanan Wang, Akihiko Odaki, Marcel Apfelbaum, Pedro Barbuda,
Richard Henderson, Paolo Bonzini, Marc-André Lureau,
Shannon Zhao, Igor Mammedov, Cameron Esfahani, Alexander Graf,
Peter Maydell, Eduardo Habkost, Phil Dennis-Jordan,
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>
Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
---
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 c88c67a9e2..55773555b7 100644
--- a/target/arm/whpx/whpx-all.c
+++ b/target/arm/whpx/whpx-all.c
@@ -939,6 +939,29 @@ int whpx_accel_init(AccelState *as, MachineState *ms)
memset(&prop, 0, sizeof(prop));
+ 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(prop));
+ 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] 35+ messages in thread* Re: [PATCH v18 20/22] target/arm: whpx: instantiate GIC early
2026-01-27 18:28 ` [PATCH v18 20/22] target/arm: whpx: instantiate GIC early Mohamed Mediouni
@ 2026-01-29 15:31 ` Peter Maydell
2026-01-29 16:25 ` Mohamed Mediouni
0 siblings, 1 reply; 35+ messages in thread
From: Peter Maydell @ 2026-01-29 15:31 UTC (permalink / raw)
To: Mohamed Mediouni
Cc: qemu-devel, Zhao Liu, Michael S. Tsirkin, Roman Bolshakov,
qemu-arm, Ani Sinha, Daniel P. Berrangé,
Philippe Mathieu-Daudé, Yanan Wang, Akihiko Odaki,
Marcel Apfelbaum, Pedro Barbuda, Richard Henderson, Paolo Bonzini,
Marc-André Lureau, Shannon Zhao, Igor Mammedov,
Cameron Esfahani, Alexander Graf, Eduardo Habkost,
Phil Dennis-Jordan, Pierrick Bouvier
On Tue, 27 Jan 2026 at 18:29, Mohamed Mediouni <mohamed@unpredictable.fr> wrote:
>
> 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>
> Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
> ---
> 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 c88c67a9e2..55773555b7 100644
> --- a/target/arm/whpx/whpx-all.c
> +++ b/target/arm/whpx/whpx-all.c
> @@ -939,6 +939,29 @@ int whpx_accel_init(AccelState *as, MachineState *ms)
>
> memset(&prop, 0, sizeof(prop));
>
> + 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(prop));
> + if (FAILED(hr)) {
> + error_report("WHPX: Failed to enable GICv3 interrupt controller, hr=%08lx", hr);
> + ret = -EINVAL;
> + goto error;
> + }
So what happens if the user asked for a GICv2 ?
Can we have a comment to explain the ordering requirement
mentioned in the commit message that is forcing this to be
here rather than in the GIC code ?
> +
> 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)
-- PMM
^ permalink raw reply [flat|nested] 35+ messages in thread* Re: [PATCH v18 20/22] target/arm: whpx: instantiate GIC early
2026-01-29 15:31 ` Peter Maydell
@ 2026-01-29 16:25 ` Mohamed Mediouni
0 siblings, 0 replies; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-29 16:25 UTC (permalink / raw)
To: Peter Maydell
Cc: qemu-devel, Zhao Liu, Michael S. Tsirkin, Roman Bolshakov,
qemu-arm, Ani Sinha, "Daniel P. Berrangé",
Philippe Mathieu-Daudé, Yanan Wang, Akihiko Odaki,
Marcel Apfelbaum, Pedro Barbuda, Richard Henderson, Paolo Bonzini,
Marc-André Lureau, Shannon Zhao, Igor Mammedov,
Cameron Esfahani, Alexander Graf, Eduardo Habkost,
Phil Dennis-Jordan, Pierrick Bouvier
> On 29. Jan 2026, at 16:31, Peter Maydell <peter.maydell@linaro.org> wrote:
>
> So what happens if the user asked for a GICv2 ?
>
Hi,
If the user asked for a GICv2 then they’re going to get an error in
finalize_gic_version_do (in hw/arm/virt.c), with it being enforced there.
> Can we have a comment to explain the ordering requirement
> mentioned in the commit message that is forcing this to be
> here rather than in the GIC code ?
Will add in the next revision.
^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH v18 21/22] whpx: enable arm64 builds
2026-01-27 18:27 [PATCH v18 00/22] WHPX support for Arm Mohamed Mediouni
` (19 preceding siblings ...)
2026-01-27 18:28 ` [PATCH v18 20/22] target/arm: whpx: instantiate GIC early Mohamed Mediouni
@ 2026-01-27 18:28 ` Mohamed Mediouni
2026-01-27 18:28 ` [PATCH v18 22/22] whpx: arm64: add partition-wide reset on the reboot path Mohamed Mediouni
21 siblings, 0 replies; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-27 18:28 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Zhao Liu, Michael S. Tsirkin, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Philippe Mathieu-Daudé,
Yanan Wang, Akihiko Odaki, Marcel Apfelbaum, Pedro Barbuda,
Richard Henderson, Paolo Bonzini, Marc-André Lureau,
Shannon Zhao, Igor Mammedov, Cameron Esfahani, Alexander Graf,
Peter Maydell, Eduardo Habkost, Phil Dennis-Jordan,
Pierrick Bouvier
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
---
meson.build | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/meson.build b/meson.build
index a84f14258b..286afca4bb 100644
--- a/meson.build
+++ b/meson.build
@@ -300,7 +300,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 += {
@@ -856,13 +857,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] 35+ messages in thread* [PATCH v18 22/22] whpx: arm64: add partition-wide reset on the reboot path
2026-01-27 18:27 [PATCH v18 00/22] WHPX support for Arm Mohamed Mediouni
` (20 preceding siblings ...)
2026-01-27 18:28 ` [PATCH v18 21/22] whpx: enable arm64 builds Mohamed Mediouni
@ 2026-01-27 18:28 ` Mohamed Mediouni
21 siblings, 0 replies; 35+ messages in thread
From: Mohamed Mediouni @ 2026-01-27 18:28 UTC (permalink / raw)
To: qemu-devel, mohamed
Cc: Zhao Liu, Michael S. Tsirkin, Roman Bolshakov, qemu-arm,
Ani Sinha, Daniel P. Berrangé, Philippe Mathieu-Daudé,
Yanan Wang, Akihiko Odaki, Marcel Apfelbaum, Pedro Barbuda,
Richard Henderson, Paolo Bonzini, Marc-André Lureau,
Shannon Zhao, Igor Mammedov, Cameron Esfahani, Alexander Graf,
Peter Maydell, Eduardo Habkost, Phil Dennis-Jordan,
Pierrick Bouvier
This resets non-architectural state to allow for reboots to succeed.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
---
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 8ded54a39b..ad6ade223e 100644
--- a/include/system/whpx-internal.h
+++ b/include/system/whpx-internal.h
@@ -86,6 +86,8 @@ void whpx_apic_get(APICCommonState *s);
X(HRESULT, WHvSetVirtualProcessorInterruptControllerState2, \
(WHV_PARTITION_HANDLE Partition, UINT32 VpIndex, PVOID State, \
UINT32 StateSize)) \
+ X(HRESULT, WHvResetPartition, \
+ (WHV_PARTITION_HANDLE Partition)) \
#define LIST_WINHVEMULATION_FUNCTIONS(X) \
X(HRESULT, WHvEmulatorCreateEmulator, (const WHV_EMULATOR_CALLBACKS* Callbacks, WHV_EMULATOR_HANDLE* Emulator)) \
diff --git a/target/arm/whpx/whpx-all.c b/target/arm/whpx/whpx-all.c
index 55773555b7..444f8c3d42 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] 35+ messages in thread