181
QLIST_INSERT_HEAD(&cpu->el_change_hooks, entry, node);
182
}
183
184
+static ARMCPRegMigTolerance *find_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx)
185
+{
186
+ ARMCPRegMigTolerance *t;
187
+ QLIST_FOREACH(t, &cpu->cpreg_mig_tolerances, node) {
188
+ if (t->kvmidx == kvmidx) {
189
+ return t;
190
+ }
191
+ }
192
+ return NULL;
193
+}
194
+
195
+void arm_register_cpreg_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx,
196
+ uint64_t mask, uint64_t value,
197
+ ARMCPRegMigToleranceType type)
198
+{
199
+ ARMCPRegMigTolerance *entry;
200
+
201
+ /* make sure the kvmidx has not tolerance already registered */
202
+ assert(!find_mig_tolerance(cpu, kvmidx));
203
+
204
+ assert(type == ToleranceNotOnBothEnds ||
205
+ type == ToleranceOnlySrcTestValue);
206
+
207
+ entry = g_new0(ARMCPRegMigTolerance, 1);
208
+
209
+ entry->kvmidx = kvmidx;
210
+ entry->mask = mask;
211
+ entry->value = value;
212
+ entry->type = type;
213
+
214
+ QLIST_INSERT_HEAD(&cpu->cpreg_mig_tolerances, entry, node);
215
+}
216
+
217
+bool arm_cpu_match_cpreg_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx,
218
+ uint64_t vmstate_value, uint64_t local_value,
219
+ ARMCPRegMigToleranceType type)
220
+{
221
+ ARMCPRegMigTolerance *t = find_mig_tolerance(cpu, kvmidx);
222
+ uint64_t diff, diff_outside_mask, field;
223
+
224
+ if (!t || t->type != type) {
225
+ return false;
226
+ }
227
+
228
+ if (type == ToleranceNotOnBothEnds) {
229
+ return true;
230
+ }
231
+
232
+ if (type == ToleranceOnlySrcTestValue &&
233
+ ((vmstate_value & t->mask) == t->value)) {
234
+ return true;
235
+ }
236
+
237
+ /* Need to check the mask */
238
+ diff = vmstate_value ^ local_value;
239
+ diff_outside_mask = diff & ~t->mask;
240
+
241
+ if (diff_outside_mask) {
242
+ /* there are differences outside of the mask */
243
+ return false;
244
+ }
245
+ if (type == ToleranceDiffInMask) {
246
+ /* differences only in the field, tolerance matched */
247
+ return true;
248
+ }
249
+ /* need to compare field value against authorized ones */
250
+ field = vmstate_value & t->mask;
251
+ if (type == ToleranceFieldLT && (field < t->value)) {
252
+ return true;
253
+ }
254
+ if (type == ToleranceFieldGT && (field > t->value)) {
255
+ return true;
256
+ }
257
+ return false;
258
+}
259
+
260
static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
261
{
262
/* Reset a single ARMCPRegInfo register */
1178
1179
QLIST_INIT(&cpu->pre_el_change_hooks);
1180
QLIST_INIT(&cpu->el_change_hooks);
1181
+ QLIST_INIT(&cpu->cpreg_mig_tolerances);
1182
1183
#ifdef CONFIG_USER_ONLY
1184
# ifdef TARGET_AARCH64
1651
{
1652
ARMCPU *cpu = ARM_CPU(obj);
1653
ARMELChangeHook *hook, *next;
1654
+ ARMCPRegMigTolerance *t, *n;
1655
1656
g_hash_table_destroy(cpu->cp_regs);
1657
1663
QLIST_REMOVE(hook, node);
1664
g_free(hook);
1665
}
1666
+ QLIST_FOREACH_SAFE(t, &cpu->cpreg_mig_tolerances, node, n) {
1667
+ QLIST_REMOVE(t, node);
1668
+ g_free(t);
1669
+ }
1670
#ifndef CONFIG_USER_ONLY
1671
if (cpu->pmu_timer) {
1672
timer_free(cpu->pmu_timer);