Commit b130a8f7 authored by Marc Zyngier's avatar Marc Zyngier Committed by Will Deacon

KVM: arm64: Check advertised Stage-2 page size capability

With ARMv8.5-GTG, the hardware (or more likely a hypervisor) can
advertise the supported Stage-2 page sizes.

Let's check this at boot time.
Reviewed-by: default avatarSuzuki K Poulose <suzuki.poulose@arm.com>
Reviewed-by: default avatarAlexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
Signed-off-by: default avatarWill Deacon <will@kernel.org>
parent 3577dd37
...@@ -670,7 +670,7 @@ static inline int kvm_arm_have_ssbd(void) ...@@ -670,7 +670,7 @@ static inline int kvm_arm_have_ssbd(void)
void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu); void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu);
void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu); void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu);
void kvm_set_ipa_limit(void); int kvm_set_ipa_limit(void);
#define __KVM_HAVE_ARCH_VM_ALLOC #define __KVM_HAVE_ARCH_VM_ALLOC
struct kvm *kvm_arch_alloc_vm(void); struct kvm *kvm_arch_alloc_vm(void);
......
...@@ -703,6 +703,9 @@ ...@@ -703,6 +703,9 @@
#define ID_AA64ZFR0_SVEVER_SVE2 0x1 #define ID_AA64ZFR0_SVEVER_SVE2 0x1
/* id_aa64mmfr0 */ /* id_aa64mmfr0 */
#define ID_AA64MMFR0_TGRAN4_2_SHIFT 40
#define ID_AA64MMFR0_TGRAN64_2_SHIFT 36
#define ID_AA64MMFR0_TGRAN16_2_SHIFT 32
#define ID_AA64MMFR0_TGRAN4_SHIFT 28 #define ID_AA64MMFR0_TGRAN4_SHIFT 28
#define ID_AA64MMFR0_TGRAN64_SHIFT 24 #define ID_AA64MMFR0_TGRAN64_SHIFT 24
#define ID_AA64MMFR0_TGRAN16_SHIFT 20 #define ID_AA64MMFR0_TGRAN16_SHIFT 20
......
...@@ -267,6 +267,24 @@ static const struct arm64_ftr_bits ftr_id_aa64zfr0[] = { ...@@ -267,6 +267,24 @@ static const struct arm64_ftr_bits ftr_id_aa64zfr0[] = {
}; };
static const struct arm64_ftr_bits ftr_id_aa64mmfr0[] = { static const struct arm64_ftr_bits ftr_id_aa64mmfr0[] = {
/*
* Page size not being supported at Stage-2 is not fatal. You
* just give up KVM if PAGE_SIZE isn't supported there. Go fix
* your favourite nesting hypervisor.
*
* There is a small corner case where the hypervisor explicitly
* advertises a given granule size at Stage-2 (value 2) on some
* vCPUs, and uses the fallback to Stage-1 (value 0) for other
* vCPUs. Although this is not forbidden by the architecture, it
* indicates that the hypervisor is being silly (or buggy).
*
* We make no effort to cope with this and pretend that if these
* fields are inconsistent across vCPUs, then it isn't worth
* trying to bring KVM up.
*/
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64MMFR0_TGRAN4_2_SHIFT, 4, 1),
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64MMFR0_TGRAN64_2_SHIFT, 4, 1),
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64MMFR0_TGRAN16_2_SHIFT, 4, 1),
/* /*
* We already refuse to boot CPUs that don't support our configured * We already refuse to boot CPUs that don't support our configured
* page size, so we can only detect mismatches for a page size other * page size, so we can only detect mismatches for a page size other
......
...@@ -337,14 +337,45 @@ u32 get_kvm_ipa_limit(void) ...@@ -337,14 +337,45 @@ u32 get_kvm_ipa_limit(void)
return kvm_ipa_limit; return kvm_ipa_limit;
} }
void kvm_set_ipa_limit(void) int kvm_set_ipa_limit(void)
{ {
unsigned int ipa_max, pa_max, va_max, parange; unsigned int ipa_max, pa_max, va_max, parange, tgran_2;
u64 mmfr0; u64 mmfr0;
mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1); mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
parange = cpuid_feature_extract_unsigned_field(mmfr0, parange = cpuid_feature_extract_unsigned_field(mmfr0,
ID_AA64MMFR0_PARANGE_SHIFT); ID_AA64MMFR0_PARANGE_SHIFT);
/*
* Check with ARMv8.5-GTG that our PAGE_SIZE is supported at
* Stage-2. If not, things will stop very quickly.
*/
switch (PAGE_SIZE) {
default:
case SZ_4K:
tgran_2 = ID_AA64MMFR0_TGRAN4_2_SHIFT;
break;
case SZ_16K:
tgran_2 = ID_AA64MMFR0_TGRAN16_2_SHIFT;
break;
case SZ_64K:
tgran_2 = ID_AA64MMFR0_TGRAN64_2_SHIFT;
break;
}
switch (cpuid_feature_extract_unsigned_field(mmfr0, tgran_2)) {
default:
case 1:
kvm_err("PAGE_SIZE not supported at Stage-2, giving up\n");
return -EINVAL;
case 0:
kvm_debug("PAGE_SIZE supported at Stage-2 (default)\n");
break;
case 2:
kvm_debug("PAGE_SIZE supported at Stage-2 (advertised)\n");
break;
}
pa_max = id_aa64mmfr0_parange_to_phys_shift(parange); pa_max = id_aa64mmfr0_parange_to_phys_shift(parange);
/* Clamp the IPA limit to the PA size supported by the kernel */ /* Clamp the IPA limit to the PA size supported by the kernel */
...@@ -378,6 +409,8 @@ void kvm_set_ipa_limit(void) ...@@ -378,6 +409,8 @@ void kvm_set_ipa_limit(void)
"KVM IPA limit (%d bit) is smaller than default size\n", ipa_max); "KVM IPA limit (%d bit) is smaller than default size\n", ipa_max);
kvm_ipa_limit = ipa_max; kvm_ipa_limit = ipa_max;
kvm_info("IPA Size Limit: %dbits\n", kvm_ipa_limit); kvm_info("IPA Size Limit: %dbits\n", kvm_ipa_limit);
return 0;
} }
/* /*
......
...@@ -1387,9 +1387,7 @@ static inline void hyp_cpu_pm_exit(void) ...@@ -1387,9 +1387,7 @@ static inline void hyp_cpu_pm_exit(void)
static int init_common_resources(void) static int init_common_resources(void)
{ {
kvm_set_ipa_limit(); return kvm_set_ipa_limit();
return 0;
} }
static int init_subsystems(void) static int init_subsystems(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment