162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * arch/arm/include/asm/pgtable-3level.h 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2011 ARM Ltd. 662306a36Sopenharmony_ci * Author: Catalin Marinas <catalin.marinas@arm.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci#ifndef _ASM_PGTABLE_3LEVEL_H 962306a36Sopenharmony_ci#define _ASM_PGTABLE_3LEVEL_H 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci/* 1262306a36Sopenharmony_ci * With LPAE, there are 3 levels of page tables. Each level has 512 entries of 1362306a36Sopenharmony_ci * 8 bytes each, occupying a 4K page. The first level table covers a range of 1462306a36Sopenharmony_ci * 512GB, each entry representing 1GB. Since we are limited to 4GB input 1562306a36Sopenharmony_ci * address range, only 4 entries in the PGD are used. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * There are enough spare bits in a page table entry for the kernel specific 1862306a36Sopenharmony_ci * state. 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ci#define PTRS_PER_PTE 512 2162306a36Sopenharmony_ci#define PTRS_PER_PMD 512 2262306a36Sopenharmony_ci#define PTRS_PER_PGD 4 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define PTE_HWTABLE_PTRS (0) 2562306a36Sopenharmony_ci#define PTE_HWTABLE_OFF (0) 2662306a36Sopenharmony_ci#define PTE_HWTABLE_SIZE (PTRS_PER_PTE * sizeof(u64)) 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define MAX_POSSIBLE_PHYSMEM_BITS 40 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* 3162306a36Sopenharmony_ci * PGDIR_SHIFT determines the size a top-level page table entry can map. 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci#define PGDIR_SHIFT 30 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* 3662306a36Sopenharmony_ci * PMD_SHIFT determines the size a middle-level page table entry can map. 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ci#define PMD_SHIFT 21 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define PMD_SIZE (1UL << PMD_SHIFT) 4162306a36Sopenharmony_ci#define PMD_MASK (~((1 << PMD_SHIFT) - 1)) 4262306a36Sopenharmony_ci#define PGDIR_SIZE (1UL << PGDIR_SHIFT) 4362306a36Sopenharmony_ci#define PGDIR_MASK (~((1 << PGDIR_SHIFT) - 1)) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* 4662306a36Sopenharmony_ci * section address mask and size definitions. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ci#define SECTION_SHIFT 21 4962306a36Sopenharmony_ci#define SECTION_SIZE (1UL << SECTION_SHIFT) 5062306a36Sopenharmony_ci#define SECTION_MASK (~((1 << SECTION_SHIFT) - 1)) 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define USER_PTRS_PER_PGD (PAGE_OFFSET / PGDIR_SIZE) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* 5562306a36Sopenharmony_ci * Hugetlb definitions. 5662306a36Sopenharmony_ci */ 5762306a36Sopenharmony_ci#define HPAGE_SHIFT PMD_SHIFT 5862306a36Sopenharmony_ci#define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT) 5962306a36Sopenharmony_ci#define HPAGE_MASK (~(HPAGE_SIZE - 1)) 6062306a36Sopenharmony_ci#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* 6362306a36Sopenharmony_ci * "Linux" PTE definitions for LPAE. 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * These bits overlap with the hardware bits but the naming is preserved for 6662306a36Sopenharmony_ci * consistency with the classic page table format. 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_ci#define L_PTE_VALID (_AT(pteval_t, 1) << 0) /* Valid */ 6962306a36Sopenharmony_ci#define L_PTE_PRESENT (_AT(pteval_t, 3) << 0) /* Present */ 7062306a36Sopenharmony_ci#define L_PTE_USER (_AT(pteval_t, 1) << 6) /* AP[1] */ 7162306a36Sopenharmony_ci#define L_PTE_SHARED (_AT(pteval_t, 3) << 8) /* SH[1:0], inner shareable */ 7262306a36Sopenharmony_ci#define L_PTE_YOUNG (_AT(pteval_t, 1) << 10) /* AF */ 7362306a36Sopenharmony_ci#define L_PTE_XN (_AT(pteval_t, 1) << 54) /* XN */ 7462306a36Sopenharmony_ci#define L_PTE_DIRTY (_AT(pteval_t, 1) << 55) 7562306a36Sopenharmony_ci#define L_PTE_SPECIAL (_AT(pteval_t, 1) << 56) 7662306a36Sopenharmony_ci#define L_PTE_NONE (_AT(pteval_t, 1) << 57) /* PROT_NONE */ 7762306a36Sopenharmony_ci#define L_PTE_RDONLY (_AT(pteval_t, 1) << 58) /* READ ONLY */ 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/* We borrow bit 7 to store the exclusive marker in swap PTEs. */ 8062306a36Sopenharmony_ci#define L_PTE_SWP_EXCLUSIVE (_AT(pteval_t, 1) << 7) 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci#define L_PMD_SECT_VALID (_AT(pmdval_t, 1) << 0) 8362306a36Sopenharmony_ci#define L_PMD_SECT_DIRTY (_AT(pmdval_t, 1) << 55) 8462306a36Sopenharmony_ci#define L_PMD_SECT_NONE (_AT(pmdval_t, 1) << 57) 8562306a36Sopenharmony_ci#define L_PMD_SECT_RDONLY (_AT(pteval_t, 1) << 58) 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/* 8862306a36Sopenharmony_ci * To be used in assembly code with the upper page attributes. 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci#define L_PTE_XN_HIGH (1 << (54 - 32)) 9162306a36Sopenharmony_ci#define L_PTE_DIRTY_HIGH (1 << (55 - 32)) 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/* 9462306a36Sopenharmony_ci * AttrIndx[2:0] encoding (mapping attributes defined in the MAIR* registers). 9562306a36Sopenharmony_ci */ 9662306a36Sopenharmony_ci#define L_PTE_MT_UNCACHED (_AT(pteval_t, 0) << 2) /* strongly ordered */ 9762306a36Sopenharmony_ci#define L_PTE_MT_BUFFERABLE (_AT(pteval_t, 1) << 2) /* normal non-cacheable */ 9862306a36Sopenharmony_ci#define L_PTE_MT_WRITETHROUGH (_AT(pteval_t, 2) << 2) /* normal inner write-through */ 9962306a36Sopenharmony_ci#define L_PTE_MT_WRITEBACK (_AT(pteval_t, 3) << 2) /* normal inner write-back */ 10062306a36Sopenharmony_ci#define L_PTE_MT_WRITEALLOC (_AT(pteval_t, 7) << 2) /* normal inner write-alloc */ 10162306a36Sopenharmony_ci#define L_PTE_MT_DEV_SHARED (_AT(pteval_t, 4) << 2) /* device */ 10262306a36Sopenharmony_ci#define L_PTE_MT_DEV_NONSHARED (_AT(pteval_t, 4) << 2) /* device */ 10362306a36Sopenharmony_ci#define L_PTE_MT_DEV_WC (_AT(pteval_t, 1) << 2) /* normal non-cacheable */ 10462306a36Sopenharmony_ci#define L_PTE_MT_DEV_CACHED (_AT(pteval_t, 3) << 2) /* normal inner write-back */ 10562306a36Sopenharmony_ci#define L_PTE_MT_MASK (_AT(pteval_t, 7) << 2) 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/* 10862306a36Sopenharmony_ci * Software PGD flags. 10962306a36Sopenharmony_ci */ 11062306a36Sopenharmony_ci#define L_PGD_SWAPPER (_AT(pgdval_t, 1) << 55) /* swapper_pg_dir entry */ 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci#ifndef __ASSEMBLY__ 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci#define pud_none(pud) (!pud_val(pud)) 11562306a36Sopenharmony_ci#define pud_bad(pud) (!(pud_val(pud) & 2)) 11662306a36Sopenharmony_ci#define pud_present(pud) (pud_val(pud)) 11762306a36Sopenharmony_ci#define pmd_table(pmd) ((pmd_val(pmd) & PMD_TYPE_MASK) == \ 11862306a36Sopenharmony_ci PMD_TYPE_TABLE) 11962306a36Sopenharmony_ci#define pmd_sect(pmd) ((pmd_val(pmd) & PMD_TYPE_MASK) == \ 12062306a36Sopenharmony_ci PMD_TYPE_SECT) 12162306a36Sopenharmony_ci#define pmd_large(pmd) pmd_sect(pmd) 12262306a36Sopenharmony_ci#define pmd_leaf(pmd) pmd_sect(pmd) 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci#define pud_clear(pudp) \ 12562306a36Sopenharmony_ci do { \ 12662306a36Sopenharmony_ci *pudp = __pud(0); \ 12762306a36Sopenharmony_ci clean_pmd_entry(pudp); \ 12862306a36Sopenharmony_ci } while (0) 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci#define set_pud(pudp, pud) \ 13162306a36Sopenharmony_ci do { \ 13262306a36Sopenharmony_ci *pudp = pud; \ 13362306a36Sopenharmony_ci flush_pmd_entry(pudp); \ 13462306a36Sopenharmony_ci } while (0) 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic inline pmd_t *pud_pgtable(pud_t pud) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci return __va(pud_val(pud) & PHYS_MASK & (s32)PAGE_MASK); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci#define pmd_bad(pmd) (!(pmd_val(pmd) & 2)) 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci#define copy_pmd(pmdpd,pmdps) \ 14462306a36Sopenharmony_ci do { \ 14562306a36Sopenharmony_ci *pmdpd = *pmdps; \ 14662306a36Sopenharmony_ci flush_pmd_entry(pmdpd); \ 14762306a36Sopenharmony_ci } while (0) 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci#define pmd_clear(pmdp) \ 15062306a36Sopenharmony_ci do { \ 15162306a36Sopenharmony_ci *pmdp = __pmd(0); \ 15262306a36Sopenharmony_ci clean_pmd_entry(pmdp); \ 15362306a36Sopenharmony_ci } while (0) 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/* 15662306a36Sopenharmony_ci * For 3 levels of paging the PTE_EXT_NG bit will be set for user address ptes 15762306a36Sopenharmony_ci * that are written to a page table but not for ptes created with mk_pte. 15862306a36Sopenharmony_ci * 15962306a36Sopenharmony_ci * In hugetlb_no_page, a new huge pte (new_pte) is generated and passed to 16062306a36Sopenharmony_ci * hugetlb_cow, where it is compared with an entry in a page table. 16162306a36Sopenharmony_ci * This comparison test fails erroneously leading ultimately to a memory leak. 16262306a36Sopenharmony_ci * 16362306a36Sopenharmony_ci * To correct this behaviour, we mask off PTE_EXT_NG for any pte that is 16462306a36Sopenharmony_ci * present before running the comparison. 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_ci#define __HAVE_ARCH_PTE_SAME 16762306a36Sopenharmony_ci#define pte_same(pte_a,pte_b) ((pte_present(pte_a) ? pte_val(pte_a) & ~PTE_EXT_NG \ 16862306a36Sopenharmony_ci : pte_val(pte_a)) \ 16962306a36Sopenharmony_ci == (pte_present(pte_b) ? pte_val(pte_b) & ~PTE_EXT_NG \ 17062306a36Sopenharmony_ci : pte_val(pte_b))) 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci#define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,__pte(pte_val(pte)|(ext))) 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci#define pte_huge(pte) (pte_val(pte) && !(pte_val(pte) & PTE_TABLE_BIT)) 17562306a36Sopenharmony_ci#define pte_mkhuge(pte) (__pte(pte_val(pte) & ~PTE_TABLE_BIT)) 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci#define pmd_isset(pmd, val) ((u32)(val) == (val) ? pmd_val(pmd) & (val) \ 17862306a36Sopenharmony_ci : !!(pmd_val(pmd) & (val))) 17962306a36Sopenharmony_ci#define pmd_isclear(pmd, val) (!(pmd_val(pmd) & (val))) 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci#define pmd_present(pmd) (pmd_isset((pmd), L_PMD_SECT_VALID)) 18262306a36Sopenharmony_ci#define pmd_young(pmd) (pmd_isset((pmd), PMD_SECT_AF)) 18362306a36Sopenharmony_ci#define pte_special(pte) (pte_isset((pte), L_PTE_SPECIAL)) 18462306a36Sopenharmony_cistatic inline pte_t pte_mkspecial(pte_t pte) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci pte_val(pte) |= L_PTE_SPECIAL; 18762306a36Sopenharmony_ci return pte; 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci#define pmd_write(pmd) (pmd_isclear((pmd), L_PMD_SECT_RDONLY)) 19162306a36Sopenharmony_ci#define pmd_dirty(pmd) (pmd_isset((pmd), L_PMD_SECT_DIRTY)) 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci#define pmd_hugewillfault(pmd) (!pmd_young(pmd) || !pmd_write(pmd)) 19462306a36Sopenharmony_ci#define pmd_thp_or_huge(pmd) (pmd_huge(pmd) || pmd_trans_huge(pmd)) 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE 19762306a36Sopenharmony_ci#define pmd_trans_huge(pmd) (pmd_val(pmd) && !pmd_table(pmd)) 19862306a36Sopenharmony_ci#endif 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci#define PMD_BIT_FUNC(fn,op) \ 20162306a36Sopenharmony_cistatic inline pmd_t pmd_##fn(pmd_t pmd) { pmd_val(pmd) op; return pmd; } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ciPMD_BIT_FUNC(wrprotect, |= L_PMD_SECT_RDONLY); 20462306a36Sopenharmony_ciPMD_BIT_FUNC(mkold, &= ~PMD_SECT_AF); 20562306a36Sopenharmony_ciPMD_BIT_FUNC(mkwrite_novma, &= ~L_PMD_SECT_RDONLY); 20662306a36Sopenharmony_ciPMD_BIT_FUNC(mkdirty, |= L_PMD_SECT_DIRTY); 20762306a36Sopenharmony_ciPMD_BIT_FUNC(mkclean, &= ~L_PMD_SECT_DIRTY); 20862306a36Sopenharmony_ciPMD_BIT_FUNC(mkyoung, |= PMD_SECT_AF); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci#define pmd_mkhuge(pmd) (__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT)) 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci#define pmd_pfn(pmd) (((pmd_val(pmd) & PMD_MASK) & PHYS_MASK) >> PAGE_SHIFT) 21362306a36Sopenharmony_ci#define pfn_pmd(pfn,prot) (__pmd(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))) 21462306a36Sopenharmony_ci#define mk_pmd(page,prot) pfn_pmd(page_to_pfn(page),prot) 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci/* No hardware dirty/accessed bits -- generic_pmdp_establish() fits */ 21762306a36Sopenharmony_ci#define pmdp_establish generic_pmdp_establish 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci/* represent a notpresent pmd by faulting entry, this is used by pmdp_invalidate */ 22062306a36Sopenharmony_cistatic inline pmd_t pmd_mkinvalid(pmd_t pmd) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci return __pmd(pmd_val(pmd) & ~L_PMD_SECT_VALID); 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci const pmdval_t mask = PMD_SECT_USER | PMD_SECT_XN | L_PMD_SECT_RDONLY | 22862306a36Sopenharmony_ci L_PMD_SECT_VALID | L_PMD_SECT_NONE; 22962306a36Sopenharmony_ci pmd_val(pmd) = (pmd_val(pmd) & ~mask) | (pgprot_val(newprot) & mask); 23062306a36Sopenharmony_ci return pmd; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic inline void set_pmd_at(struct mm_struct *mm, unsigned long addr, 23462306a36Sopenharmony_ci pmd_t *pmdp, pmd_t pmd) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci BUG_ON(addr >= TASK_SIZE); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* create a faulting entry if PROT_NONE protected */ 23962306a36Sopenharmony_ci if (pmd_val(pmd) & L_PMD_SECT_NONE) 24062306a36Sopenharmony_ci pmd_val(pmd) &= ~L_PMD_SECT_VALID; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if (pmd_write(pmd) && pmd_dirty(pmd)) 24362306a36Sopenharmony_ci pmd_val(pmd) &= ~PMD_SECT_AP2; 24462306a36Sopenharmony_ci else 24562306a36Sopenharmony_ci pmd_val(pmd) |= PMD_SECT_AP2; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci *pmdp = __pmd(pmd_val(pmd) | PMD_SECT_nG); 24862306a36Sopenharmony_ci flush_pmd_entry(pmdp); 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci#endif /* __ASSEMBLY__ */ 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci#endif /* _ASM_PGTABLE_3LEVEL_H */ 254