From 094fd7d36f2a7d3c9fb22254888fe7b99b39631b Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 1 Nov 2025 13:01:29 +0100 Subject: [PATCH 1/3] hw/arm/imx8mp-evk: Add KVM support Allows the imx8mp-evk machine to run guests with KVM acceleration. Signed-off-by: Bernhard Beschow Message-id: 20251101120130.236721-2-shentey@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- docs/system/arm/imx8mp-evk.rst | 19 +++++++++++++++++++ hw/arm/Kconfig | 3 ++- hw/arm/fsl-imx8mp.c | 34 +++++++++++++++++++++++++++++----- hw/arm/imx8mp-evk.c | 11 +++++++++++ 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst index b2f7d29ade..75c8fbd366 100644 --- a/docs/system/arm/imx8mp-evk.rst +++ b/docs/system/arm/imx8mp-evk.rst @@ -60,3 +60,22 @@ Now that everything is prepared the machine can be started as follows: -dtb imx8mp-evk.dtb \ -append "root=/dev/mmcblk2p2" \ -drive file=sdcard.img,if=sd,bus=2,format=raw,id=mmcblk2 + + +KVM Acceleration +---------------- + +To enable hardware-assisted acceleration via KVM, append +``-accel kvm -cpu host`` to the command line. While this speeds up performance +significantly, be aware of the following limitations: + +* The ``imx8mp-evk`` machine is not included under the "virtualization use case" + of :doc:`QEMU's security policy `. This means that you + should not trust that it can contain malicious guests, whether it is run + using TCG or KVM. If you don't trust your guests and you're relying on QEMU to + be the security boundary, you want to choose another machine such as ``virt``. +* Rather than Cortex-A53 CPUs, the same CPU type as the host's will be used. + This is a limitation of KVM and may not work with guests with a tight + dependency on Cortex-A53. +* No EL2 and EL3 exception levels are available which is also a KVM limitation. + Direct kernel boot should work but running U-Boot, TF-A, etc. won't succeed. diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index b44b85f436..0cdeb60f1f 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -622,7 +622,8 @@ config FSL_IMX8MP config FSL_IMX8MP_EVK bool default y - depends on TCG && AARCH64 + depends on AARCH64 + depends on TCG || KVM select FSL_IMX8MP config ARM_SMMUV3 diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c index 866f4d1d74..ee6f3e42d2 100644 --- a/hw/arm/fsl-imx8mp.c +++ b/hw/arm/fsl-imx8mp.c @@ -12,11 +12,13 @@ #include "system/address-spaces.h" #include "hw/arm/bsa.h" #include "hw/arm/fsl-imx8mp.h" -#include "hw/intc/arm_gicv3.h" #include "hw/misc/unimp.h" #include "hw/boards.h" +#include "system/kvm.h" #include "system/system.h" +#include "target/arm/cpu.h" #include "target/arm/cpu-qom.h" +#include "target/arm/kvm_arm.h" #include "qapi/error.h" #include "qobject/qlist.h" @@ -193,15 +195,15 @@ static void fsl_imx8mp_init(Object *obj) { MachineState *ms = MACHINE(qdev_get_machine()); FslImx8mpState *s = FSL_IMX8MP(obj); + const char *cpu_type = ms->cpu_type ?: ARM_CPU_TYPE_NAME("cortex-a53"); int i; for (i = 0; i < MIN(ms->smp.cpus, FSL_IMX8MP_NUM_CPUS); i++) { g_autofree char *name = g_strdup_printf("cpu%d", i); - object_initialize_child(obj, name, &s->cpu[i], - ARM_CPU_TYPE_NAME("cortex-a53")); + object_initialize_child(obj, name, &s->cpu[i], cpu_type); } - object_initialize_child(obj, "gic", &s->gic, TYPE_ARM_GICV3); + object_initialize_child(obj, "gic", &s->gic, gicv3_class_name()); object_initialize_child(obj, "ccm", &s->ccm, TYPE_IMX8MP_CCM); @@ -274,7 +276,8 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp) /* CPUs */ for (i = 0; i < ms->smp.cpus; i++) { /* On uniprocessor, the CBAR is set to 0 */ - if (ms->smp.cpus > 1) { + if (ms->smp.cpus > 1 && + object_property_find(OBJECT(&s->cpu[i]), "reset-cbar")) { object_property_set_int(OBJECT(&s->cpu[i]), "reset-cbar", fsl_imx8mp_memmap[FSL_IMX8MP_GIC_DIST].addr, &error_abort); @@ -286,6 +289,16 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp) object_property_set_int(OBJECT(&s->cpu[i]), "cntfrq", 8000000, &error_abort); + if (object_property_find(OBJECT(&s->cpu[i]), "has_el2")) { + object_property_set_bool(OBJECT(&s->cpu[i]), "has_el2", + !kvm_enabled(), &error_abort); + } + + if (object_property_find(OBJECT(&s->cpu[i]), "has_el3")) { + object_property_set_bool(OBJECT(&s->cpu[i]), "has_el3", + !kvm_enabled(), &error_abort); + } + if (i) { /* * Secondary CPUs start in powered-down state (and can be @@ -304,6 +317,7 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp) { SysBusDevice *gicsbd = SYS_BUS_DEVICE(&s->gic); QList *redist_region_count; + bool pmu = object_property_get_bool(OBJECT(first_cpu), "pmu", NULL); qdev_prop_set_uint32(gicdev, "num-cpu", ms->smp.cpus); qdev_prop_set_uint32(gicdev, "num-irq", @@ -360,6 +374,16 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ)); sysbus_connect_irq(gicsbd, i + 3 * ms->smp.cpus, qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ)); + + if (kvm_enabled()) { + if (pmu) { + assert(arm_feature(&s->cpu[i].env, ARM_FEATURE_PMU)); + if (kvm_irqchip_in_kernel()) { + kvm_arm_pmu_set_irq(&s->cpu[i], VIRTUAL_PMU_IRQ); + } + kvm_arm_pmu_init(&s->cpu[i]); + } + } } } diff --git a/hw/arm/imx8mp-evk.c b/hw/arm/imx8mp-evk.c index fc880a1d44..3ddcf1af5a 100644 --- a/hw/arm/imx8mp-evk.c +++ b/hw/arm/imx8mp-evk.c @@ -13,6 +13,7 @@ #include "hw/arm/machines-qom.h" #include "hw/boards.h" #include "hw/qdev-properties.h" +#include "system/kvm.h" #include "system/qtest.h" #include "qemu/error-report.h" #include "qapi/error.h" @@ -94,12 +95,22 @@ static void imx8mp_evk_init(MachineState *machine) } } +static const char *imx8mp_evk_get_default_cpu_type(const MachineState *ms) +{ + if (kvm_enabled()) { + return ARM_CPU_TYPE_NAME("host"); + } + + return ARM_CPU_TYPE_NAME("cortex-a53"); +} + static void imx8mp_evk_machine_init(MachineClass *mc) { mc->desc = "NXP i.MX 8M Plus EVK Board"; mc->init = imx8mp_evk_init; mc->max_cpus = FSL_IMX8MP_NUM_CPUS; mc->default_ram_id = "imx8mp-evk.ram"; + mc->get_default_cpu_type = imx8mp_evk_get_default_cpu_type; } DEFINE_MACHINE_AARCH64("imx8mp-evk", imx8mp_evk_machine_init) From 74bc6caea92de3cf6a6772d0d248a9e26aea2dd3 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 1 Nov 2025 13:01:30 +0100 Subject: [PATCH 2/3] hw/arm/imx8mp-evk: Fix guest time in KVM mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The imx8mp DTB hardcodes the clock frequency of the system counter to 8MHz. In KVM mode, the host CPU is used whose system counter runs at a different frequency, resulting in the guest clock running slower or faster. Fix this by not hardcoding the clock frequency which makes the Linux driver read the real clock frequency from the register. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Bernhard Beschow Message-id: 20251101120130.236721-3-shentey@gmail.com Signed-off-by: Peter Maydell --- hw/arm/imx8mp-evk.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hw/arm/imx8mp-evk.c b/hw/arm/imx8mp-evk.c index 3ddcf1af5a..44e0601967 100644 --- a/hw/arm/imx8mp-evk.c +++ b/hw/arm/imx8mp-evk.c @@ -44,6 +44,15 @@ static void imx8mp_evk_modify_dtb(const struct arm_boot_info *info, void *fdt) fdt_nop_property(fdt, offset, "cpu-idle-states"); offset = fdt_node_offset_by_compatible(fdt, offset, "arm,cortex-a53"); } + + if (kvm_enabled()) { + /* Use system counter frequency from host CPU to fix time in guest */ + offset = fdt_node_offset_by_compatible(fdt, -1, "arm,armv8-timer"); + while (offset >= 0) { + fdt_nop_property(fdt, offset, "clock-frequency"); + offset = fdt_node_offset_by_compatible(fdt, offset, "arm,armv8-timer"); + } + } } static void imx8mp_evk_init(MachineState *machine) From 5848d2c3a6c4cc1b37234db462b1b36bc0a18bf4 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 28 Oct 2025 16:52:35 +0000 Subject: [PATCH 3/3] docs/devel/testing/fuzzing: Note that you can get qtest to read from a file It is possible to get qtest to read fuzzer reproducers from a file rather than directly from stdio; this is useful when you want to run QEMU under gdb to debug the failure. Document how to do this, which was previously only written down in the commit message for 5b18a6bf44b9 ("chardev: Allow setting file chardev input file on the command line"). Signed-off-by: Peter Maydell Reviewed-by: Fabiano Rosas Reviewed-by: Manos Pitsidianakis Message-id: 20251028165236.3327658-1-peter.maydell@linaro.org --- docs/devel/testing/fuzzing.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/devel/testing/fuzzing.rst b/docs/devel/testing/fuzzing.rst index c3ac084311..c43f815f32 100644 --- a/docs/devel/testing/fuzzing.rst +++ b/docs/devel/testing/fuzzing.rst @@ -263,6 +263,15 @@ generic-fuzz target. - Report the bug and send a patch with the C reproducer upstream +QEMU can also read the reproducer directly from a file rather than +from standard input:: + + $QEMU_PATH $QEMU_ARGS -qtest chardev:repro \ + -chardev file,id=repro,path=/dev/null,input-path=/tmp/reproducer + +This is useful if you want to run QEMU under a debugger to investigate +the failure. + Implementation Details / Fuzzer Lifecycle -----------------------------------------