[PATCH v4 35/61] arm64: pgtable: Decouple PGDIR size macros from PGD/PUD/PMD levels

Catalin Marinas catalin.marinas at arm.com
Thu Oct 19 09:34:33 PDT 2023


On Tue, Sep 12, 2023 at 02:16:25PM +0000, Ard Biesheuvel wrote:
> From: Ard Biesheuvel <ardb at kernel.org>
> 
> The mapping from PGD/PUD/PMD to levels and shifts is very confusing,
> given that, due to folding, the shifts may be equal for different
> levels, if the macros are even #define'd to begin with.
> 
> In a subsequent patch, we will modify the ID mapping code to decouple
> the number of levels from the kernel's view of how these types are
> folded, so prepare for this by reformulating the macros without the use
> of these types.
> 
> Instead, use SWAPPER_BLOCK_SHIFT as the base quantity, and derive it
> from either PAGE_SHIFT or PMD_SHIFT, which -if defined at all- are
> defined unambiguously for a given page size, regardless of the number of
> configured levels.
> 
> Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
> ---
>  arch/arm64/include/asm/kernel-pgtable.h | 65 ++++++--------------
>  1 file changed, 19 insertions(+), 46 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kernel-pgtable.h b/arch/arm64/include/asm/kernel-pgtable.h
> index 742a4b2778f7..5000f38ae0c6 100644
> --- a/arch/arm64/include/asm/kernel-pgtable.h
> +++ b/arch/arm64/include/asm/kernel-pgtable.h
> @@ -13,27 +13,22 @@
>  #include <asm/sparsemem.h>
>  
>  /*
> - * The linear mapping and the start of memory are both 2M aligned (per
> - * the arm64 booting.txt requirements). Hence we can use section mapping
> - * with 4K (section size = 2M) but not with 16K (section size = 32M) or
> - * 64K (section size = 512M).
> + * The physical and virtual addresses of the start of the kernel image are
> + * equal modulo 2 MiB (per the arm64 booting.txt requirements). Hence we can
> + * use section mapping with 4K (section size = 2M) but not with 16K (section
> + * size = 32M) or 64K (section size = 512M).
>   */
> -
> -/*
> - * The idmap and swapper page tables need some space reserved in the kernel
> - * image. Both require pgd, pud (4 levels only) and pmd tables to (section)
> - * map the kernel. With the 64K page configuration, swapper and idmap need to
> - * map to pte level. The swapper also maps the FDT (see __create_page_tables
> - * for more information). Note that the number of ID map translation levels
> - * could be increased on the fly if system RAM is out of reach for the default
> - * VA range, so pages required to map highest possible PA are reserved in all
> - * cases.
> - */
> -#ifdef CONFIG_ARM64_4K_PAGES
> -#define SWAPPER_PGTABLE_LEVELS	(CONFIG_PGTABLE_LEVELS - 1)
> +#if defined(PMD_SIZE) && PMD_SIZE <= MIN_KIMG_ALIGN

Nitpick: we always have PMD_SIZE defined, either directly in the arm64
headers if we have more than 2 levels or included from the generic
pgtable-nopmd.h. Otherwise the logic is fine.

> +#define SWAPPER_BLOCK_SHIFT	PMD_SHIFT
> +#define SWAPPER_SKIP_LEVEL	1
>  #else
> -#define SWAPPER_PGTABLE_LEVELS	(CONFIG_PGTABLE_LEVELS)
> +#define SWAPPER_BLOCK_SHIFT	PAGE_SHIFT
> +#define SWAPPER_SKIP_LEVEL	0
>  #endif
> +#define SWAPPER_BLOCK_SIZE	(UL(1) << SWAPPER_BLOCK_SHIFT)
> +#define SWAPPER_TABLE_SHIFT	(SWAPPER_BLOCK_SHIFT + PAGE_SHIFT - 3)
> +
> +#define SWAPPER_PGTABLE_LEVELS		(CONFIG_PGTABLE_LEVELS - SWAPPER_SKIP_LEVEL)

Do you use SWAPPER_SKIP_LEVEL anywhere else? If not we might as well
define SWAPPER_PGTABLE_LEVELS directly under the #if/#else blocks.

>  #define IDMAP_VA_BITS		48
>  #define IDMAP_LEVELS		ARM64_HW_PGTABLE_LEVELS(IDMAP_VA_BITS)
> @@ -53,24 +48,13 @@
>  #define EARLY_ENTRIES(vstart, vend, shift, add) \
>  	(SPAN_NR_ENTRIES(vstart, vend, shift) + (add))
>  
> -#define EARLY_PGDS(vstart, vend, add) (EARLY_ENTRIES(vstart, vend, PGDIR_SHIFT, add))
> -
> -#if SWAPPER_PGTABLE_LEVELS > 3
> -#define EARLY_PUDS(vstart, vend, add) (EARLY_ENTRIES(vstart, vend, PUD_SHIFT, add))
> -#else
> -#define EARLY_PUDS(vstart, vend, add) (0)
> -#endif
> +#define EARLY_LEVEL(l, vstart, vend, add)	\
> +	(SWAPPER_PGTABLE_LEVELS > l ? EARLY_ENTRIES(vstart, vend, SWAPPER_BLOCK_SHIFT + l * (PAGE_SHIFT - 3), add) : 0)

It took me a while to realise that this is 'l' and not '1' (I need
better glasses). Maybe if you respin, change this to 'lvl'.

-- 
Catalin



More information about the linux-arm-kernel mailing list