[PATCH 3/3] KVM: arm64: Handle CCSIDR associativity mismatches

From: Akihiko Odaki
Date: Thu Dec 01 2022 - 05:51:22 EST


CCSIDR associativity mismatches among the physical CPUs causes a vCPU
see inconsistent values when it is migrated among physical CPUs.

It also makes QEMU fail restoring the vCPU registers because QEMU saves
and restores all of the registers including CCSIDRs, and if the vCPU
migrated among physical CPUs between saving and restoring, it tries to
restore CCSIDR values that mismatch with the current physical CPU, which
causes EFAULT.

Trap CCSIDRs if there are CCSIDR value msimatches, and override the
associativity bits when handling the trap.

Signed-off-by: Akihiko Odaki <akihiko.odaki@xxxxxxxxxx>
---
arch/arm64/include/asm/kvm_emulate.h | 1 +
arch/arm64/kvm/sys_regs.c | 7 ++++++-
2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index b45cf8903190..df2bab867e12 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -64,6 +64,7 @@ static __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
static inline bool vcpu_cache_overridden(struct kvm_vcpu *vcpu)
{
return cpus_have_const_cap(ARM64_MISMATCHED_CACHE_TYPE) ||
+ cpus_have_const_cap(ARM64_MISMATCHED_CACHE_ASSOCIATIVITY) ||
vcpu_el1_is_32bit(vcpu);
}

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 1f0cb015e81c..181a5b215a0e 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -110,8 +110,13 @@ static u32 get_ccsidr(struct kvm_vcpu *vcpu, u32 csselr)
* [If guests should attempt to infer aliasing properties from the
* geometry (which is not permitted by the architecture), they would
* only do so for virtually indexed caches.]
+ *
+ * This also makes sure the associativity bits of the CCSIDRs, including
+ * the ones of CCSIDRs for instruction caches, are overridden when the
+ * physical CPUs have a heterogeneous configuration so that a vCPU sees
+ * the consistent values if it is migrated among physical CPUs.
*/
- if (vcpu_cache_overridden(vcpu) && !(csselr & CSSELR_IN)) // data or unified cache
+ if (vcpu_cache_overridden(vcpu))
ccsidr &= ~CCSIDR_ASSOCIATIVITY_BITS_MASK;

return ccsidr;
--
2.38.1