xref: /OK3568_Linux_fs/kernel/arch/arm/include/asm/pgalloc.h (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0-only */
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  arch/arm/include/asm/pgalloc.h
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  Copyright (C) 2000-2001 Russell King
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun #ifndef _ASMARM_PGALLOC_H
8*4882a593Smuzhiyun #define _ASMARM_PGALLOC_H
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/pagemap.h>
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <asm/domain.h>
13*4882a593Smuzhiyun #include <asm/pgtable-hwdef.h>
14*4882a593Smuzhiyun #include <asm/processor.h>
15*4882a593Smuzhiyun #include <asm/cacheflush.h>
16*4882a593Smuzhiyun #include <asm/tlbflush.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #ifdef CONFIG_MMU
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #define _PAGE_USER_TABLE	(PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_USER))
21*4882a593Smuzhiyun #define _PAGE_KERNEL_TABLE	(PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_KERNEL))
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #ifdef CONFIG_ARM_LPAE
24*4882a593Smuzhiyun 
pud_populate(struct mm_struct * mm,pud_t * pud,pmd_t * pmd)25*4882a593Smuzhiyun static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun 	set_pud(pud, __pud(__pa(pmd) | PMD_TYPE_TABLE));
28*4882a593Smuzhiyun }
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #else	/* !CONFIG_ARM_LPAE */
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun /*
33*4882a593Smuzhiyun  * Since we have only two-level page tables, these are trivial
34*4882a593Smuzhiyun  */
35*4882a593Smuzhiyun #define pmd_alloc_one(mm,addr)		({ BUG(); ((pmd_t *)2); })
36*4882a593Smuzhiyun #define pmd_free(mm, pmd)		do { } while (0)
37*4882a593Smuzhiyun #define pud_populate(mm,pmd,pte)	BUG()
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #endif	/* CONFIG_ARM_LPAE */
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun extern pgd_t *pgd_alloc(struct mm_struct *mm);
42*4882a593Smuzhiyun extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
43*4882a593Smuzhiyun 
clean_pte_table(pte_t * pte)44*4882a593Smuzhiyun static inline void clean_pte_table(pte_t *pte)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun 	clean_dcache_area(pte + PTE_HWTABLE_PTRS, PTE_HWTABLE_SIZE);
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun /*
50*4882a593Smuzhiyun  * Allocate one PTE table.
51*4882a593Smuzhiyun  *
52*4882a593Smuzhiyun  * This actually allocates two hardware PTE tables, but we wrap this up
53*4882a593Smuzhiyun  * into one table thus:
54*4882a593Smuzhiyun  *
55*4882a593Smuzhiyun  *  +------------+
56*4882a593Smuzhiyun  *  | Linux pt 0 |
57*4882a593Smuzhiyun  *  +------------+
58*4882a593Smuzhiyun  *  | Linux pt 1 |
59*4882a593Smuzhiyun  *  +------------+
60*4882a593Smuzhiyun  *  |  h/w pt 0  |
61*4882a593Smuzhiyun  *  +------------+
62*4882a593Smuzhiyun  *  |  h/w pt 1  |
63*4882a593Smuzhiyun  *  +------------+
64*4882a593Smuzhiyun  */
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun #define __HAVE_ARCH_PTE_ALLOC_ONE_KERNEL
67*4882a593Smuzhiyun #define __HAVE_ARCH_PTE_ALLOC_ONE
68*4882a593Smuzhiyun #define __HAVE_ARCH_PGD_FREE
69*4882a593Smuzhiyun #include <asm-generic/pgalloc.h>
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun static inline pte_t *
pte_alloc_one_kernel(struct mm_struct * mm)72*4882a593Smuzhiyun pte_alloc_one_kernel(struct mm_struct *mm)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun 	pte_t *pte = __pte_alloc_one_kernel(mm);
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	if (pte)
77*4882a593Smuzhiyun 		clean_pte_table(pte);
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	return pte;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun #ifdef CONFIG_HIGHPTE
83*4882a593Smuzhiyun #define PGTABLE_HIGHMEM __GFP_HIGHMEM
84*4882a593Smuzhiyun #else
85*4882a593Smuzhiyun #define PGTABLE_HIGHMEM 0
86*4882a593Smuzhiyun #endif
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun static inline pgtable_t
pte_alloc_one(struct mm_struct * mm)89*4882a593Smuzhiyun pte_alloc_one(struct mm_struct *mm)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	struct page *pte;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	pte = __pte_alloc_one(mm, GFP_PGTABLE_USER | PGTABLE_HIGHMEM);
94*4882a593Smuzhiyun 	if (!pte)
95*4882a593Smuzhiyun 		return NULL;
96*4882a593Smuzhiyun 	if (!PageHighMem(pte))
97*4882a593Smuzhiyun 		clean_pte_table(page_address(pte));
98*4882a593Smuzhiyun 	return pte;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun 
__pmd_populate(pmd_t * pmdp,phys_addr_t pte,pmdval_t prot)101*4882a593Smuzhiyun static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t pte,
102*4882a593Smuzhiyun 				  pmdval_t prot)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun 	pmdval_t pmdval = (pte + PTE_HWTABLE_OFF) | prot;
105*4882a593Smuzhiyun 	pmdp[0] = __pmd(pmdval);
106*4882a593Smuzhiyun #ifndef CONFIG_ARM_LPAE
107*4882a593Smuzhiyun 	pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));
108*4882a593Smuzhiyun #endif
109*4882a593Smuzhiyun 	flush_pmd_entry(pmdp);
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun /*
113*4882a593Smuzhiyun  * Populate the pmdp entry with a pointer to the pte.  This pmd is part
114*4882a593Smuzhiyun  * of the mm address space.
115*4882a593Smuzhiyun  *
116*4882a593Smuzhiyun  * Ensure that we always set both PMD entries.
117*4882a593Smuzhiyun  */
118*4882a593Smuzhiyun static inline void
pmd_populate_kernel(struct mm_struct * mm,pmd_t * pmdp,pte_t * ptep)119*4882a593Smuzhiyun pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun 	/*
122*4882a593Smuzhiyun 	 * The pmd must be loaded with the physical address of the PTE table
123*4882a593Smuzhiyun 	 */
124*4882a593Smuzhiyun 	__pmd_populate(pmdp, __pa(ptep), _PAGE_KERNEL_TABLE);
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun static inline void
pmd_populate(struct mm_struct * mm,pmd_t * pmdp,pgtable_t ptep)128*4882a593Smuzhiyun pmd_populate(struct mm_struct *mm, pmd_t *pmdp, pgtable_t ptep)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun 	extern pmdval_t user_pmd_table;
131*4882a593Smuzhiyun 	pmdval_t prot;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	if (__LINUX_ARM_ARCH__ >= 6 && !IS_ENABLED(CONFIG_ARM_LPAE))
134*4882a593Smuzhiyun 		prot = user_pmd_table;
135*4882a593Smuzhiyun 	else
136*4882a593Smuzhiyun 		prot = _PAGE_USER_TABLE;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	__pmd_populate(pmdp, page_to_phys(ptep), prot);
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun #define pmd_pgtable(pmd) pmd_page(pmd)
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun #endif /* CONFIG_MMU */
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun #endif
145