arm64: cpufeature: Add CPU capability for AArch32 EL1 support
authorWill Deacon <will@kernel.org>
Tue, 21 Apr 2020 14:29:17 +0000 (15:29 +0100)
committerWill Deacon <will@kernel.org>
Tue, 28 Apr 2020 13:23:23 +0000 (14:23 +0100)
Although we emit a "SANITY CHECK" warning and taint the kernel if we
detect a CPU mismatch for AArch32 support at EL1, we still online the
CPU with disastrous consequences for any running 32-bit VMs.

Introduce a capability for AArch32 support at EL1 so that late onlining
of incompatible CPUs is forbidden.

Tested-by: Sai Prakash Ranjan <saiprakash.ranjan@codeaurora.org>
Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Acked-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20200421142922.18950-4-will@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
arch/arm64/include/asm/cpucaps.h
arch/arm64/include/asm/sysreg.h
arch/arm64/kernel/cpufeature.c
arch/arm64/kvm/reset.c

index 8eb5a08..c54c674 100644 (file)
@@ -61,7 +61,8 @@
 #define ARM64_HAS_AMU_EXTN                     51
 #define ARM64_HAS_ADDRESS_AUTH                 52
 #define ARM64_HAS_GENERIC_AUTH                 53
+#define ARM64_HAS_32BIT_EL1                    54
 
-#define ARM64_NCAPS                            54
+#define ARM64_NCAPS                            55
 
 #endif /* __ASM_CPUCAPS_H */
index d718197..c4e896b 100644 (file)
 #define ID_AA64PFR0_ASIMD_NI           0xf
 #define ID_AA64PFR0_ASIMD_SUPPORTED    0x0
 #define ID_AA64PFR0_EL1_64BIT_ONLY     0x1
+#define ID_AA64PFR0_EL1_32BIT_64BIT    0x2
 #define ID_AA64PFR0_EL0_64BIT_ONLY     0x1
 #define ID_AA64PFR0_EL0_32BIT_64BIT    0x2
 
index b143f8b..838fe5c 100644 (file)
@@ -1535,6 +1535,18 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .field_pos = ID_AA64PFR0_EL0_SHIFT,
                .min_field_value = ID_AA64PFR0_EL0_32BIT_64BIT,
        },
+#ifdef CONFIG_KVM
+       {
+               .desc = "32-bit EL1 Support",
+               .capability = ARM64_HAS_32BIT_EL1,
+               .type = ARM64_CPUCAP_SYSTEM_FEATURE,
+               .matches = has_cpuid_feature,
+               .sys_reg = SYS_ID_AA64PFR0_EL1,
+               .sign = FTR_UNSIGNED,
+               .field_pos = ID_AA64PFR0_EL1_SHIFT,
+               .min_field_value = ID_AA64PFR0_EL1_32BIT_64BIT,
+       },
+#endif
        {
                .desc = "Kernel page table isolation (KPTI)",
                .capability = ARM64_UNMAP_KERNEL_AT_EL0,
index 30b7ea6..102e5c4 100644 (file)
@@ -46,14 +46,6 @@ static const struct kvm_regs default_regs_reset32 = {
                        PSR_AA32_I_BIT | PSR_AA32_F_BIT),
 };
 
-static bool cpu_has_32bit_el1(void)
-{
-       u64 pfr0;
-
-       pfr0 = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
-       return !!(pfr0 & 0x20);
-}
-
 /**
  * kvm_arch_vm_ioctl_check_extension
  *
@@ -66,7 +58,7 @@ int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 
        switch (ext) {
        case KVM_CAP_ARM_EL1_32BIT:
-               r = cpu_has_32bit_el1();
+               r = cpus_have_const_cap(ARM64_HAS_32BIT_EL1);
                break;
        case KVM_CAP_GUEST_DEBUG_HW_BPS:
                r = get_num_brps();
@@ -288,7 +280,7 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
        switch (vcpu->arch.target) {
        default:
                if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features)) {
-                       if (!cpu_has_32bit_el1())
+                       if (!cpus_have_const_cap(ARM64_HAS_32BIT_EL1))
                                goto out;
                        cpu_reset = &default_regs_reset32;
                } else {