119 lines
4.2 KiB
Diff
119 lines
4.2 KiB
Diff
|
|
From 479c384f2944f52f9199bffa191b587a3f02663c Mon Sep 17 00:00:00 2001
|
||
|
|
From: Peng Liang <liangpeng10@huawei.com>
|
||
|
|
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.
|
||
|
|
|
||
|
|
(cherry-picked from a0d7a9de807639fcfcbe1fe037cb8772d459a9cf)
|
||
|
|
Signed-off-by: Peng Liang <liangpeng10@huawei.com>
|
||
|
|
---
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
--
|
||
|
|
2.27.0
|
||
|
|
|