* Wed Jun 03 2026 Miroslav Rezanina <mrezanin@redhat.com> - 10.1.0-19.el10nv.1

- backport Control dirty tracking for nesting parent HWPT
- Resolves: VOYAGER-857
This commit is contained in:
Miroslav Rezanina 2026-06-03 12:18:21 +02:00
parent 7dd611dd52
commit 00901f0ef0
18 changed files with 1712 additions and 137 deletions

View File

@ -0,0 +1,124 @@
From 17d16bc8cbf2849fa885280b49381fd2c1d039ca Mon Sep 17 00:00:00 2001
From: Shameer Kolothum <skolothumtho@nvidia.com>
Date: Wed, 1 Apr 2026 09:41:33 +0100
Subject: [PATCH] hw/vfio/iommufd: Control dirty tracking for nesting parent
HWPT
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
QEMU smmuv3 accel does not support live migration yet, so dirty
tracking for the nesting parent HWPT is not useful.
Also, nested vIOMMU use cases can break on some platforms. For
example, SMMUv3 with HTTU may advertise dirty tracking capability,
but the kernel supports it only for stage-1. Requesting dirty
tracking for a nesting parent HWPT (stage-2) can fail.
Add a vIOMMU flag to explicitly request dirty tracking for the
nesting parent HWPT. For nested cases, dirty tracking is enabled
only when requested by the vIOMMU.
Non-nested cases and Intel vIOMMU keep the existing behavior.
Conflicts:
- hw/i386/intel_iommu.c: function "vtd_get_viommu_flags"
missing on this context. Since this commit is targeting
only aarch64, removing all changes to intel_iommu.
Fixes: fc6dafb98cec ("hw/arm/smmuv3: Implement get_viommu_cap() callback")
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
Reviewed-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
Link: https://lore.kernel.org/qemu-devel/20260401084133.56266-1-skolothumtho@nvidia.com
Signed-off-by: Cédric Le Goater <clg@redhat.com>
---
hw/vfio/device.c | 11 +++++++++++
hw/vfio/iommufd.c | 11 +++++++++--
include/hw/core/iommu.h | 2 ++
include/hw/vfio/vfio-device.h | 1 +
4 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/hw/vfio/device.c b/hw/vfio/device.c
index 7bdb6db923..9c38bb89dc 100644
--- a/hw/vfio/device.c
+++ b/hw/vfio/device.c
@@ -525,6 +525,17 @@ int vfio_device_get_feature(VFIODevice *vbasedev,
return vbasedev->io_ops->device_feature(vbasedev, feature);
}
+bool vfio_device_get_viommu_flags_want_nesting_dirty(VFIODevice *vbasedev)
+{
+ VFIOPCIDevice *vdev = vfio_pci_from_vfio_device(vbasedev);
+
+ if (vdev) {
+ return !!(pci_device_get_viommu_flags(PCI_DEVICE(vdev)) &
+ VIOMMU_FLAG_WANT_NESTING_DIRTY_TRACKING);
+ }
+ return false;
+}
+
bool vfio_device_get_viommu_flags_want_nesting(VFIODevice *vbasedev)
{
VFIOPCIDevice *vdev = vfio_pci_from_vfio_device(vbasedev);
diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c
index dc9100e772..a7589e685c 100644
--- a/hw/vfio/iommufd.c
+++ b/hw/vfio/iommufd.c
@@ -307,6 +307,7 @@ static bool iommufd_cdev_autodomains_get(VFIODevice *vbasedev,
IOMMUFDBackend *iommufd = vbasedev->iommufd;
VFIOContainer *bcontainer = VFIO_IOMMU(container);
uint32_t type = IOMMU_HW_INFO_TYPE_DEFAULT, flags = 0;
+ bool viommu_nesting, viommu_nesting_dirty;
uint64_t hw_caps;
VendorCaps caps;
VFIOIOASHwpt *hwpt;
@@ -359,8 +360,14 @@ static bool iommufd_cdev_autodomains_get(VFIODevice *vbasedev,
return false;
}
+ viommu_nesting = vfio_device_get_viommu_flags_want_nesting(vbasedev);
+ viommu_nesting_dirty =
+ vfio_device_get_viommu_flags_want_nesting_dirty(vbasedev);
+
if (hw_caps & IOMMU_HW_CAP_DIRTY_TRACKING) {
- flags = IOMMU_HWPT_ALLOC_DIRTY_TRACKING;
+ if (!viommu_nesting || viommu_nesting_dirty) {
+ flags |= IOMMU_HWPT_ALLOC_DIRTY_TRACKING;
+ }
}
/*
@@ -368,7 +375,7 @@ static bool iommufd_cdev_autodomains_get(VFIODevice *vbasedev,
* force to create it so that it could be reused by vIOMMU to create
* nested HWPT.
*/
- if (vfio_device_get_viommu_flags_want_nesting(vbasedev)) {
+ if (viommu_nesting) {
flags |= IOMMU_HWPT_ALLOC_NEST_PARENT;
}
diff --git a/include/hw/core/iommu.h b/include/hw/core/iommu.h
index 86af315c15..cd59a367ce 100644
--- a/include/hw/core/iommu.h
+++ b/include/hw/core/iommu.h
@@ -21,6 +21,8 @@ enum viommu_flags {
/* vIOMMU needs nesting parent HWPT to create nested HWPT */
VIOMMU_FLAG_WANT_NESTING_PARENT = BIT_ULL(0),
VIOMMU_FLAG_PASID_SUPPORTED = BIT_ULL(1),
+ /* vIOMMU needs dirty tracking on the nesting parent HWPT for nested use */
+ VIOMMU_FLAG_WANT_NESTING_DIRTY_TRACKING = BIT_ULL(2),
};
/* Host IOMMU quirks. Extracted from host IOMMU capabilities */
diff --git a/include/hw/vfio/vfio-device.h b/include/hw/vfio/vfio-device.h
index 27e2976593..24eb840b16 100644
--- a/include/hw/vfio/vfio-device.h
+++ b/include/hw/vfio/vfio-device.h
@@ -261,6 +261,7 @@ void vfio_device_unprepare(VFIODevice *vbasedev);
int vfio_device_get_feature(VFIODevice *vbasedev,
struct vfio_device_feature *feature);
bool vfio_device_get_viommu_flags_want_nesting(VFIODevice *vbasedev);
+bool vfio_device_get_viommu_flags_want_nesting_dirty(VFIODevice *vbasedev);
int vfio_device_get_region_info(VFIODevice *vbasedev, int index,
struct vfio_region_info **info);

View File

@ -0,0 +1,58 @@
From 4b5ca7e702db3573a5392c96b43bdb01c8e2866d Mon Sep 17 00:00:00 2001
From: Eric Auger <eric.auger@redhat.com>
Date: Fri, 6 Mar 2026 09:01:12 +0000
Subject: [PATCH] vmstate: Introduce VMSTATE_VARRAY_INT32_ALLOC
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 488: [rhel-10] Backport cross-kernel migration failure mitigation series
RH-Jira: RHEL-174858
RH-Acked-by: Mohammadfaiz Bawa <None>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Commit: [1/16] 54c0c7a95e98c7d6eb73119763121c3ba30e8c58 (eauger1/centos-qemu-kvm)
Already existing VMSTATE_VARRAY_INT32 requires an array to be
pre-allocated, however there are cases when the size is not known in
advance and there is no real need to enforce it.
Introduce VMSTATE_VARRAY_INT32_ALLOC as we currently have for UINT32
and UINT16.
The first user of this variant will be the target/arm/machine.c cpreg
indexes/values arrays.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Peter Xu <peterx@redhat.com>
Message-id: 20260304101625.1962633-2-eric.auger@redhat.com
Suggested-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit f555338df754b37e042d5b88610c34b1d1845383)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
include/migration/vmstate.h | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 5fe9bbf390..47a1dc1810 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -432,6 +432,16 @@ extern const VMStateInfo vmstate_info_qlist;
.offset = vmstate_offset_pointer(_state, _field, _type), \
}
+#define VMSTATE_VARRAY_INT32_ALLOC(_field, _state, _field_num, _version, _info, _type) {\
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
+ .info = &(_info), \
+ .size = sizeof(_type), \
+ .flags = VMS_VARRAY_INT32 | VMS_POINTER | VMS_ALLOC, \
+ .offset = vmstate_offset_pointer(_state, _field, _type), \
+}
+
#define VMSTATE_VARRAY_UINT32_ALLOC(_field, _state, _field_num, _version, _info, _type) {\
.name = (stringify(_field)), \
.version_id = (_version), \

View File

