@samitouri / QOSamiQemu / commits / eac1e610f4

target/arm/machine: Trace cpreg names which do not match on migration

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>

Eric Auger committed Mar 6, 2026 at 09:01 UTC eac1e610f48923084cb07b3f1eaa05f5fedccd85
1 file changed +19 -2
target/arm/machine.c
+19 -2
@@ -1,5 +1,6 @@
1 #include "qemu/osdep.h"
2 #include "cpu.h"
3 +#include "cpregs.h"
4 #include "trace.h"
5 #include "qemu/error-report.h"
6 #include "system/kvm.h"
@@ -1047,6 +1048,15 @@ static int cpu_pre_load(void *opaque)
1048 return 0;
1049 }
1050
1051 +static gchar *print_register_name(uint64_t kvm_regidx)
1052 +{
1053 + if (kvm_enabled()) {
1054 + return kvm_print_register_name(kvm_regidx);
1055 + } else {
1056 + return g_strdup_printf("system register 0x%x", kvm_to_cpreg_id(kvm_regidx));
1057 + }
1058 +}
1059 +
1060 static int cpu_post_load(void *opaque, int version_id)
1061 {
1062 ARMCPU *cpu = opaque;
@@ -1085,11 +1095,18 @@ static int cpu_post_load(void *opaque, int version_id)
1095 for (i = 0, v = 0; i < cpu->cpreg_array_len
1096 && v < cpu->cpreg_vmstate_array_len; i++) {
1097 if (cpu->cpreg_vmstate_indexes[v] > cpu->cpreg_indexes[i]) {
1088 - /* register in our list but not incoming : skip it */
1098 + g_autofree gchar *name = print_register_name(cpu->cpreg_indexes[i]);
1099 +
1100 + warn_report("%s: %s "
1101 + "expected by the destination but not in the incoming stream: "
1102 + "skip it", __func__, name);
1103 continue;
1104 }
1105 if (cpu->cpreg_vmstate_indexes[v] < cpu->cpreg_indexes[i]) {
1092 - /* register in their list but not ours: fail migration */
1106 + g_autofree gchar *name = print_register_name(cpu->cpreg_vmstate_indexes[v]);
1107 +
1108 + error_report("%s: %s in the incoming stream but unknown on the destination: "
1109 + "fail migration", __func__, name);
1110 return -1;
1111 }
1112 /* matching register, copy the value over */