]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: arm64: Copy guest CTR_EL0 into hyp VM
authorOliver Upton <oliver.upton@linux.dev>
Wed, 5 Mar 2025 23:08:23 +0000 (15:08 -0800)
committerOliver Upton <oliver.upton@linux.dev>
Thu, 6 Mar 2025 00:55:41 +0000 (16:55 -0800)
Since commit 2843cae26644 ("KVM: arm64: Treat CTR_EL0 as a VM feature
ID register") KVM has allowed userspace to configure the VM-wide view of
CTR_EL0, falling back to trap-n-emulate if the value doesn't match
hardware. It appears that this has worked by chance in protected-mode
for some time, and on systems with FEAT_EVT protected-mode
unconditionally sets TID4 (i.e. TID2 traps sans CTR_EL0).

Forward the guest CTR_EL0 value through to the hyp VM and align the
TID2/TID4 configuration with the non-protected setup.

Fixes: 2843cae26644 ("KVM: arm64: Treat CTR_EL0 as a VM feature ID register")
Reviewed-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20250305230825.484091-2-oliver.upton@linux.dev
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
arch/arm64/kvm/hyp/nvhe/pkvm.c

index 3927fe52a3dde8f59ddb996d674dd252630613a3..96348abeb5c2e1bc4be51ce997b40ff85eb1f108 100644 (file)
@@ -46,7 +46,8 @@ static void pkvm_vcpu_reset_hcr(struct kvm_vcpu *vcpu)
                vcpu->arch.hcr_el2 |= HCR_FWB;
 
        if (cpus_have_final_cap(ARM64_HAS_EVT) &&
-           !cpus_have_final_cap(ARM64_MISMATCHED_CACHE_TYPE))
+           !cpus_have_final_cap(ARM64_MISMATCHED_CACHE_TYPE) &&
+           kvm_read_vm_id_reg(vcpu->kvm, SYS_CTR_EL0) == read_cpuid(CTR_EL0))
                vcpu->arch.hcr_el2 |= HCR_TID4;
        else
                vcpu->arch.hcr_el2 |= HCR_TID2;
@@ -315,6 +316,9 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
        unsigned long host_arch_flags = READ_ONCE(host_kvm->arch.flags);
        DECLARE_BITMAP(allowed_features, KVM_VCPU_MAX_FEATURES);
 
+       /* CTR_EL0 is always under host control, even for protected VMs. */
+       hyp_vm->kvm.arch.ctr_el0 = host_kvm->arch.ctr_el0;
+
        if (test_bit(KVM_ARCH_FLAG_MTE_ENABLED, &host_kvm->arch.flags))
                set_bit(KVM_ARCH_FLAG_MTE_ENABLED, &kvm->arch.flags);