[PATCH] arm64: mm: Align PGDs to at least 64 bytes

Ard Biesheuvel ardb at kernel.org
Wed Nov 23 23:42:09 PST 2022


On Thu, 24 Nov 2022 at 05:34, Anshuman Khandual
<anshuman.khandual at arm.com> wrote:
>
>
>
> On 11/22/22 22:26, Ard Biesheuvel wrote:
> > My copy of the ARM ARM (DDI 0487G.a) no longer describes the 64 byte
> > minimum alignment of root page tables as being conditional on whether
> > 52-bit physical addressing is supported and enabled, even though I seem
> > to remember that this was the case formerly (and our code suggests the
> > same).
> ARM ARM (DDI 0487G.a) says,
>
> "The minimum alignment of a translation table containing fewer than eight
> entries is 64 bytes." But that does not seem to be conditional on 52-bit
> physical address support, unless only the 52 bit physical address space
> support could produce table configurations, which will have fewer than 8
> entries in the PGD level.
>

The architecture permits you to dimension the top level table freely,
so this could happen with smaller PA sizes too.

> >
> > So align pgd_t[] allocations to 64 bytes. Note that this only affects
> > 16k/4 levels configurations, which are unlikely to be in wide use.
>
> Instead of "16k/4 levels configurations", could we mention the in terms
> of [PG_SIZE/VA_BITS/PA_BITS] format which can be easily related with
> available config options.
>

"""
With 16k granule and 48 bits of VA space, the root level table is only
16 bytes in size (two entries), and so aligning to PGD_SIZE is
insufficient here.
"""

> >
> > Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
> > ---
> >  arch/arm64/mm/pgd.c | 13 +++----------
> >  1 file changed, 3 insertions(+), 10 deletions(-)
> >
> > diff --git a/arch/arm64/mm/pgd.c b/arch/arm64/mm/pgd.c
> > index 4a64089e5771c1e2..8f01a75c35caaa9a 100644
> > --- a/arch/arm64/mm/pgd.c
> > +++ b/arch/arm64/mm/pgd.c
> > @@ -40,17 +40,10 @@ void __init pgtable_cache_init(void)
> >       if (PGD_SIZE == PAGE_SIZE)
> >               return;
> >
> > -#ifdef CONFIG_ARM64_PA_BITS_52
> >       /*
> > -      * With 52-bit physical addresses, the architecture requires the
> > -      * top-level table to be aligned to at least 64 bytes.
> > +      * Naturally aligned pgds required by the architecture, with a minimum
> > +      * alignment of 64 bytes.
> >        */
> > -     BUILD_BUG_ON(PGD_SIZE < 64);
> > -#endif
> > -
> > -     /*
> > -      * Naturally aligned pgds required by the architecture.
> > -      */
> > -     pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, PGD_SIZE,
> > +     pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, max(PGD_SIZE, 64),
> >                                     SLAB_PANIC, NULL);
>
> There is a build warning as follows, which can be fixed with typecasting
> constant 64 with (size_t). While here, it would also make sense to define
> a macro for PGD minimum alignment requirement i.e 64 bytes.
>

Hmm, I didn't spot this.

Maybe something like

#define TTBR_MIN_ALIGN 64UL

in the pgtable-hwdef header should do the trick?

> diff --git a/arch/arm64/mm/pgd.c b/arch/arm64/mm/pgd.c
> index 8f01a75c35ca..8d4b28d9590f 100644
> --- a/arch/arm64/mm/pgd.c
> +++ b/arch/arm64/mm/pgd.c
> @@ -44,6 +44,6 @@ void __init pgtable_cache_init(void)
>          * Naturally aligned pgds required by the architecture, with a minimum
>          * alignment of 64 bytes.
>          */
> -       pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, max(PGD_SIZE, 64),
> +       pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, max(PGD_SIZE, (size_t) 64),
>                                       SLAB_PANIC, NULL);
>  }
>
> In file included from ./include/linux/kernel.h:26,
>                  from ./arch/arm64/include/asm/cpufeature.h:22,
>                  from ./arch/arm64/include/asm/ptrace.h:11,
>                  from ./arch/arm64/include/asm/irqflags.h:10,
>                  from ./include/linux/irqflags.h:16,
>                  from ./include/linux/spinlock.h:59,
>                  from ./include/linux/mmzone.h:8,
>                  from ./include/linux/gfp.h:7,
>                  from ./include/linux/mm.h:7,
>                  from arch/arm64/mm/pgd.c:9:
> arch/arm64/mm/pgd.c: In function ‘pgtable_cache_init’:
> ./include/linux/minmax.h:20:28: warning: comparison of distinct pointer types lacks a cast
>    20 |  (!!(sizeof((typeof(x) *)1 == (typeof(y) *)1)))
>       |                            ^~
> ./include/linux/minmax.h:26:4: note: in expansion of macro ‘__typecheck’
>    26 |   (__typecheck(x, y) && __no_side_effects(x, y))
>       |    ^~~~~~~~~~~
> ./include/linux/minmax.h:36:24: note: in expansion of macro ‘__safe_cmp’
>    36 |  __builtin_choose_expr(__safe_cmp(x, y), \
>       |                        ^~~~~~~~~~
> ./include/linux/minmax.h:52:19: note: in expansion of macro ‘__careful_cmp’
>    52 | #define max(x, y) __careful_cmp(x, y, >)
>       |                   ^~~~~~~~~~~~~
> arch/arm64/mm/pgd.c:47:55: note: in expansion of macro ‘max’
>    47 |  pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, max(PGD_SIZE, 64),
>
> >  }
>
> Besides, tested on config [16K|48VA|48PA] producing "CONFIG_PGTABLE_LEVELS=4"
> and with PGD_SIZE != PAGE_SIZE, which booted successfully.

Thanks!



More information about the linux-arm-kernel mailing list