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.

Create dedicated helper functions that print the name of the culprit reg
and analyze whether a tolerance is set. According set the level of traces
and analyze whether the migration must eventually fail.

Signed-off-by: Eric Auger <[email protected]>
---
 target/arm/machine.c    | 67 +++++++++++++++++++++++++++--------------
 target/arm/trace-events |  2 ++
 2 files changed, 47 insertions(+), 22 deletions(-)

diff --git a/target/arm/machine.c b/target/arm/machine.c
index 9297a8f5b41..abc66448cef 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -1046,6 +1046,45 @@ 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);
+
+    if (!arm_cpu_cpreg_has_mig_tolerance(cpu, kvmidx,
+                                         0, 0, ToleranceNotOnBothEnds)) {
+        warn_report("%s: %s "
+                    "expected by the destination but not in the incoming 
stream, "
+                     "skip it", __func__, name);
+    } else {
+        trace_tolerate_cpreg_missing_in_incoming_stream(name);
+    }
+}
+
+/*
+ * Handle the situation where @kvmidx is in the incoming
+ * stream but not on destination. This fails the migration if
+ * no cpreg mig tolerance is set for this @kvmidx
+ */
+static bool handle_cpreg_only_in_incoming_stream(ARMCPU *cpu, uint64_t kvmidx)
+{
+    g_autofree gchar *name = print_register_name(kvmidx);
+    bool fail = false;
+
+    if (!arm_cpu_cpreg_has_mig_tolerance(cpu, kvmidx,
+                                        0, 0, ToleranceNotOnBothEnds)) {
+        error_report("%s: %s in the incoming stream but unknown on the "
+                     "destination, fail migration", __func__, name);
+        fail = true;
+    } else {
+        trace_tolerate_cpreg_only_in_incoming_stream(name);
+    }
+    return fail;
+}
+
 static int cpu_post_load(void *opaque, int version_id)
 {
     ARMCPU *cpu = opaque;
@@ -1085,21 +1124,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 */
@@ -1113,22 +1143,15 @@ static int cpu_post_load(void *opaque, int version_id)
      * in the input stream
      */
     for ( ; i < cpu->cpreg_array_len; 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);
+        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++) {
-        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);
-        fail = true;
+        fail = handle_cpreg_only_in_incoming_stream(cpu,
+                                                    
cpu->cpreg_vmstate_indexes[v]);
     }
     if (fail) {
         return -1;
diff --git a/target/arm/trace-events b/target/arm/trace-events
index 2de0406f784..dceb3c63f77 100644
--- a/target/arm/trace-events
+++ b/target/arm/trace-events
@@ -29,3 +29,5 @@ arm_psci_call(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t 
x3, uint32_t cpuid
 
 # 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) "cpreg %s is missing in 
incoming stream but this is explicitly tolerated"
+tolerate_cpreg_only_in_incoming_stream(char *name) "cpreg %s is in incoming 
stream but not on destination but this is explicitly tolerated"
-- 
2.53.0


Reply via email to