Some fields should not be written back to KVM for various reasons:
 - ID_AA64PFR0_EL1.GIC / ID_PFR1_EL1.GIC are fabricated by KVM based on
   the gic-version property.
 - KVM does not allow writing 0 to ID_DFR0_EL1.CopDbg, which breaks
   booting an AArch64-only guest on a host that also supports AArch32.
 - ID_DFR0_EL1.PerfMon is populated by KVM even for AArch64-only guests
   but is not writable there.
 - MPIDR_EL1 is managed by KVM based on vCPU index.
 - Hold off writing back CLIDR_EL1 until we properly support exposing
   cache topology to a KVM guest.

Signed-off-by: Khushit Shah <[email protected]>
---
 target/arm/cpu-idregs.c |  6 ++++++
 target/arm/cpu-idregs.h |  2 ++
 target/arm/kvm.c        | 40 +++++++++++++++++++++++++++++++++++++++-
 3 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/target/arm/cpu-idregs.c b/target/arm/cpu-idregs.c
index d58b8ed063..1f7ebfe9bb 100644
--- a/target/arm/cpu-idregs.c
+++ b/target/arm/cpu-idregs.c
@@ -107,3 +107,9 @@ bool arm_field_is_writable(const ARM64SysRegField *field)
     return (arm64_id_regs[field->index].writable_mask & field_mask)
            == field_mask;
 }
+
+bool field_matches(const ARM64SysRegField *field, ARMIDRegisterIdx index,
+                   const char *name)
+{
+    return field->index == index && !strcmp(field->name, name);
+}
diff --git a/target/arm/cpu-idregs.h b/target/arm/cpu-idregs.h
index aab1a79db1..8ef3f9350e 100644
--- a/target/arm/cpu-idregs.h
+++ b/target/arm/cpu-idregs.h
@@ -35,4 +35,6 @@ extern ARM64SysReg arm64_id_regs[NUM_ID_IDX];
 
 uint64_t arm_get_field_mask(const ARM64SysRegField *field);
 bool arm_field_is_writable(const ARM64SysRegField *field);
+bool field_matches(const ARM64SysRegField *field, ARMIDRegisterIdx index,
+                   const char *name);
 #endif
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 2d94b3a884..70d9a07580 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1317,10 +1317,40 @@ bool kvm_arm_cpu_post_load(ARMCPU *cpu)
     return true;
 }
 
+static bool arm_field_skip_writeback_always(const ARM64SysRegField *field)
+{
+    /*
+     * GIC is controlled by the gic-version property and fabricated by KVM
+     * when the vGIC device is created, so a named CPU model must not touch
+     * it. KVM also rejects writing 0 to ID_DFR0_EL1.CopDbg, which breaks
+     * booting a model that lacks AArch32 support on a host that supports
+     * it. MPIDR_EL1 is managed by KVM based on vCPU index, skip writing it
+     * back. Similarly, skip writing back CLIDR_EL1 till we properly
+     * support exposing cache for KVM guest.
+     */
+    return field_matches(field, ID_AA64PFR0_EL1_IDX, "GIC")
+        || field_matches(field, ID_PFR1_EL1_IDX, "GIC")
+        || field_matches(field, ID_DFR0_EL1_IDX, "CopDbg")
+        || field->index == MPIDR_EL1_IDX
+        || field->index == CLIDR_EL1_IDX;
+}
+
+static bool
+arm_field_skip_writeback_if_not_writable(const ARM64SysRegField *field)
+{
+    /*
+     * KVM populates ID_DFR0_EL1.PerfMon even for AArch64-only guests but
+     * does not expose it as writable there, so skip it when it is not
+     * writable.
+     */
+    return field_matches(field, ID_DFR0_EL1_IDX, "PerfMon");
+}
+
 /*
  * Copy writable ID reg fields from isar.idregs[] into the KVM cpreg list,
  * so the subsequent write_list_to_kvmstate() pushes them to KVM.
- * Only writable fields are copied.
+ * Only writable fields are copied; fields that must not be written back
+ * (see arm_field_skip_writeback_*) are skipped.
  * Returns -1 if any vCPU's ID reg value differs from the host value and the
  * field is not writable.
  */
@@ -1357,6 +1387,14 @@ static int kvm_arm_write_idregs_to_cpreg_list(ARMCPU 
*cpu)
                 continue;
             }
 
+            if (arm_field_skip_writeback_always(field) ||
+                (!arm_field_is_writable(field) &&
+                 arm_field_skip_writeback_if_not_writable(field))) {
+                /* Never write this field back; keep KVM's value. */
+                writable_mask &= ~field_mask;
+                continue;
+            }
+
             if (!arm_field_is_writable(field)) {
                 error_report("%s.%s is not writable: host=0x%" PRIx64
                              ", requested=0x%" PRIx64,
-- 
2.52.0


Reply via email to