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. Signed-off-by: Eric Auger <[email protected]> Fixes: 721fae12536 ("target-arm: Convert TCG to using (index,value) list for cp migration") --- 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 13f3955be67..2108e7916bb 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c @@ -1054,6 +1054,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; @@ -1093,21 +1122,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 */ @@ -1115,6 +1135,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; } -- 2.53.0