@ -0,0 +1,87 @@
From 51067e840f35f0f3ac4e4f69f5ec1091d5e7e5ba Mon Sep 17 00:00:00 2001
From: Eric Auger <eric.auger@redhat.com>
Date: Mon, 11 May 2026 12:06:24 -0400
Subject: [PATCH] target/arm: Move compare_u64 to helper.c
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 488: [rhel-10] Backport cross-kernel migration failure mitigation series
RH-Jira: RHEL-174858
RH-Acked-by: Mohammadfaiz Bawa <None>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Commit: [2/16] 497fedf076c0f7945bbe584efc060d7238c50837 (eauger1/centos-qemu-kvm)
We will use this function beyond kvm.c.
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 5a8af95cb31122d2fcd2e6d3427b8e8427cd8bdc)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
target/arm/helper.c | 11 +++++++++++
target/arm/internals.h | 3 +++
target/arm/kvm.c | 11 -----------
3 files changed, 14 insertions(+), 11 deletions(-)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 0c1299ff84..d230f9e766 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -40,6 +40,17 @@
static void switch_mode(CPUARMState *env, int mode);
+int compare_u64(const void *a, const void *b)
+{
+ if (*(uint64_t *)a > *(uint64_t *)b) {
+ return 1;
+ }
+ if (*(uint64_t *)a < *(uint64_t *)b) {
+ return -1;
+ }
+ return 0;
+}
+
uint64_t raw_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
assert(ri->fieldoffset);
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 1b3d0244fd..08e2acdb99 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1981,4 +1981,7 @@ void vfp_clear_float_status_exc_flags(CPUARMState *env);
void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask);
bool arm_pan_enabled(CPUARMState *env);
+/* Compare uint64_t for qsort and bsearch. */
+int compare_u64(const void *a, const void *b);
+
#endif
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 864f75600f..366a096287 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -718,17 +718,6 @@ void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid, uint64_t group,
memory_region_ref(kd->mr);
}
-static int compare_u64(const void *a, const void *b)
-{
- if (*(uint64_t *)a > *(uint64_t *)b) {
- return 1;
- }
- if (*(uint64_t *)a < *(uint64_t *)b) {
- return -1;
- }
- return 0;
-}
-
/*
* cpreg_values are sorted in ascending order by KVM register ID
* (see kvm_arm_init_cpreg_list). This allows us to cheaply find

View File

@ -0,0 +1,134 @@
From a89686bb07272e8c705cb2aefac561c9a26d9998 Mon Sep 17 00:00:00 2001
From: Eric Auger <eric.auger@redhat.com>
Date: Mon, 11 May 2026 12:06:39 -0400
Subject: [PATCH] target/arm: Convert init_cpreg_list to g_hash_table_foreach
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 488: [rhel-10] Backport cross-kernel migration failure mitigation series
RH-Jira: RHEL-174858
RH-Acked-by: Mohammadfaiz Bawa <None>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Commit: [3/16] 704e757f243d944ee544496d50b7ead4a1e2e681 (eauger1/centos-qemu-kvm)
Adjust count_cpreg and add_cpreg_to_list to be used with
g_hash_table_foreach instead of g_list_foreach. In this way we have
the ARMCPRegInfo pointer directly rather than having to look it up
from the key.
Delay the sorting of the cpreg_indexes until after add_cpreg_to_list.
This allows us to sort the data that we actually care about,
the kvm id, as computed within add_cpreg_to_list, instead of
having to repeatedly compute the kvm id within cpreg_key_compare.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit dee3c0c2cf9848cd849744474cdac108ce68a1ef)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
target/arm/helper.c | 54 ++++++++++++++++++---------------------------
1 file changed, 21 insertions(+), 33 deletions(-)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index d230f9e766..1cff4c5a68 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -209,11 +209,11 @@ bool write_list_to_cpustate(ARMCPU *cpu)
return ok;
}
-static void add_cpreg_to_list(gpointer key, gpointer opaque)
+static void add_cpreg_to_list(gpointer key, gpointer value, gpointer opaque)
{
ARMCPU *cpu = opaque;
uint32_t regidx = (uintptr_t)key;
- const ARMCPRegInfo *ri = get_arm_cp_reginfo(cpu->cp_regs, regidx);
+ const ARMCPRegInfo *ri = value;
if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_ALIAS))) {
cpu->cpreg_indexes[cpu->cpreg_array_len] = cpreg_to_kvm_id(regidx);
@@ -222,61 +222,49 @@ static void add_cpreg_to_list(gpointer key, gpointer opaque)
}
}
-static void count_cpreg(gpointer key, gpointer opaque)
+static void count_cpreg(gpointer key, gpointer value, gpointer opaque)
{
ARMCPU *cpu = opaque;
- const ARMCPRegInfo *ri;
-
- ri = g_hash_table_lookup(cpu->cp_regs, key);
+ const ARMCPRegInfo *ri = value;
if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_ALIAS))) {
cpu->cpreg_array_len++;
}
}
-static gint cpreg_key_compare(gconstpointer a, gconstpointer b, gpointer d)
-{
- uint64_t aidx = cpreg_to_kvm_id((uintptr_t)a);
- uint64_t bidx = cpreg_to_kvm_id((uintptr_t)b);
-
- if (aidx > bidx) {
- return 1;
- }
- if (aidx < bidx) {
- return -1;
- }
- return 0;
-}
-
void init_cpreg_list(ARMCPU *cpu)
{
/*
* Initialise the cpreg_tuples[] array based on the cp_regs hash.
* Note that we require cpreg_tuples[] to be sorted by key ID.
*/
- GList *keys;
int arraylen;
- keys = g_hash_table_get_keys(cpu->cp_regs);
- keys = g_list_sort_with_data(keys, cpreg_key_compare, NULL);
-
cpu->cpreg_array_len = 0;
-
- g_list_foreach(keys, count_cpreg, cpu);
+ g_hash_table_foreach(cpu->cp_regs, count_cpreg, cpu);
arraylen = cpu->cpreg_array_len;
- cpu->cpreg_indexes = g_new(uint64_t, arraylen);
- cpu->cpreg_values = g_new(uint64_t, arraylen);
- cpu->cpreg_vmstate_indexes = g_new(uint64_t, arraylen);
- cpu->cpreg_vmstate_values = g_new(uint64_t, arraylen);
- cpu->cpreg_vmstate_array_len = cpu->cpreg_array_len;
+ if (arraylen) {
+ cpu->cpreg_indexes = g_new(uint64_t, arraylen);
+ cpu->cpreg_values = g_new(uint64_t, arraylen);
+ cpu->cpreg_vmstate_indexes = g_new(uint64_t, arraylen);
+ cpu->cpreg_vmstate_values = g_new(uint64_t, arraylen);
+ } else {
+ cpu->cpreg_indexes = NULL;
+ cpu->cpreg_values = NULL;
+ cpu->cpreg_vmstate_indexes = NULL;
+ cpu->cpreg_vmstate_values = NULL;
+ }
+ cpu->cpreg_vmstate_array_len = arraylen;
cpu->cpreg_array_len = 0;
- g_list_foreach(keys, add_cpreg_to_list, cpu);
+ g_hash_table_foreach(cpu->cp_regs, add_cpreg_to_list, cpu);
assert(cpu->cpreg_array_len == arraylen);
- g_list_free(keys);
+ if (arraylen) {
+ qsort(cpu->cpreg_indexes, arraylen, sizeof(uint64_t), compare_u64);
+ }
}
bool arm_pan_enabled(CPUARMState *env)

View File

@ -0,0 +1,191 @@
From d11effe48c156e7e389bfc23a0ca33b93e944241 Mon Sep 17 00:00:00 2001
From: Eric Auger <eric.auger@redhat.com>
Date: Fri, 6 Mar 2026 09:01:12 +0000
Subject: [PATCH] target/arm/machine: Use VMSTATE_VARRAY_INT32_ALLOC for cpreg
arrays
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 488: [rhel-10] Backport cross-kernel migration failure mitigation series
RH-Jira: RHEL-174858
RH-Acked-by: Mohammadfaiz Bawa <None>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Commit: [4/16] 833ad7f2be8a02eb811c8562d809e4cc2eedc2a6 (eauger1/centos-qemu-kvm)
Conflicts:
- contextual conflict in target/arm/trace-events as we don't have
cpu.c, arm-powerctl.c, tcg/psci.c and hvf/hvf.c trace events
- target/arm/whpx/whpx-all.c does not exist downstream
This removes the need for explicitly allocating cpreg_vmstate arrays.
On post save we simply point to cpreg arrays and set the length
accordingly.
Remove VMSTATE_VARRAY_INT32 for cpreg_vmstate_array_len as now
the array is dynamically allocated.
Also add a trace point on post_load to trace potential mismatch
between the number of incoming cpregs versus current ones.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20260304101625.1962633-3-eric.auger@redhat.com
Suggested-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit ab2ddc7b662d34c242ddfcfbe35996417b047ce2)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
target/arm/helper.c | 5 -----
target/arm/kvm.c | 5 -----
target/arm/machine.c | 45 +++++++++++++++++++++++++++++------------
target/arm/trace-events | 3 +++
4 files changed, 35 insertions(+), 23 deletions(-)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 1cff4c5a68..5e643ed6b2 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -247,15 +247,10 @@ void init_cpreg_list(ARMCPU *cpu)
if (arraylen) {
cpu->cpreg_indexes = g_new(uint64_t, arraylen);
cpu->cpreg_values = g_new(uint64_t, arraylen);
- cpu->cpreg_vmstate_indexes = g_new(uint64_t, arraylen);
- cpu->cpreg_vmstate_values = g_new(uint64_t, arraylen);
} else {
cpu->cpreg_indexes = NULL;
cpu->cpreg_values = NULL;
- cpu->cpreg_vmstate_indexes = NULL;
- cpu->cpreg_vmstate_values = NULL;
}
- cpu->cpreg_vmstate_array_len = arraylen;
cpu->cpreg_array_len = 0;
g_hash_table_foreach(cpu->cp_regs, add_cpreg_to_list, cpu);
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 366a096287..f1be509c86 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -805,12 +805,7 @@ static int kvm_arm_init_cpreg_list(ARMCPU *cpu)
cpu->cpreg_indexes = g_renew(uint64_t, cpu->cpreg_indexes, arraylen);
cpu->cpreg_values = g_renew(uint64_t, cpu->cpreg_values, arraylen);
- cpu->cpreg_vmstate_indexes = g_renew(uint64_t, cpu->cpreg_vmstate_indexes,
- arraylen);
- cpu->cpreg_vmstate_values = g_renew(uint64_t, cpu->cpreg_vmstate_values,
- arraylen);
cpu->cpreg_array_len = arraylen;
- cpu->cpreg_vmstate_array_len = arraylen;
for (i = 0, arraylen = 0; i < rlp->n; i++) {
uint64_t regidx = rlp->reg[i];
diff --git a/target/arm/machine.c b/target/arm/machine.c
index 6986915bee..5caf2885c2 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -1,5 +1,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
+#include "trace.h"
#include "qemu/error-report.h"
#include "system/kvm.h"
#include "system/tcg.h"
@@ -894,11 +895,14 @@ static int cpu_pre_save(void *opaque)
}
}
+ /*
+ * On outbound migration, send the data in our cpreg_{values,indexes}
+ * arrays. The migration code will not allocate anything, but just
+ * reads the data pointed to by the VMSTATE_VARRAY_INT32_ALLOC() fields.
+ */
+ cpu->cpreg_vmstate_indexes = cpu->cpreg_indexes;
+ cpu->cpreg_vmstate_values = cpu->cpreg_values;
cpu->cpreg_vmstate_array_len = cpu->cpreg_array_len;
- memcpy(cpu->cpreg_vmstate_indexes, cpu->cpreg_indexes,
- cpu->cpreg_array_len * sizeof(uint64_t));
- memcpy(cpu->cpreg_vmstate_values, cpu->cpreg_values,
- cpu->cpreg_array_len * sizeof(uint64_t));
return 0;
}
@@ -911,6 +915,9 @@ static int cpu_post_save(void *opaque)
pmu_op_finish(&cpu->env);
}
+ cpu->cpreg_vmstate_indexes = NULL;
+ cpu->cpreg_vmstate_values = NULL;
+
return 0;
}
@@ -944,6 +951,9 @@ static int cpu_pre_load(void *opaque)
pmu_op_start(env);
}
+ g_assert(!cpu->cpreg_vmstate_indexes);
+ g_assert(!cpu->cpreg_vmstate_values);
+
return 0;
}
@@ -953,6 +963,9 @@ static int cpu_post_load(void *opaque, int version_id)
CPUARMState *env = &cpu->env;
int i, v;
+ trace_cpu_post_load(cpu->cpreg_vmstate_array_len,
+ cpu->cpreg_array_len);
+
/*
* Handle migration compatibility from old QEMU which didn't
* send the irq-line-state subsection. A QEMU without it did not
@@ -1004,6 +1017,11 @@ static int cpu_post_load(void *opaque, int version_id)
}
}
+ g_free(cpu->cpreg_vmstate_indexes);
+ g_free(cpu->cpreg_vmstate_values);
+ cpu->cpreg_vmstate_indexes = NULL;
+ cpu->cpreg_vmstate_values = NULL;
+
/*
* Misaligned thumb pc is architecturally impossible. Fail the
* incoming migration. For TCG it would trigger the assert in
@@ -1071,16 +1089,17 @@ const VMStateDescription vmstate_arm_cpu = {
VMSTATE_UINT32_ARRAY(env.fiq_regs, ARMCPU, 5),
VMSTATE_UINT64_ARRAY(env.elr_el, ARMCPU, 4),
VMSTATE_UINT64_ARRAY(env.sp_el, ARMCPU, 4),
- /* The length-check must come before the arrays to avoid
- * incoming data possibly overflowing the array.
+ /*
+ * The length must come before the arrays so we can
+ * allocate the arrays before their data arrives
*/
- VMSTATE_INT32_POSITIVE_LE(cpreg_vmstate_array_len, ARMCPU),
- VMSTATE_VARRAY_INT32(cpreg_vmstate_indexes, ARMCPU,
- cpreg_vmstate_array_len,
- 0, vmstate_info_uint64, uint64_t),
- VMSTATE_VARRAY_INT32(cpreg_vmstate_values, ARMCPU,
- cpreg_vmstate_array_len,
- 0, vmstate_info_uint64, uint64_t),
+ VMSTATE_INT32(cpreg_vmstate_array_len, ARMCPU),
+ VMSTATE_VARRAY_INT32_ALLOC(cpreg_vmstate_indexes, ARMCPU,
+ cpreg_vmstate_array_len,
+ 0, vmstate_info_uint64, uint64_t),
+ VMSTATE_VARRAY_INT32_ALLOC(cpreg_vmstate_values, ARMCPU,
+ cpreg_vmstate_array_len,
+ 0, vmstate_info_uint64, uint64_t),
VMSTATE_UINT64(env.exclusive_addr, ARMCPU),
VMSTATE_UINT64(env.exclusive_val, ARMCPU),
VMSTATE_UINT64(env.exclusive_high, ARMCPU),
diff --git a/target/arm/trace-events b/target/arm/trace-events
index 4438dce7be..4e2502af9f 100644
--- a/target/arm/trace-events
+++ b/target/arm/trace-events
@@ -13,3 +13,6 @@ arm_gt_update_irq(int timer, int irqstate) "gt_update_irq: timer %d irqstate %d"
# kvm.c
kvm_arm_fixup_msi_route(uint64_t iova, uint64_t gpa) "MSI iova = 0x%"PRIx64" is translated into 0x%"PRIx64
+
+# machine.c
+cpu_post_load(uint32_t cpreg_vmstate_array_len, uint32_t cpreg_array_len) "cpreg_vmstate_array_len=%d cpreg_array_len=%d"

