xref: /linux-6.15/arch/arm/include/asm/pgalloc.h (revision 1c2f7d14)
1d2912cb1SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */
24baa9922SRussell King /*
34baa9922SRussell King  *  arch/arm/include/asm/pgalloc.h
44baa9922SRussell King  *
54baa9922SRussell King  *  Copyright (C) 2000-2001 Russell King
64baa9922SRussell King  */
74baa9922SRussell King #ifndef _ASMARM_PGALLOC_H
84baa9922SRussell King #define _ASMARM_PGALLOC_H
94baa9922SRussell King 
1097594b0fSUwe Kleine-König #include <linux/pagemap.h>
1197594b0fSUwe Kleine-König 
124baa9922SRussell King #include <asm/domain.h>
134baa9922SRussell King #include <asm/pgtable-hwdef.h>
144baa9922SRussell King #include <asm/processor.h>
154baa9922SRussell King #include <asm/cacheflush.h>
164baa9922SRussell King #include <asm/tlbflush.h>
174baa9922SRussell King 
184baa9922SRussell King #ifdef CONFIG_MMU
194baa9922SRussell King 
204baa9922SRussell King #define _PAGE_USER_TABLE	(PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_USER))
214baa9922SRussell King #define _PAGE_KERNEL_TABLE	(PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_KERNEL))
224baa9922SRussell King 
23da028779SCatalin Marinas #ifdef CONFIG_ARM_LPAE
24*5615f69bSLinus Walleij #define PGD_SIZE		(PTRS_PER_PGD * sizeof(pgd_t))
25da028779SCatalin Marinas 
pud_populate(struct mm_struct * mm,pud_t * pud,pmd_t * pmd)26da028779SCatalin Marinas static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
27da028779SCatalin Marinas {
28da028779SCatalin Marinas 	set_pud(pud, __pud(__pa(pmd) | PMD_TYPE_TABLE));
29da028779SCatalin Marinas }
30da028779SCatalin Marinas 
31da028779SCatalin Marinas #else	/* !CONFIG_ARM_LPAE */
32*5615f69bSLinus Walleij #define PGD_SIZE		(PAGE_SIZE << 2)
33da028779SCatalin Marinas 
344baa9922SRussell King /*
354baa9922SRussell King  * Since we have only two-level page tables, these are trivial
364baa9922SRussell King  */
374baa9922SRussell King #define pmd_alloc_one(mm,addr)		({ BUG(); ((pmd_t *)2); })
384baa9922SRussell King #define pmd_free(mm, pmd)		do { } while (0)
39*5615f69bSLinus Walleij #ifdef CONFIG_KASAN
40*5615f69bSLinus Walleij /* The KASan core unconditionally calls pud_populate() on all architectures */
41*5615f69bSLinus Walleij #define pud_populate(mm,pmd,pte)	do { } while (0)
42*5615f69bSLinus Walleij #else
43a32618d2SRussell King #define pud_populate(mm,pmd,pte)	BUG()
44*5615f69bSLinus Walleij #endif
45da028779SCatalin Marinas #endif	/* CONFIG_ARM_LPAE */
46da028779SCatalin Marinas 
47b0d03745SRussell King extern pgd_t *pgd_alloc(struct mm_struct *mm);
48b0d03745SRussell King extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
494baa9922SRussell King 
clean_pte_table(pte_t * pte)50d30e45eeSRussell King static inline void clean_pte_table(pte_t *pte)
51d30e45eeSRussell King {
52d30e45eeSRussell King 	clean_dcache_area(pte + PTE_HWTABLE_PTRS, PTE_HWTABLE_SIZE);
53d30e45eeSRussell King }
54d30e45eeSRussell King 
554baa9922SRussell King /*
564baa9922SRussell King  * Allocate one PTE table.
574baa9922SRussell King  *
584baa9922SRussell King  * This actually allocates two hardware PTE tables, but we wrap this up
594baa9922SRussell King  * into one table thus:
604baa9922SRussell King  *
614baa9922SRussell King  *  +------------+
624baa9922SRussell King  *  | Linux pt 0 |
634baa9922SRussell King  *  +------------+
644baa9922SRussell King  *  | Linux pt 1 |
654baa9922SRussell King  *  +------------+
66d30e45eeSRussell King  *  |  h/w pt 0  |
67d30e45eeSRussell King  *  +------------+
68d30e45eeSRussell King  *  |  h/w pt 1  |
69d30e45eeSRussell King  *  +------------+
704baa9922SRussell King  */
7128bcf593SMike Rapoport 
7228bcf593SMike Rapoport #define __HAVE_ARCH_PTE_ALLOC_ONE_KERNEL
7328bcf593SMike Rapoport #define __HAVE_ARCH_PTE_ALLOC_ONE
74f9cb654cSMike Rapoport #define __HAVE_ARCH_PGD_FREE
7528bcf593SMike Rapoport #include <asm-generic/pgalloc.h>
7628bcf593SMike Rapoport 
774baa9922SRussell King static inline pte_t *
pte_alloc_one_kernel(struct mm_struct * mm)784cf58924SJoel Fernandes (Google) pte_alloc_one_kernel(struct mm_struct *mm)
794baa9922SRussell King {
8028bcf593SMike Rapoport 	pte_t *pte = __pte_alloc_one_kernel(mm);
814baa9922SRussell King 
82d30e45eeSRussell King 	if (pte)
83d30e45eeSRussell King 		clean_pte_table(pte);
844baa9922SRussell King 
854baa9922SRussell King 	return pte;
864baa9922SRussell King }
874baa9922SRussell King 
8828bcf593SMike Rapoport #ifdef CONFIG_HIGHPTE
8928bcf593SMike Rapoport #define PGTABLE_HIGHMEM __GFP_HIGHMEM
9028bcf593SMike Rapoport #else
9128bcf593SMike Rapoport #define PGTABLE_HIGHMEM 0
9228bcf593SMike Rapoport #endif
9328bcf593SMike Rapoport 
944baa9922SRussell King static inline pgtable_t
pte_alloc_one(struct mm_struct * mm)954cf58924SJoel Fernandes (Google) pte_alloc_one(struct mm_struct *mm)
964baa9922SRussell King {
974baa9922SRussell King 	struct page *pte;
984baa9922SRussell King 
9928bcf593SMike Rapoport 	pte = __pte_alloc_one(mm, GFP_PGTABLE_USER | PGTABLE_HIGHMEM);
100affce508SKirill A. Shutemov 	if (!pte)
101affce508SKirill A. Shutemov 		return NULL;
102d30e45eeSRussell King 	if (!PageHighMem(pte))
103d30e45eeSRussell King 		clean_pte_table(page_address(pte));
1044baa9922SRussell King 	return pte;
1054baa9922SRussell King }
1064baa9922SRussell King 
__pmd_populate(pmd_t * pmdp,phys_addr_t pte,pmdval_t prot)10797092e0cSRussell King static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t pte,
108442e70c0SCatalin Marinas 				  pmdval_t prot)
1094baa9922SRussell King {
110442e70c0SCatalin Marinas 	pmdval_t pmdval = (pte + PTE_HWTABLE_OFF) | prot;
1114baa9922SRussell King 	pmdp[0] = __pmd(pmdval);
112da028779SCatalin Marinas #ifndef CONFIG_ARM_LPAE
1134baa9922SRussell King 	pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));
114da028779SCatalin Marinas #endif
1154baa9922SRussell King 	flush_pmd_entry(pmdp);
1164baa9922SRussell King }
1174baa9922SRussell King 
1184baa9922SRussell King /*
1194baa9922SRussell King  * Populate the pmdp entry with a pointer to the pte.  This pmd is part
1204baa9922SRussell King  * of the mm address space.
1214baa9922SRussell King  *
1224baa9922SRussell King  * Ensure that we always set both PMD entries.
1234baa9922SRussell King  */
1244baa9922SRussell King static inline void
pmd_populate_kernel(struct mm_struct * mm,pmd_t * pmdp,pte_t * ptep)1254baa9922SRussell King pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep)
1264baa9922SRussell King {
1274baa9922SRussell King 	/*
128d30e45eeSRussell King 	 * The pmd must be loaded with the physical address of the PTE table
1294baa9922SRussell King 	 */
130d30e45eeSRussell King 	__pmd_populate(pmdp, __pa(ptep), _PAGE_KERNEL_TABLE);
1314baa9922SRussell King }
1324baa9922SRussell King 
1334baa9922SRussell King static inline void
pmd_populate(struct mm_struct * mm,pmd_t * pmdp,pgtable_t ptep)1344baa9922SRussell King pmd_populate(struct mm_struct *mm, pmd_t *pmdp, pgtable_t ptep)
1354baa9922SRussell King {
1361d4d3715SJungseung Lee 	extern pmdval_t user_pmd_table;
1371d4d3715SJungseung Lee 	pmdval_t prot;
1381d4d3715SJungseung Lee 
1391d4d3715SJungseung Lee 	if (__LINUX_ARM_ARCH__ >= 6 && !IS_ENABLED(CONFIG_ARM_LPAE))
1401d4d3715SJungseung Lee 		prot = user_pmd_table;
1411d4d3715SJungseung Lee 	else
1421d4d3715SJungseung Lee 		prot = _PAGE_USER_TABLE;
1431d4d3715SJungseung Lee 
1441d4d3715SJungseung Lee 	__pmd_populate(pmdp, page_to_phys(ptep), prot);
1454baa9922SRussell King }
1464baa9922SRussell King 
1474baa9922SRussell King #endif /* CONFIG_MMU */
1484baa9922SRussell King 
1494baa9922SRussell King #endif
150