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 <[email protected]> Reviewed-by: Peter Maydell <[email protected]> --- v1 -> v2: - replaced ',' by ':' in the traces - added system register in print_register_name when kvm is not enabled --- 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 aa617dd64db..7dd649e8f64 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" @@ -1044,6 +1045,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; @@ -1082,11 +1092,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 */ -- 2.53.0
