]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
arm64/kvm: Configure HYP TCR.PS/DS based on host stage1
authorArd Biesheuvel <ardb@kernel.org>
Thu, 12 Dec 2024 08:18:45 +0000 (09:18 +0100)
committerWill Deacon <will@kernel.org>
Thu, 19 Dec 2024 17:23:53 +0000 (17:23 +0000)
When the host stage1 is configured for LPA2, the value currently being
programmed into TCR_EL2.T0SZ may be invalid unless LPA2 is configured
at HYP as well.  This means kvm_lpa2_is_enabled() is not the right
condition to test when setting TCR_EL2.DS, as it will return false if
LPA2 is only available for stage 1 but not for stage 2.

Similary, programming TCR_EL2.PS based on a limited IPA range due to
lack of stage2 LPA2 support could potentially result in problems.

So use lpa2_is_enabled() instead, and set the PS field according to the
host's IPS, which is capped at 48 bits if LPA2 support is absent or
disabled. Whether or not we can make meaningful use of such a
configuration is a different question.

Cc: stable@vger.kernel.org
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Acked-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20241212081841.2168124-11-ardb+git@google.com
Signed-off-by: Will Deacon <will@kernel.org>
arch/arm64/kvm/arm.c

index a102c3aebdbc419fe94a0f973eb2b3f06f0ba698..7b2735ad32e91125ee64239e6c3458fc91b3f9d5 100644 (file)
@@ -1990,8 +1990,7 @@ static int kvm_init_vector_slots(void)
 static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits)
 {
        struct kvm_nvhe_init_params *params = per_cpu_ptr_nvhe_sym(kvm_init_params, cpu);
-       u64 mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
-       unsigned long tcr;
+       unsigned long tcr, ips;
 
        /*
         * Calculate the raw per-cpu offset without a translation from the
@@ -2005,6 +2004,7 @@ static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits)
        params->mair_el2 = read_sysreg(mair_el1);
 
        tcr = read_sysreg(tcr_el1);
+       ips = FIELD_GET(TCR_IPS_MASK, tcr);
        if (cpus_have_final_cap(ARM64_KVM_HVHE)) {
                tcr |= TCR_EPD1_MASK;
        } else {
@@ -2014,8 +2014,8 @@ static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits)
        tcr &= ~TCR_T0SZ_MASK;
        tcr |= TCR_T0SZ(hyp_va_bits);
        tcr &= ~TCR_EL2_PS_MASK;
-       tcr |= FIELD_PREP(TCR_EL2_PS_MASK, kvm_get_parange(mmfr0));
-       if (kvm_lpa2_is_enabled())
+       tcr |= FIELD_PREP(TCR_EL2_PS_MASK, ips);
+       if (lpa2_is_enabled())
                tcr |= TCR_EL2_DS;
        params->tcr_el2 = tcr;