target/arm/machine: Fix detection of unknown incoming cpregs
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.
Fixes: 721fae1253 ("target-arm: Convert TCG to using (index,value) list for cp migration")
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20260304101625.1962633-8-eric.auger@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
committed by
Peter Maydell
parent
e25c63c3b3
commit
dbfed8d808
@@ -1057,6 +1057,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;
|
||||
@@ -1096,21 +1125,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 */
|
||||
@@ -1118,6 +1138,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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user