Message ID | 20230912141549.278777-98-ardb@google.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | arm64: Add support for LPA2 at stage1 and WXN | expand |
On Tue, Sep 12, 2023 at 02:16:25PM +0000, Ard Biesheuvel wrote: > From: Ard Biesheuvel <ardb@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@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'.
On Thu, Oct 19, 2023 at 05:34:33PM +0100, Catalin Marinas wrote: > On Tue, Sep 12, 2023 at 02:16:25PM +0000, Ard Biesheuvel wrote: > > 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. I pushed a patch removing this defined(PMD_SIZE) but it turns out that we include this file in assembly and while the generic PMD_SIZE is only defined if !defined(__ASSEMBLY__). Not sure the macro is used or just the linker complaining. I'll revert my patch temporarily on top of for-next/core and think about it tomorrow. I don't like that this #if check is only false because some other header bracketed it with #ifndef __ASSEMBLY__.
On Tue, 24 Oct 2023 at 19:58, Catalin Marinas <catalin.marinas@arm.com> wrote: > > On Thu, Oct 19, 2023 at 05:34:33PM +0100, Catalin Marinas wrote: > > On Tue, Sep 12, 2023 at 02:16:25PM +0000, Ard Biesheuvel wrote: > > > 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. > > I pushed a patch removing this defined(PMD_SIZE) but it turns out that > we include this file in assembly and while the generic PMD_SIZE is only > defined if !defined(__ASSEMBLY__). Not sure the macro is used or just > the linker complaining. > > I'll revert my patch temporarily on top of for-next/core and think about > it tomorrow. I don't like that this #if check is only false because some > other header bracketed it with #ifndef __ASSEMBLY__. > I don't remember exactly as it's been a while but I suppose this is why I added the check in the first place. I agree that having this conditional is not great, but it is fine for deciding whether to skip a level, given that we only do so when we have more than 2 levels of paging.
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 +#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) #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) -#if SWAPPER_PGTABLE_LEVELS > 2 -#define EARLY_PMDS(vstart, vend, add) (EARLY_ENTRIES(vstart, vend, SWAPPER_TABLE_SHIFT, add)) -#else -#define EARLY_PMDS(vstart, vend, add) (0) -#endif - -#define EARLY_PAGES(vstart, vend, add) ( 1 /* PGDIR page */ \ - + EARLY_PGDS((vstart), (vend), add) /* each PGDIR needs a next level page table */ \ - + EARLY_PUDS((vstart), (vend), add) /* each PUD needs a next level page table */ \ - + EARLY_PMDS((vstart), (vend), add)) /* each PMD needs a next level page table */ +#define EARLY_PAGES(vstart, vend, add) (1 /* PGDIR page */ \ + + EARLY_LEVEL(3, (vstart), (vend), add) /* each entry needs a next level page table */ \ + + EARLY_LEVEL(2, (vstart), (vend), add) /* each entry needs a next level page table */ \ + + EARLY_LEVEL(1, (vstart), (vend), add))/* each entry needs a next level page table */ #define INIT_DIR_SIZE (PAGE_SIZE * (EARLY_PAGES(KIMAGE_VADDR, _end, EXTRA_PAGE) + EARLY_SEGMENT_EXTRA_PAGES)) /* the initial ID map may need two extra pages if it needs to be extended */ @@ -81,17 +65,6 @@ #endif #define INIT_IDMAP_DIR_PAGES EARLY_PAGES(KIMAGE_VADDR, _end + MAX_FDT_SIZE + SWAPPER_BLOCK_SIZE, 1) -/* Initial memory map size */ -#ifdef CONFIG_ARM64_4K_PAGES -#define SWAPPER_BLOCK_SHIFT PMD_SHIFT -#define SWAPPER_BLOCK_SIZE PMD_SIZE -#define SWAPPER_TABLE_SHIFT PUD_SHIFT -#else -#define SWAPPER_BLOCK_SHIFT PAGE_SHIFT -#define SWAPPER_BLOCK_SIZE PAGE_SIZE -#define SWAPPER_TABLE_SHIFT PMD_SHIFT -#endif - /* The number of segments in the kernel image (text, rodata, inittext, initdata, data+bss) */ #define KERNEL_SEGMENT_COUNT 5