]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: arm64: Make all 32bit ID registers fully writable
authorMarc Zyngier <maz@kernel.org>
Thu, 30 Oct 2025 12:27:05 +0000 (12:27 +0000)
committerMarc Zyngier <maz@kernel.org>
Sat, 8 Nov 2025 11:17:28 +0000 (11:17 +0000)
32bit ID registers aren't getting much love these days, and are
often missed in updates. One of these updates broke restoring
a GICv2 guest on a GICv3 machine.

Instead of performing a piecemeal fix, just bite the bullet
and make all 32bit ID regs fully writable. KVM itself never
relies on them for anything, and if the VMM wants to mess up
the guest, so be it.

Fixes: 5cb57a1aff755 ("KVM: arm64: Zero ID_AA64PFR0_EL1.GIC when no GICv3 is presented to the guest")
Reported-by: Peter Maydell <peter.maydell@linaro.org>
Cc: stable@vger.kernel.org
Reviewed-by: Oliver Upton <oupton@kernel.org>
Link: https://patch.msgid.link/20251030122707.2033690-2-maz@kernel.org
Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/kvm/sys_regs.c

index e67eb39ddc11844f0bc4c862c1784f95f8a34676..ad82264c6cbe19b8c047936aa8c59ee0c9a8136b 100644 (file)
@@ -2595,19 +2595,23 @@ static bool bad_redir_trap(struct kvm_vcpu *vcpu,
        .val = 0,                               \
 }
 
-/* sys_reg_desc initialiser for known cpufeature ID registers */
-#define AA32_ID_SANITISED(name) {              \
-       ID_DESC(name),                          \
-       .visibility = aa32_id_visibility,       \
-       .val = 0,                               \
-}
-
 /* sys_reg_desc initialiser for writable ID registers */
 #define ID_WRITABLE(name, mask) {              \
        ID_DESC(name),                          \
        .val = mask,                            \
 }
 
+/*
+ * 32bit ID regs are fully writable when the guest is 32bit
+ * capable. Nothing in the KVM code should rely on 32bit features
+ * anyway, only 64bit, so let the VMM do its worse.
+ */
+#define AA32_ID_WRITABLE(name) {               \
+       ID_DESC(name),                          \
+       .visibility = aa32_id_visibility,       \
+       .val = GENMASK(31, 0),                  \
+}
+
 /* sys_reg_desc initialiser for cpufeature ID registers that need filtering */
 #define ID_FILTERED(sysreg, name, mask) {      \
        ID_DESC(sysreg),                                \
@@ -3128,40 +3132,39 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 
        /* AArch64 mappings of the AArch32 ID registers */
        /* CRm=1 */
-       AA32_ID_SANITISED(ID_PFR0_EL1),
-       AA32_ID_SANITISED(ID_PFR1_EL1),
+       AA32_ID_WRITABLE(ID_PFR0_EL1),
+       AA32_ID_WRITABLE(ID_PFR1_EL1),
        { SYS_DESC(SYS_ID_DFR0_EL1),
          .access = access_id_reg,
          .get_user = get_id_reg,
          .set_user = set_id_dfr0_el1,
          .visibility = aa32_id_visibility,
          .reset = read_sanitised_id_dfr0_el1,
-         .val = ID_DFR0_EL1_PerfMon_MASK |
-                ID_DFR0_EL1_CopDbg_MASK, },
+         .val = GENMASK(31, 0) },
        ID_HIDDEN(ID_AFR0_EL1),
-       AA32_ID_SANITISED(ID_MMFR0_EL1),
-       AA32_ID_SANITISED(ID_MMFR1_EL1),
-       AA32_ID_SANITISED(ID_MMFR2_EL1),
-       AA32_ID_SANITISED(ID_MMFR3_EL1),
+       AA32_ID_WRITABLE(ID_MMFR0_EL1),
+       AA32_ID_WRITABLE(ID_MMFR1_EL1),
+       AA32_ID_WRITABLE(ID_MMFR2_EL1),
+       AA32_ID_WRITABLE(ID_MMFR3_EL1),
 
        /* CRm=2 */
-       AA32_ID_SANITISED(ID_ISAR0_EL1),
-       AA32_ID_SANITISED(ID_ISAR1_EL1),
-       AA32_ID_SANITISED(ID_ISAR2_EL1),
-       AA32_ID_SANITISED(ID_ISAR3_EL1),
-       AA32_ID_SANITISED(ID_ISAR4_EL1),
-       AA32_ID_SANITISED(ID_ISAR5_EL1),
-       AA32_ID_SANITISED(ID_MMFR4_EL1),
-       AA32_ID_SANITISED(ID_ISAR6_EL1),
+       AA32_ID_WRITABLE(ID_ISAR0_EL1),
+       AA32_ID_WRITABLE(ID_ISAR1_EL1),
+       AA32_ID_WRITABLE(ID_ISAR2_EL1),
+       AA32_ID_WRITABLE(ID_ISAR3_EL1),
+       AA32_ID_WRITABLE(ID_ISAR4_EL1),
+       AA32_ID_WRITABLE(ID_ISAR5_EL1),
+       AA32_ID_WRITABLE(ID_MMFR4_EL1),
+       AA32_ID_WRITABLE(ID_ISAR6_EL1),
 
        /* CRm=3 */
-       AA32_ID_SANITISED(MVFR0_EL1),
-       AA32_ID_SANITISED(MVFR1_EL1),
-       AA32_ID_SANITISED(MVFR2_EL1),
+       AA32_ID_WRITABLE(MVFR0_EL1),
+       AA32_ID_WRITABLE(MVFR1_EL1),
+       AA32_ID_WRITABLE(MVFR2_EL1),
        ID_UNALLOCATED(3,3),
-       AA32_ID_SANITISED(ID_PFR2_EL1),
+       AA32_ID_WRITABLE(ID_PFR2_EL1),
        ID_HIDDEN(ID_DFR1_EL1),
-       AA32_ID_SANITISED(ID_MMFR5_EL1),
+       AA32_ID_WRITABLE(ID_MMFR5_EL1),
        ID_UNALLOCATED(3,7),
 
        /* AArch64 ID registers */