[PATCH v2 09/12] KVM: arm64: Support up to 5 levels of translation in kvm_pgtable

Ryan Roberts ryan.roberts at arm.com
Mon Mar 6 12:02:17 PST 2023


On 06/03/2023 19:54, Ryan Roberts wrote:
> FEAT_LPA2 increases the maximum levels of translation from 4 to 5 for
> the 4KB page case, when IA is >48 bits. While we can still use 4 levels
> for stage2 translation in this case (due to stage2 allowing concatenated
> page tables for first level lookup), the same kvm_pgtable library is
> used for the hyp stage1 page tables and stage1 does not support
> concatenation.
> 
> Therefore, modify the library to support up to 5 levels. Previous
> patches already laid the groundwork for this by refactoring code to work
> in terms of KVM_PGTABLE_FIRST_LEVEL and KVM_PGTABLE_LAST_LEVEL. So we
> just need to change these macros.
> 
> The hardware sometimes encodes the new level differently from the
> others: One such place is when reading the level from the FSC field in
> the ESR_EL2 register. We never expect to see the lowest level (-1) here
> since the stage 2 page tables always use concatenated tables for first
> level lookup and therefore only use 4 levels of lookup. So we get away
> with just adding a comment to explain why we are not being careful about
> decoding level -1.
> 
> For stage2 VTCR_EL2.SL2 is introduced to encode the new start level.
> However, since we always use concatenated page tables for first level
> look up at stage2 (and therefore we will never need the new extra level)
> we never touch this new field.
> 
> Signed-off-by: Ryan Roberts <ryan.roberts at arm.com>
> ---
>  arch/arm64/include/asm/kvm_emulate.h | 10 ++++++++++
>  arch/arm64/include/asm/kvm_pgtable.h |  2 +-
>  arch/arm64/kvm/hyp/pgtable.c         | 10 ++++++++++
>  3 files changed, 21 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> index 26666a623fa8..542575aad159 100644
> --- a/arch/arm64/include/asm/kvm_emulate.h
> +++ b/arch/arm64/include/asm/kvm_emulate.h
> @@ -405,6 +405,16 @@ static __always_inline u8 kvm_vcpu_trap_get_fault_type(const struct kvm_vcpu *vc
>  
>  static __always_inline s8 kvm_vcpu_trap_get_fault_level(const struct kvm_vcpu *vcpu)
>  {
> +	/*
> +	 * Note: With the introduction of FEAT_LPA2 an extra level of
> +	 * translation (level -1) is added. This level (obviously) doesn't
> +	 * follow the previous convention of encoding the 4 levels in the 2 LSBs
> +	 * of the FSC so this function breaks if the fault is for level -1.
> +	 *
> +	 * However, stage2 tables always use concatenated tables for first level
> +	 * lookup and therefore it is guaranteed that the level will be between
> +	 * 0 and 3, and this function continues to work.
> +	 */
>  	return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_LEVEL;
>  }
>  
> diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
> index 8c7e65147777..a5d96592c658 100644
> --- a/arch/arm64/include/asm/kvm_pgtable.h
> +++ b/arch/arm64/include/asm/kvm_pgtable.h
> @@ -11,7 +11,7 @@
>  #include <linux/kvm_host.h>
>  #include <linux/types.h>
>  
> -#define KVM_PGTABLE_FIRST_LEVEL		0
> +#define KVM_PGTABLE_FIRST_LEVEL		-1
>  #define KVM_PGTABLE_LAST_LEVEL		3
>  
>  /*
> diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
> index 939eab245205..a09c17242da7 100644
> --- a/arch/arm64/kvm/hyp/pgtable.c
> +++ b/arch/arm64/kvm/hyp/pgtable.c
> @@ -612,6 +612,15 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
>  	lvls = stage2_pgtable_levels(phys_shift);
>  	if (lvls < 2)
>  		lvls = 2;
> +
> +	/*
> +	 * When LPA2 is enabled, the HW supports an extra level of translation
> +	 * (for 5 in total) when using 4K pages. It also introduces VTCR_EL2.SL2
> +	 * to as an addition to SL0 to enable encoding this extra start level.
> +	 * However, since we always use concatenated pages for the first level
> +	 * lookup, we will never need this extra level and therefore do not need
> +	 * to touch SL2.
> +	 */
>  	vtcr |= VTCR_EL2_LVLS_TO_SL0(lvls);
>  
>  #ifdef CONFIG_ARM64_HW_AFDBM
> @@ -1053,6 +1062,7 @@ struct stage2_attr_data {
>  	kvm_pte_t			attr_clr;
>  	kvm_pte_t			pte;
>  	s8				level;
> +	struct kvm_pgtable_mm_ops	*mm_ops;

Naturally, as soon as I sent this out, I noticed this, which clearly should not
be here. I suspect it's an artifact from rebasing. Sorry about that, please
ignore and I'll fix it in the next version.


>  };
>  
>  static int stage2_attr_walker(const struct kvm_pgtable_visit_ctx *ctx,




More information about the linux-arm-kernel mailing list