From 92122685e5ed95c143fdfa223c170f11867db7bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 21 Oct 2025 16:53:13 +0200 Subject: [PATCH 01/38] hw/gpio/pl061: Declare pullups/pulldowns as 8-bit types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit uint8_t is good enough to hold a property "between 0 and 0xff". Define pullups/pulldowns properties using DEFINE_PROP_UINT8() macro, remove unnecessary range checks in pl061_realize(). Update the two caller sites. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/virt.c | 4 ++-- hw/gpio/pl061.c | 16 ++++------------ hw/vmapple/vmapple.c | 4 ++-- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index d07cfe1651..b3ecd6dce3 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1136,8 +1136,8 @@ static void create_gpio_devices(const VirtMachineState *vms, int gpio, pl061_dev = qdev_new("pl061"); /* Pull lines down to 0 if not driven by the PL061 */ - qdev_prop_set_uint32(pl061_dev, "pullups", 0); - qdev_prop_set_uint32(pl061_dev, "pulldowns", 0xff); + qdev_prop_set_uint8(pl061_dev, "pullups", 0); + qdev_prop_set_uint8(pl061_dev, "pulldowns", 0xff); s = SYS_BUS_DEVICE(pl061_dev); sysbus_realize_and_unref(s, &error_fatal); memory_region_add_subregion(mem, base, sysbus_mmio_get_region(s, 0)); diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c index 1acca3f2f8..a3ac038c2f 100644 --- a/hw/gpio/pl061.c +++ b/hw/gpio/pl061.c @@ -79,8 +79,8 @@ struct PL061State { qemu_irq out[N_GPIOS]; const unsigned char *id; /* Properties, for non-Luminary PL061 */ - uint32_t pullups; - uint32_t pulldowns; + uint8_t pullups; + uint8_t pulldowns; }; static const VMStateDescription vmstate_pl061 = { @@ -547,14 +547,6 @@ static void pl061_realize(DeviceState *dev, Error **errp) { PL061State *s = PL061(dev); - if (s->pullups > 0xff) { - error_setg(errp, "pullups property must be between 0 and 0xff"); - return; - } - if (s->pulldowns > 0xff) { - error_setg(errp, "pulldowns property must be between 0 and 0xff"); - return; - } if (s->pullups & s->pulldowns) { error_setg(errp, "no bit may be set both in pullups and pulldowns"); return; @@ -562,8 +554,8 @@ static void pl061_realize(DeviceState *dev, Error **errp) } static const Property pl061_props[] = { - DEFINE_PROP_UINT32("pullups", PL061State, pullups, 0xff), - DEFINE_PROP_UINT32("pulldowns", PL061State, pulldowns, 0x0), + DEFINE_PROP_UINT8("pullups", PL061State, pullups, 0xff), + DEFINE_PROP_UINT8("pulldowns", PL061State, pulldowns, 0x0), }; static void pl061_class_init(ObjectClass *klass, const void *data) diff --git a/hw/vmapple/vmapple.c b/hw/vmapple/vmapple.c index 1e4365f32c..f3cff32924 100644 --- a/hw/vmapple/vmapple.c +++ b/hw/vmapple/vmapple.c @@ -326,8 +326,8 @@ static void create_gpio_devices(const VMAppleMachineState *vms, int gpio, pl061_dev = qdev_new("pl061"); /* Pull lines down to 0 if not driven by the PL061 */ - qdev_prop_set_uint32(pl061_dev, "pullups", 0); - qdev_prop_set_uint32(pl061_dev, "pulldowns", 0xff); + qdev_prop_set_uint8(pl061_dev, "pullups", 0); + qdev_prop_set_uint8(pl061_dev, "pulldowns", 0xff); s = SYS_BUS_DEVICE(pl061_dev); sysbus_realize_and_unref(s, &error_fatal); memory_region_add_subregion(mem, base, sysbus_mmio_get_region(s, 0)); From 65e3b1de55ed6625197a188469e52fe6c6096406 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 27 Oct 2025 12:40:47 +0000 Subject: [PATCH 02/38] docs/system/arm/virt: Document user-creatable SMMUv3 The virt machine now supports creating multiple SMMUv3 instances, each associated with a separate PCIe root complex. Update the documentation with an example. Signed-off-by: Shameer Kolothum [PMM: some minor wording tweaks] Reviewed-by: Peter Maydell Reviewed-by: Eric Auger Signed-off-by: Peter Maydell --- docs/system/arm/virt.rst | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst index 10cbffc8a7..e5570773ba 100644 --- a/docs/system/arm/virt.rst +++ b/docs/system/arm/virt.rst @@ -37,7 +37,8 @@ The virt board supports: - An RTC - The fw_cfg device that allows a guest to obtain data from QEMU - A PL061 GPIO controller -- An optional SMMUv3 IOMMU +- An optional machine-wide SMMUv3 IOMMU +- User-creatable SMMUv3 devices (see below for example) - hotpluggable DIMMs - hotpluggable NVDIMMs - An MSI controller (GICv2M or ITS). GICv2M is selected by default along @@ -176,7 +177,7 @@ iommu ``none`` Don't create an IOMMU (the default) ``smmuv3`` - Create an SMMUv3 + Create a machine-wide SMMUv3. default-bus-bypass-iommu Set ``on``/``off`` to enable/disable `bypass_iommu @@ -219,6 +220,36 @@ x-oem-table-id Set string (up to 8 bytes) to override the default value of field OEM Table ID in ACPI table header. +SMMU configuration +"""""""""""""""""" + +Machine-wide SMMUv3 IOMMU + Setting the machine-specific option ``iommu=smmuv3`` causes QEMU to + create a single, machine-wide SMMUv3 instance that applies to all + devices in the PCIe topology. + + For information about selectively bypassing devices, refer to + ``docs/bypass-iommu.txt``. + +User-creatable SMMUv3 devices + You can use the ``-device arm-smmuv3`` option to create multiple + user-defined SMMUv3 devices, each associated with a separate PCIe + root complex. This is only permitted if the machine-wide SMMUv3 + (``iommu=smmuv3``) option is not used. Each ``arm-smmuv3`` device + uses the ``primary-bus`` sub-option to specify which PCIe root + complex it is associated with. + + This model is useful when you want to mirror a host configuration where + each NUMA node typically has its own SMMU, allowing the VM topology to + align more closely with the host’s hardware layout. + + Example:: + + -device arm-smmuv3,primary-bus=pcie.0,id=smmuv3.0 + ... + -device pxb-pcie,id=pcie.1,numa_node=1 + -device arm-smmuv3,primary-bus=pcie.1,id=smmuv3.1 + Linux guest kernel configuration """""""""""""""""""""""""""""""" From f16f2586ec95da3c2fb06bad9047d9c43f76185b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 16 Oct 2025 14:11:59 +0100 Subject: [PATCH 03/38] docs/system/security: Restrict "virtualization use case" to specific machines Currently our security policy defines a "virtualization use case" where we consider bugs to be security issues, and a "non-virtualization use case" where we do not make any security guarantees and don't consider bugs to be security issues. The rationale for this split is that much code in QEMU is older and was not written with malicious guests in mind, and we don't have the resources to audit, fix and defend it. So instead we inform users about what the can in practice rely on as a security barrier, and what they can't. We don't currently restrict the "virtualization use case" to any particular set of machine types. This means that we have effectively barred ourselves from adding KVM support to any machine type that we don't want to put into the "bugs are security issues" category, even if it would be useful for users to be able to get better performance with a trusted guest by enabling KVM. This seems an unnecessary restriction, and in practice the set of machine types it makes sense to use for untrusted-guest virtualization is quite small. Specifically, we would like to be able to enable the use of KVM with the imx8 development board machine types, but we don't want to commit ourselves to having to support those SoC models and device models as part of QEMU's security boundary: https://lore.kernel.org/qemu-devel/20250629204851.1778-3-shentey@gmail.com/ This patch updates the security policy to explicitly list the machine types we consider to be useful for the "virtualization use case". Signed-off-by: Peter Maydell Acked-by: Christian Borntraeger Reviewed-by: Bibo Mao Reviewed-by: Thomas Huth Reviewed-by: Harsh Prateek Bora Reviewed-by: Bernhard Beschow Message-id: 20251016131159.750480-1-peter.maydell@linaro.org Acked-by: Markus Armbruster --- docs/system/security.rst | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/system/security.rst b/docs/system/security.rst index f2092c8768..53992048e6 100644 --- a/docs/system/security.rst +++ b/docs/system/security.rst @@ -35,6 +35,32 @@ malicious: Bugs affecting these entities are evaluated on whether they can cause damage in real-world use cases and treated as security bugs if this is the case. +To be covered by this security support policy you must: + +- use a virtualization accelerator like KVM or HVF +- use one of the machine types listed below + +It may be possible to use other machine types with a virtualization +accelerator to provide improved performance with a trusted guest +workload, but any machine type not listed here should not be +considered to be providing guest isolation or security guarantees, +and falls under the "non-virtualization use case". + +Supported machine types for the virtualization use case, by target architecture: + +aarch64 + ``virt`` +i386, x86_64 + ``microvm``, ``xenfv``, ``xenpv``, ``xenpvh``, ``pc``, ``q35`` +s390x + ``s390-ccw-virtio`` +loongarch64: + ``virt`` +ppc64: + ``pseries`` +riscv32, riscv64: + ``virt`` + Non-virtualization Use Case ''''''''''''''''''''''''''' From ac55e58c05241b50f64a4631a722a01db0af05a9 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 23 Oct 2025 11:13:39 +0100 Subject: [PATCH 04/38] target/arm: Add assert to arm_to_core_mmu_idx() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before commit f76cee647c ("target/arm: Introduce mmu indexes for GCS") it was impossible for arm_to_core_mmu_idx() to return an invalid core MMU index, because NB_MMU_MODES was 16 and ARM_MMU_IDX_COREIDX_MASK was 0xf. That commit raises ARM_MMU_IDX_COREIDX_MASK to 0x1f and NB_MMU_MODES to 22, so it's now possible for a bogus Arm mmu index to result in an out of range core mmu index (which can then get used as an array index in the CPUTLB struct arrays). Coverity complains that this might result in an out-of-bounds access. The out-of-bounds access can't happen because we construct all the ARMMMUIdx values we will use for TLBs to have valid core MMU indexes in the COREIDX field. But we can add an assert() so that if we ever do end up operating on a corrupted or wrong ARMMMUIdx value we get an assert rather than silently indexing off the end of an array. This should also make Coverity happier. Coverity: CID 1641404 Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20251023101339.1983809-1-peter.maydell@linaro.org --- target/arm/internals.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target/arm/internals.h b/target/arm/internals.h index 6fbf7e1ca4..4c0fa28ef8 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -969,7 +969,9 @@ bool arm_cpu_tlb_fill_align(CPUState *cs, CPUTLBEntryFull *out, vaddr addr, static inline int arm_to_core_mmu_idx(ARMMMUIdx mmu_idx) { - return mmu_idx & ARM_MMU_IDX_COREIDX_MASK; + int coreidx = mmu_idx & ARM_MMU_IDX_COREIDX_MASK; + assert(coreidx < NB_MMU_MODES); + return coreidx; } static inline ARMMMUIdx core_to_arm_mmu_idx(CPUARMState *env, int mmu_idx) From b7c52f28bf5b61751a9d3fbf4961dc826068ef51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 20 Oct 2025 11:40:18 +0200 Subject: [PATCH 05/38] hw/arm/virt: Remove deprecated virt-4.1 machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This machine has been supported for a period of more than 6 years. According to our versioned machine support policy (see commit ce80c4fa6ff "docs: document special exception for machine type deprecation & removal") it can now be removed. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20251020094022.68768-2-philmd@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/virt.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index b3ecd6dce3..6cf8ed58d5 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -3711,14 +3711,3 @@ static void virt_machine_4_2_options(MachineClass *mc) vmc->kvm_no_adjvtime = true; } DEFINE_VIRT_MACHINE(4, 2) - -static void virt_machine_4_1_options(MachineClass *mc) -{ - VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc)); - - virt_machine_4_2_options(mc); - compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len); - vmc->no_ged = true; - mc->auto_enable_numa_with_memhp = false; -} -DEFINE_VIRT_MACHINE(4, 1) From 5eb33245f96c17de7616ee239569b09f9561b376 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 20 Oct 2025 11:40:19 +0200 Subject: [PATCH 06/38] hw/arm/virt: Remove VirtMachineClass::no_ged field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VirtMachineClass::no_ged field was only used by virt-4.1 machine, which got removed. Remove it as now unused. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20251020094022.68768-3-philmd@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/virt.c | 3 +-- include/hw/arm/virt.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 6cf8ed58d5..4d03317b59 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2213,7 +2213,6 @@ static void machvirt_init(MachineState *machine) int n, virt_max_cpus; bool firmware_loaded; bool aarch64 = true; - bool has_ged = !vmc->no_ged; unsigned int smp_cpus = machine->smp.cpus; unsigned int max_cpus = machine->smp.max_cpus; @@ -2515,7 +2514,7 @@ static void machvirt_init(MachineState *machine) create_pcie(vms); create_cxl_host_reg_region(vms); - if (has_ged && aarch64 && firmware_loaded && virt_is_acpi_enabled(vms)) { + if (aarch64 && firmware_loaded && virt_is_acpi_enabled(vms)) { vms->acpi_dev = create_acpi_ged(vms); vms->generic_error_notifier.notify = virt_generic_error_req; notifier_list_add(&acpi_generic_error_notifiers, diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index 04a09af354..993872bb68 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -123,7 +123,6 @@ struct VirtMachineClass { MachineClass parent; bool no_tcg_its; bool no_highmem_compact; - bool no_ged; /* Machines < 4.2 have no support for ACPI GED device */ bool kvm_no_adjvtime; bool no_kvm_steal_time; bool acpi_expose_flash; From c43313a0c7a1ba7e9ed090d76f91f3adb40d6975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 20 Oct 2025 11:40:20 +0200 Subject: [PATCH 07/38] hw/arm/virt: Remove deprecated virt-4.2 machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This machine has been supported for a period of more than 6 years. According to our versioned machine support policy (see commit ce80c4fa6ff "docs: document special exception for machine type deprecation & removal") it can now be removed. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20251020094022.68768-4-philmd@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/virt.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 4d03317b59..751e22e6f4 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -3700,13 +3700,3 @@ static void virt_machine_5_0_options(MachineClass *mc) mc->auto_enable_numa_with_memdev = false; } DEFINE_VIRT_MACHINE(5, 0) - -static void virt_machine_4_2_options(MachineClass *mc) -{ - VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc)); - - virt_machine_5_0_options(mc); - compat_props_add(mc->compat_props, hw_compat_4_2, hw_compat_4_2_len); - vmc->kvm_no_adjvtime = true; -} -DEFINE_VIRT_MACHINE(4, 2) From 725770c2cbaef07cb3cf558f02ac502503f07a49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 20 Oct 2025 11:40:21 +0200 Subject: [PATCH 08/38] hw/arm/virt: Remove VirtMachineClass::kvm_no_adjvtime field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VirtMachineClass::kvm_no_adjvtime field was only used by the virt-4.2 machine, which got removed. Remove it as now unused, but keep the ARMCPU homonym property. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20251020094022.68768-5-philmd@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/virt.c | 5 ----- include/hw/arm/virt.h | 1 - 2 files changed, 6 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 751e22e6f4..25fb2bab56 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2365,11 +2365,6 @@ static void machvirt_init(MachineState *machine) object_property_set_bool(cpuobj, "has_el2", false, NULL); } - if (vmc->kvm_no_adjvtime && - object_property_find(cpuobj, "kvm-no-adjvtime")) { - object_property_set_bool(cpuobj, "kvm-no-adjvtime", true, NULL); - } - if (vmc->no_kvm_steal_time && object_property_find(cpuobj, "kvm-steal-time")) { object_property_set_bool(cpuobj, "kvm-steal-time", false, NULL); diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index 993872bb68..c77a33f6df 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -123,7 +123,6 @@ struct VirtMachineClass { MachineClass parent; bool no_tcg_its; bool no_highmem_compact; - bool kvm_no_adjvtime; bool no_kvm_steal_time; bool acpi_expose_flash; bool no_secure_gpio; From d9b51fadecdcef8c8e42efc0e3c24b172e54f58c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:41:37 +0100 Subject: [PATCH 09/38] target/arm/hvf: Release memory allocated by hv_vcpu_config_create() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hv_vcpu_config_create() is documented in as: /*! @abstract Creates a vcpu configuration object. @result A new vcpu configuration object. This should be released with os_release when no longer used. */ OS_OBJECT_RETURNS_RETAINED OS_WARN_RESULT hv_vcpu_config_t hv_vcpu_config_create(void); Release the memory allocated by hv_vcpu_config_create() with os_release(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Mads Ynddal Signed-off-by: Peter Maydell --- target/arm/hvf/hvf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 0658a99a2d..83db108838 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -150,6 +150,8 @@ void hvf_arm_init_debug(void) max_hw_wps = hvf_arm_num_wrps(config); hw_watchpoints = g_array_sized_new(true, true, sizeof(HWWatchpoint), max_hw_wps); + + os_release(config); } #define SYSREG_OP0_SHIFT 20 From 080b8a49ed5a50124ef18cc81c15362582f0117a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:41:38 +0100 Subject: [PATCH 10/38] target/arm/hvf: Trace vCPU KICK events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- target/arm/hvf/hvf.c | 1 + target/arm/hvf/trace-events | 1 + 2 files changed, 2 insertions(+) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 83db108838..91bbd3a6aa 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -963,6 +963,7 @@ int hvf_arch_init_vcpu(CPUState *cpu) void hvf_kick_vcpu_thread(CPUState *cpu) { + trace_hvf_kick_vcpu_thread(cpu->cpu_index, cpu->stop); cpus_kick_thread(cpu); hv_vcpus_exit(&cpu->accel->fd, 1); } diff --git a/target/arm/hvf/trace-events b/target/arm/hvf/trace-events index b29a995f3d..538af6e070 100644 --- a/target/arm/hvf/trace-events +++ b/target/arm/hvf/trace-events @@ -12,3 +12,4 @@ hvf_psci_call(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint32_t cpuid hvf_vgic_write(const char *name, uint64_t val) "vgic write to %s [val=0x%016"PRIx64"]" hvf_vgic_read(const char *name, uint64_t val) "vgic read from %s [val=0x%016"PRIx64"]" hvf_illegal_guest_state(void) "HV_ILLEGAL_GUEST_STATE" +hvf_kick_vcpu_thread(unsigned cpuidx, bool stop) "cpu:%u stop:%u" From 1645ebabd496a13d8603349e04d460341cb65930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:41:39 +0100 Subject: [PATCH 11/38] target/arm/hvf: Check hv_vcpus_exit() returned value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hv_vcpus_exit() returns a hv_return_t enum type (defined in ). Assert we succeeded, as we are not ready to handle any error path. Suggested-by: Alex Bennée Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Mads Ynddal Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- target/arm/hvf/hvf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 91bbd3a6aa..4c98faebbe 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -963,9 +963,11 @@ int hvf_arch_init_vcpu(CPUState *cpu) void hvf_kick_vcpu_thread(CPUState *cpu) { + hv_return_t ret; trace_hvf_kick_vcpu_thread(cpu->cpu_index, cpu->stop); cpus_kick_thread(cpu); - hv_vcpus_exit(&cpu->accel->fd, 1); + ret = hv_vcpus_exit(&cpu->accel->fd, 1); + assert_hvf_ok(ret); } static void hvf_raise_exception(CPUState *cpu, uint32_t excp, From 320496f4ecff7c290933e1910f6d93d7d8572b6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:41:40 +0100 Subject: [PATCH 12/38] target/arm/hvf: Check hv_vcpu_set_vtimer_mask() returned value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hv_vcpu_set_vtimer_mask() returns a hv_return_t enum type (defined in ). Assert we succeeded, as we are not ready to handle any error path. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Mads Ynddal Signed-off-by: Peter Maydell --- target/arm/hvf/hvf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 4c98faebbe..bbe0b24b82 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -1782,7 +1782,8 @@ static void hvf_sync_vtimer(CPUState *cpu) if (!irq_state) { /* Timer no longer asserting, we can unmask it */ - hv_vcpu_set_vtimer_mask(cpu->accel->fd, false); + r = hv_vcpu_set_vtimer_mask(cpu->accel->fd, false); + assert_hvf_ok(r); cpu->accel->vtimer_masked = false; } } From 963f1576c0cd4893f566572535edeed9d341017b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:41:41 +0100 Subject: [PATCH 13/38] accel/hvf: Rename hvf_vcpu_exec() -> hvf_arch_vcpu_exec() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hvf_vcpu_exec() is implemented per target, rename it as hvf_arch_vcpu_exec(), following the per target pattern. Since it calls hv_vcpu_run(), mention it must be called on the vCPU. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Mads Ynddal Signed-off-by: Peter Maydell --- accel/hvf/hvf-accel-ops.c | 2 +- include/system/hvf_int.h | 4 +++- target/arm/hvf/hvf.c | 2 +- target/i386/hvf/hvf.c | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c index 8b794c2d41..005e2bd891 100644 --- a/accel/hvf/hvf-accel-ops.c +++ b/accel/hvf/hvf-accel-ops.c @@ -194,7 +194,7 @@ static void *hvf_cpu_thread_fn(void *arg) do { qemu_process_cpu_events(cpu); if (cpu_can_run(cpu)) { - r = hvf_vcpu_exec(cpu); + r = hvf_arch_vcpu_exec(cpu); if (r == EXCP_DEBUG) { cpu_handle_guest_debug(cpu); } diff --git a/include/system/hvf_int.h b/include/system/hvf_int.h index a3b06a3e75..32b32e1d02 100644 --- a/include/system/hvf_int.h +++ b/include/system/hvf_int.h @@ -73,12 +73,14 @@ int hvf_arch_init(void); hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range); int hvf_arch_init_vcpu(CPUState *cpu); void hvf_arch_vcpu_destroy(CPUState *cpu); -int hvf_vcpu_exec(CPUState *); hvf_slot *hvf_find_overlap_slot(uint64_t, uint64_t); int hvf_put_registers(CPUState *); int hvf_get_registers(CPUState *); void hvf_kick_vcpu_thread(CPUState *cpu); +/* Must be called by the owning thread */ +int hvf_arch_vcpu_exec(CPUState *); + struct hvf_sw_breakpoint { vaddr pc; vaddr saved_insn; diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index bbe0b24b82..9111c1d717 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -1788,7 +1788,7 @@ static void hvf_sync_vtimer(CPUState *cpu) } } -int hvf_vcpu_exec(CPUState *cpu) +int hvf_arch_vcpu_exec(CPUState *cpu) { ARMCPU *arm_cpu = ARM_CPU(cpu); CPUARMState *env = &arm_cpu->env; diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 33f723a76a..b2bf59cb48 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -721,7 +721,7 @@ void hvf_simulate_wrmsr(CPUState *cs) printf("write msr %llx\n", RCX(cs));*/ } -int hvf_vcpu_exec(CPUState *cpu) +int hvf_arch_vcpu_exec(CPUState *cpu) { X86CPU *x86_cpu = X86_CPU(cpu); CPUX86State *env = &x86_cpu->env; From 1182ede151c4c034001a36375202500c5afe871f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:41:42 +0100 Subject: [PATCH 14/38] accel/hvf: Rename hvf_put|get_registers -> hvf_arch_put|get_registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hvf_put_registers() and hvf_get_registers() are implemented per target, rename them using the 'hvf_arch_' prefix following the per target pattern. Since they call hv_vcpu_set_reg() / hv_vcpu_get_reg(), mention they must be called on the vCPU. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Mads Ynddal Signed-off-by: Peter Maydell --- accel/hvf/hvf-accel-ops.c | 2 +- include/system/hvf_int.h | 6 ++++-- target/arm/hvf/hvf.c | 8 +++++--- target/i386/hvf/hvf.c | 2 +- target/i386/hvf/x86hvf.c | 4 ++-- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c index 005e2bd891..3e5feecd8a 100644 --- a/accel/hvf/hvf-accel-ops.c +++ b/accel/hvf/hvf-accel-ops.c @@ -81,7 +81,7 @@ hvf_slot *hvf_find_overlap_slot(uint64_t start, uint64_t size) static void do_hvf_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg) { if (!cpu->vcpu_dirty) { - hvf_get_registers(cpu); + hvf_arch_get_registers(cpu); cpu->vcpu_dirty = true; } } diff --git a/include/system/hvf_int.h b/include/system/hvf_int.h index 32b32e1d02..8fce627b08 100644 --- a/include/system/hvf_int.h +++ b/include/system/hvf_int.h @@ -74,12 +74,14 @@ hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range); int hvf_arch_init_vcpu(CPUState *cpu); void hvf_arch_vcpu_destroy(CPUState *cpu); hvf_slot *hvf_find_overlap_slot(uint64_t, uint64_t); -int hvf_put_registers(CPUState *); -int hvf_get_registers(CPUState *); void hvf_kick_vcpu_thread(CPUState *cpu); /* Must be called by the owning thread */ int hvf_arch_vcpu_exec(CPUState *); +/* Must be called by the owning thread */ +int hvf_arch_put_registers(CPUState *); +/* Must be called by the owning thread */ +int hvf_arch_get_registers(CPUState *); struct hvf_sw_breakpoint { vaddr pc; diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 9111c1d717..f0a0e5d1a7 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -424,7 +424,7 @@ static const hv_sys_reg_t hvf_sreg_list[] = { #undef DEF_SYSREG -int hvf_get_registers(CPUState *cpu) +int hvf_arch_get_registers(CPUState *cpu) { ARMCPU *arm_cpu = ARM_CPU(cpu); CPUARMState *env = &arm_cpu->env; @@ -564,7 +564,7 @@ int hvf_get_registers(CPUState *cpu) return 0; } -int hvf_put_registers(CPUState *cpu) +int hvf_arch_put_registers(CPUState *cpu) { ARMCPU *arm_cpu = ARM_CPU(cpu); CPUARMState *env = &arm_cpu->env; @@ -692,11 +692,12 @@ int hvf_put_registers(CPUState *cpu) static void flush_cpu_state(CPUState *cpu) { if (cpu->vcpu_dirty) { - hvf_put_registers(cpu); + hvf_arch_put_registers(cpu); cpu->vcpu_dirty = false; } } +/* Must be called by the owning thread */ static void hvf_set_reg(CPUState *cpu, int rt, uint64_t val) { hv_return_t r; @@ -709,6 +710,7 @@ static void hvf_set_reg(CPUState *cpu, int rt, uint64_t val) } } +/* Must be called by the owning thread */ static uint64_t hvf_get_reg(CPUState *cpu, int rt) { uint64_t val = 0; diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index b2bf59cb48..76a58cb035 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -734,7 +734,7 @@ int hvf_arch_vcpu_exec(CPUState *cpu) do { if (cpu->vcpu_dirty) { - hvf_put_registers(cpu); + hvf_arch_put_registers(cpu); cpu->vcpu_dirty = false; } diff --git a/target/i386/hvf/x86hvf.c b/target/i386/hvf/x86hvf.c index 3838c9f5a6..bb480311b0 100644 --- a/target/i386/hvf/x86hvf.c +++ b/target/i386/hvf/x86hvf.c @@ -236,7 +236,7 @@ void hvf_get_msrs(CPUState *cs) env->tsc = rdtscp() + rvmcs(cs->accel->fd, VMCS_TSC_OFFSET); } -int hvf_put_registers(CPUState *cs) +int hvf_arch_put_registers(CPUState *cs) { X86CPU *x86cpu = X86_CPU(cs); CPUX86State *env = &x86cpu->env; @@ -280,7 +280,7 @@ int hvf_put_registers(CPUState *cs) return 0; } -int hvf_get_registers(CPUState *cs) +int hvf_arch_get_registers(CPUState *cs) { X86CPU *x86cpu = X86_CPU(cs); CPUX86State *env = &x86cpu->env; From d1a0caa0826a377fba11e79bf9920f8c301d2fca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:41:43 +0100 Subject: [PATCH 15/38] target/arm/hvf: Mention flush_cpu_state() must run on vCPU thread MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since flush_cpu_state() calls hvf_arch_put_registers(), which must run on a vCPU, it also must. Mention it. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Mads Ynddal Signed-off-by: Peter Maydell --- target/arm/hvf/hvf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index f0a0e5d1a7..fdf8df09d4 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -689,6 +689,7 @@ int hvf_arch_put_registers(CPUState *cpu) return 0; } +/* Must be called by the owning thread */ static void flush_cpu_state(CPUState *cpu) { if (cpu->vcpu_dirty) { From a641384325506d035490ce79d3c3319a829c47d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:41:44 +0100 Subject: [PATCH 16/38] accel/hvf: Mention hvf_arch_init_vcpu() must run on vCPU thread MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hvf_arch_init_vcpu(), along with hvf_put_guest_debug_registers() and hvf_put_gdbstub_debug_registers(), calls hv_vcpu_set_sys_reg(), which must run on a vCPU. Mention they also must. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Mads Ynddal Signed-off-by: Peter Maydell --- include/system/hvf_int.h | 3 ++- target/arm/hvf/hvf.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/system/hvf_int.h b/include/system/hvf_int.h index 8fce627b08..0c335facc3 100644 --- a/include/system/hvf_int.h +++ b/include/system/hvf_int.h @@ -71,11 +71,12 @@ 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); -int hvf_arch_init_vcpu(CPUState *cpu); void hvf_arch_vcpu_destroy(CPUState *cpu); hvf_slot *hvf_find_overlap_slot(uint64_t, uint64_t); void hvf_kick_vcpu_thread(CPUState *cpu); +/* Must be called by the owning thread */ +int hvf_arch_init_vcpu(CPUState *cpu); /* Must be called by the owning thread */ int hvf_arch_vcpu_exec(CPUState *); /* Must be called by the owning thread */ diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index fdf8df09d4..8095cb0805 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -2119,6 +2119,7 @@ void hvf_arch_remove_all_hw_breakpoints(void) * Update the vCPU with the gdbstub's view of debug registers. This view * consists of all hardware breakpoints and watchpoints inserted so far while * debugging the guest. + * Must be called by the owning thread. */ static void hvf_put_gdbstub_debug_registers(CPUState *cpu) { @@ -2157,6 +2158,7 @@ static void hvf_put_gdbstub_debug_registers(CPUState *cpu) /* * Update the vCPU with the guest's view of debug registers. This view is kept * in the environment at all times. + * Must be called by the owning thread. */ static void hvf_put_guest_debug_registers(CPUState *cpu) { From 30d277f2cdd85ca3a519d6c03b126d37bef29a60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:41:45 +0100 Subject: [PATCH 17/38] target/arm/hvf: Mention hvf_sync_vtimer() must run on vCPU thread MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since hvf_sync_vtimer() calls hv_vcpu_get_sys_reg(), which must run on a vCPU, it also must. Mention it. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Mads Ynddal Signed-off-by: Peter Maydell --- target/arm/hvf/hvf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 8095cb0805..bfccf5e9a2 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -1764,6 +1764,7 @@ static void hvf_wfi(CPUState *cpu) hvf_wait_for_ipi(cpu, &ts); } +/* Must be called by the owning thread */ static void hvf_sync_vtimer(CPUState *cpu) { ARMCPU *arm_cpu = ARM_CPU(cpu); From 21bab557a9ad3209552321789c9feb4b5ad1c437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:41:46 +0100 Subject: [PATCH 18/38] target/arm/hvf: Mention hvf_arch_set_traps() must run on vCPU thread MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since hvf_arch_set_traps() calls hv_vcpu_set_trap_debug_exceptions() and hv_vcpu_set_trap_debug_reg_accesses(), which must run on a vCPU, it also must. Mention it. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Mads Ynddal Signed-off-by: Peter Maydell --- target/arm/hvf/hvf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index bfccf5e9a2..ee04943b0f 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -2192,6 +2192,7 @@ static inline bool hvf_arm_hw_debug_active(CPUState *cpu) return ((cur_hw_wps > 0) || (cur_hw_bps > 0)); } +/* Must be called by the owning thread */ static void hvf_arch_set_traps(CPUState *cpu) { bool should_enable_traps = false; From 073e7e1cbea96d2bd36310d9119faceb4bf58989 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:41:47 +0100 Subject: [PATCH 19/38] accel/hvf: Mention hvf_arch_update_guest_debug() must run on vCPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since hvf_arch_update_guest_debug() calls hvf_arch_set_traps() and hvf_arch_update_guest_debug(), which must run on a vCPU, it also must. Mention it. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Mads Ynddal Signed-off-by: Peter Maydell --- include/system/hvf_int.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/system/hvf_int.h b/include/system/hvf_int.h index 0c335facc3..241c668795 100644 --- a/include/system/hvf_int.h +++ b/include/system/hvf_int.h @@ -83,6 +83,8 @@ int hvf_arch_vcpu_exec(CPUState *); int hvf_arch_put_registers(CPUState *); /* Must be called by the owning thread */ int hvf_arch_get_registers(CPUState *); +/* Must be called by the owning thread */ +void hvf_arch_update_guest_debug(CPUState *cpu); struct hvf_sw_breakpoint { vaddr pc; @@ -109,7 +111,6 @@ void hvf_arch_remove_all_hw_breakpoints(void); * handled by calling down to hvf_arch_update_guest_debug. */ int hvf_update_guest_debug(CPUState *cpu); -void hvf_arch_update_guest_debug(CPUState *cpu); /* * Return whether the guest supports debugging. From 3747befb2a64ddd216ba01a4836100d7a4909fff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:41:48 +0100 Subject: [PATCH 20/38] target/arm/hvf: Mention hvf_inject_interrupts() must run on vCPU thread MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since hvf_inject_interrupts() calls hv_vcpu_set_pending_interrupt(), which must run on a vCPU, it also must. Mention it. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Mads Ynddal Signed-off-by: Peter Maydell --- target/arm/hvf/hvf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index ee04943b0f..0d8ff49ae1 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -1664,6 +1664,7 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val) return 1; } +/* Must be called by the owning thread */ static int hvf_inject_interrupts(CPUState *cpu) { if (cpu_test_interrupt(cpu, CPU_INTERRUPT_FIQ)) { From feee55d36a1c5d494ee73812d279b439bb05137c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:41:49 +0100 Subject: [PATCH 21/38] accel/hvf: Implement hvf_arch_vcpu_destroy() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Call hv_vcpu_destroy() to destroy our vCPU context. As hv_vcpu_destroy() must be called by the owning thread, document hvf_arch_vcpu_destroy() also does. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Mads Ynddal Signed-off-by: Peter Maydell --- include/system/hvf_int.h | 3 ++- target/arm/hvf/hvf.c | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/system/hvf_int.h b/include/system/hvf_int.h index 241c668795..195d64dcf1 100644 --- a/include/system/hvf_int.h +++ b/include/system/hvf_int.h @@ -71,13 +71,14 @@ 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); -void hvf_arch_vcpu_destroy(CPUState *cpu); hvf_slot *hvf_find_overlap_slot(uint64_t, uint64_t); void hvf_kick_vcpu_thread(CPUState *cpu); /* Must be called by the owning thread */ int hvf_arch_init_vcpu(CPUState *cpu); /* Must be called by the owning thread */ +void hvf_arch_vcpu_destroy(CPUState *cpu); +/* Must be called by the owning thread */ int hvf_arch_vcpu_exec(CPUState *); /* Must be called by the owning thread */ int hvf_arch_put_registers(CPUState *); diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 0d8ff49ae1..d13ccf5508 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -868,6 +868,10 @@ void hvf_arm_set_cpu_features_from_host(ARMCPU *cpu) void hvf_arch_vcpu_destroy(CPUState *cpu) { + hv_return_t ret; + + ret = hv_vcpu_destroy(cpu->accel->fd); + assert_hvf_ok(ret); } hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range) From bddf353ab167e9c8c5664727b9822c3e906e90ca Mon Sep 17 00:00:00 2001 From: Mohamed Mediouni Date: Tue, 28 Oct 2025 06:41:50 +0100 Subject: [PATCH 22/38] target/arm/hvf: Hardcode Apple MIDR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hardcode MIDR because Apple deliberately doesn't expose a divergent MIDR across systems. Signed-off-by: Mohamed Mediouni Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- target/arm/hvf/hvf.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index d13ccf5508..890e9266f9 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -763,6 +763,7 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) hv_vcpu_t fd; hv_return_t r = HV_SUCCESS; hv_vcpu_exit_t *exit; + uint64_t t; int i; ahcf->dtb_compatible = "arm,armv8"; @@ -781,9 +782,19 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) for (i = 0; i < ARRAY_SIZE(regs); i++) { r |= hv_vcpu_get_sys_reg(fd, regs[i].reg, regs[i].val); } - r |= hv_vcpu_get_sys_reg(fd, HV_SYS_REG_MIDR_EL1, &ahcf->midr); r |= hv_vcpu_destroy(fd); + /* + * Hardcode MIDR because Apple deliberately doesn't expose a divergent + * MIDR across systems. + */ + t = FIELD_DP64(0, MIDR_EL1, IMPLEMENTER, 0x61); /* Apple */ + t = FIELD_DP64(t, MIDR_EL1, ARCHITECTURE, 0xf); /* v7 or later */ + t = FIELD_DP64(t, MIDR_EL1, PARTNUM, 0); + t = FIELD_DP64(t, MIDR_EL1, VARIANT, 0); + t = FIELD_DP64(t, MIDR_EL1, REVISION, 0); + ahcf->midr = t; + clamp_id_aa64mmfr0_parange_to_ipa_size(&host_isar); /* From 710778695ddc4c3d8834a2d92d9e7ff6292f89c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:41:51 +0100 Subject: [PATCH 23/38] target/arm/hvf: Simplify hvf_arm_get_host_cpu_features() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use index in the structure, dereference &host_isar.idregs[] once. Suggested-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- target/arm/hvf/hvf.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 890e9266f9..dea1cb37d1 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -743,21 +743,21 @@ static void clamp_id_aa64mmfr0_parange_to_ipa_size(ARMISARegisters *isar) static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) { ARMISARegisters host_isar = {}; - const struct isar_regs { + static const struct isar_regs { int reg; - uint64_t *val; + ARMIDRegisterIdx index; } regs[] = { - { HV_SYS_REG_ID_AA64PFR0_EL1, &host_isar.idregs[ID_AA64PFR0_EL1_IDX] }, - { HV_SYS_REG_ID_AA64PFR1_EL1, &host_isar.idregs[ID_AA64PFR1_EL1_IDX] }, + { HV_SYS_REG_ID_AA64PFR0_EL1, ID_AA64PFR0_EL1_IDX }, + { HV_SYS_REG_ID_AA64PFR1_EL1, ID_AA64PFR1_EL1_IDX }, /* Add ID_AA64PFR2_EL1 here when HVF supports it */ - { HV_SYS_REG_ID_AA64DFR0_EL1, &host_isar.idregs[ID_AA64DFR0_EL1_IDX] }, - { HV_SYS_REG_ID_AA64DFR1_EL1, &host_isar.idregs[ID_AA64DFR1_EL1_IDX] }, - { HV_SYS_REG_ID_AA64ISAR0_EL1, &host_isar.idregs[ID_AA64ISAR0_EL1_IDX] }, - { HV_SYS_REG_ID_AA64ISAR1_EL1, &host_isar.idregs[ID_AA64ISAR1_EL1_IDX] }, + { HV_SYS_REG_ID_AA64DFR0_EL1, ID_AA64DFR0_EL1_IDX }, + { HV_SYS_REG_ID_AA64DFR1_EL1, ID_AA64DFR1_EL1_IDX }, + { HV_SYS_REG_ID_AA64ISAR0_EL1, ID_AA64ISAR0_EL1_IDX }, + { HV_SYS_REG_ID_AA64ISAR1_EL1, ID_AA64ISAR1_EL1_IDX }, /* Add ID_AA64ISAR2_EL1 here when HVF supports it */ - { HV_SYS_REG_ID_AA64MMFR0_EL1, &host_isar.idregs[ID_AA64MMFR0_EL1_IDX] }, - { HV_SYS_REG_ID_AA64MMFR1_EL1, &host_isar.idregs[ID_AA64MMFR1_EL1_IDX] }, - { HV_SYS_REG_ID_AA64MMFR2_EL1, &host_isar.idregs[ID_AA64MMFR2_EL1_IDX] }, + { HV_SYS_REG_ID_AA64MMFR0_EL1, ID_AA64MMFR0_EL1_IDX }, + { HV_SYS_REG_ID_AA64MMFR1_EL1, ID_AA64MMFR1_EL1_IDX }, + { HV_SYS_REG_ID_AA64MMFR2_EL1, ID_AA64MMFR2_EL1_IDX }, /* Add ID_AA64MMFR3_EL1 here when HVF supports it */ }; hv_vcpu_t fd; @@ -780,7 +780,8 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) } for (i = 0; i < ARRAY_SIZE(regs); i++) { - r |= hv_vcpu_get_sys_reg(fd, regs[i].reg, regs[i].val); + r |= hv_vcpu_get_sys_reg(fd, regs[i].reg, + &host_isar.idregs[regs[i].index]); } r |= hv_vcpu_destroy(fd); From 299a85b4acf3368da75401d8072ec6a0364d42e8 Mon Sep 17 00:00:00 2001 From: Mohamed Mediouni Date: Tue, 28 Oct 2025 06:41:52 +0100 Subject: [PATCH 24/38] target/arm/hvf: switch hvf_arm_get_host_cpu_features to not create a vCPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Creating a vCPU locks out APIs such as hv_gic_create(). As a result, switch to using the hv_vcpu_config_get_feature_reg interface. Besides, all the following methods must be run on a vCPU thread: - hv_vcpu_create() - hv_vcpu_get_sys_reg() - hv_vcpu_destroy() Signed-off-by: Mohamed Mediouni Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Reviewed-by: Mads Ynddal Message-ID: <20250808070137.48716-3-mohamed@unpredictable.fr> [PMD: Release config calling os_release()] Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- target/arm/hvf/hvf.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index dea1cb37d1..fcb6950692 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -744,25 +744,24 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) { ARMISARegisters host_isar = {}; static const struct isar_regs { - int reg; + hv_feature_reg_t reg; ARMIDRegisterIdx index; } regs[] = { - { HV_SYS_REG_ID_AA64PFR0_EL1, ID_AA64PFR0_EL1_IDX }, - { HV_SYS_REG_ID_AA64PFR1_EL1, ID_AA64PFR1_EL1_IDX }, + { HV_FEATURE_REG_ID_AA64PFR0_EL1, ID_AA64PFR0_EL1_IDX }, + { HV_FEATURE_REG_ID_AA64PFR1_EL1, ID_AA64PFR1_EL1_IDX }, /* Add ID_AA64PFR2_EL1 here when HVF supports it */ - { HV_SYS_REG_ID_AA64DFR0_EL1, ID_AA64DFR0_EL1_IDX }, - { HV_SYS_REG_ID_AA64DFR1_EL1, ID_AA64DFR1_EL1_IDX }, - { HV_SYS_REG_ID_AA64ISAR0_EL1, ID_AA64ISAR0_EL1_IDX }, - { HV_SYS_REG_ID_AA64ISAR1_EL1, ID_AA64ISAR1_EL1_IDX }, + { HV_FEATURE_REG_ID_AA64DFR0_EL1, ID_AA64DFR0_EL1_IDX }, + { HV_FEATURE_REG_ID_AA64DFR1_EL1, ID_AA64DFR1_EL1_IDX }, + { HV_FEATURE_REG_ID_AA64ISAR0_EL1, ID_AA64ISAR0_EL1_IDX }, + { HV_FEATURE_REG_ID_AA64ISAR1_EL1, ID_AA64ISAR1_EL1_IDX }, /* Add ID_AA64ISAR2_EL1 here when HVF supports it */ - { HV_SYS_REG_ID_AA64MMFR0_EL1, ID_AA64MMFR0_EL1_IDX }, - { HV_SYS_REG_ID_AA64MMFR1_EL1, ID_AA64MMFR1_EL1_IDX }, - { HV_SYS_REG_ID_AA64MMFR2_EL1, ID_AA64MMFR2_EL1_IDX }, + { HV_FEATURE_REG_ID_AA64MMFR0_EL1, ID_AA64MMFR0_EL1_IDX }, + { HV_FEATURE_REG_ID_AA64MMFR1_EL1, ID_AA64MMFR1_EL1_IDX }, + { HV_FEATURE_REG_ID_AA64MMFR2_EL1, ID_AA64MMFR2_EL1_IDX }, /* Add ID_AA64MMFR3_EL1 here when HVF supports it */ }; - hv_vcpu_t fd; hv_return_t r = HV_SUCCESS; - hv_vcpu_exit_t *exit; + hv_vcpu_config_t config = hv_vcpu_config_create(); uint64_t t; int i; @@ -773,17 +772,11 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) (1ULL << ARM_FEATURE_PMU) | (1ULL << ARM_FEATURE_GENERIC_TIMER); - /* We set up a small vcpu to extract host registers */ - - if (hv_vcpu_create(&fd, &exit, NULL) != HV_SUCCESS) { - return false; - } - for (i = 0; i < ARRAY_SIZE(regs); i++) { - r |= hv_vcpu_get_sys_reg(fd, regs[i].reg, - &host_isar.idregs[regs[i].index]); + r |= hv_vcpu_config_get_feature_reg(config, regs[i].reg, + &host_isar.idregs[regs[i].index]); } - r |= hv_vcpu_destroy(fd); + os_release(config); /* * Hardcode MIDR because Apple deliberately doesn't expose a divergent From 7efc3819e8a2d2e15eea0ab0b1e8b02b7f4af70d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:41:53 +0100 Subject: [PATCH 25/38] target/arm/hvf: Factor hvf_handle_exception() out MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Factor hvf_handle_exception() out of hvf_vcpu_exec(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Mads Ynddal Signed-off-by: Peter Maydell --- target/arm/hvf/hvf.c | 123 +++++++++++++++++++++++-------------------- 1 file changed, 65 insertions(+), 58 deletions(-) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index fcb6950692..8553ce6adc 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -1802,61 +1802,15 @@ static void hvf_sync_vtimer(CPUState *cpu) } } -int hvf_arch_vcpu_exec(CPUState *cpu) +static int hvf_handle_exception(CPUState *cpu, hv_vcpu_exit_exception_t *excp) { - ARMCPU *arm_cpu = ARM_CPU(cpu); - CPUARMState *env = &arm_cpu->env; - int ret; - hv_vcpu_exit_t *hvf_exit = cpu->accel->exit; - hv_return_t r; - bool advance_pc = false; - - if (!(cpu->singlestep_enabled & SSTEP_NOIRQ) && - hvf_inject_interrupts(cpu)) { - return EXCP_INTERRUPT; - } - - if (cpu->halted) { - return EXCP_HLT; - } - - flush_cpu_state(cpu); - - bql_unlock(); - r = hv_vcpu_run(cpu->accel->fd); - bql_lock(); - switch (r) { - case HV_SUCCESS: - break; - case HV_ILLEGAL_GUEST_STATE: - trace_hvf_illegal_guest_state(); - /* fall through */ - default: - g_assert_not_reached(); - } - - /* handle VMEXIT */ - uint64_t exit_reason = hvf_exit->reason; - uint64_t syndrome = hvf_exit->exception.syndrome; + CPUARMState *env = cpu_env(cpu); + ARMCPU *arm_cpu = env_archcpu(env); + uint64_t syndrome = excp->syndrome; uint32_t ec = syn_get_ec(syndrome); - - ret = 0; - switch (exit_reason) { - case HV_EXIT_REASON_EXCEPTION: - /* This is the main one, handle below. */ - break; - case HV_EXIT_REASON_VTIMER_ACTIVATED: - qemu_set_irq(arm_cpu->gt_timer_outputs[GTIMER_VIRT], 1); - cpu->accel->vtimer_masked = true; - return 0; - case HV_EXIT_REASON_CANCELED: - /* we got kicked, no exit to process */ - return 0; - default: - g_assert_not_reached(); - } - - hvf_sync_vtimer(cpu); + bool advance_pc = false; + hv_return_t r; + int ret = 0; switch (ec) { case EC_SOFTWARESTEP: { @@ -1895,7 +1849,7 @@ int hvf_arch_vcpu_exec(CPUState *cpu) cpu_synchronize_state(cpu); CPUWatchpoint *wp = - find_hw_watchpoint(cpu, hvf_exit->exception.virtual_address); + find_hw_watchpoint(cpu, excp->virtual_address); if (!wp) { error_report("EXCP_DEBUG but unknown hw watchpoint"); } @@ -1913,8 +1867,8 @@ int hvf_arch_vcpu_exec(CPUState *cpu) uint32_t cm = (syndrome >> 8) & 0x1; uint64_t val = 0; - trace_hvf_data_abort(hvf_exit->exception.virtual_address, - hvf_exit->exception.physical_address, isv, + trace_hvf_data_abort(excp->virtual_address, + excp->physical_address, isv, iswrite, s1ptw, len, srt); if (cm) { @@ -1928,11 +1882,11 @@ int hvf_arch_vcpu_exec(CPUState *cpu) if (iswrite) { val = hvf_get_reg(cpu, srt); address_space_write(&address_space_memory, - hvf_exit->exception.physical_address, + excp->physical_address, MEMTXATTRS_UNSPECIFIED, &val, len); } else { address_space_read(&address_space_memory, - hvf_exit->exception.physical_address, + excp->physical_address, MEMTXATTRS_UNSPECIFIED, &val, len); if (sse) { val = sextract64(val, 0, len * 8); @@ -2030,6 +1984,59 @@ int hvf_arch_vcpu_exec(CPUState *cpu) return ret; } +int hvf_arch_vcpu_exec(CPUState *cpu) +{ + ARMCPU *arm_cpu = ARM_CPU(cpu); + hv_vcpu_exit_t *hvf_exit = cpu->accel->exit; + hv_return_t r; + + if (!(cpu->singlestep_enabled & SSTEP_NOIRQ) && + hvf_inject_interrupts(cpu)) { + return EXCP_INTERRUPT; + } + + if (cpu->halted) { + return EXCP_HLT; + } + + flush_cpu_state(cpu); + + bql_unlock(); + r = hv_vcpu_run(cpu->accel->fd); + bql_lock(); + switch (r) { + case HV_SUCCESS: + break; + case HV_ILLEGAL_GUEST_STATE: + trace_hvf_illegal_guest_state(); + /* fall through */ + default: + g_assert_not_reached(); + } + + /* handle VMEXIT */ + uint64_t exit_reason = hvf_exit->reason; + + switch (exit_reason) { + case HV_EXIT_REASON_EXCEPTION: + /* This is the main one, handle below. */ + break; + case HV_EXIT_REASON_VTIMER_ACTIVATED: + qemu_set_irq(arm_cpu->gt_timer_outputs[GTIMER_VIRT], 1); + cpu->accel->vtimer_masked = true; + return 0; + case HV_EXIT_REASON_CANCELED: + /* we got kicked, no exit to process */ + return 0; + default: + g_assert_not_reached(); + } + + hvf_sync_vtimer(cpu); + + return hvf_handle_exception(cpu, &hvf_exit->exception); +} + static const VMStateDescription vmstate_hvf_vtimer = { .name = "hvf-vtimer", .version_id = 1, From 2a21c92447407756d691e2b2dc4c4d97c1f88cd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:41:54 +0100 Subject: [PATCH 26/38] target/i386/hvf: Factor hvf_handle_vmexit() out MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Factor hvf_handle_vmexit() out of hvf_arch_vcpu_exec(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/i386/hvf/hvf.c | 478 +++++++++++++++++++++--------------------- 1 file changed, 244 insertions(+), 234 deletions(-) diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 76a58cb035..28d98659ec 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -721,6 +721,249 @@ void hvf_simulate_wrmsr(CPUState *cs) printf("write msr %llx\n", RCX(cs));*/ } +static int hvf_handle_vmexit(CPUState *cpu) +{ + X86CPU *x86_cpu = env_archcpu(cpu_env(cpu)); + uint64_t exit_reason = rvmcs(cpu->accel->fd, VMCS_EXIT_REASON); + uint64_t exit_qual = rvmcs(cpu->accel->fd, VMCS_EXIT_QUALIFICATION); + uint32_t ins_len = (uint32_t)rvmcs(cpu->accel->fd, + VMCS_EXIT_INSTRUCTION_LENGTH); + + uint64_t idtvec_info = rvmcs(cpu->accel->fd, VMCS_IDT_VECTORING_INFO); + int ret = 0; + + hvf_store_events(cpu, ins_len, idtvec_info); + rip = rreg(cpu->accel->fd, HV_X86_RIP); + env->eflags = rreg(cpu->accel->fd, HV_X86_RFLAGS); + + bql_lock(); + + update_apic_tpr(cpu); + current_cpu = cpu; + + switch (exit_reason) { + case EXIT_REASON_HLT: { + macvm_set_rip(cpu, rip + ins_len); + if (!(cpu_test_interrupt(cpu, CPU_INTERRUPT_HARD) + && (env->eflags & IF_MASK)) + && !cpu_test_interrupt(cpu, CPU_INTERRUPT_NMI) + && !(idtvec_info & VMCS_IDT_VEC_VALID)) { + cpu->halted = 1; + ret = EXCP_HLT; + break; + } + ret = EXCP_INTERRUPT; + break; + } + case EXIT_REASON_MWAIT: { + ret = EXCP_INTERRUPT; + break; + } + /* Need to check if MMIO or unmapped fault */ + case EXIT_REASON_EPT_FAULT: + { + hvf_slot *slot; + uint64_t gpa = rvmcs(cpu->accel->fd, VMCS_GUEST_PHYSICAL_ADDRESS); + + if (((idtvec_info & VMCS_IDT_VEC_VALID) == 0) && + ((exit_qual & EXIT_QUAL_NMIUDTI) != 0)) { + vmx_set_nmi_blocking(cpu); + } + + slot = hvf_find_overlap_slot(gpa, 1); + /* mmio */ + if (ept_emulation_fault(slot, gpa, exit_qual)) { + struct x86_decode decode; + + hvf_load_regs(cpu); + decode_instruction(env, &decode); + exec_instruction(env, &decode); + hvf_store_regs(cpu); + break; + } + break; + } + case EXIT_REASON_INOUT: + { + uint32_t in = (exit_qual & 8) != 0; + uint32_t size = (exit_qual & 7) + 1; + uint32_t string = (exit_qual & 16) != 0; + uint32_t port = exit_qual >> 16; + /*uint32_t rep = (exit_qual & 0x20) != 0;*/ + struct x86_decode decode; + + if (!string && in) { + uint64_t val = 0; + + hvf_load_regs(cpu); + hvf_handle_io(env_cpu(env), port, &val, 0, size, 1); + if (size == 1) { + AL(env) = val; + } else if (size == 2) { + AX(env) = val; + } else if (size == 4) { + RAX(env) = (uint32_t)val; + } else { + RAX(env) = (uint64_t)val; + } + env->eip += ins_len; + hvf_store_regs(cpu); + break; + } else if (!string && !in) { + RAX(env) = rreg(cpu->accel->fd, HV_X86_RAX); + hvf_handle_io(env_cpu(env), port, &RAX(env), 1, size, 1); + macvm_set_rip(cpu, rip + ins_len); + break; + } + + hvf_load_regs(cpu); + decode_instruction(env, &decode); + assert(ins_len == decode.len); + exec_instruction(env, &decode); + hvf_store_regs(cpu); + + break; + } + case EXIT_REASON_CPUID: { + uint32_t rax = (uint32_t)rreg(cpu->accel->fd, HV_X86_RAX); + uint32_t rbx = (uint32_t)rreg(cpu->accel->fd, HV_X86_RBX); + uint32_t rcx = (uint32_t)rreg(cpu->accel->fd, HV_X86_RCX); + uint32_t rdx = (uint32_t)rreg(cpu->accel->fd, HV_X86_RDX); + + if (rax == 1) { + /* CPUID1.ecx.OSXSAVE needs to know CR4 */ + env->cr[4] = rvmcs(cpu->accel->fd, VMCS_GUEST_CR4); + } + hvf_cpu_x86_cpuid(env, rax, rcx, &rax, &rbx, &rcx, &rdx); + + wreg(cpu->accel->fd, HV_X86_RAX, rax); + wreg(cpu->accel->fd, HV_X86_RBX, rbx); + wreg(cpu->accel->fd, HV_X86_RCX, rcx); + wreg(cpu->accel->fd, HV_X86_RDX, rdx); + + macvm_set_rip(cpu, rip + ins_len); + break; + } + case EXIT_REASON_XSETBV: { + uint32_t eax = (uint32_t)rreg(cpu->accel->fd, HV_X86_RAX); + uint32_t ecx = (uint32_t)rreg(cpu->accel->fd, HV_X86_RCX); + uint32_t edx = (uint32_t)rreg(cpu->accel->fd, HV_X86_RDX); + + if (ecx) { + macvm_set_rip(cpu, rip + ins_len); + break; + } + env->xcr0 = ((uint64_t)edx << 32) | eax; + wreg(cpu->accel->fd, HV_X86_XCR0, env->xcr0 | 1); + macvm_set_rip(cpu, rip + ins_len); + break; + } + case EXIT_REASON_INTR_WINDOW: + vmx_clear_int_window_exiting(cpu); + ret = EXCP_INTERRUPT; + break; + case EXIT_REASON_NMI_WINDOW: + vmx_clear_nmi_window_exiting(cpu); + ret = EXCP_INTERRUPT; + break; + case EXIT_REASON_EXT_INTR: + /* force exit and allow io handling */ + ret = EXCP_INTERRUPT; + break; + case EXIT_REASON_RDMSR: + case EXIT_REASON_WRMSR: + { + hvf_load_regs(cpu); + if (exit_reason == EXIT_REASON_RDMSR) { + hvf_simulate_rdmsr(cpu); + } else { + hvf_simulate_wrmsr(cpu); + } + env->eip += ins_len; + hvf_store_regs(cpu); + break; + } + case EXIT_REASON_CR_ACCESS: { + int cr; + int reg; + + hvf_load_regs(cpu); + cr = exit_qual & 15; + reg = (exit_qual >> 8) & 15; + + switch (cr) { + case 0x0: { + macvm_set_cr0(cpu->accel->fd, RRX(env, reg)); + break; + } + case 4: { + macvm_set_cr4(cpu->accel->fd, RRX(env, reg)); + break; + } + case 8: { + if (exit_qual & 0x10) { + RRX(env, reg) = cpu_get_apic_tpr(x86_cpu->apic_state); + } else { + int tpr = RRX(env, reg); + cpu_set_apic_tpr(x86_cpu->apic_state, tpr); + ret = EXCP_INTERRUPT; + } + break; + } + default: + error_report("Unrecognized CR %d", cr); + abort(); + } + env->eip += ins_len; + hvf_store_regs(cpu); + break; + } + case EXIT_REASON_APIC_ACCESS: { /* TODO */ + struct x86_decode decode; + + hvf_load_regs(cpu); + decode_instruction(env, &decode); + exec_instruction(env, &decode); + hvf_store_regs(cpu); + break; + } + case EXIT_REASON_TPR: { + ret = 1; + break; + } + case EXIT_REASON_TASK_SWITCH: { + uint64_t vinfo = rvmcs(cpu->accel->fd, VMCS_IDT_VECTORING_INFO); + x86_segment_selector sel = {.sel = exit_qual & 0xffff}; + + vmx_handle_task_switch(cpu, sel, (exit_qual >> 30) & 0x3, + vinfo & VMCS_INTR_VALID, + vinfo & VECTORING_INFO_VECTOR_MASK, + vinfo & VMCS_INTR_T_MASK); + break; + } + case EXIT_REASON_TRIPLE_FAULT: { + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + ret = EXCP_INTERRUPT; + break; + } + case EXIT_REASON_RDPMC: + wreg(cpu->accel->fd, HV_X86_RAX, 0); + wreg(cpu->accel->fd, HV_X86_RDX, 0); + macvm_set_rip(cpu, rip + ins_len); + break; + case VMX_REASON_VMCALL: + env->exception_nr = EXCP0D_GPF; + env->exception_injected = 1; + env->has_error_code = true; + env->error_code = 0; + break; + default: + error_report("%llx: unhandled exit %llx", rip, exit_reason); + } + + return ret; +} + int hvf_arch_vcpu_exec(CPUState *cpu) { X86CPU *x86_cpu = X86_CPU(cpu); @@ -752,240 +995,7 @@ int hvf_arch_vcpu_exec(CPUState *cpu) hv_return_t r = hv_vcpu_run_until(cpu->accel->fd, HV_DEADLINE_FOREVER); assert_hvf_ok(r); - /* handle VMEXIT */ - uint64_t exit_reason = rvmcs(cpu->accel->fd, VMCS_EXIT_REASON); - uint64_t exit_qual = rvmcs(cpu->accel->fd, VMCS_EXIT_QUALIFICATION); - uint32_t ins_len = (uint32_t)rvmcs(cpu->accel->fd, - VMCS_EXIT_INSTRUCTION_LENGTH); - - uint64_t idtvec_info = rvmcs(cpu->accel->fd, VMCS_IDT_VECTORING_INFO); - - hvf_store_events(cpu, ins_len, idtvec_info); - rip = rreg(cpu->accel->fd, HV_X86_RIP); - env->eflags = rreg(cpu->accel->fd, HV_X86_RFLAGS); - - bql_lock(); - - update_apic_tpr(cpu); - current_cpu = cpu; - - ret = 0; - switch (exit_reason) { - case EXIT_REASON_HLT: { - macvm_set_rip(cpu, rip + ins_len); - if (!(cpu_test_interrupt(cpu, CPU_INTERRUPT_HARD) && - (env->eflags & IF_MASK)) - && !cpu_test_interrupt(cpu, CPU_INTERRUPT_NMI) && - !(idtvec_info & VMCS_IDT_VEC_VALID)) { - cpu->halted = 1; - ret = EXCP_HLT; - break; - } - ret = EXCP_INTERRUPT; - break; - } - case EXIT_REASON_MWAIT: { - ret = EXCP_INTERRUPT; - break; - } - /* Need to check if MMIO or unmapped fault */ - case EXIT_REASON_EPT_FAULT: - { - hvf_slot *slot; - uint64_t gpa = rvmcs(cpu->accel->fd, VMCS_GUEST_PHYSICAL_ADDRESS); - - if (((idtvec_info & VMCS_IDT_VEC_VALID) == 0) && - ((exit_qual & EXIT_QUAL_NMIUDTI) != 0)) { - vmx_set_nmi_blocking(cpu); - } - - slot = hvf_find_overlap_slot(gpa, 1); - /* mmio */ - if (ept_emulation_fault(slot, gpa, exit_qual)) { - struct x86_decode decode; - - hvf_load_regs(cpu); - decode_instruction(env, &decode); - exec_instruction(env, &decode); - hvf_store_regs(cpu); - break; - } - break; - } - case EXIT_REASON_INOUT: - { - uint32_t in = (exit_qual & 8) != 0; - uint32_t size = (exit_qual & 7) + 1; - uint32_t string = (exit_qual & 16) != 0; - uint32_t port = exit_qual >> 16; - /*uint32_t rep = (exit_qual & 0x20) != 0;*/ - - if (!string && in) { - uint64_t val = 0; - hvf_load_regs(cpu); - hvf_handle_io(env_cpu(env), port, &val, 0, size, 1); - if (size == 1) { - AL(env) = val; - } else if (size == 2) { - AX(env) = val; - } else if (size == 4) { - RAX(env) = (uint32_t)val; - } else { - RAX(env) = (uint64_t)val; - } - env->eip += ins_len; - hvf_store_regs(cpu); - break; - } else if (!string && !in) { - RAX(env) = rreg(cpu->accel->fd, HV_X86_RAX); - hvf_handle_io(env_cpu(env), port, &RAX(env), 1, size, 1); - macvm_set_rip(cpu, rip + ins_len); - break; - } - struct x86_decode decode; - - hvf_load_regs(cpu); - decode_instruction(env, &decode); - assert(ins_len == decode.len); - exec_instruction(env, &decode); - hvf_store_regs(cpu); - - break; - } - case EXIT_REASON_CPUID: { - uint32_t rax = (uint32_t)rreg(cpu->accel->fd, HV_X86_RAX); - uint32_t rbx = (uint32_t)rreg(cpu->accel->fd, HV_X86_RBX); - uint32_t rcx = (uint32_t)rreg(cpu->accel->fd, HV_X86_RCX); - uint32_t rdx = (uint32_t)rreg(cpu->accel->fd, HV_X86_RDX); - - if (rax == 1) { - /* CPUID1.ecx.OSXSAVE needs to know CR4 */ - env->cr[4] = rvmcs(cpu->accel->fd, VMCS_GUEST_CR4); - } - hvf_cpu_x86_cpuid(env, rax, rcx, &rax, &rbx, &rcx, &rdx); - - wreg(cpu->accel->fd, HV_X86_RAX, rax); - wreg(cpu->accel->fd, HV_X86_RBX, rbx); - wreg(cpu->accel->fd, HV_X86_RCX, rcx); - wreg(cpu->accel->fd, HV_X86_RDX, rdx); - - macvm_set_rip(cpu, rip + ins_len); - break; - } - case EXIT_REASON_XSETBV: { - uint32_t eax = (uint32_t)rreg(cpu->accel->fd, HV_X86_RAX); - uint32_t ecx = (uint32_t)rreg(cpu->accel->fd, HV_X86_RCX); - uint32_t edx = (uint32_t)rreg(cpu->accel->fd, HV_X86_RDX); - - if (ecx) { - macvm_set_rip(cpu, rip + ins_len); - break; - } - env->xcr0 = ((uint64_t)edx << 32) | eax; - wreg(cpu->accel->fd, HV_X86_XCR0, env->xcr0 | 1); - macvm_set_rip(cpu, rip + ins_len); - break; - } - case EXIT_REASON_INTR_WINDOW: - vmx_clear_int_window_exiting(cpu); - ret = EXCP_INTERRUPT; - break; - case EXIT_REASON_NMI_WINDOW: - vmx_clear_nmi_window_exiting(cpu); - ret = EXCP_INTERRUPT; - break; - case EXIT_REASON_EXT_INTR: - /* force exit and allow io handling */ - ret = EXCP_INTERRUPT; - break; - case EXIT_REASON_RDMSR: - case EXIT_REASON_WRMSR: - { - hvf_load_regs(cpu); - if (exit_reason == EXIT_REASON_RDMSR) { - hvf_simulate_rdmsr(cpu); - } else { - hvf_simulate_wrmsr(cpu); - } - env->eip += ins_len; - hvf_store_regs(cpu); - break; - } - case EXIT_REASON_CR_ACCESS: { - int cr; - int reg; - - hvf_load_regs(cpu); - cr = exit_qual & 15; - reg = (exit_qual >> 8) & 15; - - switch (cr) { - case 0x0: { - macvm_set_cr0(cpu->accel->fd, RRX(env, reg)); - break; - } - case 4: { - macvm_set_cr4(cpu->accel->fd, RRX(env, reg)); - break; - } - case 8: { - if (exit_qual & 0x10) { - RRX(env, reg) = cpu_get_apic_tpr(x86_cpu->apic_state); - } else { - int tpr = RRX(env, reg); - cpu_set_apic_tpr(x86_cpu->apic_state, tpr); - ret = EXCP_INTERRUPT; - } - break; - } - default: - error_report("Unrecognized CR %d", cr); - abort(); - } - env->eip += ins_len; - hvf_store_regs(cpu); - break; - } - case EXIT_REASON_APIC_ACCESS: { /* TODO */ - struct x86_decode decode; - - hvf_load_regs(cpu); - decode_instruction(env, &decode); - exec_instruction(env, &decode); - hvf_store_regs(cpu); - break; - } - case EXIT_REASON_TPR: { - ret = 1; - break; - } - case EXIT_REASON_TASK_SWITCH: { - uint64_t vinfo = rvmcs(cpu->accel->fd, VMCS_IDT_VECTORING_INFO); - x86_segment_selector sel = {.sel = exit_qual & 0xffff}; - vmx_handle_task_switch(cpu, sel, (exit_qual >> 30) & 0x3, - vinfo & VMCS_INTR_VALID, vinfo & VECTORING_INFO_VECTOR_MASK, vinfo - & VMCS_INTR_T_MASK); - break; - } - case EXIT_REASON_TRIPLE_FAULT: { - qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); - ret = EXCP_INTERRUPT; - break; - } - case EXIT_REASON_RDPMC: - wreg(cpu->accel->fd, HV_X86_RAX, 0); - wreg(cpu->accel->fd, HV_X86_RDX, 0); - macvm_set_rip(cpu, rip + ins_len); - break; - case VMX_REASON_VMCALL: - env->exception_nr = EXCP0D_GPF; - env->exception_injected = 1; - env->has_error_code = true; - env->error_code = 0; - break; - default: - error_report("%llx: unhandled exit %llx", rip, exit_reason); - } + ret = hvf_handle_vmexit(cpu); } while (ret == 0); return ret; From 4d03dca5685f9d15fdf608d7093abc02cd540192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:41:55 +0100 Subject: [PATCH 27/38] target/arm/hvf: Factor hvf_handle_vmexit() out MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Factor hvf_handle_vmexit() out of hvf_vcpu_exec(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Mads Ynddal Signed-off-by: Peter Maydell --- target/arm/hvf/hvf.c | 50 ++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 8553ce6adc..27c600148f 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -1984,10 +1984,33 @@ static int hvf_handle_exception(CPUState *cpu, hv_vcpu_exit_exception_t *excp) return ret; } +static int hvf_handle_vmexit(CPUState *cpu, hv_vcpu_exit_t *exit) +{ + ARMCPU *arm_cpu = env_archcpu(cpu_env(cpu)); + int ret = 0; + + switch (exit->reason) { + case HV_EXIT_REASON_EXCEPTION: + hvf_sync_vtimer(cpu); + ret = hvf_handle_exception(cpu, &exit->exception); + break; + case HV_EXIT_REASON_VTIMER_ACTIVATED: + qemu_set_irq(arm_cpu->gt_timer_outputs[GTIMER_VIRT], 1); + cpu->accel->vtimer_masked = true; + break; + case HV_EXIT_REASON_CANCELED: + /* we got kicked, no exit to process */ + break; + default: + g_assert_not_reached(); + } + + return ret; +} + int hvf_arch_vcpu_exec(CPUState *cpu) { - ARMCPU *arm_cpu = ARM_CPU(cpu); - hv_vcpu_exit_t *hvf_exit = cpu->accel->exit; + int ret; hv_return_t r; if (!(cpu->singlestep_enabled & SSTEP_NOIRQ) && @@ -2006,6 +2029,7 @@ int hvf_arch_vcpu_exec(CPUState *cpu) bql_lock(); switch (r) { case HV_SUCCESS: + ret = hvf_handle_vmexit(cpu, cpu->accel->exit); break; case HV_ILLEGAL_GUEST_STATE: trace_hvf_illegal_guest_state(); @@ -2014,27 +2038,7 @@ int hvf_arch_vcpu_exec(CPUState *cpu) g_assert_not_reached(); } - /* handle VMEXIT */ - uint64_t exit_reason = hvf_exit->reason; - - switch (exit_reason) { - case HV_EXIT_REASON_EXCEPTION: - /* This is the main one, handle below. */ - break; - case HV_EXIT_REASON_VTIMER_ACTIVATED: - qemu_set_irq(arm_cpu->gt_timer_outputs[GTIMER_VIRT], 1); - cpu->accel->vtimer_masked = true; - return 0; - case HV_EXIT_REASON_CANCELED: - /* we got kicked, no exit to process */ - return 0; - default: - g_assert_not_reached(); - } - - hvf_sync_vtimer(cpu); - - return hvf_handle_exception(cpu, &hvf_exit->exception); + return ret; } static const VMStateDescription vmstate_hvf_vtimer = { From 93ac765076a4adf676974353c542a9c2f02d3d10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:41:56 +0100 Subject: [PATCH 28/38] target/arm/hvf: Keep calling hv_vcpu_run() in loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Mads Ynddal Signed-off-by: Peter Maydell --- target/arm/hvf/hvf.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 27c600148f..79861dcacf 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -2013,30 +2013,32 @@ int hvf_arch_vcpu_exec(CPUState *cpu) int ret; hv_return_t r; - if (!(cpu->singlestep_enabled & SSTEP_NOIRQ) && - hvf_inject_interrupts(cpu)) { - return EXCP_INTERRUPT; - } - if (cpu->halted) { return EXCP_HLT; } flush_cpu_state(cpu); - bql_unlock(); - r = hv_vcpu_run(cpu->accel->fd); - bql_lock(); - switch (r) { - case HV_SUCCESS: - ret = hvf_handle_vmexit(cpu, cpu->accel->exit); - break; - case HV_ILLEGAL_GUEST_STATE: - trace_hvf_illegal_guest_state(); - /* fall through */ - default: - g_assert_not_reached(); - } + do { + if (!(cpu->singlestep_enabled & SSTEP_NOIRQ) && + hvf_inject_interrupts(cpu)) { + return EXCP_INTERRUPT; + } + + bql_unlock(); + r = hv_vcpu_run(cpu->accel->fd); + bql_lock(); + switch (r) { + case HV_SUCCESS: + ret = hvf_handle_vmexit(cpu, cpu->accel->exit); + break; + case HV_ILLEGAL_GUEST_STATE: + trace_hvf_illegal_guest_state(); + /* fall through */ + default: + g_assert_not_reached(); + } + } while (ret == 0); return ret; } From 65e438d9ea3b2c5fdbf3a2255e95d73887d15e74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:41:57 +0100 Subject: [PATCH 29/38] cpus: Trace cpu_exec_start() and cpu_exec_end() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- cpu-common.c | 3 +++ trace-events | 2 ++ 2 files changed, 5 insertions(+) diff --git a/cpu-common.c b/cpu-common.c index 0eb5c7b8f2..988d057d84 100644 --- a/cpu-common.c +++ b/cpu-common.c @@ -249,6 +249,8 @@ void end_exclusive(void) /* Wait for exclusive ops to finish, and begin cpu execution. */ void cpu_exec_start(CPUState *cpu) { + trace_cpu_exec_start(cpu->cpu_index); + qatomic_set(&cpu->running, true); /* Write cpu->running before reading pending_cpus. */ @@ -319,6 +321,7 @@ void cpu_exec_end(CPUState *cpu) } } } + trace_cpu_exec_end(cpu->cpu_index); } void async_safe_run_on_cpu(CPUState *cpu, run_on_cpu_func func, diff --git a/trace-events b/trace-events index 3ec8a6c720..faeba6242f 100644 --- a/trace-events +++ b/trace-events @@ -29,6 +29,8 @@ breakpoint_insert(int cpu_index, uint64_t pc, int flags) "cpu=%d pc=0x%" PRIx64 " flags=0x%x" breakpoint_remove(int cpu_index, uint64_t pc, int flags) "cpu=%d pc=0x%" PRIx64 " flags=0x%x" breakpoint_singlestep(int cpu_index, int enabled) "cpu=%d enable=%d" +cpu_exec_start(int cpu_index) "cpu=%d" +cpu_exec_end(int cpu_index) "cpu=%d" # job.c job_state_transition(void *job, int ret, const char *legal, const char *s0, const char *s1) "job %p (ret: %d) attempting %s transition (%s-->%s)" From 5f34a5b6428f86944342498adc67d56e876d1003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:41:58 +0100 Subject: [PATCH 30/38] accel/hvf: Guard hv_vcpu_run() between cpu_exec_start/end() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similarly to 1d78a3c3ab8 for KVM, wrap hv_vcpu_run() with cpu_exec_start/end(), so that the accelerator can perform pending operations while all vCPUs are quiescent. See also explanation in commit c265e976f46 ("cpus-common: lock-free fast path for cpu_exec_start/end"). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- target/arm/hvf/hvf.c | 2 ++ target/i386/hvf/hvf.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 79861dcacf..c882f4c89c 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -2026,7 +2026,9 @@ int hvf_arch_vcpu_exec(CPUState *cpu) } bql_unlock(); + cpu_exec_start(cpu); r = hv_vcpu_run(cpu->accel->fd); + cpu_exec_end(cpu); bql_lock(); switch (r) { case HV_SUCCESS: diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 28d98659ec..16febbac48 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -992,9 +992,13 @@ int hvf_arch_vcpu_exec(CPUState *cpu) return EXCP_HLT; } + cpu_exec_start(cpu); + hv_return_t r = hv_vcpu_run_until(cpu->accel->fd, HV_DEADLINE_FOREVER); assert_hvf_ok(r); + cpu_exec_end(cpu); + ret = hvf_handle_vmexit(cpu); } while (ret == 0); From 7da8b562ae694039e8c2f36e87a5e99b1f4745ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:41:59 +0100 Subject: [PATCH 31/38] target/arm: Call aarch64_add_pauth_properties() once in host_initfn() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- target/arm/cpu64.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 26cf7e6dfa..f81cfd0113 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -762,20 +762,20 @@ static void aarch64_a53_initfn(Object *obj) static void aarch64_host_initfn(Object *obj) { -#if defined(CONFIG_KVM) ARMCPU *cpu = ARM_CPU(obj); +#if defined(CONFIG_KVM) kvm_arm_set_cpu_features_from_host(cpu); if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { aarch64_add_sve_properties(obj); - aarch64_add_pauth_properties(obj); } #elif defined(CONFIG_HVF) - ARMCPU *cpu = ARM_CPU(obj); hvf_arm_set_cpu_features_from_host(cpu); - aarch64_add_pauth_properties(obj); #else g_assert_not_reached(); #endif + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { + aarch64_add_pauth_properties(obj); + } } static void aarch64_max_initfn(Object *obj) From 2ad756383e1bcf8001696c81f64b26f35f1af142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:42:00 +0100 Subject: [PATCH 32/38] accel/hvf: Restrict ARM specific fields of AccelCPUState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not expose ARM specific fields to X86 implementation, allowing to use the proper 'hv_vcpu_exit_t' type. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- include/system/hvf_int.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/system/hvf_int.h b/include/system/hvf_int.h index 195d64dcf1..3d2be4092e 100644 --- a/include/system/hvf_int.h +++ b/include/system/hvf_int.h @@ -59,10 +59,12 @@ extern HVFState *hvf_state; struct AccelCPUState { hvf_vcpuid fd; - void *exit; +#ifdef __aarch64__ + hv_vcpu_exit_t *exit; bool vtimer_masked; sigset_t unblock_ipi_mask; bool guest_debug_enabled; +#endif }; void assert_hvf_ok_impl(hv_return_t ret, const char *file, unsigned int line, From 1ada8eb7c90f7625196975231e68736173f703ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:42:01 +0100 Subject: [PATCH 33/38] target/arm: Rename init_cpreg_list() -> arm_init_cpreg_list() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prefix init_cpreg_list() with 'arm_'. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/cpu.c | 2 +- target/arm/helper.c | 2 +- target/arm/internals.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index d2fc17eab6..39292fb9bc 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2141,7 +2141,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) arm_cpu_register_gdb_regs_for_features(cpu); arm_cpu_register_gdb_commands(cpu); - init_cpreg_list(cpu); + arm_init_cpreg_list(cpu); #ifndef CONFIG_USER_ONLY MachineState *ms = MACHINE(qdev_get_machine()); diff --git a/target/arm/helper.c b/target/arm/helper.c index ef6435c3ef..27ebc6f29b 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -253,7 +253,7 @@ static void count_cpreg(gpointer key, gpointer value, gpointer opaque) } } -void init_cpreg_list(ARMCPU *cpu) +void arm_init_cpreg_list(ARMCPU *cpu) { /* * Initialise the cpreg_tuples[] array based on the cp_regs hash. diff --git a/target/arm/internals.h b/target/arm/internals.h index 4c0fa28ef8..75677945af 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -377,7 +377,7 @@ void arm_cpu_register(const ARMCPUInfo *info); void arm_do_plugin_vcpu_discon_cb(CPUState *cs, uint64_t from); void register_cp_regs_for_features(ARMCPU *cpu); -void init_cpreg_list(ARMCPU *cpu); +void arm_init_cpreg_list(ARMCPU *cpu); void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu); void arm_translate_init(void); From 6d1a5105eeb7e1fc7f052007923306975f4f85e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:42:02 +0100 Subject: [PATCH 34/38] target/arm/hvf: Rename 'vgic' -> 'emu_reginfo' in trace events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to extend the trace events to other registers, rename and pass the register group as argument. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/hvf/hvf.c | 14 ++++++++------ target/arm/hvf/trace-events | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index c882f4c89c..26bafee259 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -1149,7 +1149,8 @@ static uint32_t hvf_reg2cp_reg(uint32_t reg) (reg >> SYSREG_OP2_SHIFT) & SYSREG_OP2_MASK); } -static bool hvf_sysreg_read_cp(CPUState *cpu, uint32_t reg, uint64_t *val) +static bool hvf_sysreg_read_cp(CPUState *cpu, const char *cpname, + uint32_t reg, uint64_t *val) { ARMCPU *arm_cpu = ARM_CPU(cpu); CPUARMState *env = &arm_cpu->env; @@ -1172,7 +1173,7 @@ static bool hvf_sysreg_read_cp(CPUState *cpu, uint32_t reg, uint64_t *val) } else { *val = raw_read(env, ri); } - trace_hvf_vgic_read(ri->name, *val); + trace_hvf_emu_reginfo_read(cpname, ri->name, *val); return true; } @@ -1261,7 +1262,7 @@ static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint64_t *val) case SYSREG_ICC_SRE_EL1: case SYSREG_ICC_CTLR_EL1: /* Call the TCG sysreg handler. This is only safe for GICv3 regs. */ - if (hvf_sysreg_read_cp(cpu, reg, val)) { + if (hvf_sysreg_read_cp(cpu, "GICv3", reg, val)) { return 0; } break; @@ -1432,7 +1433,8 @@ static void pmswinc_write(CPUARMState *env, uint64_t value) } } -static bool hvf_sysreg_write_cp(CPUState *cpu, uint32_t reg, uint64_t val) +static bool hvf_sysreg_write_cp(CPUState *cpu, const char *cpname, + uint32_t reg, uint64_t val) { ARMCPU *arm_cpu = ARM_CPU(cpu); CPUARMState *env = &arm_cpu->env; @@ -1455,7 +1457,7 @@ static bool hvf_sysreg_write_cp(CPUState *cpu, uint32_t reg, uint64_t val) raw_write(env, ri, val); } - trace_hvf_vgic_write(ri->name, val); + trace_hvf_emu_reginfo_write(cpname, ri->name, val); return true; } @@ -1581,7 +1583,7 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val) case SYSREG_ICC_SGI1R_EL1: case SYSREG_ICC_SRE_EL1: /* Call the TCG sysreg handler. This is only safe for GICv3 regs. */ - if (hvf_sysreg_write_cp(cpu, reg, val)) { + if (hvf_sysreg_write_cp(cpu, "GICv3", reg, val)) { return 0; } break; diff --git a/target/arm/hvf/trace-events b/target/arm/hvf/trace-events index 538af6e070..29387780e3 100644 --- a/target/arm/hvf/trace-events +++ b/target/arm/hvf/trace-events @@ -9,7 +9,7 @@ hvf_unknown_hvc(uint64_t pc, uint64_t x0) "pc=0x%"PRIx64" unknown HVC! 0x%016"PR hvf_unknown_smc(uint64_t x0) "unknown SMC! 0x%016"PRIx64 hvf_exit(uint64_t syndrome, uint32_t ec, uint64_t pc) "exit: 0x%"PRIx64" [ec=0x%x pc=0x%"PRIx64"]" hvf_psci_call(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint32_t cpuid) "PSCI Call x0=0x%016"PRIx64" x1=0x%016"PRIx64" x2=0x%016"PRIx64" x3=0x%016"PRIx64" cpuid=0x%x" -hvf_vgic_write(const char *name, uint64_t val) "vgic write to %s [val=0x%016"PRIx64"]" -hvf_vgic_read(const char *name, uint64_t val) "vgic read from %s [val=0x%016"PRIx64"]" +hvf_emu_reginfo_write(const char *cpname, const char *regname, uint64_t val) "[%s] write to %s [val=0x%016"PRIx64"]" +hvf_emu_reginfo_read(const char *cpname, const char *regname, uint64_t val) "[%s] read from %s [val=0x%016"PRIx64"]" hvf_illegal_guest_state(void) "HV_ILLEGAL_GUEST_STATE" hvf_kick_vcpu_thread(unsigned cpuidx, bool stop) "cpu:%u stop:%u" From 4695daacc068cd0aa9a91c0063c4f2a9ec9b7ba1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:42:03 +0100 Subject: [PATCH 35/38] target/arm: Re-use arm_is_psci_call() in HVF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Re-use arm_is_psci_call() instead of open-coding it. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- target/arm/hvf/hvf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 26bafee259..a3bb71e63b 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -1934,7 +1934,7 @@ static int hvf_handle_exception(CPUState *cpu, hv_vcpu_exit_exception_t *excp) break; case EC_AA64_HVC: cpu_synchronize_state(cpu); - if (arm_cpu->psci_conduit == QEMU_PSCI_CONDUIT_HVC) { + if (arm_is_psci_call(arm_cpu, EXCP_HVC)) { if (!hvf_handle_psci_call(cpu)) { trace_hvf_unknown_hvc(env->pc, env->xregs[0]); /* SMCCC 1.3 section 5.2 says every unknown SMCCC call returns -1 */ @@ -1947,7 +1947,7 @@ static int hvf_handle_exception(CPUState *cpu, hv_vcpu_exit_exception_t *excp) break; case EC_AA64_SMC: cpu_synchronize_state(cpu); - if (arm_cpu->psci_conduit == QEMU_PSCI_CONDUIT_SMC) { + if (arm_is_psci_call(arm_cpu, EXCP_SMC)) { advance_pc = true; if (!hvf_handle_psci_call(cpu)) { From 06ddd61f81ea10da92743d4d0f0f88b8cfa8c5b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:42:04 +0100 Subject: [PATCH 36/38] target/arm: Share ARM_PSCI_CALL trace event between TCG and HVF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is useful to compare PSCI calls of the same guest running under TCG or HVF. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- target/arm/hvf/hvf.c | 3 ++- target/arm/tcg/psci.c | 3 +++ target/arm/trace-events | 3 +++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index a3bb71e63b..f31b6e54ee 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -34,6 +34,7 @@ #include "target/arm/internals.h" #include "target/arm/multiprocessing.h" #include "target/arm/gtimer.h" +#include "target/arm/trace.h" #include "trace.h" #include "migration/vmstate.h" @@ -1025,7 +1026,7 @@ static bool hvf_handle_psci_call(CPUState *cpu) int target_el = 1; int32_t ret = 0; - trace_hvf_psci_call(param[0], param[1], param[2], param[3], + trace_arm_psci_call(param[0], param[1], param[2], param[3], arm_cpu_mp_affinity(arm_cpu)); switch (param[0]) { diff --git a/target/arm/tcg/psci.c b/target/arm/tcg/psci.c index cabed43e8a..2d40930157 100644 --- a/target/arm/tcg/psci.c +++ b/target/arm/tcg/psci.c @@ -25,6 +25,7 @@ #include "internals.h" #include "arm-powerctl.h" #include "target/arm/multiprocessing.h" +#include "target/arm/trace.h" bool arm_is_psci_call(ARMCPU *cpu, int excp_type) { @@ -79,6 +80,8 @@ void arm_handle_psci_call(ARMCPU *cpu) */ param[i] = is_a64(env) ? env->xregs[i] : env->regs[i]; } + trace_arm_psci_call(param[0], param[1], param[2], param[3], + arm_cpu_mp_affinity(cpu)); if ((param[0] & QEMU_PSCI_0_2_64BIT) && !is_a64(env)) { ret = QEMU_PSCI_RET_NOT_SUPPORTED; diff --git a/target/arm/trace-events b/target/arm/trace-events index 72a2c7d096..676d29fe51 100644 --- a/target/arm/trace-events +++ b/target/arm/trace-events @@ -23,3 +23,6 @@ arm_powerctl_set_cpu_on(uint64_t mp_aff, unsigned target_el, const char *mode, u arm_powerctl_set_cpu_on_and_reset(uint64_t mp_aff) "cpu %" PRIu64 arm_powerctl_set_cpu_off(uint64_t mp_aff) "cpu %" PRIu64 arm_powerctl_reset_cpu(uint64_t mp_aff) "cpu %" PRIu64 + +# tcg/psci.c and hvf/hvf.c +arm_psci_call(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint32_t cpuid) "PSCI Call x0=0x%016"PRIx64" x1=0x%016"PRIx64" x2=0x%016"PRIx64" x3=0x%016"PRIx64" cpuid=0x%x" From 31e1b9823056f4d1d95b5a76029411954aaaf2af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:42:05 +0100 Subject: [PATCH 37/38] target/arm/hvf/hvf: Document $pc adjustment in HVF & SMC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- target/arm/hvf/hvf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index f31b6e54ee..805fe75e6b 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -1936,6 +1936,7 @@ static int hvf_handle_exception(CPUState *cpu, hv_vcpu_exit_exception_t *excp) case EC_AA64_HVC: cpu_synchronize_state(cpu); if (arm_is_psci_call(arm_cpu, EXCP_HVC)) { + /* Do NOT advance $pc for HVC */ if (!hvf_handle_psci_call(cpu)) { trace_hvf_unknown_hvc(env->pc, env->xregs[0]); /* SMCCC 1.3 section 5.2 says every unknown SMCCC call returns -1 */ @@ -1949,6 +1950,7 @@ static int hvf_handle_exception(CPUState *cpu, hv_vcpu_exit_exception_t *excp) case EC_AA64_SMC: cpu_synchronize_state(cpu); if (arm_is_psci_call(arm_cpu, EXCP_SMC)) { + /* Secure Monitor Call exception, we need to advance $pc */ advance_pc = true; if (!hvf_handle_psci_call(cpu)) { From 8b733be9f408f9b550fc998c790e32aded5119f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 06:42:06 +0100 Subject: [PATCH 38/38] accel/hvf: Trace prefetch abort MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- target/arm/hvf/hvf.c | 11 +++++++++++ target/arm/hvf/trace-events | 1 + 2 files changed, 12 insertions(+) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 805fe75e6b..de1e8fb8a0 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -1963,6 +1963,17 @@ static int hvf_handle_exception(CPUState *cpu, hv_vcpu_exit_exception_t *excp) hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized(), 1); } break; + case EC_INSNABORT: { + uint32_t set = (syndrome >> 12) & 3; + bool fnv = (syndrome >> 10) & 1; + bool ea = (syndrome >> 9) & 1; + bool s1ptw = (syndrome >> 7) & 1; + uint32_t ifsc = (syndrome >> 0) & 0x3f; + + trace_hvf_insn_abort(env->pc, set, fnv, ea, s1ptw, ifsc); + + /* fall through */ + } default: cpu_synchronize_state(cpu); trace_hvf_exit(syndrome, ec, env->pc); diff --git a/target/arm/hvf/trace-events b/target/arm/hvf/trace-events index 29387780e3..b0d3d7bd32 100644 --- a/target/arm/hvf/trace-events +++ b/target/arm/hvf/trace-events @@ -3,6 +3,7 @@ hvf_unhandled_sysreg_write(uint64_t pc, uint32_t reg, uint32_t op0, uint32_t op1 hvf_inject_fiq(void) "injecting FIQ" hvf_inject_irq(void) "injecting IRQ" hvf_data_abort(uint64_t va, uint64_t pa, bool isv, bool iswrite, bool s1ptw, uint32_t len, uint32_t srt) "data abort: [va=0x%016"PRIx64" pa=0x%016"PRIx64" isv=%d iswrite=%d s1ptw=%d len=%d srt=%d]" +hvf_insn_abort(uint64_t pc, uint32_t set, bool fnv, bool ea, bool s1ptw, uint32_t ifsc) "insn abort: [pc=0x%"PRIx64" set=%d fnv=%d ea=%d s1ptw=%d ifsc=%d]" hvf_sysreg_read(uint32_t reg, uint32_t op0, uint32_t op1, uint32_t crn, uint32_t crm, uint32_t op2, uint64_t val) "sysreg read 0x%08x (op0=%d op1=%d crn=%d crm=%d op2=%d) = 0x%016"PRIx64 hvf_sysreg_write(uint32_t reg, uint32_t op0, uint32_t op1, uint32_t crn, uint32_t crm, uint32_t op2, uint64_t val) "sysreg write 0x%08x (op0=%d op1=%d crn=%d crm=%d op2=%d, val=0x%016"PRIx64")" hvf_unknown_hvc(uint64_t pc, uint64_t x0) "pc=0x%"PRIx64" unknown HVC! 0x%016"PRIx64