162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Kernel page table mapping
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2015 ARM Ltd.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#ifndef __ASM_KERNEL_PGTABLE_H
962306a36Sopenharmony_ci#define __ASM_KERNEL_PGTABLE_H
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <asm/boot.h>
1262306a36Sopenharmony_ci#include <asm/pgtable-hwdef.h>
1362306a36Sopenharmony_ci#include <asm/sparsemem.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/*
1662306a36Sopenharmony_ci * The linear mapping and the start of memory are both 2M aligned (per
1762306a36Sopenharmony_ci * the arm64 booting.txt requirements). Hence we can use section mapping
1862306a36Sopenharmony_ci * with 4K (section size = 2M) but not with 16K (section size = 32M) or
1962306a36Sopenharmony_ci * 64K (section size = 512M).
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/*
2362306a36Sopenharmony_ci * The idmap and swapper page tables need some space reserved in the kernel
2462306a36Sopenharmony_ci * image. Both require pgd, pud (4 levels only) and pmd tables to (section)
2562306a36Sopenharmony_ci * map the kernel. With the 64K page configuration, swapper and idmap need to
2662306a36Sopenharmony_ci * map to pte level. The swapper also maps the FDT (see __create_page_tables
2762306a36Sopenharmony_ci * for more information). Note that the number of ID map translation levels
2862306a36Sopenharmony_ci * could be increased on the fly if system RAM is out of reach for the default
2962306a36Sopenharmony_ci * VA range, so pages required to map highest possible PA are reserved in all
3062306a36Sopenharmony_ci * cases.
3162306a36Sopenharmony_ci */
3262306a36Sopenharmony_ci#ifdef CONFIG_ARM64_4K_PAGES
3362306a36Sopenharmony_ci#define SWAPPER_PGTABLE_LEVELS	(CONFIG_PGTABLE_LEVELS - 1)
3462306a36Sopenharmony_ci#else
3562306a36Sopenharmony_ci#define SWAPPER_PGTABLE_LEVELS	(CONFIG_PGTABLE_LEVELS)
3662306a36Sopenharmony_ci#endif
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/*
4062306a36Sopenharmony_ci * If KASLR is enabled, then an offset K is added to the kernel address
4162306a36Sopenharmony_ci * space. The bottom 21 bits of this offset are zero to guarantee 2MB
4262306a36Sopenharmony_ci * alignment for PA and VA.
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci * For each pagetable level of the swapper, we know that the shift will
4562306a36Sopenharmony_ci * be larger than 21 (for the 4KB granule case we use section maps thus
4662306a36Sopenharmony_ci * the smallest shift is actually 30) thus there is the possibility that
4762306a36Sopenharmony_ci * KASLR can increase the number of pagetable entries by 1, so we make
4862306a36Sopenharmony_ci * room for this extra entry.
4962306a36Sopenharmony_ci *
5062306a36Sopenharmony_ci * Note KASLR cannot increase the number of required entries for a level
5162306a36Sopenharmony_ci * by more than one because it increments both the virtual start and end
5262306a36Sopenharmony_ci * addresses equally (the extra entry comes from the case where the end
5362306a36Sopenharmony_ci * address is just pushed over a boundary and the start address isn't).
5462306a36Sopenharmony_ci */
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#ifdef CONFIG_RANDOMIZE_BASE
5762306a36Sopenharmony_ci#define EARLY_KASLR	(1)
5862306a36Sopenharmony_ci#else
5962306a36Sopenharmony_ci#define EARLY_KASLR	(0)
6062306a36Sopenharmony_ci#endif
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci#define SPAN_NR_ENTRIES(vstart, vend, shift) \
6362306a36Sopenharmony_ci	((((vend) - 1) >> (shift)) - ((vstart) >> (shift)) + 1)
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#define EARLY_ENTRIES(vstart, vend, shift, add) \
6662306a36Sopenharmony_ci	(SPAN_NR_ENTRIES(vstart, vend, shift) + (add))
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#define EARLY_PGDS(vstart, vend, add) (EARLY_ENTRIES(vstart, vend, PGDIR_SHIFT, add))
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci#if SWAPPER_PGTABLE_LEVELS > 3
7162306a36Sopenharmony_ci#define EARLY_PUDS(vstart, vend, add) (EARLY_ENTRIES(vstart, vend, PUD_SHIFT, add))
7262306a36Sopenharmony_ci#else
7362306a36Sopenharmony_ci#define EARLY_PUDS(vstart, vend, add) (0)
7462306a36Sopenharmony_ci#endif
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#if SWAPPER_PGTABLE_LEVELS > 2
7762306a36Sopenharmony_ci#define EARLY_PMDS(vstart, vend, add) (EARLY_ENTRIES(vstart, vend, SWAPPER_TABLE_SHIFT, add))
7862306a36Sopenharmony_ci#else
7962306a36Sopenharmony_ci#define EARLY_PMDS(vstart, vend, add) (0)
8062306a36Sopenharmony_ci#endif
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci#define EARLY_PAGES(vstart, vend, add) ( 1 			/* PGDIR page */				\
8362306a36Sopenharmony_ci			+ EARLY_PGDS((vstart), (vend), add) 	/* each PGDIR needs a next level page table */	\
8462306a36Sopenharmony_ci			+ EARLY_PUDS((vstart), (vend), add)	/* each PUD needs a next level page table */	\
8562306a36Sopenharmony_ci			+ EARLY_PMDS((vstart), (vend), add))	/* each PMD needs a next level page table */
8662306a36Sopenharmony_ci#define INIT_DIR_SIZE (PAGE_SIZE * EARLY_PAGES(KIMAGE_VADDR, _end, EARLY_KASLR))
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/* the initial ID map may need two extra pages if it needs to be extended */
8962306a36Sopenharmony_ci#if VA_BITS < 48
9062306a36Sopenharmony_ci#define INIT_IDMAP_DIR_SIZE	((INIT_IDMAP_DIR_PAGES + 2) * PAGE_SIZE)
9162306a36Sopenharmony_ci#else
9262306a36Sopenharmony_ci#define INIT_IDMAP_DIR_SIZE	(INIT_IDMAP_DIR_PAGES * PAGE_SIZE)
9362306a36Sopenharmony_ci#endif
9462306a36Sopenharmony_ci#define INIT_IDMAP_DIR_PAGES	EARLY_PAGES(KIMAGE_VADDR, _end + MAX_FDT_SIZE + SWAPPER_BLOCK_SIZE, 1)
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/* Initial memory map size */
9762306a36Sopenharmony_ci#ifdef CONFIG_ARM64_4K_PAGES
9862306a36Sopenharmony_ci#define SWAPPER_BLOCK_SHIFT	PMD_SHIFT
9962306a36Sopenharmony_ci#define SWAPPER_BLOCK_SIZE	PMD_SIZE
10062306a36Sopenharmony_ci#define SWAPPER_TABLE_SHIFT	PUD_SHIFT
10162306a36Sopenharmony_ci#else
10262306a36Sopenharmony_ci#define SWAPPER_BLOCK_SHIFT	PAGE_SHIFT
10362306a36Sopenharmony_ci#define SWAPPER_BLOCK_SIZE	PAGE_SIZE
10462306a36Sopenharmony_ci#define SWAPPER_TABLE_SHIFT	PMD_SHIFT
10562306a36Sopenharmony_ci#endif
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci/*
10862306a36Sopenharmony_ci * Initial memory map attributes.
10962306a36Sopenharmony_ci */
11062306a36Sopenharmony_ci#define SWAPPER_PTE_FLAGS	(PTE_TYPE_PAGE | PTE_AF | PTE_SHARED | PTE_UXN)
11162306a36Sopenharmony_ci#define SWAPPER_PMD_FLAGS	(PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S | PTE_UXN)
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci#ifdef CONFIG_ARM64_4K_PAGES
11462306a36Sopenharmony_ci#define SWAPPER_RW_MMUFLAGS	(PMD_ATTRINDX(MT_NORMAL) | SWAPPER_PMD_FLAGS | PTE_WRITE)
11562306a36Sopenharmony_ci#define SWAPPER_RX_MMUFLAGS	(SWAPPER_RW_MMUFLAGS | PMD_SECT_RDONLY)
11662306a36Sopenharmony_ci#else
11762306a36Sopenharmony_ci#define SWAPPER_RW_MMUFLAGS	(PTE_ATTRINDX(MT_NORMAL) | SWAPPER_PTE_FLAGS | PTE_WRITE)
11862306a36Sopenharmony_ci#define SWAPPER_RX_MMUFLAGS	(SWAPPER_RW_MMUFLAGS | PTE_RDONLY)
11962306a36Sopenharmony_ci#endif
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci#endif	/* __ASM_KERNEL_PGTABLE_H */
122