[PATCH v8 1/6] target/arm/cpu: Introduce the infrastructure for cpreg migration tolerances

Eric Auger posted 6 patches 1 month, 1 week ago
There is a newer version of this series
[PATCH v8 1/6] target/arm/cpu: Introduce the infrastructure for cpreg migration tolerances
Posted by Eric Auger 1 month, 1 week ago
We introduce a datatype for a tolerance with respect to a given
cpreg migration issue. The tolerance applies to a given cpreg kvm index,
and can be of different types:
- ToleranceNotOnBothEnds (cpreg index is allowed to be only on one end)
- ToleranceDiffInMask (value differences are allowed only within a mask)
- ToleranceFieldLT (incoming field value must be less than a given value)
- ToleranceFieldGT (incoming field value must be greater than a given value)

A QLIST of such tolerances can be populated using a new helper:
arm_register_cpreg_mig_tolerance() and arm_cpu_cpreg_has_mig_tolerance()
allows to check whether a tolerance exists for a given kvm index.

callers for those helpers will be introduced in subsequent patches.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
 target/arm/cpu.h | 32 +++++++++++++++++++++
 target/arm/cpu.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 107 insertions(+)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 657ff4ab20b..9dcc838f611 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -843,6 +843,21 @@ struct ARMELChangeHook {
     QLIST_ENTRY(ARMELChangeHook) node;
 };
 
+typedef enum {
+    ToleranceNotOnBothEnds,
+    ToleranceDiffInMask,
+    ToleranceFieldLT,
+    ToleranceFieldGT,
+} ARMCPUCPREGMigToleranceType;
+
+typedef struct ARMCPUCPREGMigTolerance {
+    uint64_t kvmidx;
+    uint64_t mask;
+    uint64_t value;
+    ARMCPUCPREGMigToleranceType type;
+    QLIST_ENTRY(ARMCPUCPREGMigTolerance) node;
+} ARMCPUCPREGMigTolerance;
+
 /* These values map onto the return values for
  * QEMU_PSCI_0_2_FN_AFFINITY_INFO */
 typedef enum ARMPSCIState {
@@ -1139,6 +1154,7 @@ struct ArchCPU {
 
     QLIST_HEAD(, ARMELChangeHook) pre_el_change_hooks;
     QLIST_HEAD(, ARMELChangeHook) el_change_hooks;
+    QLIST_HEAD(, ARMCPUCPREGMigTolerance) cpreg_mig_tolerances;
 
     int32_t node_id; /* NUMA node this CPU belongs to */
 
@@ -2632,6 +2648,22 @@ void arm_register_pre_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
 void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook, void
         *opaque);
 
+/**
+ * arm_register_cpreg_mig_tolerance:
+ * Register a migration tolerance wrt one given cpreg identified by its
+ * @kvmidx. Only one tolerance can be registered by kvm reg idx.
+ */
+void arm_register_cpreg_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx,
+                                      uint64_t mask, uint64_t value,
+                                      ARMCPUCPREGMigToleranceType type);
+
+/**
+ * arm_cpu_cpreg_has_mig_tolerance:
+ * Check whether a tolerance of type @type exists for a given @kvmidx
+ */
+bool arm_cpu_cpreg_has_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx,
+                                     uint64_t vmstate_value, uint64_t local_value,
+                                     ARMCPUCPREGMigToleranceType type);
 /**
  * arm_rebuild_hflags:
  * Rebuild the cached TBFLAGS for arbitrary changed processor state.
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 7e3e84b4bbb..1c499d1b15c 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -181,6 +181,75 @@ void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
     QLIST_INSERT_HEAD(&cpu->el_change_hooks, entry, node);
 }
 
+void arm_register_cpreg_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx,
+                                      uint64_t mask, uint64_t value,
+                                      ARMCPUCPREGMigToleranceType type)
+{
+    ARMCPUCPREGMigTolerance *t, *entry;
+
+    /* make sure the kvmidx has not tolerance already registered */
+    QLIST_FOREACH(t, &cpu->cpreg_mig_tolerances, node) {
+        if (t->kvmidx == kvmidx) {
+            g_assert_not_reached();
+        }
+    }
+    entry = g_new0(ARMCPUCPREGMigTolerance, 1);
+
+    entry->kvmidx = kvmidx;
+    entry->mask = mask;
+    entry->value = value;
+    entry->type = type;
+
+    QLIST_INSERT_HEAD(&cpu->cpreg_mig_tolerances, entry, node);
+}
+
+bool arm_cpu_cpreg_has_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx,
+                                     uint64_t vmstate_value, uint64_t local_value,
+                                     ARMCPUCPREGMigToleranceType type)
+{
+    ARMCPUCPREGMigTolerance *t;
+    uint64_t diff, diff_outside_mask, field;
+    bool found = false;
+
+    QLIST_FOREACH(t, &cpu->cpreg_mig_tolerances, node) {
+        if (t->kvmidx == kvmidx)  {
+            found = true;
+            break;
+        }
+    }
+    if (!found) {
+        return false;
+    }
+
+    /* we found one tolerance associated to the @kvmidx */
+
+    if (type == ToleranceNotOnBothEnds) {
+        return true;
+    }
+
+    /* Need to check mask */
+    diff = vmstate_value ^ local_value;
+    diff_outside_mask = diff & ~t->mask;
+
+    if (diff_outside_mask) {
+        /* there are differences outside of the mask */
+        return false;
+    }
+    if (type == ToleranceDiffInMask) {
+        /* differences only in the field, tolerance granted */
+        return true;
+    }
+    /* need to compare field value against authorized ones */
+    field = vmstate_value & t->mask;
+    if (type == ToleranceFieldLT && (field < t->value)) {
+        return true;
+    }
+    if (type == ToleranceFieldGT && (field > t->value)) {
+        return true;
+    }
+    return false;
+}
+
 static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
 {
     /* Reset a single ARMCPRegInfo register */
@@ -1106,6 +1175,7 @@ static void arm_cpu_initfn(Object *obj)
 
     QLIST_INIT(&cpu->pre_el_change_hooks);
     QLIST_INIT(&cpu->el_change_hooks);
+    QLIST_INIT(&cpu->cpreg_mig_tolerances);
 
 #ifdef CONFIG_USER_ONLY
 # ifdef TARGET_AARCH64
@@ -1550,6 +1620,7 @@ static void arm_cpu_finalizefn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
     ARMELChangeHook *hook, *next;
+    ARMCPUCPREGMigTolerance *t, *n;
 
     g_hash_table_destroy(cpu->cp_regs);
 
@@ -1561,6 +1632,10 @@ static void arm_cpu_finalizefn(Object *obj)
         QLIST_REMOVE(hook, node);
         g_free(hook);
     }