View File

@ -0,0 +1,77 @@
From b70cf627c0a32a57c8e529ba1262001ae036d26b Mon Sep 17 00:00:00 2001
From: Eric Auger <eric.auger@redhat.com>
Date: Fri, 6 Mar 2026 09:01:12 +0000
Subject: [PATCH] target/arm/kvm: Export kvm_print_register_name()
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 488: [rhel-10] Backport cross-kernel migration failure mitigation series
RH-Jira: RHEL-174858
RH-Acked-by: Mohammadfaiz Bawa <None>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Commit: [5/16] 66bc6985b3162adca02cac4efbbb86f5e973ed7f (eauger1/centos-qemu-kvm)
Conflicts: contextual conflicts in target/arm/kvm-stub.c
and target/arm/kvm_arm.h since we don't have arm_gic_cap_kvm_probe()
downstream
We want to use kvm_print_register_name() in machine.c so
let's export the helper and implement a stub when kvm
is not enabled.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20260304101625.1962633-4-eric.auger@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 5ae081fb493510f62280afc005aa36f702192539)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
target/arm/kvm-stub.c | 5 +++++
target/arm/kvm.c | 2 +-
target/arm/kvm_arm.h | 9 +++++++++
3 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/target/arm/kvm-stub.c b/target/arm/kvm-stub.c
index c93462c5b9..58b37e0dfe 100644
--- a/target/arm/kvm-stub.c
+++ b/target/arm/kvm-stub.c
@@ -124,3 +124,8 @@ bool kvm_arm_cpu_post_load(ARMCPU *cpu)
{
g_assert_not_reached();
}
+
+char *kvm_print_register_name(uint64_t regidx)
+{
+ g_assert_not_reached();
+}
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index f1be509c86..ef29256dfe 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -911,7 +911,7 @@ static gchar *kvm_print_sve_register_name(uint64_t regidx)
}
}
-static gchar *kvm_print_register_name(uint64_t regidx)
+char *kvm_print_register_name(uint64_t regidx)
{
switch ((regidx & KVM_REG_ARM_COPROC_MASK)) {
case KVM_REG_ARM_CORE:
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index 6a9b6374a6..c4e7dc28ef 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -263,4 +263,13 @@ void kvm_arm_enable_mte(Object *cpuobj, Error **errp);
void arm_cpu_kvm_set_irq(void *arm_cpu, int irq, int level);
+/*
+ * kvm_print_register_name:
+ * @regidx: register KVM index
+ *
+ * Returns a human-readable string representing this register
+ * The caller must free the string with g_free().
+ */
+char *kvm_print_register_name(uint64_t regidx);
+
#endif

View File

@ -0,0 +1,41 @@
From 14931aaec9f141f7ee601020991a6ddc5d4a2c70 Mon Sep 17 00:00:00 2001
From: Eric Auger <eric.auger@redhat.com>
Date: Fri, 6 Mar 2026 09:01:12 +0000
Subject: [PATCH] target/arm/kvm: Tweak print_register_name() for arm64 system
register
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 488: [rhel-10] Backport cross-kernel migration failure mitigation series
RH-Jira: RHEL-174858
RH-Acked-by: Mohammadfaiz Bawa <None>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Commit: [6/16] e434272a6ecab513d6bc8c4811cd8e1463cdbfad (eauger1/centos-qemu-kvm)
As opposed to other register types, arm64 system register decoding
is not introduced by any 'register' mention which can lead to
unfriendly user-facing traces. Let's add "system register"
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20260304101625.1962633-5-eric.auger@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 3e0a3a8e91efabef01dad8ea1cd1f13dcc46b14d)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
target/arm/kvm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index ef29256dfe..fe731cc49f 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -919,7 +919,7 @@ char *kvm_print_register_name(uint64_t regidx)
case KVM_REG_ARM_DEMUX:
return g_strdup_printf("demuxed reg %"PRIx64, regidx);
case KVM_REG_ARM64_SYSREG:
- return g_strdup_printf("op0:%d op1:%d crn:%d crm:%d op2:%d",
+ return g_strdup_printf("system register op0:%d op1:%d crn:%d crm:%d op2:%d",
CP_REG_ARM64_SYSREG_OP(regidx, OP0),
CP_REG_ARM64_SYSREG_OP(regidx, OP1),
CP_REG_ARM64_SYSREG_OP(regidx, CRN),

View File

@ -0,0 +1,90 @@
From ec93904014f8fd0d461a05c4f18886dfc4d5d21b Mon Sep 17 00:00:00 2001
From: Eric Auger <eric.auger@redhat.com>
Date: Fri, 6 Mar 2026 09:01:12 +0000
Subject: [PATCH] target/arm/machine: Trace cpreg names which do not match on
migration
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 488: [rhel-10] Backport cross-kernel migration failure mitigation series
RH-Jira: RHEL-174858
RH-Acked-by: Mohammadfaiz Bawa <None>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Commit: [7/16] 4fd2c91158511a672da05643c961fe55f964fe31 (eauger1/centos-qemu-kvm)
Whenever there is a mismatch between cpreg indexes in the incoming
stream and cpregs exposed by the destination output the name of
the register. We use a print_register_name() wrapper helper. At the
moment we are only able to do a nice decoding of the index for
KVM regs.
Without this patch, the error would be:
qemu-system-aarch64: load of migration failed: Operation not permitted:
error while loading state for instance 0x0 of device 'cpu': post load
hook failed for: cpu, version_id: 22, minimum_version: 22, ret: -1
which is not helpful for the end user to understand the actual
issue.
This patch adds the actual information about the probme:
qemu-system-aarch64: cpu_post_load: system register
op0:3 op1:0 crn:2 crm:0 op2:3 in the incoming stream but
unknown on the destination, fail migration
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20260304101625.1962633-6-eric.auger@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit eac1e610f48923084cb07b3f1eaa05f5fedccd85)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
target/arm/machine.c | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/target/arm/machine.c b/target/arm/machine.c
index 5caf2885c2..36c9d9946e 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -1,5 +1,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
+#include "cpregs.h"
#include "trace.h"
#include "qemu/error-report.h"
#include "system/kvm.h"
@@ -957,6 +958,15 @@ static int cpu_pre_load(void *opaque)
return 0;
}
+static gchar *print_register_name(uint64_t kvm_regidx)
+{
+ if (kvm_enabled()) {
+ return kvm_print_register_name(kvm_regidx);
+ } else {
+ return g_strdup_printf("system register 0x%x", kvm_to_cpreg_id(kvm_regidx));
+ }
+}
+
static int cpu_post_load(void *opaque, int version_id)
{
ARMCPU *cpu = opaque;
@@ -995,11 +1005,18 @@ static int cpu_post_load(void *opaque, int version_id)
for (i = 0, v = 0; i < cpu->cpreg_array_len
&& v < cpu->cpreg_vmstate_array_len; i++) {
if (cpu->cpreg_vmstate_indexes[v] > cpu->cpreg_indexes[i]) {
- /* register in our list but not incoming : skip it */
+ g_autofree gchar *name = print_register_name(cpu->cpreg_indexes[i]);
+
+ warn_report("%s: %s "
+ "expected by the destination but not in the incoming stream: "
+ "skip it", __func__, name);
continue;
}
if (cpu->cpreg_vmstate_indexes[v] < cpu->cpreg_indexes[i]) {
- /* register in their list but not ours: fail migration */
+ g_autofree gchar *name = print_register_name(cpu->cpreg_vmstate_indexes[v]);
+
+ error_report("%s: %s in the incoming stream but unknown on the destination: "
+ "fail migration", __func__, name);
return -1;
}
/* matching register, copy the value over */

View File

@ -0,0 +1,75 @@
From b1878dbb2058e2c5f61a01a0bbc91f83fc014267 Mon Sep 17 00:00:00 2001
From: Eric Auger <eric.auger@redhat.com>
Date: Fri, 6 Mar 2026 09:01:12 +0000
Subject: [PATCH] target/arm/machine: Trace all register mismatches
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 488: [rhel-10] Backport cross-kernel migration failure mitigation series
RH-Jira: RHEL-174858
RH-Acked-by: Mohammadfaiz Bawa <None>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Commit: [8/16] 270563b74465e4bf42901a2f0332a61621b22123 (eauger1/centos-qemu-kvm)
At the moment, cpu_post_load() exits with error on the first
catch of unexpected register in the incoming stream. Let the code
go further and trace all the issues before exiting.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20260304101625.1962633-7-eric.auger@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit e25c63c3b368118dc109e49393554f85f1203d1e)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
target/arm/machine.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/target/arm/machine.c b/target/arm/machine.c
index 36c9d9946e..70157e000b 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -971,6 +971,7 @@ static int cpu_post_load(void *opaque, int version_id)
{
ARMCPU *cpu = opaque;
CPUARMState *env = &cpu->env;
+ bool fail = false;
int i, v;
trace_cpu_post_load(cpu->cpreg_vmstate_array_len,
@@ -1003,13 +1004,14 @@ static int cpu_post_load(void *opaque, int version_id)
*/
for (i = 0, v = 0; i < cpu->cpreg_array_len
- && v < cpu->cpreg_vmstate_array_len; i++) {
+ && v < cpu->cpreg_vmstate_array_len;) {
if (cpu->cpreg_vmstate_indexes[v] > cpu->cpreg_indexes[i]) {
g_autofree gchar *name = print_register_name(cpu->cpreg_indexes[i]);
warn_report("%s: %s "
"expected by the destination but not in the incoming stream: "
"skip it", __func__, name);
+ i++;
continue;
}
if (cpu->cpreg_vmstate_indexes[v] < cpu->cpreg_indexes[i]) {
@@ -1017,12 +1019,18 @@ static int cpu_post_load(void *opaque, int version_id)
error_report("%s: %s in the incoming stream but unknown on the destination: "
"fail migration", __func__, name);
- return -1;
+ v++;
+ fail = true;
+ continue;
}
/* matching register, copy the value over */
cpu->cpreg_values[i] = cpu->cpreg_vmstate_values[v];
+ i++;
v++;
}
+ if (fail) {
+ return -1;
+ }
if (kvm_enabled()) {
if (!kvm_arm_cpu_post_load(cpu)) {

View File

@ -0,0 +1,122 @@
From 80a3a9a35e8498ecb4cb0ba04dc5c9dee7a1e666 Mon Sep 17 00:00:00 2001
From: Eric Auger <eric.auger@redhat.com>
Date: Fri, 6 Mar 2026 09:01:12 +0000
Subject: [PATCH] target/arm/machine: Fix detection of unknown incoming cpregs
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 488: [rhel-10] Backport cross-kernel migration failure mitigation series
RH-Jira: RHEL-174858
RH-Acked-by: Mohammadfaiz Bawa <None>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Commit: [9/16] 6450081257ce770c0825a69e794036bc181b5a6c (eauger1/centos-qemu-kvm)
Currently the check of cpreg index matches fail to detect
a situation where the length of both arrays is same but
- destination has an extra register not found in the incoming stream (idx1)
- source has an extra register not found in the destination (idx2)
where idx1 < = idx2
Normally this should fail but it does not.
Fix the logic to scan all indexes.
Fixes: 721fae12536 ("target-arm: Convert TCG to using (index,value) list for cp migration")
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20260304101625.1962633-8-eric.auger@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit dbfed8d80837ff7d36e763163f38549169ee64cc)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
target/arm/machine.c | 61 +++++++++++++++++++++++++++++++++++---------
1 file changed, 49 insertions(+), 12 deletions(-)
diff --git a/target/arm/machine.c b/target/arm/machine.c
index 70157e000b..e0447083ee 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -967,6 +967,35 @@ static gchar *print_register_name(uint64_t kvm_regidx)
}
}
+/*
+ * Handle the situation where @kvmidx is on destination but not
+ * in the incoming stream. This never fails the migration.
+ */
+static void handle_cpreg_missing_in_incoming_stream(ARMCPU *cpu, uint64_t kvmidx)
+{
+ g_autofree gchar *name = print_register_name(kvmidx);
+
+ warn_report("%s: %s "
+ "expected by the destination but not in the incoming stream: "
+ "skip it", __func__, name);
+}
+
+/*
+ * Handle the situation where @kvmidx is in the incoming stream
+ * but not on destination. This currently fails the migration but
+ * we plan to accomodate some exceptions, hence the boolean returned value.
+ */
+static bool handle_cpreg_only_in_incoming_stream(ARMCPU *cpu, uint64_t kvmidx)
+{
+ g_autofree gchar *name = print_register_name(kvmidx);
+ bool fail = true;
+
+ error_report("%s: %s in the incoming stream but unknown on the "
+ "destination: fail migration", __func__, name);
+
+ return fail;
+}
+
static int cpu_post_load(void *opaque, int version_id)
{
ARMCPU *cpu = opaque;
@@ -1006,21 +1035,12 @@ static int cpu_post_load(void *opaque, int version_id)
for (i = 0, v = 0; i < cpu->cpreg_array_len
&& v < cpu->cpreg_vmstate_array_len;) {
if (cpu->cpreg_vmstate_indexes[v] > cpu->cpreg_indexes[i]) {
- g_autofree gchar *name = print_register_name(cpu->cpreg_indexes[i]);
-
- warn_report("%s: %s "
- "expected by the destination but not in the incoming stream: "
- "skip it", __func__, name);
- i++;
+ handle_cpreg_missing_in_incoming_stream(cpu, cpu->cpreg_indexes[i++]);
continue;
}
if (cpu->cpreg_vmstate_indexes[v] < cpu->cpreg_indexes[i]) {
- g_autofree gchar *name = print_register_name(cpu->cpreg_vmstate_indexes[v]);
-
- error_report("%s: %s in the incoming stream but unknown on the destination: "
- "fail migration", __func__, name);
- v++;
- fail = true;
+ fail = handle_cpreg_only_in_incoming_stream(cpu,
+ cpu->cpreg_vmstate_indexes[v++]);
continue;
}
/* matching register, copy the value over */
@@ -1028,6 +1048,23 @@ static int cpu_post_load(void *opaque, int version_id)
i++;
v++;
}
+
+ /*
+ * if we have reached the end of the incoming array but there are
+ * still regs in cpreg, continue parsing the regs which are missing
+ * in the input stream
+ */
+ for ( ; i < cpu->cpreg_array_len; i++) {
+ handle_cpreg_missing_in_incoming_stream(cpu, cpu->cpreg_indexes[i]);
+ }
+ /*
+ * if we have reached the end of the cpreg array but there are
+ * still regs in the input stream, continue parsing the vmstate array
+ */
+ for ( ; v < cpu->cpreg_vmstate_array_len; v++) {
+ fail = handle_cpreg_only_in_incoming_stream(cpu,
+ cpu->cpreg_vmstate_indexes[v]);
+ }
if (fail) {
return -1;
}

View File

@ -0,0 +1,241 @@
From 45314e6772f7b28997596c6585e40ff7e94367f6 Mon Sep 17 00:00:00 2001
From: Eric Auger <eric.auger@redhat.com>
Date: Mon, 20 Apr 2026 16:03:51 +0200
Subject: [PATCH] target/arm/cpu: Introduce the infrastructure for cpreg
migration tolerances
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 488: [rhel-10] Backport cross-kernel migration failure mitigation series
RH-Jira: RHEL-174858
RH-Acked-by: Mohammadfaiz Bawa <None>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Commit: [10/16] 71bbf8b6df2c02de6349343040f7edb827161f4c (eauger1/centos-qemu-kvm)
Conflicts: contextual conflict in target/arm/internals.h as we don't
have #define MECID_WIDTH 16 introduced by commit
700f08d5829f ("target/arm: Implement FEAT_MEC registers")
We introduce a datatype for a tolerance with respect to a given
cpreg migration issue. The tolerance applies to a given cpreg kvm index,
and can be of different types:
a) mismatch in cpreg indexes
- ToleranceNotOnBothEnds (cpreg index is allowed to be only present
on one end)
- ToleranceOnlySrcTestValue (cpreg index is allowed to be only
present in source if its value @mask field matches @value)
b) mismatch in cpreg values
- ToleranceDiffInMask (value differences are allowed only within a mask)
- ToleranceFieldLT (incoming field value must be less than a given value)
- ToleranceFieldGT (incoming field value must be greater than a given value)
A QLIST of such tolerances can be populated using a new helper:
arm_register_cpreg_mig_tolerance() and arm_cpu_match_cpreg_mig_tolerance()
allows to check whether a tolerance exists for a given kvm index and its
criterion is matched.
callers for those helpers will be introduced in subsequent patches.
Only registration of migration tolerances related to cpreg index
mismatch is currently allowed.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Message-id: 20260420140552.104369-2-eric.auger@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit bb36be6fd799c4fdb2ac893cfab7f307c12527f2)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
target/arm/cpu.c | 82 ++++++++++++++++++++++++++++++++++++++++++
target/arm/cpu.h | 1 +
target/arm/internals.h | 53 +++++++++++++++++++++++++++
3 files changed, 136 insertions(+)
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index e2b2337399..9f7938d8fa 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -172,6 +172,82 @@ void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
QLIST_INSERT_HEAD(&cpu->el_change_hooks, entry, node);
}
+static ARMCPRegMigTolerance *find_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx)
+{
+ ARMCPRegMigTolerance *t;
+ QLIST_FOREACH(t, &cpu->cpreg_mig_tolerances, node) {
+ if (t->kvmidx == kvmidx) {
+ return t;
+ }
+ }
+ return NULL;
+}
+
+void arm_register_cpreg_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx,
+ uint64_t mask, uint64_t value,
+ ARMCPRegMigToleranceType type)
+{
+ ARMCPRegMigTolerance *entry;
+
+ /* make sure the kvmidx has not tolerance already registered */
+ assert(!find_mig_tolerance(cpu, kvmidx));
+
+ assert(type == ToleranceNotOnBothEnds ||
+ type == ToleranceOnlySrcTestValue);
+
+ entry = g_new0(ARMCPRegMigTolerance, 1);
+
+ entry->kvmidx = kvmidx;
+ entry->mask = mask;
+ entry->value = value;
+ entry->type = type;
+
+ QLIST_INSERT_HEAD(&cpu->cpreg_mig_tolerances, entry, node);
+}
+
+bool arm_cpu_match_cpreg_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx,
+ uint64_t vmstate_value, uint64_t local_value,
+ ARMCPRegMigToleranceType type)
+{
+ ARMCPRegMigTolerance *t = find_mig_tolerance(cpu, kvmidx);
+ uint64_t diff, diff_outside_mask, field;
+
+ if (!t || t->type != type) {
+ return false;
+ }
+
+ if (type == ToleranceNotOnBothEnds) {
+ return true;
+ }
+
+ if (type == ToleranceOnlySrcTestValue &&
+ ((vmstate_value & t->mask) == t->value)) {
+ return true;
+ }
+
+ /* Need to check the mask */
+ diff = vmstate_value ^ local_value;
+ diff_outside_mask = diff & ~t->mask;
+
+ if (diff_outside_mask) {
+ /* there are differences outside of the mask */
+ return false;
+ }
+ if (type == ToleranceDiffInMask) {
+ /* differences only in the field, tolerance matched */
+ return true;
+ }
+ /* need to compare field value against authorized ones */
+ field = vmstate_value & t->mask;
+ if (type == ToleranceFieldLT && (field < t->value)) {
+ return true;
+ }
+ if (type == ToleranceFieldGT && (field > t->value)) {
+ return true;
+ }
+ return false;
+}
+
static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
{
/* Reset a single ARMCPRegInfo register */
@@ -1455,6 +1531,7 @@ static void arm_cpu_initfn(Object *obj)
QLIST_INIT(&cpu->pre_el_change_hooks);
QLIST_INIT(&cpu->el_change_hooks);
+ QLIST_INIT(&cpu->cpreg_mig_tolerances);
#ifdef CONFIG_USER_ONLY
# ifdef TARGET_AARCH64
@@ -1895,6 +1972,7 @@ static void arm_cpu_finalizefn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
ARMELChangeHook *hook, *next;
+ ARMCPRegMigTolerance *t, *n;
g_hash_table_destroy(cpu->cp_regs);
@@ -1906,6 +1984,10 @@ static void arm_cpu_finalizefn(Object *obj)
QLIST_REMOVE(hook, node);
g_free(hook);
}
+ QLIST_FOREACH_SAFE(t, &cpu->cpreg_mig_tolerances, node, n) {
+ QLIST_REMOVE(t, node);
+ g_free(t);
+ }
#ifndef CONFIG_USER_ONLY
if (cpu->pmu_timer) {
timer_free(cpu->pmu_timer);
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index dc0da8b0ae..e5dbc5a3f9 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1126,6 +1126,7 @@ struct ArchCPU {
QLIST_HEAD(, ARMELChangeHook) pre_el_change_hooks;
QLIST_HEAD(, ARMELChangeHook) el_change_hooks;
+ QLIST_HEAD(, ARMCPRegMigTolerance) cpreg_mig_tolerances;
int32_t node_id; /* NUMA node this CPU belongs to */
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 08e2acdb99..b8444aa8ab 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1984,4 +1984,57 @@ bool arm_pan_enabled(CPUARMState *env);
/* Compare uint64_t for qsort and bsearch. */
int compare_u64(const void *a, const void *b);
+typedef enum {
+ ToleranceNotOnBothEnds,
+ ToleranceOnlySrcTestValue,
+ ToleranceDiffInMask,
+ ToleranceFieldLT,
+ ToleranceFieldGT,
+} ARMCPRegMigToleranceType;
+
+typedef struct ARMCPRegMigTolerance {
+ uint64_t kvmidx;
+ uint64_t mask;
+ uint64_t value;
+ ARMCPRegMigToleranceType type;
+ QLIST_ENTRY(ARMCPRegMigTolerance) node;
+} ARMCPRegMigTolerance;
+
+/**
+ * arm_register_cpreg_mig_tolerance:
+ * Register a migration tolerance wrt one given cpreg identified by its
+ * @kvmidx. Calling this function twice for the same @kvmidx is a
+ * programming error and will cause an assertion failure.
+ *
+ * @cpu: vcpu to apply the migration tolerance on
+ * @kvmidx: kvm index of the cpreg the tolerance applies to
+ * @mask: bitmask where a difference is tolerated
+ * (relevant with ToleranceDiffInMask)
+ * @value: value the bitmask field is compared with
+ * (relevant with ToleranceFieldLT and ToleranceFieldGT)
+ * @type: type of the migration tolerance:
+ * - ToleranceNotOnBothEnds (cpreg index is allowed to be only present
+ * on one end)
+ * - ToleranceOnlySrcTestValue (cpreg index is allowed to be only
+ * present in source if its value @mask field matches @value)
+ * - ToleranceDiffInMask (mismatch in cpreg values are only tolerated
+ * if differences are within @mask)
+ * - ToleranceFieldLT (mismatch in cpreg values are only tolerated
+ * if incoming @bitmask field value is less than @value)
+ * - ToleranceFieldGT (mismatch in cpreg values are only tolerated
+ * if incoming @bitmask field value is greater than @value)
+ */
+void arm_register_cpreg_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx,
+ uint64_t mask, uint64_t value,
+ ARMCPRegMigToleranceType type);
+
+/**
+ * arm_cpu_match_cpreg_mig_tolerance:
+ * Check whether a tolerance of type @type exists for a given @kvmidx
+ * and the tolerance criterion is satisfied
+ */
+bool arm_cpu_match_cpreg_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx,
+ uint64_t vmstate_value, uint64_t local_value,
+ ARMCPRegMigToleranceType type);
+
#endif

