The DBGDTRTX register definition was removed from cpu->cp_regs in the
10.1 cycle. This breaks migration from QEMU versions < 10.1 due to the
present of an extra, unknown (to 10.1) register in the migration
stream.

Change the cpu_post_load validation code to recognise that the
register has been removed and ignore it when present in the stream.

Keep a compatibility list with the registers that should be ignored
when sent from versions older than 10.1. The value of the cpregs
hashtable key is used because it can be derived on the destination
(where this patch applies) from the cpreg_vmstate_indexes array.

Note that this solution is *not* generic for other QEMU versions
moving forward, this is a stop gap to avoid machines being stuck in
QEMU < 10.1 without a migration path. A proper solution would include
versioning of the register list and recognizing any registers
removed/changed.

Fixes: 655659a74a ("target/arm: Correct encoding of Debug Communications 
Channel registers")
Signed-off-by: Fabiano Rosas <faro...@suse.de>
---
Will an older guest using the register have issues after migration
once the register gets set to its default value?
---
 target/arm/machine.c | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/target/arm/machine.c b/target/arm/machine.c
index 6986915bee..2d4df53817 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -8,6 +8,7 @@
 #include "cpu-features.h"
 #include "migration/qemu-file-types.h"
 #include "migration/vmstate.h"
+#include "target/arm/cpregs.h"
 #include "target/arm/gtimer.h"
 
 static bool vfp_needed(void *opaque)
@@ -868,6 +869,14 @@ static const VMStateInfo vmstate_powered_off = {
     .put = put_power,
 };
 
+static uint64_t compat_cpreg_keys_virt_10_0[] = {
+    /*
+     * { .name = "DBGDTRTX", .state = ARM_CP_STATE_AA32,
+     * .cp = 14, .crn = 0, .crm = 5, .opc1 = 3, .opc2 = 0 }
+     */
+    ENCODE_CP_REG(14, 0, 1, 0, 5, 3, 0),
+};
+
 static int cpu_pre_save(void *opaque)
 {
     ARMCPU *cpu = opaque;
@@ -951,7 +960,7 @@ static int cpu_post_load(void *opaque, int version_id)
 {
     ARMCPU *cpu = opaque;
     CPUARMState *env = &cpu->env;
-    int i, v;
+    int i, j, v;
 
     /*
      * Handle migration compatibility from old QEMU which didn't
@@ -987,10 +996,23 @@ static int cpu_post_load(void *opaque, int version_id)
         }
         if (cpu->cpreg_vmstate_indexes[v] < cpu->cpreg_indexes[i]) {
             /* register in their list but not ours: fail migration */
+
+            for (j = 0; j < ARRAY_SIZE(compat_cpreg_keys_virt_10_0); j++) {
+                if (cpu->cpreg_vmstate_indexes[v] ==
+                    cpreg_to_kvm_id(compat_cpreg_keys_virt_10_0[j])) {
+                    /*
+                     * ...unless the extra register is being explicitly
+                     * ignored for migration compatibility purposes.
+                     */
+                    i--;
+                    goto next;
+                }
+            }
             return -1;
         }
         /* matching register, copy the value over */
         cpu->cpreg_values[i] = cpu->cpreg_vmstate_values[v];
+    next:
         v++;
     }
 
-- 
2.35.3


Reply via email to