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: Suzuki K Poulose <suzuki.poulose@arm.com> Reviewed-by: Alexandru Elisei <alexandru.elisei@arm.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
parent
3577dd37c7
commit
b130a8f70c
|
@ -670,7 +670,7 @@ static inline int kvm_arm_have_ssbd(void)
|
|||
void kvm_vcpu_load_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
|
||||
struct kvm *kvm_arch_alloc_vm(void);
|
||||
|
|
|
@ -703,6 +703,9 @@
|
|||
#define ID_AA64ZFR0_SVEVER_SVE2 0x1
|
||||
|
||||
/* 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_TGRAN64_SHIFT 24
|
||||
#define ID_AA64MMFR0_TGRAN16_SHIFT 20
|
||||
|
|
|
@ -267,6 +267,24 @@ static const struct arm64_ftr_bits ftr_id_aa64zfr0[] = {
|
|||
};
|
||||
|
||||
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
|
||||
* page size, so we can only detect mismatches for a page size other
|
||||
|
|
|
@ -337,14 +337,45 @@ u32 get_kvm_ipa_limit(void)
|
|||
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;
|
||||
|
||||
mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
|
||||
parange = cpuid_feature_extract_unsigned_field(mmfr0,
|
||||
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);
|
||||
|
||||
/* Clamp the IPA limit to the PA size supported by the kernel */
|
||||
|
@ -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 = ipa_max;
|
||||
kvm_info("IPA Size Limit: %dbits\n", kvm_ipa_limit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1387,9 +1387,7 @@ static inline void hyp_cpu_pm_exit(void)
|
|||
|
||||
static int init_common_resources(void)
|
||||
{
|
||||
kvm_set_ipa_limit();
|
||||
|
||||
return 0;
|
||||
return kvm_set_ipa_limit();
|
||||
}
|
||||
|
||||
static int init_subsystems(void)
|
||||
|
|
Loading…
Reference in New Issue