View File

@ -0,0 +1,84 @@
From 9059108a55366e6337b67f7f101340c4d2a141b5 Mon Sep 17 00:00:00 2001
From: Eric Auger <eric.auger@redhat.com>
Date: Mon, 20 Apr 2026 16:03:52 +0200
Subject: [PATCH] target/arm/machine: Handle ToleranceNotOnBothEnds migration
tolerances
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 488: [rhel-10] Backport cross-kernel migration failure mitigation series
RH-Jira: RHEL-174858
RH-Acked-by: Mohammadfaiz Bawa <None>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Commit: [11/16] 26354a54c0d479bd06bdbb1e8d6ec47d7a4688e8 (eauger1/centos-qemu-kvm)
If there is a mismatch between the cpreg indexes found on both ends,
check whether a tolerance was registered for the given kvmidx. If any,
silence warning/errors.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20260420140552.104369-3-eric.auger@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 5e65e7aa4a1b57b1dbfcecec629c9e3fb55e94b1)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
target/arm/machine.c | 21 +++++++++++++++------
target/arm/trace-events | 2 ++
2 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/target/arm/machine.c b/target/arm/machine.c
index e0447083ee..0d749fc8fb 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -975,25 +975,34 @@ static void handle_cpreg_missing_in_incoming_stream(ARMCPU *cpu, uint64_t kvmidx
{
g_autofree gchar *name = print_register_name(kvmidx);
+ if (arm_cpu_match_cpreg_mig_tolerance(cpu, kvmidx,
+ 0, 0, ToleranceNotOnBothEnds)) {
+ trace_tolerate_cpreg_missing_in_incoming_stream(name);
+ return;
+ }
warn_report("%s: %s "
"expected by the destination but not in the incoming stream: "
"skip it", __func__, name);
}
/*
- * Handle the situation where @kvmidx is in the incoming stream
- * but not on destination. This currently fails the migration but
- * we plan to accomodate some exceptions, hence the boolean returned value.
+ * Handle the situation where @kvmidx is in the incoming
+ * stream but not on destination. This fails the migration if
+ * no cpreg mig tolerance is matched for this @kvmidx
+ * Return true if the migration should eventually fail
*/
static bool handle_cpreg_only_in_incoming_stream(ARMCPU *cpu, uint64_t kvmidx)
{
g_autofree gchar *name = print_register_name(kvmidx);
- bool fail = true;
+ if (arm_cpu_match_cpreg_mig_tolerance(cpu, kvmidx,
+ 0, 0, ToleranceNotOnBothEnds)) {
+ trace_tolerate_cpreg_only_in_incoming_stream(name);
+ return false;
+ }
error_report("%s: %s in the incoming stream but unknown on the "
"destination: fail migration", __func__, name);
-
- return fail;
+ return true;
}
static int cpu_post_load(void *opaque, int version_id)
diff --git a/target/arm/trace-events b/target/arm/trace-events
index 4e2502af9f..062a011881 100644
--- a/target/arm/trace-events
+++ b/target/arm/trace-events
@@ -16,3 +16,5 @@ kvm_arm_fixup_msi_route(uint64_t iova, uint64_t gpa) "MSI iova = 0x%"PRIx64" is
# machine.c
cpu_post_load(uint32_t cpreg_vmstate_array_len, uint32_t cpreg_array_len) "cpreg_vmstate_array_len=%d cpreg_array_len=%d"
+tolerate_cpreg_missing_in_incoming_stream(char *name) "%s is missing in incoming stream but this is explicitly tolerated"
+tolerate_cpreg_only_in_incoming_stream(char *name) "%s is in incoming stream but not on destination but this is explicitly tolerated"

View File

@ -0,0 +1,71 @@
From ed4122a9a79520987cbd51100770c03726d9c7d8 Mon Sep 17 00:00:00 2001
From: Eric Auger <eric.auger@redhat.com>
Date: Mon, 20 Apr 2026 16:03:53 +0200
Subject: [PATCH] target/arm/machine: Handle ToleranceOnlySrcTestValue
migration tolerance
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 488: [rhel-10] Backport cross-kernel migration failure mitigation series
RH-Jira: RHEL-174858
RH-Acked-by: Mohammadfaiz Bawa <None>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Commit: [12/16] df44347fd53723ee81c4167e82bb85a15b94ac23 (eauger1/centos-qemu-kvm)
Pass the value of the incoming register to
handle_cpreg_only_in_incoming_stream and check whether there is
a matching ToleranceOnlySrcTestValue tolerance.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Message-id: 20260420140552.104369-4-eric.auger@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 9d2e717da4f4822ddb89c1ae78a0afd328a1f554)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
target/arm/machine.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/target/arm/machine.c b/target/arm/machine.c
index 0d749fc8fb..b75097f371 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -991,12 +991,15 @@ static void handle_cpreg_missing_in_incoming_stream(ARMCPU *cpu, uint64_t kvmidx
* no cpreg mig tolerance is matched for this @kvmidx
* Return true if the migration should eventually fail
*/
-static bool handle_cpreg_only_in_incoming_stream(ARMCPU *cpu, uint64_t kvmidx)
+static bool
+handle_cpreg_only_in_incoming_stream(ARMCPU *cpu, uint64_t kvmidx, uint64_t value)
{
g_autofree gchar *name = print_register_name(kvmidx);
if (arm_cpu_match_cpreg_mig_tolerance(cpu, kvmidx,
- 0, 0, ToleranceNotOnBothEnds)) {
+ 0, 0, ToleranceNotOnBothEnds) ||
+ arm_cpu_match_cpreg_mig_tolerance(cpu, kvmidx,
+ value, 0, ToleranceOnlySrcTestValue)) {
trace_tolerate_cpreg_only_in_incoming_stream(name);
return false;
}
@@ -1049,7 +1052,9 @@ static int cpu_post_load(void *opaque, int version_id)
}
if (cpu->cpreg_vmstate_indexes[v] < cpu->cpreg_indexes[i]) {
fail = handle_cpreg_only_in_incoming_stream(cpu,
- cpu->cpreg_vmstate_indexes[v++]);
+ cpu->cpreg_vmstate_indexes[v],
+ cpu->cpreg_vmstate_values[v]);
+ v++;
continue;
}
/* matching register, copy the value over */
@@ -1072,7 +1077,8 @@ static int cpu_post_load(void *opaque, int version_id)
*/
for ( ; v < cpu->cpreg_vmstate_array_len; v++) {
fail = handle_cpreg_only_in_incoming_stream(cpu,
- cpu->cpreg_vmstate_indexes[v]);
+ cpu->cpreg_vmstate_indexes[v],
+ cpu->cpreg_vmstate_values[v]);
}
if (fail) {
return -1;

View File

@ -0,0 +1,88 @@
From 77103c408f6011cb662bfa80a6246cc3d8201789 Mon Sep 17 00:00:00 2001
From: Eric Auger <eric.auger@redhat.com>
Date: Mon, 20 Apr 2026 16:03:54 +0200
Subject: [PATCH] target/arm/cpu64: Mitigate migration failures due to spurious
TCR_EL1, PIRE0_EL1 and PIR_EL1
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 488: [rhel-10] Backport cross-kernel migration failure mitigation series
RH-Jira: RHEL-174858
RH-Acked-by: Mohammadfaiz Bawa <None>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Commit: [13/16] 90857210d7a915351c637756650071ff44f8d378 (eauger1/centos-qemu-kvm)
Conflicts: contextual conflict in target/arm/cpu64.c as cpu local
variable is declared in the #if defined(CONFIG_KVM) and not at the top
Before linux v6.13 those registers were erroneously unconditionally
exposed and this was fixed by commits:
- 0fcb4eea5345 ("KVM: arm64: Hide TCR2_EL1 from userspace when
disabled for guests")
- a68cddbe47ef ("KVM: arm64: Hide S1PIE registers from userspace
when disabled for guests")
in v6.13.
This means if we migrate from an old kernel host to a >= 6.13 kernel
host, migration currently fails.
Declare cpreg migration tolerance for those registers.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Sebastian Ott <sebott@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20260420140552.104369-5-eric.auger@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 113ed8e53c08a46af2d3307ece846caf5a719f99)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
target/arm/cpu64.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 051d5d653b..820d2542fa 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -762,10 +762,39 @@ static void aarch64_a53_initfn(Object *obj)
}
#endif
+#if defined(CONFIG_KVM)
+static void kvm_arm_set_cpreg_mig_tolerances(ARMCPU *cpu)
+{
+ /*
+ * Registers that may be in the incoming stream and not exposed
+ * on the destination
+ */
+
+ /*
+ * TCR_EL1 was erroneously unconditionnally exposed before linux v6.13.
+ * See commit 0fcb4eea5345 ("KVM: arm64: Hide TCR2_EL1 from userspace
+ * when disabled for guests")
+ */
+ arm_register_cpreg_mig_tolerance(cpu, ARM64_SYS_REG(3, 0, 2, 0, 3),
+ 0, 0, ToleranceNotOnBothEnds);
+ /*
+ * PIRE0_EL1 and PIR_EL1 were erroneously unconditionnally exposed
+ * before linux v6.13. See commit a68cddbe47ef ("KVM: arm64: Hide
+ * S1PIE registers from userspace when disabled for guests")
+ */
+ arm_register_cpreg_mig_tolerance(cpu, ARM64_SYS_REG(3, 0, 10, 2, 2),
+ 0, 0, ToleranceNotOnBothEnds);
+ arm_register_cpreg_mig_tolerance(cpu, ARM64_SYS_REG(3, 0, 10, 2, 3),
+ 0, 0, ToleranceNotOnBothEnds);
+}
+#endif
+
static void aarch64_host_initfn(Object *obj)
{
#if defined(CONFIG_KVM)
ARMCPU *cpu = ARM_CPU(obj);
+
+ kvm_arm_set_cpreg_mig_tolerances(cpu);
kvm_arm_set_cpu_features_from_host(cpu);
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
aarch64_add_sve_properties(obj);

View File

@ -0,0 +1,55 @@
From a4ed027e8feb7625bd97f9c13600b490e2427291 Mon Sep 17 00:00:00 2001
From: Eric Auger <eric.auger@redhat.com>
Date: Mon, 20 Apr 2026 16:03:55 +0200
Subject: [PATCH] target/arm/cpu64: Define cpreg migration tolerance for
KVM_REG_ARM_VENDOR_HYP_BMAP_2
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 488: [rhel-10] Backport cross-kernel migration failure mitigation series
RH-Jira: RHEL-174858
RH-Acked-by: Mohammadfaiz Bawa <None>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Commit: [14/16] 2289633dd2eadbde2e57a19da4259fa7c7c00013 (eauger1/centos-qemu-kvm)
KVM_REG_ARM_VENDOR_HYP_BMAP_2 pseudo FW register is exposed
from v6.15 onwards. Backward migration from a >= v6.15 to an older
kernel would fail without cpreg migration tolerance definition
for this register. If the register is present on source but not
on destination, its value must be checked to make sure it matches
the reset value, ie. 0, meaning no service is exposed to the guest,
hence the choice of a ToleranceOnlySrcTestValue migration
tolerance.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20260420140552.104369-6-eric.auger@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 6dd8be31f8fbbeba65a80b1e96c7331886c6f6d5)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
target/arm/cpu64.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 820d2542fa..98d9f34550 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -786,6 +786,17 @@ static void kvm_arm_set_cpreg_mig_tolerances(ARMCPU *cpu)
0, 0, ToleranceNotOnBothEnds);
arm_register_cpreg_mig_tolerance(cpu, ARM64_SYS_REG(3, 0, 10, 2, 3),
0, 0, ToleranceNotOnBothEnds);
+
+ /*
+ * KVM_REG_ARM_VENDOR_HYP_BMAP_2 pseudo FW register is exposed
+ * from v6.15 onwards. Backward migration from a >= v6.15 to an older
+ * kernel would fail without cpreg migration tolerance definition.
+ * If the register is present on source but not on destination, make
+ * sure it has its reset value, ie. 0, meaning no service is exposed
+ * to the guest.
+ */
+ arm_register_cpreg_mig_tolerance(cpu, KVM_REG_ARM_FW_FEAT_BMAP_REG(3),
+ UINT64_MAX, 0, ToleranceOnlySrcTestValue);
}
#endif