+    QLIST_FOREACH_SAFE(t, &cpu->cpreg_mig_tolerances, node, n) {
+        QLIST_REMOVE(t, node);
+        g_free(t);
+    }
 #ifndef CONFIG_USER_ONLY
     if (cpu->pmu_timer) {
         timer_free(cpu->pmu_timer);
-- 
2.53.0
Re: [PATCH v8 1/6] target/arm/cpu: Introduce the infrastructure for cpreg migration tolerances
Posted by Sebastian Ott 1 month ago
On Wed, 4 Mar 2026, Eric Auger wrote:
> We introduce a datatype for a tolerance with respect to a given
> cpreg migration issue. The tolerance applies to a given cpreg kvm index,
> and can be of different types:
> - ToleranceNotOnBothEnds (cpreg index is allowed to be only on one end)
                                                              ^
                                                        available/present?

> - ToleranceDiffInMask (value differences are allowed only within a mask)
> - ToleranceFieldLT (incoming field value must be less than a given value)
> - ToleranceFieldGT (incoming field value must be greater than a given value)
>
> A QLIST of such tolerances can be populated using a new helper:
> arm_register_cpreg_mig_tolerance() and arm_cpu_cpreg_has_mig_tolerance()
> allows to check whether a tolerance exists for a given kvm index.
>
> callers for those helpers will be introduced in subsequent patches.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> ---
> target/arm/cpu.h | 32 +++++++++++++++++++++
> target/arm/cpu.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 107 insertions(+)
>
> diff --git a/target/arm/cpu.h b/target/arm/cpu.h
> index 657ff4ab20b..9dcc838f611 100644
> --- a/target/arm/cpu.h
> +++ b/target/arm/cpu.h
> @@ -843,6 +843,21 @@ struct ARMELChangeHook {
>     QLIST_ENTRY(ARMELChangeHook) node;
> };
>
> +typedef enum {
> +    ToleranceNotOnBothEnds,
> +    ToleranceDiffInMask,
> +    ToleranceFieldLT,
> +    ToleranceFieldGT,
> +} ARMCPUCPREGMigToleranceType;
> +
> +typedef struct ARMCPUCPREGMigTolerance {
> +    uint64_t kvmidx;
> +    uint64_t mask;
> +    uint64_t value;
> +    ARMCPUCPREGMigToleranceType type;
> +    QLIST_ENTRY(ARMCPUCPREGMigTolerance) node;
> +} ARMCPUCPREGMigTolerance;
> +
> /* These values map onto the return values for
>  * QEMU_PSCI_0_2_FN_AFFINITY_INFO */
> typedef enum ARMPSCIState {
> @@ -1139,6 +1154,7 @@ struct ArchCPU {
>
>     QLIST_HEAD(, ARMELChangeHook) pre_el_change_hooks;
>     QLIST_HEAD(, ARMELChangeHook) el_change_hooks;
> +    QLIST_HEAD(, ARMCPUCPREGMigTolerance) cpreg_mig_tolerances;
>
>     int32_t node_id; /* NUMA node this CPU belongs to */
>
> @@ -2632,6 +2648,22 @@ void arm_register_pre_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
> void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook, void
>         *opaque);
>
> +/**
> + * arm_register_cpreg_mig_tolerance:
> + * Register a migration tolerance wrt one given cpreg identified by its
> + * @kvmidx. Only one tolerance can be registered by kvm reg idx.
> + */
> +void arm_register_cpreg_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx,
> +                                      uint64_t mask, uint64_t value,
> +                                      ARMCPUCPREGMigToleranceType type);
> +
> +/**
> + * arm_cpu_cpreg_has_mig_tolerance:
> + * Check whether a tolerance of type @type exists for a given @kvmidx
> + */

This function does more than the name and description suggests - it not
only checks if the tolerance exists but also if it applies..

arm_cpu_cpreg_mig_tolerated ?

> +bool arm_cpu_cpreg_has_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx,
> +                                     uint64_t vmstate_value, uint64_t local_value,
> +                                     ARMCPUCPREGMigToleranceType type);
> /**
>  * arm_rebuild_hflags:
>  * Rebuild the cached TBFLAGS for arbitrary changed processor state.
> diff --git a/target/arm/cpu.c b/target/arm/cpu.c
> index 7e3e84b4bbb..1c499d1b15c 100644
> --- a/target/arm/cpu.c
> +++ b/target/arm/cpu.c
> @@ -181,6 +181,75 @@ void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
>     QLIST_INSERT_HEAD(&cpu->el_change_hooks, entry, node);
> }
>
> +void arm_register_cpreg_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx,
> +                                      uint64_t mask, uint64_t value,
> +                                      ARMCPUCPREGMigToleranceType type)
> +{
> +    ARMCPUCPREGMigTolerance *t, *entry;
> +
> +    /* make sure the kvmidx has not tolerance already registered */
> +    QLIST_FOREACH(t, &cpu->cpreg_mig_tolerances, node) {
> +        if (t->kvmidx == kvmidx) {
> +            g_assert_not_reached();
> +        }
> +    }
> +    entry = g_new0(ARMCPUCPREGMigTolerance, 1);
> +
> +    entry->kvmidx = kvmidx;
> +    entry->mask = mask;
> +    entry->value = value;
> +    entry->type = type;
> +
> +    QLIST_INSERT_HEAD(&cpu->cpreg_mig_tolerances, entry, node);
> +}
> +
> +bool arm_cpu_cpreg_has_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx,
> +                                     uint64_t vmstate_value, uint64_t local_value,
> +                                     ARMCPUCPREGMigToleranceType type)
> +{
> +    ARMCPUCPREGMigTolerance *t;
> +    uint64_t diff, diff_outside_mask, field;
> +    bool found = false;
> +
> +    QLIST_FOREACH(t, &cpu->cpreg_mig_tolerances, node) {
> +        if (t->kvmidx == kvmidx)  {
> +            found = true;
> +            break;
> +        }
> +    }
> +    if (!found) {
> +        return false;
> +    }
> +
> +    /* we found one tolerance associated to the @kvmidx */
> +
> +    if (type == ToleranceNotOnBothEnds) {

This should use t->type and type can be removed as an argument.

> +        return true;
> +    }
> +
> +    /* Need to check mask */
> +    diff = vmstate_value ^ local_value;
> +    diff_outside_mask = diff & ~t->mask;
> +
> +    if (diff_outside_mask) {
> +        /* there are differences outside of the mask */
> +        return false;
> +    }
> +    if (type == ToleranceDiffInMask) {
> +        /* differences only in the field, tolerance granted */
> +        return true;
> +    }
> +    /* need to compare field value against authorized ones */
> +    field = vmstate_value & t->mask;
> +    if (type == ToleranceFieldLT && (field < t->value)) {
> +        return true;
> +    }
> +    if (type == ToleranceFieldGT && (field > t->value)) {
> +        return true;
> +    }

Ah, so this is only compared with a static value not with the local_value.
Would there be a need for a more sophisticated check than
ToleranceDiffInMask?

We could instead of having the type per ARMCPUCPREGMigTolerance register a
callback that makes the decision. The 4 types would be 4 pre-defined
callbacks and if a user needs something more sophisticated it can create
a custom callback.

But yea, that's just an idea - not sure if we'll ever need something like
this..

> +    return false;
> +}
> +
> static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
> {
>     /* Reset a single ARMCPRegInfo register */
> @@ -1106,6 +1175,7 @@ static void arm_cpu_initfn(Object *obj)
>
>     QLIST_INIT(&cpu->pre_el_change_hooks);
>     QLIST_INIT(&cpu->el_change_hooks);
> +    QLIST_INIT(&cpu->cpreg_mig_tolerances);
>
> #ifdef CONFIG_USER_ONLY
> # ifdef TARGET_AARCH64
> @@ -1550,6 +1620,7 @@ static void arm_cpu_finalizefn(Object *obj)
> {
>     ARMCPU *cpu = ARM_CPU(obj);
>     ARMELChangeHook *hook, *next;
> +    ARMCPUCPREGMigTolerance *t, *n;
>
>     g_hash_table_destroy(cpu->cp_regs);
>
> @@ -1561,6 +1632,10 @@ static void arm_cpu_finalizefn(Object *obj)
>         QLIST_REMOVE(hook, node);
>         g_free(hook);
>     }
> +    QLIST_FOREACH_SAFE(t, &cpu->cpreg_mig_tolerances, node, n) {
> +        QLIST_REMOVE(t, node);
> +        g_free(t);
> +    }
> #ifndef CONFIG_USER_ONLY
>     if (cpu->pmu_timer) {
>         timer_free(cpu->pmu_timer);
> -- 
> 2.53.0
>
>

Reviewed-by: Sebastian Ott <sebott@redhat.com>
Re: [PATCH v8 1/6] target/arm/cpu: Introduce the infrastructure for cpreg migration tolerances
Posted by Eric Auger 1 month ago
Hi Sebastian,

On 3/6/26 11:28 AM, Sebastian Ott wrote:
> On Wed, 4 Mar 2026, Eric Auger wrote:
>> We introduce a datatype for a tolerance with respect to a given
>> cpreg migration issue. The tolerance applies to a given cpreg kvm index,
>> and can be of different types:
>> - ToleranceNotOnBothEnds (cpreg index is allowed to be only on one end)
>                                                              ^
>                                                        available/present?
>
>> - ToleranceDiffInMask (value differences are allowed only within a mask)
>> - ToleranceFieldLT (incoming field value must be less than a given
>> value)
>> - ToleranceFieldGT (incoming field value must be greater than a given
>> value)
>>
>> A QLIST of such tolerances can be populated using a new helper:
>> arm_register_cpreg_mig_tolerance() and arm_cpu_cpreg_has_mig_tolerance()
>> allows to check whether a tolerance exists for a given kvm index.
>>
>> callers for those helpers will be introduced in subsequent patches.
>>
>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>> ---
>> target/arm/cpu.h | 32 +++++++++++++++++++++
>> target/arm/cpu.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 107 insertions(+)
>>
>> diff --git a/target/arm/cpu.h b/target/arm/cpu.h
>> index 657ff4ab20b..9dcc838f611 100644
>> --- a/target/arm/cpu.h
>> +++ b/target/arm/cpu.h
>> @@ -843,6 +843,21 @@ struct ARMELChangeHook {
>>     QLIST_ENTRY(ARMELChangeHook) node;
>> };
>>
>> +typedef enum {
>> +    ToleranceNotOnBothEnds,
>> +    ToleranceDiffInMask,
>> +    ToleranceFieldLT,
>> +    ToleranceFieldGT,
>> +} ARMCPUCPREGMigToleranceType;
>> +
>> +typedef struct ARMCPUCPREGMigTolerance {
>> +    uint64_t kvmidx;
>> +    uint64_t mask;
>> +    uint64_t value;
>> +    ARMCPUCPREGMigToleranceType type;
>> +    QLIST_ENTRY(ARMCPUCPREGMigTolerance) node;
>> +} ARMCPUCPREGMigTolerance;
>> +
>> /* These values map onto the return values for
>>  * QEMU_PSCI_0_2_FN_AFFINITY_INFO */
>> typedef enum ARMPSCIState {
>> @@ -1139,6 +1154,7 @@ struct ArchCPU {
>>
>>     QLIST_HEAD(, ARMELChangeHook) pre_el_change_hooks;
>>     QLIST_HEAD(, ARMELChangeHook) el_change_hooks;
>> +    QLIST_HEAD(, ARMCPUCPREGMigTolerance) cpreg_mig_tolerances;
>>
>>     int32_t node_id; /* NUMA node this CPU belongs to */
>>
>> @@ -2632,6 +2648,22 @@ void arm_register_pre_el_change_hook(ARMCPU
>> *cpu, ARMELChangeHookFn *hook,
>> void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn
>> *hook, void
>>         *opaque);
>>
>> +/**
>> + * arm_register_cpreg_mig_tolerance:
>> + * Register a migration tolerance wrt one given cpreg identified by its
>> + * @kvmidx. Only one tolerance can be registered by kvm reg idx.
>> + */
>> +void arm_register_cpreg_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx,
>> +                                      uint64_t mask, uint64_t value,
>> +                                      ARMCPUCPREGMigToleranceType
>> type);
>> +
>> +/**
>> + * arm_cpu_cpreg_has_mig_tolerance:
>> + * Check whether a tolerance of type @type exists for a given @kvmidx
>> + */
>
> This function does more than the name and description suggests - it not
> only checks if the tolerance exists but also if it applies..
>
> arm_cpu_cpreg_mig_tolerated ? 
Well it is supposed to really check a tolerance exists (and thus
applies), of a given type, for a given kvmidx.
But I admit the check of ->type versus type is missing below. 
>
>> +bool arm_cpu_cpreg_has_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx,
>> +                                     uint64_t vmstate_value,
>> uint64_t local_value,
>> +                                     ARMCPUCPREGMigToleranceType type);
>> /**
>>  * arm_rebuild_hflags:
>>  * Rebuild the cached TBFLAGS for arbitrary changed processor state.
>> diff --git a/target/arm/cpu.c b/target/arm/cpu.c
>> index 7e3e84b4bbb..1c499d1b15c 100644
>> --- a/target/arm/cpu.c
>> +++ b/target/arm/cpu.c
>> @@ -181,6 +181,75 @@ void arm_register_el_change_hook(ARMCPU *cpu,
>> ARMELChangeHookFn *hook,
>>     QLIST_INSERT_HEAD(&cpu->el_change_hooks, entry, node);
>> }
>>
>> +void arm_register_cpreg_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx,
>> +                                      uint64_t mask, uint64_t value,
>> +                                      ARMCPUCPREGMigToleranceType type)
>> +{
>> +    ARMCPUCPREGMigTolerance *t, *entry;
>> +
>> +    /* make sure the kvmidx has not tolerance already registered */
>> +    QLIST_FOREACH(t, &cpu->cpreg_mig_tolerances, node) {
>> +        if (t->kvmidx == kvmidx) {
>> +            g_assert_not_reached();
>> +        }
>> +    }
>> +    entry = g_new0(ARMCPUCPREGMigTolerance, 1);
>> +
>> +    entry->kvmidx = kvmidx;
>> +    entry->mask = mask;
>> +    entry->value = value;
>> +    entry->type = type;
>> +
>> +    QLIST_INSERT_HEAD(&cpu->cpreg_mig_tolerances, entry, node);
>> +}
>> +
>> +bool arm_cpu_cpreg_has_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx,
>> +                                     uint64_t vmstate_value,
>> uint64_t local_value,
>> +                                     ARMCPUCPREGMigToleranceType type)
>> +{
>> +    ARMCPUCPREGMigTolerance *t;
>> +    uint64_t diff, diff_outside_mask, field;
>> +    bool found = false;
>> +
>> +    QLIST_FOREACH(t, &cpu->cpreg_mig_tolerances, node) {
>> +        if (t->kvmidx == kvmidx)  {
>> +            found = true;
>> +            break;
>> +        }
>> +    }
>> +    if (!found) {
>> +        return false;
>> +    }
>> +
>> +    /* we found one tolerance associated to the @kvmidx */
>> +
>> +    if (type == ToleranceNotOnBothEnds) {
>
> This should use t->type and type can be removed as an argument. 
Actually if we found a tolerance registered for this regidx, I should
test the @type matches the registered tolerance once. This is missing.
>
>> +        return true;
>> +    }
>> +
>> +    /* Need to check mask */
>> +    diff = vmstate_value ^ local_value;
>> +    diff_outside_mask = diff & ~t->mask;
>> +
>> +    if (diff_outside_mask) {
>> +        /* there are differences outside of the mask */
>> +        return false;
>> +    }
>> +    if (type == ToleranceDiffInMask) {
>> +        /* differences only in the field, tolerance granted */
>> +        return true;
>> +    }
>> +    /* need to compare field value against authorized ones */
>> +    field = vmstate_value & t->mask;
>> +    if (type == ToleranceFieldLT && (field < t->value)) {
>> +        return true;
>> +    }
>> +    if (type == ToleranceFieldGT && (field > t->value)) {
>> +        return true;
>> +    }
>
> Ah, so this is only compared with a static value not with the
> local_value.
> Would there be a need for a more sophisticated check than
> ToleranceDiffInMask?
>
> We could instead of having the type per ARMCPUCPREGMigTolerance
> register a
> callback that makes the decision. The 4 types would be 4 pre-defined
> callbacks and if a user needs something more sophisticated it can create
> a custom callback. 
The goal is to tolerate some differences in a fields versus a given
static value. For instance if we know a field value was corrected in the
kernel.
This we have no example of such usage, it is a bit difficult to provide
a comprehensive infra. Maybe I should even remove that code until we get
the need.
>
> But yea, that's just an idea - not sure if we'll ever need something like
> this..
>
>> +    return false;
>> +}
>> +
>> static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
>> {
>>     /* Reset a single ARMCPRegInfo register */
>> @@ -1106,6 +1175,7 @@ static void arm_cpu_initfn(Object *obj)
>>
>>     QLIST_INIT(&cpu->pre_el_change_hooks);
>>     QLIST_INIT(&cpu->el_change_hooks);
>> +    QLIST_INIT(&cpu->cpreg_mig_tolerances);
>>
>> #ifdef CONFIG_USER_ONLY
>> # ifdef TARGET_AARCH64
>> @@ -1550,6 +1620,7 @@ static void arm_cpu_finalizefn(Object *obj)
>> {
>>     ARMCPU *cpu = ARM_CPU(obj);
>>     ARMELChangeHook *hook, *next;
>> +    ARMCPUCPREGMigTolerance *t, *n;
>>
>>     g_hash_table_destroy(cpu->cp_regs);
>>
>> @@ -1561,6 +1632,10 @@ static void arm_cpu_finalizefn(Object *obj)
>>         QLIST_REMOVE(hook, node);
>>         g_free(hook);
>>     }
>> +    QLIST_FOREACH_SAFE(t, &cpu->cpreg_mig_tolerances, node, n) {
>> +        QLIST_REMOVE(t, node);
>> +        g_free(t);
>> +    }
>> #ifndef CONFIG_USER_ONLY
>>     if (cpu->pmu_timer) {
>>         timer_free(cpu->pmu_timer);
>> -- 
>> 2.53.0
>>
>>
>
> Reviewed-by: Sebastian Ott <sebott@redhat.com>
>
Thank you for the review

Eric