From a0d7a9de807639fcfcbe1fe037cb8772d459a9cf Mon Sep 17 00:00:00 2001 From: Peng Liang Date: Wed, 9 Dec 2020 19:35:08 +0800 Subject: [PATCH] target/arm: Fix write redundant values to kvm After modifying the value of a ID register, we'd better to try to write it to KVM so that we can known the value is acceptable for KVM. Because it may modify the registers' values of KVM, it's not suitable for other registers. Signed-off-by: Peng Liang --- target/arm/helper.c | 73 ++++++++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 24 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index b262f5d6c5..bddd355fa0 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -252,6 +252,16 @@ static bool raw_accessors_invalid(const ARMCPRegInfo *ri) return true; } +static bool is_id_reg(const ARMCPRegInfo *ri) +{ + /* + * (Op0, Op1, CRn, CRm, Op2) of ID registers is (3, 0, 0, crm, op2), + * where 1<=crm<8, 0<=op2<8. + */ + return ri->opc0 == 3 && ri->opc1 == 0 && ri->crn == 0 && + ri->crm > 0 && ri->crm < 8; +} + bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync) { /* Write the coprocessor state from cpu->env to the (index,value) list. */ @@ -268,38 +278,53 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync) ok = false; continue; } - /* - * (Op0, Op1, CRn, CRm, Op2) of ID registers is (3, 0, 0, crm, op2), - * where 1<=crm<8, 0<=op2<8. Let's give ID registers a chance to - * synchronize to kvm. - */ - if ((ri->type & ARM_CP_NO_RAW) && !(kvm_sync && - ri->opc0 == 3 && ri->opc1 == 0 && ri->crn == 0 && ri->crm > 0)) { + if ((ri->type & ARM_CP_NO_RAW) && !(kvm_sync && is_id_reg(ri))) { continue; } newval = read_raw_cp_reg(&cpu->env, ri); if (kvm_sync) { - /* Only sync if we can sync to KVM successfully. */ - uint64_t oldval; - uint64_t kvmval; + if (is_id_reg(ri)) { + /* Only sync if we can sync to KVM successfully. */ + uint64_t oldval; + uint64_t kvmval; - if (kvm_arm_get_one_reg(cpu, cpu->cpreg_indexes[i], &oldval)) { - continue; - } - if (oldval == newval) { - continue; - } + if (kvm_arm_get_one_reg(cpu, cpu->cpreg_indexes[i], &oldval)) { + continue; + } + if (oldval == newval) { + continue; + } - if (kvm_arm_set_one_reg(cpu, cpu->cpreg_indexes[i], &newval)) { - continue; - } - if (kvm_arm_get_one_reg(cpu, cpu->cpreg_indexes[i], &kvmval) || - kvmval != newval) { - continue; - } + if (kvm_arm_set_one_reg(cpu, cpu->cpreg_indexes[i], &newval)) { + continue; + } + if (kvm_arm_get_one_reg(cpu, cpu->cpreg_indexes[i], &kvmval) || + kvmval != newval) { + continue; + } + + kvm_arm_set_one_reg(cpu, cpu->cpreg_indexes[i], &oldval); + } else { + /* + * Only sync if the previous list->cpustate sync succeeded. + * Rather than tracking the success/failure state for every + * item in the list, we just recheck "does the raw write we must + * have made in write_list_to_cpustate() read back OK" here. + */ + uint64_t oldval = cpu->cpreg_values[i]; + + if (oldval == newval) { + continue; + } - kvm_arm_set_one_reg(cpu, cpu->cpreg_indexes[i], &oldval); + write_raw_cp_reg(&cpu->env, ri, oldval); + if (read_raw_cp_reg(&cpu->env, ri) != oldval) { + continue; + } + + write_raw_cp_reg(&cpu->env, ri, newval); + } } cpu->cpreg_values[i] = newval; } -- Gitee