View File

@ -0,0 +1,72 @@
From 1d432ec5787507b2c25eca46ce95e3560289c00f Mon Sep 17 00:00:00 2001
From: Eric Auger <eric.auger@redhat.com>
Date: Mon, 20 Apr 2026 16:03:56 +0200
Subject: [PATCH] target/arm/helper: Define cpreg migration tolerance for
DGBDTR_EL0
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 488: [rhel-10] Backport cross-kernel migration failure mitigation series
RH-Jira: RHEL-174858
RH-Acked-by: Mohammadfaiz Bawa <None>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Commit: [15/16] 4c159a6da8530899c605c9aa81c99a06be2f0819 (eauger1/centos-qemu-kvm)
We want to remove AArch32 DBGDTRTX which was erroneously exposed.
This was attempted by 655659a74a36b ("target/arm: Correct encoding
of Debug Communications Channel registers") but it was discovered
that the removal of this debug register broke forward migration on
TCG. Now we have the cpreg migration tolerance infrastructure, we
can declare one for the DBGDTRTX. This allow to revert the reinstate
patch.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Sebastian Ott <sebott@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20260420140552.104369-7-eric.auger@redhat.com
[PMM: revised comment, included note about when we can drop
the workaround]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 234b3eaddd4ff08b8b62d563742e37f7bb6486bd)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
target/arm/helper.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 5e643ed6b2..0deb2bd760 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -6129,9 +6129,32 @@ void register_cp_regs_for_features(ARMCPU *cpu)
.fgt = FGT_CLIDR_EL1,
.resetvalue = GET_IDREG(isar, CLIDR)
};
+ uint64_t dbgtr_el0_kvmidx =
+ cpreg_to_kvm_id(ENCODE_CP_REG(14, 0, 1, 0, 5, 3, 0));
+
define_one_arm_cp_reg(cpu, &clidr);
define_arm_cp_regs(cpu, v7_cp_reginfo);
define_debug_regs(cpu);
+ /*
+ * We used to incorrectly expose a non-existent AArch32 "DBGDTRTX"
+ * register with this encoding. This has been fixed by commit
+ * 655659a74a36 ("target/arm: Correct encoding of Debug
+ * Communications Channel registers") by the introduction of correct
+ * separate cpreg definitions for AA64 and AA32 versions. However,
+ * the old cpreg definition couldn't be removed without breaking
+ * migration, so commit 4f2b82f604 reinstated the bogus encoding
+ * for migration data only.
+ *
+ * Now that we have migration tolerance infrastructure, we can use
+ * this to allow forward migration from the buggy QEMU versions,
+ * accepting and ignoring the bogus register if it is in the
+ * source data. QEMU 11.0 was the last version that sent the
+ * bogus encoding, so this workaround can be removed at the point
+ * where we no longer care about migration from that version
+ * (i.e. when we remove the "virt-11.0" machine type).
+ */
+ arm_register_cpreg_mig_tolerance(cpu, dbgtr_el0_kvmidx,
+ 0, 0, ToleranceNotOnBothEnds);
} else {
define_arm_cp_regs(cpu, not_v7_cp_reginfo);
}

