One of the issues blocking the migration from KVM to TCG is that the former processor reads the coprocessors values directly from the underlying hardware. TCG however, for the way it emulates some registers, is not able to verify the incoming values, failing the migration.
Add a mask to the ARMCPRegInfo structure to exclude the bits not supported of the incoming registers values. In case of an outgoing migration, the unsupported data is retrieved from the cpreg_vmstate array. Signed-off-by: Alvise Rigo <a.r...@virtualopensystems.com> --- target-arm/cpu.h | 1 + target-arm/helper.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 0a7edfe..adcfa42 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -955,6 +955,7 @@ struct ARMCPRegInfo { * fieldoffset is 0 then no reset will be done. */ CPResetFn *resetfn; + uint64_t attr_mask; }; /* Macros which are lvalues for the field in CPUARMState for the diff --git a/target-arm/helper.c b/target-arm/helper.c index 2791dac..30973cc 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -166,6 +166,50 @@ static void write_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri, } } +static bool cpreg_find_vmstate_val(ARMCPU *cpu, uint64_t id, + const uint64_t *val) +{ + int i; + + for (i = 0; i < cpu->cpreg_vmstate_array_len; i++) { + if (cpu->cpreg_vmstate_indexes[i] == id) { + val = &cpu->cpreg_vmstate_values[i]; + return true; + } + } + + return false; +} + +static uint64_t read_incoming_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *ri, + uint64_t reg_id) +{ + CPUARMState *env = &cpu->env; + uint64_t val = read_raw_cp_reg(env, ri); + const uint64_t *inc_val = NULL; + + if (cpreg_find_vmstate_val(cpu, reg_id, inc_val) && ri->attr_mask) { + val &= ri->attr_mask; + val |= (*inc_val & ~ri->attr_mask); + } + + return val; +} + +static void write_incoming_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *v) +{ + if (ri->attr_mask) { + *v &= ri->attr_mask; + if (ri->type & ARM_CP_CONST) { + /* verify equality only of the supported values */ + *v |= ri->resetvalue & ~ri->attr_mask; + } + } + + write_raw_cp_reg(env, ri, *v); +} + bool write_cpustate_to_list(ARMCPU *cpu) { /* Write the coprocessor state from cpu->env to the (index,value) list. */ @@ -184,7 +228,8 @@ bool write_cpustate_to_list(ARMCPU *cpu) if (ri->type & ARM_CP_NO_MIGRATE) { continue; } - cpu->cpreg_values[i] = read_raw_cp_reg(&cpu->env, ri); + cpu->cpreg_values[i] = read_incoming_cp_reg(cpu, ri, + cpu->cpreg_indexes[i]); } return ok; } @@ -211,7 +256,7 @@ bool write_list_to_cpustate(ARMCPU *cpu) * (to catch read-only registers and partially read-only * registers where the incoming migration value doesn't match) */ - write_raw_cp_reg(&cpu->env, ri, v); + write_incoming_cp_reg(&cpu->env, ri, &v); if (read_raw_cp_reg(&cpu->env, ri) != v) { ok = false; } -- 1.8.3.2