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: 721fae12536 ("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>
Eric Auger committed
Mar 6, 2026 at 09:01 UTC
dbfed8d80837ff7d36e763163f38549169ee64cc
1 file changed
+49
-12
target/arm/machine.c
+49
-12
@@ -1057,6 +1057,35 @@ static gchar *print_register_name(uint64_t kvm_regidx)
1057
}
1058
}
1059
1060
+/*
1061
+ * Handle the situation where @kvmidx is on destination but not
1062
+ * in the incoming stream. This never fails the migration.
1063
+ */
1064
+static void handle_cpreg_missing_in_incoming_stream(ARMCPU *cpu, uint64_t kvmidx)
1065
+{
1066
+ g_autofree gchar *name = print_register_name(kvmidx);
1067
+
1068
+ warn_report("%s: %s "
1069
+ "expected by the destination but not in the incoming stream: "
1070
+ "skip it", __func__, name);
1071
+}
1072
+
1073
+/*
1074
+ * Handle the situation where @kvmidx is in the incoming stream
1075
+ * but not on destination. This currently fails the migration but
1076
+ * we plan to accomodate some exceptions, hence the boolean returned value.
1077
+ */
1078
+static bool handle_cpreg_only_in_incoming_stream(ARMCPU *cpu, uint64_t kvmidx)
1079
+{
1080
+ g_autofree gchar *name = print_register_name(kvmidx);
1081
+ bool fail = true;
1082
+
1083
+ error_report("%s: %s in the incoming stream but unknown on the "
1084
+ "destination: fail migration", __func__, name);
1085
+
1086
+ return fail;
1087
+}
1088
+
1089
static int cpu_post_load(void *opaque, int version_id)
1090
{
1091
ARMCPU *cpu = opaque;
@@ -1096,21 +1125,12 @@ static int cpu_post_load(void *opaque, int version_id)
1125
for (i = 0, v = 0; i < cpu->cpreg_array_len
1126
&& v < cpu->cpreg_vmstate_array_len;) {
1127
if (cpu->cpreg_vmstate_indexes[v] > cpu->cpreg_indexes[i]) {
1099
- g_autofree gchar *name = print_register_name(cpu->cpreg_indexes[i]);
1100
-
1101
- warn_report("%s: %s "
1102
- "expected by the destination but not in the incoming stream: "
1103
- "skip it", __func__, name);
1104
- i++;
1128
+ handle_cpreg_missing_in_incoming_stream(cpu, cpu->cpreg_indexes[i++]);
1129
continue;
1130
}
1131
if (cpu->cpreg_vmstate_indexes[v] < cpu->cpreg_indexes[i]) {
1108
- g_autofree gchar *name = print_register_name(cpu->cpreg_vmstate_indexes[v]);
1109
-
1110
- error_report("%s: %s in the incoming stream but unknown on the destination: "
1111
- "fail migration", __func__, name);
1112
- v++;
1113
- fail = true;
1132
+ fail = handle_cpreg_only_in_incoming_stream(cpu,
1133
+ cpu->cpreg_vmstate_indexes[v++]);
1134
continue;
1135
}
1136
/* matching register, copy the value over */
@@ -1118,6 +1138,23 @@ static int cpu_post_load(void *opaque, int version_id)
1138
i++;
1139
v++;
1140
}
1141
+
1142
+ /*
1143
+ * if we have reached the end of the incoming array but there are
1144
+ * still regs in cpreg, continue parsing the regs which are missing
1145
+ * in the input stream
1146
+ */
1147
+ for ( ; i < cpu->cpreg_array_len; i++) {
1148
+ handle_cpreg_missing_in_incoming_stream(cpu, cpu->cpreg_indexes[i]);
1149
+ }
1150
+ /*
1151
+ * if we have reached the end of the cpreg array but there are
1152
+ * still regs in the input stream, continue parsing the vmstate array
1153
+ */
1154
+ for ( ; v < cpu->cpreg_vmstate_array_len; v++) {
1155
+ fail = handle_cpreg_only_in_incoming_stream(cpu,
1156
+ cpu->cpreg_vmstate_indexes[v]);
1157
+ }
1158
if (fail) {
1159
return -1;
1160
}