View File

@ -0,0 +1,77 @@
From dc13639a241cb3f89aabb52c552802de5e174ffe Mon Sep 17 00:00:00 2001
From: Eric Auger <eric.auger@redhat.com>
Date: Mon, 20 Apr 2026 16:03:57 +0200
Subject: [PATCH] Revert "target/arm: Reinstate bogus AArch32 DBGDTRTX register
for migration compat"
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 488: [rhel-10] Backport cross-kernel migration failure mitigation series
RH-Jira: RHEL-174858
RH-Acked-by: Mohammadfaiz Bawa <None>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Commit: [16/16] 60be5ef3f6fe516b480e578cd610618d180a9655 (eauger1/centos-qemu-kvm)
This reverts commit 4f2b82f60431 ("target/arm: Reinstate bogus AArch32
DBGDTRTX register for migration compat). We don't need that commit
anymore as the AArch32 DBGDTRTX register is declared to
be safe to ignore in the incoming migration stream.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Sebastian Ott <sebott@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20260420140552.104369-8-eric.auger@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 202126dcb9d6261c38e629799265defeb3260d25)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
target/arm/debug_helper.c | 29 -----------------------------
1 file changed, 29 deletions(-)
diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c
index 579516e154..aee06d4d42 100644
--- a/target/arm/debug_helper.c
+++ b/target/arm/debug_helper.c
@@ -940,13 +940,6 @@ static void dbgclaimclr_write(CPUARMState *env, const ARMCPRegInfo *ri,
env->cp15.dbgclaim &= ~(value & 0xFF);
}
-static CPAccessResult access_bogus(CPUARMState *env, const ARMCPRegInfo *ri,
- bool isread)
-{
- /* Always UNDEF, as if this cpreg didn't exist */
- return CP_ACCESS_UNDEFINED;
-}
-
static const ARMCPRegInfo debug_cp_reginfo[] = {
/*
* DBGDRAR, DBGDSAR: always RAZ since we don't implement memory mapped
@@ -1009,28 +1002,6 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
.opc0 = 2, .opc1 = 3, .crn = 0, .crm = 4, .opc2 = 0,
.access = PL0_RW, .accessfn = access_tdcc,
.type = ARM_CP_CONST, .resetvalue = 0 },
- /*
- * This is not a real AArch32 register. We used to incorrectly expose
- * this due to a QEMU bug; to avoid breaking migration compatibility we
- * need to continue to provide it so that we don't fail the inbound
- * migration when it tells us about a sysreg that we don't have.
- * We set an always-fails .accessfn, which means that the guest doesn't
- * actually see this register (it will always UNDEF, identically to if
- * there were no cpreg definition for it other than that we won't print
- * a LOG_UNIMP message about it), and we set the ARM_CP_NO_GDB flag so the
- * gdbstub won't see it either.
- * (We can't just set .access = 0, because add_cpreg_to_hashtable()
- * helpfully ignores cpregs which aren't accessible to the highest
- * implemented EL.)
- *
- * TODO: implement a system for being able to describe "this register
- * can be ignored if it appears in the inbound stream"; then we can
- * remove this temporary hack.
- */
- { .name = "BOGUS_DBGDTR_EL0", .state = ARM_CP_STATE_AA32,
- .cp = 14, .opc1 = 3, .crn = 0, .crm = 5, .opc2 = 0,
- .access = PL0_RW, .accessfn = access_bogus,
- .type = ARM_CP_CONST | ARM_CP_NO_GDB, .resetvalue = 0 },
/*
* OSECCR_EL1 provides a mechanism for an operating system
* to access the contents of EDECCR. EDECCR is not implemented though,

View File

@ -143,7 +143,7 @@ Obsoletes: %{name}-block-ssh <= %{epoch}:%{version} \
Summary: QEMU is a machine emulator and virtualizer
Name: qemu-kvm
Version: 10.1.0
Release: 18%{?rcrel}%{?dist}%{?cc_suffix}.1
Release: 19%{?rcrel}%{?dist}%{?cc_suffix}.1
# Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped
# Epoch 15 used for RHEL 8
# Epoch 17 used for RHEL 9 (due to release versioning offset in RHEL 8.5)
@ -507,142 +507,23 @@ Patch338: 0338-hw-tpm-Simplify-tpm_ppi_enabled.patch
Patch339: 0339-docs-specs-tpm-document-PPI-support-on-ARM64-virt.patch
Patch340: 0340-hw-acpi-tpm-parameterize-PPI-base-address-in-tpm_bui.patch
Patch341: 0341-hw-tpm-add-PPI-support-to-tpm-tis-device-for-ARM64-v.patch
# For RHEL-112882 - [DEV Task]: Assertion `core->delayed_causes == 0' failed with e1000e NIC
# For RHEL-119368 - [rhel10] Backport "arm/kvm: report registers we failed to set"
# For RHEL-116443 - qemu crash after hot-unplug disk from the multifunction enabled bus,crash point PCIDevice *vf = dev->exp.sriov_pf.vf[i]
# For RHEL-120253 - Backport fixes for PDCM and ARCH_CAPABILITIES migration incompatibility
# For RHEL-120253 - Backport fixes for PDCM and ARCH_CAPABILITIES migration incompatibility
# For RHEL-104009 - [IBM 10.2 FEAT] KVM: Enhance machine type definition to include CPI and PCI passthru capabilities (qemu)
# For RHEL-105823 - Add new -rhel10.2.0 machine type to qemu-kvm [s390x]
# For RHEL-73008 - [IBM 10.2 FEAT] KVM: Implement Control Program Identification (qemu)
# For RHEL-104009 - [IBM 10.2 FEAT] KVM: Enhance machine type definition to include CPI and PCI passthru capabilities (qemu)
# For RHEL-105823 - Add new -rhel10.2.0 machine type to qemu-kvm [s390x]
# For RHEL-73008 - [IBM 10.2 FEAT] KVM: Implement Control Program Identification (qemu)
# For RHEL-104009 - [IBM 10.2 FEAT] KVM: Enhance machine type definition to include CPI and PCI passthru capabilities (qemu)
# For RHEL-105823 - Add new -rhel10.2.0 machine type to qemu-kvm [s390x]
# For RHEL-73008 - [IBM 10.2 FEAT] KVM: Implement Control Program Identification (qemu)
# For RHEL-118810 - [RHEL 10.2] Windows 11 VM fails to boot up with ramfb='on' with QEMU 10.1
# For RHEL-118810 - [RHEL 10.2] Windows 11 VM fails to boot up with ramfb='on' with QEMU 10.1
# For RHEL-105826 - Add new -rhel10.2.0 machine type to qemu-kvm [aarch64]
# For RHEL-105828 - Add new -rhel10.2.0 machine type to qemu-kvm [x86_64]
# For RHEL-105826 - Add new -rhel10.2.0 machine type to qemu-kvm [aarch64]
# For RHEL-105828 - Add new -rhel10.2.0 machine type to qemu-kvm [x86_64]
# For RHEL-105826 - Add new -rhel10.2.0 machine type to qemu-kvm [aarch64]
# For RHEL-105828 - Add new -rhel10.2.0 machine type to qemu-kvm [x86_64]
# For RHEL-105826 - Add new -rhel10.2.0 machine type to qemu-kvm [aarch64]
# For RHEL-105828 - Add new -rhel10.2.0 machine type to qemu-kvm [x86_64]
# For RHEL-101929 - enable 'usb-bot' device for proper support of USB CD-ROM drives via libvirt
# For RHEL-120116 - CVE-2025-11234 qemu-kvm: VNC WebSocket handshake use-after-free [rhel-10.2]
# For RHEL-120116 - CVE-2025-11234 qemu-kvm: VNC WebSocket handshake use-after-free [rhel-10.2]
# For RHEL-126573 - VFIO migration using multifd should be disabled by default
# For RHEL-67323 - [aarch64] Support ACPI based PCI hotplug on ARM
# For RHEL-73800 - NVIDIA:Grace-Hopper:Backport support for user-creatable nested SMMUv3 - RHEL 10.1
# For RHEL-73800 - NVIDIA:Grace-Hopper:Backport support for user-creatable nested SMMUv3 - RHEL 10.1
# For RHEL-73800 - NVIDIA:Grace-Hopper:Backport support for user-creatable nested SMMUv3 - RHEL 10.1
# For RHEL-73800 - NVIDIA:Grace-Hopper:Backport support for user-creatable nested SMMUv3 - RHEL 10.1
# For RHEL-73800 - NVIDIA:Grace-Hopper:Backport support for user-creatable nested SMMUv3 - RHEL 10.1
# For RHEL-73800 - NVIDIA:Grace-Hopper:Backport support for user-creatable nested SMMUv3 - RHEL 10.1
# For RHEL-73800 - NVIDIA:Grace-Hopper:Backport support for user-creatable nested SMMUv3 - RHEL 10.1
# For RHEL-73800 - NVIDIA:Grace-Hopper:Backport support for user-creatable nested SMMUv3 - RHEL 10.1
# For RHEL-73800 - NVIDIA:Grace-Hopper:Backport support for user-creatable nested SMMUv3 - RHEL 10.1
# For RHEL-73800 - NVIDIA:Grace-Hopper:Backport support for user-creatable nested SMMUv3 - RHEL 10.1
# For RHEL-73800 - NVIDIA:Grace-Hopper:Backport support for user-creatable nested SMMUv3 - RHEL 10.1
# For RHEL-126708 - [RHEL 10]snp guest fail to boot with hugepage
# For RHEL-126708 - [RHEL 10]snp guest fail to boot with hugepage
# For RHEL-128085 - VM crashes during boot when virtio device is attached through vfio_ccw
# For RHEL-130704 - [rhel10] Fix the typo under vfio-pci device's enable-migration option
# For RHEL-120115 - The vf nic created using the IGB emulated nic can not obtain ip address
# For RHEL-130478 - Migration from RHEL 10.2 to RHEL 10.1 with virt-rhel10.0.0 machine type fails on Grace
# For RHEL-129540 - Assertion failure on drain with iothread and I/O load
# For RHEL-121543 - The VM hit io error when do S3-PR integration on the pass-through failover multipath device
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-134212 - [RHEL10.2] L1VH qemu downstream initial merge RHEL10.2
# For RHEL-110003 - Expose block limits of block nodes in QMP and qemu-img
# For RHEL-110003 - Expose block limits of block nodes in QMP and qemu-img
# For RHEL-110003 - Expose block limits of block nodes in QMP and qemu-img
# For RHEL-110003 - Expose block limits of block nodes in QMP and qemu-img
# For RHEL-111853 - [Intel 10.0 FEAT] [SPR] TDX: Virt-QEMU: QEMU Support [rhel-10]
# For RHEL-108142 - QEMU crashes when stopping source VM during live migration
# For RHEL-126707 - [qemu, rhel-10] increase default TSEG size
# For RHEL-126707 - [qemu, rhel-10] increase default TSEG size
# For RHEL-139028 - Intel IOMMU VM freezes: "call_irq_handler: 3.37 No irq handler for vector"[rhel-10.2]
# For RHEL-111853 - [Intel 10.0 FEAT] [SPR] TDX: Virt-QEMU: QEMU Support [rhel-10]
# For RHEL-79118 - [network-storage][rbd][core-dump]installation of guest failed sometimes with multiqueue enabled [rhel10]
# For RHEL-79118 - [network-storage][rbd][core-dump]installation of guest failed sometimes with multiqueue enabled [rhel10]
# For RHEL-79118 - [network-storage][rbd][core-dump]installation of guest failed sometimes with multiqueue enabled [rhel10]
# For RHEL-79118 - [network-storage][rbd][core-dump]installation of guest failed sometimes with multiqueue enabled [rhel10]
# For RHEL-79118 - [network-storage][rbd][core-dump]installation of guest failed sometimes with multiqueue enabled [rhel10]
# For RHEL-143785 - backport support for GSO over UDP tunnel offload
# For RHEL-143785 - backport support for GSO over UDP tunnel offload
# For RHEL-143785 - backport support for GSO over UDP tunnel offload
# For RHEL-143785 - backport support for GSO over UDP tunnel offload
# For RHEL-143785 - backport support for GSO over UDP tunnel offload
# For RHEL-143785 - backport support for GSO over UDP tunnel offload
# For RHEL-143785 - backport support for GSO over UDP tunnel offload
# For RHEL-143785 - backport support for GSO over UDP tunnel offload
# For RHEL-143785 - backport support for GSO over UDP tunnel offload
# For RHEL-143785 - backport support for GSO over UDP tunnel offload
# For RHEL-143785 - backport support for GSO over UDP tunnel offload
# For RHEL-143785 - backport support for GSO over UDP tunnel offload
# For RHEL-143785 - backport support for GSO over UDP tunnel offload
# For RHEL-143785 - backport support for GSO over UDP tunnel offload
# For RHEL-147425 - virtiofs: processes become stuck in request_wait_answer on virtiofs mounts
# For RHEL-132749 - Migrate SCSI PR state and preempt reservation upon live migration
# For RHEL-132749 - Migrate SCSI PR state and preempt reservation upon live migration
# For RHEL-132749 - Migrate SCSI PR state and preempt reservation upon live migration
# For RHEL-132749 - Migrate SCSI PR state and preempt reservation upon live migration
# For RHEL-132749 - Migrate SCSI PR state and preempt reservation upon live migration
# For RHEL-134989 - Hotplugged interface device can not be shown in the guest
# For RHEL-146584 - [RHEL-10.2][ARM]: Unable to Check the mem prefetched size on Guest
# For RHEL-153058 - Qemu crashes with "double free" during restore --reset-nvram with uefi-vars secure boot
# For RHEL-144004 - [rhel-10] Regression in BLOCK_IO_ERROR event delivery with (w|r)error setting of 'stop' or 'enospc' due to event rate limiting
# For RHEL-155601 - Mirror job can miss writes during startup, corrupting the copy [rhel-10.2]
# For RHEL-158224 - qemu-kvm: disk writes of fewer bytes than requested is a retry condition, not necessarily an indication of ENOSPC [rhel-10.2]
# For RHEL-158224 - qemu-kvm: disk writes of fewer bytes than requested is a retry condition, not necessarily an indication of ENOSPC [rhel-10.2]
# For RHEL-158224 - qemu-kvm: disk writes of fewer bytes than requested is a retry condition, not necessarily an indication of ENOSPC [rhel-10.2]
# For RHEL-158224 - qemu-kvm: disk writes of fewer bytes than requested is a retry condition, not necessarily an indication of ENOSPC [rhel-10.2]
# For RHEL-114231 - Add stats-intervals support to --blockdev
# For RHEL-114231 - Add stats-intervals support to --blockdev
# For RHEL-158212 - qemu-kvm doesn't retry SG-IO on 05/25/00 (ILLEGAL REQUEST / LOGICAL UNIT NOT SUPPORTED) [rhel-10.3]
# For RHEL-112608 - [ARM64] Windows 11 VM should install without TPM Bypass
# For RHEL-112608 - [ARM64] Windows 11 VM should install without TPM Bypass
# For RHEL-112608 - [ARM64] Windows 11 VM should install without TPM Bypass
# For RHEL-112608 - [ARM64] Windows 11 VM should install without TPM Bypass
# For RHEL-112608 - [ARM64] Windows 11 VM should install without TPM Bypass
# For RHEL-112608 - [ARM64] Windows 11 VM should install without TPM Bypass
# For RHEL-112608 - [ARM64] Windows 11 VM should install without TPM Bypass
# For RHEL-112608 - [ARM64] Windows 11 VM should install without TPM Bypass
Patch342: 0342-hw-vfio-iommufd-Control-dirty-tracking-for-nesting-p.patch
Patch343: 0343-vmstate-Introduce-VMSTATE_VARRAY_INT32_ALLOC.patch
Patch344: 0344-target-arm-Move-compare_u64-to-helper.c.patch
Patch345: 0345-target-arm-Convert-init_cpreg_list-to-g_hash_table_f.patch
Patch346: 0346-target-arm-machine-Use-VMSTATE_VARRAY_INT32_ALLOC-fo.patch
Patch347: 0347-target-arm-kvm-Export-kvm_print_register_name.patch
Patch348: 0348-target-arm-kvm-Tweak-print_register_name-for-arm64-s.patch
Patch349: 0349-target-arm-machine-Trace-cpreg-names-which-do-not-ma.patch
Patch350: 0350-target-arm-machine-Trace-all-register-mismatches.patch
Patch351: 0351-target-arm-machine-Fix-detection-of-unknown-incoming.patch
Patch352: 0352-target-arm-cpu-Introduce-the-infrastructure-for-cpre.patch
Patch353: 0353-target-arm-machine-Handle-ToleranceNotOnBothEnds-mig.patch
Patch354: 0354-target-arm-machine-Handle-ToleranceOnlySrcTestValue-.patch
Patch355: 0355-target-arm-cpu64-Mitigate-migration-failures-due-to-.patch
Patch356: 0356-target-arm-cpu64-Define-cpreg-migration-tolerance-fo.patch
Patch357: 0357-target-arm-helper-Define-cpreg-migration-tolerance-f.patch
Patch358: 0358-Revert-target-arm-Reinstate-bogus-AArch32-DBGDTRTX-r.patch
%if %{have_clang}
BuildRequires: clang
@ -1722,6 +1603,13 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \
%endif
%changelog
* Wed Jun 03 2026 Miroslav Rezanina <mrezanin@redhat.com> - 10.1.0-19.el10nv.1
- backport Control dirty tracking for nesting parent HWPT
- Resolves: VOYAGER-857
* Tue May 26 2026 Miroslav Rezanina <mrezanin@redhat.com> - 10.1.0-19
- Backport cross-kernel migration failure mitigation series
* Thu May 14 2026 Miroslav Rezanina <mrezanin@redhat.com> - 10.1.0-18.el10nv.1
- CMDQV v4 and other GPU passthrough add-ons
- Resolves: VOYAGER-15