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

Anshuman Khandual anshuman.khandual at arm.com
Thu Nov 24 03:56:16 PST 2022



On 11/24/22 13:12, Ard Biesheuvel wrote:
> 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.

Okay.

> 
>>>
>>> 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.
> """

Sounds good.

> 
>>>
>>> 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?

Right, makes sense. Please add this macro.

> 
>> 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