@samitouri / QOSamiQemu / commits / dbfed8d808

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 }